Compare commits
	
		
			8 Commits
		
	
	
		
			3026d22750
			...
			c606432be2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | c606432be2 | ||
|   | 6b6ba1d712 | ||
|   | dcb261fd84 | ||
|   | 4f74136d97 | ||
|   | 8cd5e588a0 | ||
|   | c54e005b62 | ||
|   | 938391ae09 | ||
|   | 0c18b976d7 | 
							
								
								
									
										5
									
								
								sketching/may_2025/print.dm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								sketching/may_2025/print.dm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | ns std::core; | ||||||
|  | 
 | ||||||
|  | platform fn print(msg: Any) -> Void; | ||||||
|  | 
 | ||||||
|  | platform fn println(msg: Any) -> Void; | ||||||
							
								
								
									
										3
									
								
								sketching/may_2025/use.dm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								sketching/may_2025/use.dm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | use std::core::println; | ||||||
|  | use std::core::*; | ||||||
|  | use std::core::{print, println}; | ||||||
							
								
								
									
										145
									
								
								src/ast/build.rs
									
									
									
									
									
								
							
							
						
						
									
										145
									
								
								src/ast/build.rs
									
									
									
									
									
								
							| @ -15,8 +15,12 @@ fn expect_and_use<T>( | |||||||
|     f(file_id, pair) |     f(file_id, pair) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn build_ast(file_id: usize, compilation_unit_pair: Pair<Rule>) -> CompilationUnit { | pub fn build_ast( | ||||||
|     build_compilation_unit(file_id, compilation_unit_pair) |     file_name: &str, | ||||||
|  |     file_id: usize, | ||||||
|  |     compilation_unit_pair: Pair<Rule>, | ||||||
|  | ) -> CompilationUnit { | ||||||
|  |     build_compilation_unit(file_name, file_id, compilation_unit_pair) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn build_identifier(file_id: usize, identifier_pair: Pair<Rule>) -> Identifier { | fn build_identifier(file_id: usize, identifier_pair: Pair<Rule>) -> Identifier { | ||||||
| @ -293,8 +297,13 @@ fn build_references(file_id: usize, ref_list_pair: Pair<Rule>) -> References { | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn build_compilation_unit(file_id: usize, compilation_unit_pair: Pair<Rule>) -> CompilationUnit { | fn build_compilation_unit( | ||||||
|  |     file_name: &str, | ||||||
|  |     file_id: usize, | ||||||
|  |     compilation_unit_pair: Pair<Rule>, | ||||||
|  | ) -> CompilationUnit { | ||||||
|     let mut namespace = None; |     let mut namespace = None; | ||||||
|  |     let mut use_statements = vec![]; | ||||||
|     let mut declarations = vec![]; |     let mut declarations = vec![]; | ||||||
| 
 | 
 | ||||||
|     for inner_pair in compilation_unit_pair.into_inner() { |     for inner_pair in compilation_unit_pair.into_inner() { | ||||||
| @ -302,16 +311,22 @@ fn build_compilation_unit(file_id: usize, compilation_unit_pair: Pair<Rule>) -> | |||||||
|             Rule::Namespace => { |             Rule::Namespace => { | ||||||
|                 namespace = Some(build_namespace(file_id, inner_pair)); |                 namespace = Some(build_namespace(file_id, inner_pair)); | ||||||
|             } |             } | ||||||
|  |             Rule::UseStatement => { | ||||||
|  |                 use_statements.push(build_use_statement(file_id, inner_pair)); | ||||||
|  |             } | ||||||
|             Rule::ModuleLevelDeclaration => { |             Rule::ModuleLevelDeclaration => { | ||||||
|                 declarations.push(build_module_level_declaration(file_id, inner_pair)); |                 declarations.push(build_module_level_declaration(file_id, inner_pair)); | ||||||
|             } |             } | ||||||
|             Rule::EOI => {} |             Rule::Semicolon | Rule::EOI => {} | ||||||
|             _ => unreachable!(), |             _ => unreachable!(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     CompilationUnit { |     CompilationUnit { | ||||||
|  |         file_name: file_name.to_string(), | ||||||
|  |         file_id, | ||||||
|         namespace, |         namespace, | ||||||
|  |         use_statements, | ||||||
|         declarations, |         declarations, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -579,7 +594,46 @@ fn build_platform_function_declaration( | |||||||
|     file_id: usize, |     file_id: usize, | ||||||
|     platform_function_pair: Pair<Rule>, |     platform_function_pair: Pair<Rule>, | ||||||
| ) -> PlatformFunctionDeclaration { | ) -> PlatformFunctionDeclaration { | ||||||
|     todo!() |     let mut is_public = false; | ||||||
|  |     let mut modifier = None; | ||||||
|  |     let mut generics = GenericParameters::default(); | ||||||
|  |     let mut identifier = None; | ||||||
|  |     let mut parameters = Parameters::default(); | ||||||
|  |     let mut return_type = None; | ||||||
|  | 
 | ||||||
|  |     for inner_pair in platform_function_pair.into_inner() { | ||||||
|  |         match inner_pair.as_rule() { | ||||||
|  |             Rule::Pub => { | ||||||
|  |                 is_public = true; | ||||||
|  |             } | ||||||
|  |             Rule::FunctionModifier => { | ||||||
|  |                 modifier = Some(build_function_modifier(file_id, inner_pair)); | ||||||
|  |             } | ||||||
|  |             Rule::Platform | Rule::Fn => {} | ||||||
|  |             Rule::GenericParameters => { | ||||||
|  |                 generics = build_generic_parameters(file_id, inner_pair); | ||||||
|  |             } | ||||||
|  |             Rule::Identifier => { | ||||||
|  |                 identifier = Some(build_identifier(file_id, inner_pair)); | ||||||
|  |             } | ||||||
|  |             Rule::Parameters => { | ||||||
|  |                 parameters = build_parameters(file_id, inner_pair); | ||||||
|  |             } | ||||||
|  |             Rule::ReturnType => { | ||||||
|  |                 return_type = Some(build_return_type(file_id, inner_pair)); | ||||||
|  |             } | ||||||
|  |             _ => unreachable!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     PlatformFunctionDeclaration { | ||||||
|  |         is_public, | ||||||
|  |         modifier, | ||||||
|  |         generics, | ||||||
|  |         identifier: identifier.unwrap(), | ||||||
|  |         parameters, | ||||||
|  |         return_type: return_type.unwrap(), | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn build_interface_function_declaration( | fn build_interface_function_declaration( | ||||||
| @ -739,6 +793,59 @@ fn build_field_declaration(file_id: usize, field_pair: Pair<Rule>) -> FieldDecla | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn build_use_statement(file_id: usize, use_statement_pair: Pair<Rule>) -> UseStatement { | ||||||
|  |     let as_span = use_statement_pair.as_span(); | ||||||
|  |     let mut inner = use_statement_pair.into_inner(); | ||||||
|  |     let inner_length = inner.len(); | ||||||
|  | 
 | ||||||
|  |     inner.next().unwrap(); // use
 | ||||||
|  | 
 | ||||||
|  |     let mut identifiers = vec![]; | ||||||
|  |     let mut last = None; | ||||||
|  | 
 | ||||||
|  |     for (i, inner_pair) in inner.into_iter().enumerate() { | ||||||
|  |         if i != inner_length - 2 { | ||||||
|  |             identifiers.push(expect_and_use( | ||||||
|  |                 file_id, | ||||||
|  |                 inner_pair, | ||||||
|  |                 Rule::Identifier, | ||||||
|  |                 build_identifier, | ||||||
|  |             )) | ||||||
|  |         } else { | ||||||
|  |             last = Some(match inner_pair.as_rule() { | ||||||
|  |                 Rule::Identifier => UseStatementLast::Identifier(Rc::new(RefCell::new( | ||||||
|  |                     build_identifier(file_id, inner_pair), | ||||||
|  |                 ))), | ||||||
|  |                 Rule::Star => UseStatementLast::Star, | ||||||
|  |                 Rule::UseList => UseStatementLast::Identifiers( | ||||||
|  |                     inner_pair | ||||||
|  |                         .into_inner() | ||||||
|  |                         .map(|identifier_pair| { | ||||||
|  |                             Rc::new(RefCell::new(expect_and_use( | ||||||
|  |                                 file_id, | ||||||
|  |                                 identifier_pair, | ||||||
|  |                                 Rule::Identifier, | ||||||
|  |                                 build_identifier, | ||||||
|  |                             ))) | ||||||
|  |                         }) | ||||||
|  |                         .collect(), | ||||||
|  |                 ), | ||||||
|  |                 _ => unreachable!(), | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     UseStatement::new( | ||||||
|  |         identifiers, | ||||||
|  |         last.unwrap(), | ||||||
|  |         file_id, | ||||||
|  |         Range { | ||||||
|  |             start: as_span.start(), | ||||||
|  |             end: as_span.end(), | ||||||
|  |         }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn build_block_statement(file_id: usize, block_statement_pair: Pair<Rule>) -> BlockStatement { | fn build_block_statement(file_id: usize, block_statement_pair: Pair<Rule>) -> BlockStatement { | ||||||
|     let mut statements = vec![]; |     let mut statements = vec![]; | ||||||
|     let mut expression = None; |     let mut expression = None; | ||||||
| @ -1558,7 +1665,7 @@ mod tests { | |||||||
|             if pairs.as_str().trim() != src.trim() { |             if pairs.as_str().trim() != src.trim() { | ||||||
|                 panic!("Parsing did not consume entire input."); |                 panic!("Parsing did not consume entire input."); | ||||||
|             } |             } | ||||||
|             let ast = build_ast(0, pairs.next().unwrap()); |             let ast = build_ast("test.dm", 0, pairs.next().unwrap()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1688,7 +1795,7 @@ mod tests { | |||||||
|             } |             } | ||||||
|         "})
 |         "})
 | ||||||
|     } |     } | ||||||
|     
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn if_with_call_condition() { |     fn if_with_call_condition() { | ||||||
|         assert_builds(indoc! {" |         assert_builds(indoc! {" | ||||||
| @ -1699,7 +1806,7 @@ mod tests { | |||||||
|             } |             } | ||||||
|         "})
 |         "})
 | ||||||
|     } |     } | ||||||
|     
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn while_with_call_condition() { |     fn while_with_call_condition() { | ||||||
|         assert_builds(indoc! {" |         assert_builds(indoc! {" | ||||||
| @ -1710,7 +1817,7 @@ mod tests { | |||||||
|             } |             } | ||||||
|         "})
 |         "})
 | ||||||
|     } |     } | ||||||
|     
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn for_with_call_iterator() { |     fn for_with_call_iterator() { | ||||||
|         assert_builds(indoc! {" |         assert_builds(indoc! {" | ||||||
| @ -1721,4 +1828,24 @@ mod tests { | |||||||
|             } |             } | ||||||
|         "})
 |         "})
 | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn use_statement() { | ||||||
|  |         assert_builds("use std::core::println;"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn use_star() { | ||||||
|  |         assert_builds("use std::core::*;"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn use_list() { | ||||||
|  |         assert_builds("use std::core::{print, println};"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn platform_function() { | ||||||
|  |         assert_builds("platform fn println(msg: Any) -> Void;"); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										100
									
								
								src/ast/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								src/ast/mod.rs
									
									
									
									
									
								
							| @ -1,6 +1,10 @@ | |||||||
|  | use crate::ast::named::Named; | ||||||
| use crate::name_analysis::symbol::Symbol; | use crate::name_analysis::symbol::Symbol; | ||||||
| use pest::Parser; | use pest::Parser; | ||||||
|  | use std::borrow::Cow; | ||||||
|  | use std::cell::RefCell; | ||||||
| use std::range::Range; | use std::range::Range; | ||||||
|  | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| pub mod build; | pub mod build; | ||||||
| pub mod named; | pub mod named; | ||||||
| @ -87,6 +91,10 @@ impl Identifier { | |||||||
|     pub fn symbol(&self) -> &Option<Symbol> { |     pub fn symbol(&self) -> &Option<Symbol> { | ||||||
|         &self.symbol |         &self.symbol | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn symbol_mut(&mut self) -> Option<Symbol> { | ||||||
|  |         self.symbol.clone() | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| @ -287,7 +295,10 @@ impl Default for References { | |||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct CompilationUnit { | pub struct CompilationUnit { | ||||||
|  |     pub file_name: String, | ||||||
|  |     pub file_id: usize, | ||||||
|     pub namespace: Option<FullyQualifiedName>, |     pub namespace: Option<FullyQualifiedName>, | ||||||
|  |     pub use_statements: Vec<UseStatement>, | ||||||
|     pub declarations: Vec<ModuleLevelDeclaration>, |     pub declarations: Vec<ModuleLevelDeclaration>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -448,6 +459,91 @@ pub struct FieldDeclaration { | |||||||
| 
 | 
 | ||||||
| // Statements
 | // Statements
 | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct UseStatement { | ||||||
|  |     pub identifiers: Vec<Identifier>, | ||||||
|  |     pub last: UseStatementLast, | ||||||
|  |     pub file_id: usize, | ||||||
|  |     pub range: Range<usize>, | ||||||
|  |     scope_id: Option<usize>, | ||||||
|  |     symbol: Option<Symbol>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct UseStatementImport<'a> { | ||||||
|  |     pub declared_name: String, | ||||||
|  |     pub fqn: String, | ||||||
|  |     pub identifier: &'a mut Identifier, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl UseStatement { | ||||||
|  |     pub fn new( | ||||||
|  |         identifiers: Vec<Identifier>, | ||||||
|  |         last: UseStatementLast, | ||||||
|  |         file_id: usize, | ||||||
|  |         range: Range<usize>, | ||||||
|  |     ) -> Self { | ||||||
|  |         UseStatement { | ||||||
|  |             identifiers, | ||||||
|  |             last, | ||||||
|  |             file_id, | ||||||
|  |             range, | ||||||
|  |             scope_id: None, | ||||||
|  |             symbol: None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn base_name(&self) -> Cow<'_, str> { | ||||||
|  |         use UseStatementLast::*; | ||||||
|  |         if self.identifiers.is_empty() { | ||||||
|  |             match &self.last { | ||||||
|  |                 Identifier(_) => Cow::from(""), | ||||||
|  |                 Star | Identifiers(_) => panic!(), // should never get here because of grammar
 | ||||||
|  |             } | ||||||
|  |         } else if self.identifiers.len() == 1 { | ||||||
|  |             self.identifiers[0].name() | ||||||
|  |         } else { | ||||||
|  |             let mut acc = String::new(); | ||||||
|  |             for (i, identifier) in self.identifiers.iter().enumerate() { | ||||||
|  |                 acc.push_str(&identifier.name()); | ||||||
|  |                 if i != self.identifiers.len() - 1 { | ||||||
|  |                     acc.push_str("::"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Cow::from(acc) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn is_star(&self) -> bool { | ||||||
|  |         match &self.last { | ||||||
|  |             UseStatementLast::Star => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn set_scope_id(&mut self, scope_id: usize) { | ||||||
|  |         self.scope_id = Some(scope_id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn scope_id(&self) -> Option<usize> { | ||||||
|  |         self.scope_id | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn set_symbol(&mut self, symbol: Symbol) { | ||||||
|  |         self.symbol = Some(symbol); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn symbol(&self) -> &Option<Symbol> { | ||||||
|  |         &self.symbol | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum UseStatementLast { | ||||||
|  |     Identifier(Rc<RefCell<Identifier>>), | ||||||
|  |     Identifiers(Vec<Rc<RefCell<Identifier>>>), | ||||||
|  |     Star, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct BlockStatement { | pub struct BlockStatement { | ||||||
|     pub statements: Vec<Statement>, |     pub statements: Vec<Statement>, | ||||||
| @ -556,8 +652,8 @@ pub struct PrefixExpression { | |||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct SuffixExpression { | pub struct SuffixExpression { | ||||||
|     expression: Box<Expression>, |     pub expression: Box<Expression>, | ||||||
|     operator: SuffixUnaryOperator, |     pub operator: SuffixUnaryOperator, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
|  | |||||||
| @ -282,6 +282,9 @@ impl PrettyPrint for CompilationUnit { | |||||||
|             namespace.pretty_print(writer)?; |             namespace.pretty_print(writer)?; | ||||||
|             writer.decrease_indent(); |             writer.decrease_indent(); | ||||||
|         } |         } | ||||||
|  |         for use_statement in &self.use_statements { | ||||||
|  |             use_statement.pretty_print(writer)?; | ||||||
|  |         } | ||||||
|         for declaration in &self.declarations { |         for declaration in &self.declarations { | ||||||
|             declaration.pretty_print(writer)?; |             declaration.pretty_print(writer)?; | ||||||
|         } |         } | ||||||
| @ -585,6 +588,39 @@ impl PrettyPrint for FieldDeclaration { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl PrettyPrint for UseStatement { | ||||||
|  |     fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { | ||||||
|  |         writer.writeln_indented("UseStatement")?; | ||||||
|  |         writer.increase_indent(); | ||||||
|  |         for identifier in &self.identifiers { | ||||||
|  |             identifier.pretty_print(writer)?; | ||||||
|  |         } | ||||||
|  |         self.last.pretty_print(writer)?; | ||||||
|  |         writer.decrease_indent(); | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl PrettyPrint for UseStatementLast { | ||||||
|  |     fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { | ||||||
|  |         writer.writeln_indented("UseStatementLast")?; | ||||||
|  |         writer.increase_indent(); | ||||||
|  |         match self { | ||||||
|  |             UseStatementLast::Identifier(i) => i.borrow().pretty_print(writer)?, | ||||||
|  |             UseStatementLast::Identifiers(is) => { | ||||||
|  |                 for i in is { | ||||||
|  |                     i.borrow().pretty_print(writer)?; | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             UseStatementLast::Star => { | ||||||
|  |                 writer.writeln_indented("Star")?; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         writer.decrease_indent(); | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl PrettyPrint for BlockStatement { | impl PrettyPrint for BlockStatement { | ||||||
|     fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { |     fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { | ||||||
|         writer.writeln_indented("BlockStatement")?; |         writer.writeln_indented("BlockStatement")?; | ||||||
|  | |||||||
| @ -373,7 +373,11 @@ impl Unparse for CompilationUnit { | |||||||
|         if let Some(namespace) = &self.namespace { |         if let Some(namespace) = &self.namespace { | ||||||
|             writer.write("ns ")?; |             writer.write("ns ")?; | ||||||
|             namespace.unparse(writer)?; |             namespace.unparse(writer)?; | ||||||
|             writer.write("\n\n")?; |             writer.write(";\n\n")?; | ||||||
|  |         } | ||||||
|  |         for use_statement in &self.use_statements { | ||||||
|  |             use_statement.unparse(writer)?; | ||||||
|  |             writer.write(";\n")?; | ||||||
|         } |         } | ||||||
|         unparse_list(writer, "\n\n", &to_unparse_vec!(self.declarations))?; |         unparse_list(writer, "\n\n", &to_unparse_vec!(self.declarations))?; | ||||||
|         Ok(()) |         Ok(()) | ||||||
| @ -570,6 +574,7 @@ impl Unparse for PlatformFunctionDeclaration { | |||||||
|         self.parameters.unparse(writer)?; |         self.parameters.unparse(writer)?; | ||||||
|         writer.write(" ")?; |         writer.write(" ")?; | ||||||
|         self.return_type.unparse(writer)?; |         self.return_type.unparse(writer)?; | ||||||
|  |         writer.write(";")?; | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -722,6 +727,41 @@ impl Unparse for FieldDeclaration { | |||||||
| 
 | 
 | ||||||
| /* Statements */ | /* Statements */ | ||||||
| 
 | 
 | ||||||
|  | impl Unparse for UseStatement { | ||||||
|  |     fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { | ||||||
|  |         writer.write_indented("use ")?; | ||||||
|  |         for (i, identifier) in self.identifiers.iter().enumerate() { | ||||||
|  |             identifier.unparse(writer)?; | ||||||
|  |             if i != self.identifiers.len() - 2 { | ||||||
|  |                 // 2 because of use
 | ||||||
|  |                 writer.write("::")?; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         self.last.unparse(writer)?; | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Unparse for UseStatementLast { | ||||||
|  |     fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { | ||||||
|  |         match self { | ||||||
|  |             UseStatementLast::Star => writer.write("*"), | ||||||
|  |             UseStatementLast::Identifiers(identifiers) => { | ||||||
|  |                 writer.write("{")?; | ||||||
|  |                 for (i, identifier) in identifiers.iter().enumerate() { | ||||||
|  |                     identifier.borrow().unparse(writer)?; | ||||||
|  |                     if i != identifiers.len() - 1 { | ||||||
|  |                         writer.write(", ")?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 writer.write("}")?; | ||||||
|  |                 Ok(()) | ||||||
|  |             } | ||||||
|  |             UseStatementLast::Identifier(i) => i.borrow().unparse(writer), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl Unparse for BlockStatement { | impl Unparse for BlockStatement { | ||||||
|     fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { |     fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { | ||||||
|         writer.writeln_indented("{")?; |         writer.writeln_indented("{")?; | ||||||
|  | |||||||
| @ -45,11 +45,9 @@ fn main() { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Commands::NameAnalysis { paths } => { |         Commands::NameAnalysis { paths } => { | ||||||
|             for path in paths { |             let result = name_analysis(&paths); | ||||||
|                 let result = name_analysis(&path); |             if let Err(e) = result { | ||||||
|                 if let Err(e) = result { |                 eprintln!("{}", e) | ||||||
|                     eprintln!("{}", e); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -6,33 +6,41 @@ use deimos::name_analysis::analyze_names; | |||||||
| use deimos::name_analysis::symbol_table::SymbolTable; | use deimos::name_analysis::symbol_table::SymbolTable; | ||||||
| use deimos::parser::{DeimosParser, Rule}; | use deimos::parser::{DeimosParser, Rule}; | ||||||
| use pest::Parser; | use pest::Parser; | ||||||
| use std::path::Path; | use std::path::PathBuf; | ||||||
| 
 | 
 | ||||||
| pub fn name_analysis(path: &Path) -> Result<(), Box<dyn std::error::Error>> { | pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|     let src = std::fs::read_to_string(path).unwrap(); |     let mut compilation_units = vec![]; | ||||||
|     let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src); |  | ||||||
|     let mut files = SimpleFiles::new(); |     let mut files = SimpleFiles::new(); | ||||||
|     let file_id = files.add(path.display().to_string(), &src); |     
 | ||||||
|  |     for path in paths { | ||||||
|  |         let src = std::fs::read_to_string(path).unwrap(); | ||||||
|  |         let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src); | ||||||
|  |         let file_id = files.add(path.display().to_string(), src.clone()); // I don't love this clone
 | ||||||
| 
 | 
 | ||||||
|     match parse_result { |         match parse_result { | ||||||
|         Ok(mut pairs) => { |             Ok(mut pairs) => { | ||||||
|             let compilation_unit_pair = pairs.next().unwrap(); |                 let compilation_unit_pair = pairs.next().unwrap(); | ||||||
|             let mut compilation_unit = build_ast(file_id, compilation_unit_pair); |                 let compilation_unit = build_ast(&path.display().to_string(), file_id, compilation_unit_pair); | ||||||
|             let mut symbol_table = SymbolTable::new(); |                 compilation_units.push(compilation_unit); | ||||||
|             let diagnostics = analyze_names(file_id, &mut compilation_unit, &mut symbol_table); |                 Ok::<(), Box<dyn std::error::Error>>(()) | ||||||
|             if diagnostics.is_empty() { |  | ||||||
|                 println!("Name analysis complete."); |  | ||||||
|                 println!("Symbol table\n-------\n{}", symbol_table); |  | ||||||
|                 Ok(()) |  | ||||||
|             } else { |  | ||||||
|                 let writer = StandardStream::stderr(ColorChoice::Always); |  | ||||||
|                 let config = term::Config::default(); |  | ||||||
|                 for diagnostic in diagnostics { |  | ||||||
|                     term::emit(&mut writer.lock(), &config, &files, &diagnostic)?; |  | ||||||
|                 } |  | ||||||
|                 Ok(()) |  | ||||||
|             } |             } | ||||||
|         } |             Err(e) => Err(e.into()), | ||||||
|         Err(e) => Err(e.into()), |         }?; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     let mut symbol_table = SymbolTable::new(); | ||||||
|  |     
 | ||||||
|  |     let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table); | ||||||
|  |     if diagnostics.is_empty() { | ||||||
|  |         println!("Name analysis complete."); | ||||||
|  |         println!("Symbol table\n-------\n{}", symbol_table); | ||||||
|  |     } else { | ||||||
|  |         let writer = StandardStream::stderr(ColorChoice::Always); | ||||||
|  |         let config = term::Config::default(); | ||||||
|  |         for diagnostic in diagnostics { | ||||||
|  |             term::emit(&mut writer.lock(), &config, &files, &diagnostic)?; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     
 | ||||||
|  |     Ok(()) | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ pub fn pretty_print_parse(path: &PathBuf) { | |||||||
|     match parse_result { |     match parse_result { | ||||||
|         Ok(mut pairs) => { |         Ok(mut pairs) => { | ||||||
|             let compilation_unit_pair = pairs.next().unwrap(); |             let compilation_unit_pair = pairs.next().unwrap(); | ||||||
|             let compilation_unit = build_ast(0, compilation_unit_pair); |             let compilation_unit = build_ast(&path.display().to_string(), 0, compilation_unit_pair); | ||||||
|             let mut indent_writer = IndentWriter::new(0, "  ", Box::new(std::io::stdout())); |             let mut indent_writer = IndentWriter::new(0, "  ", Box::new(std::io::stdout())); | ||||||
|             compilation_unit |             compilation_unit | ||||||
|                 .pretty_print(&mut indent_writer) |                 .pretty_print(&mut indent_writer) | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ pub fn unparse(path: &PathBuf) { | |||||||
|     match parse_result { |     match parse_result { | ||||||
|         Ok(mut pairs) => { |         Ok(mut pairs) => { | ||||||
|             let compilation_unit_pair = pairs.next().unwrap(); |             let compilation_unit_pair = pairs.next().unwrap(); | ||||||
|             let compilation_unit = build_ast(0, compilation_unit_pair); |             let compilation_unit = build_ast(&path.display().to_string(), 0, compilation_unit_pair); | ||||||
|             let mut writer = IndentWriter::new(0, "  ", Box::new(std::io::stdout())); |             let mut writer = IndentWriter::new(0, "  ", Box::new(std::io::stdout())); | ||||||
|             compilation_unit |             compilation_unit | ||||||
|                 .unparse(&mut writer) |                 .unparse(&mut writer) | ||||||
|  | |||||||
| @ -6,5 +6,6 @@ pub mod module; | |||||||
| pub mod name_analysis; | pub mod name_analysis; | ||||||
| pub mod object_file; | pub mod object_file; | ||||||
| pub mod parser; | pub mod parser; | ||||||
|  | mod std_core; | ||||||
| pub mod util; | pub mod util; | ||||||
| pub mod vm; | pub mod vm; | ||||||
|  | |||||||
| @ -1,11 +1,13 @@ | |||||||
| use crate::ast::named::Named; | use crate::ast::named::Named; | ||||||
| use crate::ast::*; | use crate::ast::*; | ||||||
|  | use crate::diagnostic::DmDiagnostic; | ||||||
| use crate::name_analysis::fqn_context::FqnContext; | use crate::name_analysis::fqn_context::FqnContext; | ||||||
| use crate::name_analysis::symbol::{FunctionSymbol, ModuleSymbol, SourceDefinition, Symbol, VariableSymbol}; | use crate::name_analysis::symbol::*; | ||||||
| use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; | use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; | ||||||
| use crate::name_analysis::DiagnosticsContainer; |  | ||||||
| use codespan_reporting::diagnostic::{Diagnostic, Label}; | use codespan_reporting::diagnostic::{Diagnostic, Label}; | ||||||
|  | use std::cell::RefCell; | ||||||
| use std::range::Range; | use std::range::Range; | ||||||
|  | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| fn handle_insert_error( | fn handle_insert_error( | ||||||
|     err: SymbolInsertError, |     err: SymbolInsertError, | ||||||
| @ -13,48 +15,221 @@ fn handle_insert_error( | |||||||
|     error_file_id: usize, |     error_file_id: usize, | ||||||
|     error_range: Range<usize>, |     error_range: Range<usize>, | ||||||
|     symbol_types: &str, |     symbol_types: &str, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     match err { |     match err { | ||||||
|         SymbolInsertError::SymbolAlreadyDefined(s) => { |         SymbolInsertError::SymbolAlreadyDefined(s) => { | ||||||
|             let already_defined_definition = s.definition(); |             let mut diagnostic = Diagnostic::error() | ||||||
|  |                 .with_message(format!( | ||||||
|  |                     "{} symbol '{}' already defined in the current scope.", | ||||||
|  |                     symbol_types, error_symbol_name, | ||||||
|  |                 )) | ||||||
|  |                 .with_label( | ||||||
|  |                     Label::primary(error_file_id, error_range) | ||||||
|  |                         .with_message("Symbol duplicated here."), | ||||||
|  |                 ); | ||||||
| 
 | 
 | ||||||
|             diagnostics.add( |             if let Some(source_definition) = s.definition() { | ||||||
|                 Diagnostic::error() |                 diagnostic = diagnostic.with_label( | ||||||
|                     .with_message(format!( |                     Label::secondary(source_definition.file_id(), source_definition.range()) | ||||||
|                         "{} symbol '{}' already defined in the current scope.", |  | ||||||
|                         symbol_types, error_symbol_name, |  | ||||||
|                     )) |  | ||||||
|                     .with_label( |  | ||||||
|                         Label::primary(error_file_id, error_range) |  | ||||||
|                             .with_message("Symbol duplicated here."), |  | ||||||
|                     ) |  | ||||||
|                     .with_label( |  | ||||||
|                         Label::secondary( |  | ||||||
|                             already_defined_definition.file_id(), |  | ||||||
|                             already_defined_definition.range(), |  | ||||||
|                         ) |  | ||||||
|                         .with_message("Symbol defined here."), |                         .with_message("Symbol defined here."), | ||||||
|                     ), |                 ); | ||||||
|             ); |             } | ||||||
|  | 
 | ||||||
|  |             diagnostics.push(diagnostic); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(super) fn gather_module_level_declaration( | fn gather_fully_qualified_name( | ||||||
|  |     fully_qualified_name: &mut FullyQualifiedName, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  | ) { | ||||||
|  |     fully_qualified_name.set_scope_id(symbol_table.current_scope_id()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_type_use( | ||||||
|  |     type_use: &mut TypeUse, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     match type_use { | ||||||
|  |         TypeUse::Void => {} | ||||||
|  |         TypeUse::InterfaceOrClass(interface_or_class_type_use) => { | ||||||
|  |             gather_interface_or_class_type_use( | ||||||
|  |                 interface_or_class_type_use, | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         TypeUse::Tuple(tuple_type_use) => { | ||||||
|  |             gather_tuple_type_use(tuple_type_use, symbol_table, fqn_context, diagnostics); | ||||||
|  |         } | ||||||
|  |         TypeUse::Function(function_type_use) => { | ||||||
|  |             gather_function_type_use(function_type_use, symbol_table, fqn_context, diagnostics); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_interface_or_class_type_use( | ||||||
|  |     interface_or_class_type_use: &mut InterfaceOrClassTypeUse, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     gather_fully_qualified_name(&mut interface_or_class_type_use.fqn, symbol_table); | ||||||
|  |     gather_generic_arguments( | ||||||
|  |         &mut interface_or_class_type_use.generics, | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_tuple_type_use( | ||||||
|  |     tuple_type_use: &mut TupleTypeUse, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     for generic_argument in &mut tuple_type_use.arguments.0 { | ||||||
|  |         gather_type_use(generic_argument, symbol_table, fqn_context, diagnostics); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_function_type_use( | ||||||
|  |     function_type_use: &mut FunctionTypeUse, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_generic_arguments( | ||||||
|  |     generic_arguments: &mut GenericArguments, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     for argument in &mut generic_arguments.0 { | ||||||
|  |         gather_type_use(argument, symbol_table, fqn_context, diagnostics); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(super) fn gather_compilation_unit( | ||||||
|  |     compilation_unit: &mut CompilationUnit, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let mut fqn_context = FqnContext::new(); | ||||||
|  |     if let Some(namespace) = &compilation_unit.namespace { | ||||||
|  |         fqn_context.push(namespace.name().to_string()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     symbol_table.push_scope(&format!("FileScope({})", compilation_unit.file_name)); | ||||||
|  |     for use_statement in &mut compilation_unit.use_statements { | ||||||
|  |         gather_use_statement(use_statement, symbol_table, &mut fqn_context, diagnostics) | ||||||
|  |     } | ||||||
|  |     for declaration in &mut compilation_unit.declarations { | ||||||
|  |         gather_module_level_declaration(declaration, symbol_table, &mut fqn_context, diagnostics); | ||||||
|  |     } | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  |     assert_eq!(symbol_table.current_scope_id(), 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn handle_use_statement_import( | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     base_name: &str, | ||||||
|  |     identifier: Rc<RefCell<Identifier>>, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let borrowed_identifier = identifier.borrow(); | ||||||
|  |     let declared_name = borrowed_identifier.name().to_string(); | ||||||
|  |     let insert_result = symbol_table.insert_use_statement_symbol(UseStatementSymbol::new( | ||||||
|  |         &format!("{}::{}", base_name, &declared_name), | ||||||
|  |         &declared_name, | ||||||
|  |         Some(identifier.clone()), | ||||||
|  |     )); | ||||||
|  |     if let Err(err) = insert_result { | ||||||
|  |         handle_insert_error( | ||||||
|  |             err, | ||||||
|  |             &declared_name, | ||||||
|  |             borrowed_identifier.file_id, | ||||||
|  |             borrowed_identifier.range, | ||||||
|  |             "Use statement", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     drop(borrowed_identifier); | ||||||
|  |     let mut mutable_borrowed_identifier = identifier.borrow_mut(); | ||||||
|  |     mutable_borrowed_identifier.set_scope_id(symbol_table.current_scope_id()); | ||||||
|  | 
 | ||||||
|  |     let use_statement_symbol = symbol_table | ||||||
|  |         .lookup( | ||||||
|  |             &declared_name, | ||||||
|  |             mutable_borrowed_identifier.scope_id().unwrap(), | ||||||
|  |         ) | ||||||
|  |         .unwrap(); | ||||||
|  | 
 | ||||||
|  |     mutable_borrowed_identifier.set_symbol(use_statement_symbol); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_use_statement( | ||||||
|  |     use_statement: &mut UseStatement, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     if use_statement.is_star() { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  |     let base_name = use_statement.base_name().to_string(); | ||||||
|  |     match &mut use_statement.last { | ||||||
|  |         UseStatementLast::Identifier(identifier) => { | ||||||
|  |             handle_use_statement_import(symbol_table, &base_name, identifier.clone(), diagnostics) | ||||||
|  |         } | ||||||
|  |         UseStatementLast::Identifiers(identifiers) => { | ||||||
|  |             for identifier in identifiers { | ||||||
|  |                 handle_use_statement_import( | ||||||
|  |                     symbol_table, | ||||||
|  |                     &base_name, | ||||||
|  |                     identifier.clone(), | ||||||
|  |                     diagnostics, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         UseStatementLast::Star => panic!(), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_module_level_declaration( | ||||||
|     declaration: &mut ModuleLevelDeclaration, |     declaration: &mut ModuleLevelDeclaration, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     use ModuleLevelDeclaration::*; |     use ModuleLevelDeclaration::*; | ||||||
|     match declaration { |     match declaration { | ||||||
|         Module(module_declaration) => { |         Module(module_declaration) => { | ||||||
|             gather_module_declaration(module_declaration, symbol_table, fqn_context, diagnostics); |             gather_module_declaration(module_declaration, symbol_table, fqn_context, diagnostics); | ||||||
|         } |         } | ||||||
|  |         Class(class_declaration) => { | ||||||
|  |             gather_class_declaration(class_declaration, symbol_table, fqn_context, diagnostics) | ||||||
|  |         } | ||||||
|         Function(function_definition) => { |         Function(function_definition) => { | ||||||
|             gather_function_definition(function_definition, symbol_table, fqn_context, diagnostics) |             gather_function_definition(function_definition, symbol_table, fqn_context, diagnostics) | ||||||
|         } |         } | ||||||
|  |         PlatformFunction(platform_function_definition) => { | ||||||
|  |             gather_platform_function_definition( | ||||||
|  |                 platform_function_definition, | ||||||
|  |                 symbol_table, | ||||||
|  |                 fqn_context, | ||||||
|  |                 diagnostics, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|         _ => todo!(), |         _ => todo!(), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -63,7 +238,7 @@ fn gather_module_declaration( | |||||||
|     declaration: &mut ModuleDeclaration, |     declaration: &mut ModuleDeclaration, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     // 1. Add mod identifier symbol
 |     // 1. Add mod identifier symbol
 | ||||||
|     // 2. Update fqn context
 |     // 2. Update fqn context
 | ||||||
| @ -73,15 +248,12 @@ fn gather_module_declaration( | |||||||
| 
 | 
 | ||||||
|     let module_name = declaration.identifier.name(); |     let module_name = declaration.identifier.name(); | ||||||
| 
 | 
 | ||||||
|     let insert_result = symbol_table.insert( |     let insert_result = symbol_table.insert_module_symbol(ModuleSymbol::new( | ||||||
|  |         &fqn_context.resolve(&module_name), | ||||||
|         &module_name, |         &module_name, | ||||||
|         Symbol::Module(ModuleSymbol::new( |         declaration.is_public, | ||||||
|             &fqn_context.resolve(&module_name), |         Some(&declaration.identifier), | ||||||
|             &module_name, |     )); | ||||||
|             declaration.is_public, |  | ||||||
|             &declaration.identifier, |  | ||||||
|         )), |  | ||||||
|     ); |  | ||||||
| 
 | 
 | ||||||
|     if let Err(err) = insert_result { |     if let Err(err) = insert_result { | ||||||
|         handle_insert_error( |         handle_insert_error( | ||||||
| @ -96,31 +268,58 @@ fn gather_module_declaration( | |||||||
| 
 | 
 | ||||||
|     fqn_context.push(module_name.to_string()); |     fqn_context.push(module_name.to_string()); | ||||||
| 
 | 
 | ||||||
|     symbol_table.push_scope(&format!("Module '{}' Scope", module_name)); |     symbol_table.push_scope(&format!("ModuleScope({})", module_name)); | ||||||
|     for inner_declaration in &mut declaration.declarations { |     for inner_declaration in &mut declaration.declarations { | ||||||
|         gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics); |         gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics); | ||||||
|     } |     } | ||||||
|     symbol_table.pop_scope() |     symbol_table.pop_scope() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn gather_class_declaration( | ||||||
|  |     class_declaration: &mut ClassDeclaration, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let declared_name = class_declaration.identifier.name(); | ||||||
|  |     let resolved_name = fqn_context.resolve(&declared_name); | ||||||
|  | 
 | ||||||
|  |     let insert_result = symbol_table.insert_type_symbol(TypeSymbol::new( | ||||||
|  |         &resolved_name, | ||||||
|  |         &declared_name, | ||||||
|  |         class_declaration.is_public, | ||||||
|  |         Some(&class_declaration.identifier), | ||||||
|  |     )); | ||||||
|  |     if let Err(err) = insert_result { | ||||||
|  |         handle_insert_error( | ||||||
|  |             err, | ||||||
|  |             &declared_name, | ||||||
|  |             class_declaration.identifier.file_id, | ||||||
|  |             class_declaration.identifier.range, | ||||||
|  |             "interface/class", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // todo: scopes, generics, etc.
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn gather_function_definition( | fn gather_function_definition( | ||||||
|     function: &mut FunctionDefinition, |     function: &mut FunctionDefinition, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     let declared_name = function.identifier.name(); |     let declared_name = function.identifier.name(); | ||||||
|     let resolved_name = fqn_context.resolve(&declared_name); |     let resolved_name = fqn_context.resolve(&declared_name); | ||||||
| 
 | 
 | ||||||
|     let insert_result = symbol_table.insert( |     let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( | ||||||
|  |         &resolved_name, | ||||||
|         &declared_name, |         &declared_name, | ||||||
|         Symbol::Function(FunctionSymbol::new( |         function.is_public, | ||||||
|             &resolved_name, |         false, | ||||||
|             &declared_name, |         Some(&function.identifier), | ||||||
|             function.is_public, |     )); | ||||||
|             &function.identifier, |  | ||||||
|         )), |  | ||||||
|     ); |  | ||||||
| 
 | 
 | ||||||
|     if let Err(err) = insert_result { |     if let Err(err) = insert_result { | ||||||
|         handle_insert_error( |         handle_insert_error( | ||||||
| @ -148,11 +347,55 @@ fn gather_function_definition( | |||||||
|     symbol_table.pop_scope(); |     symbol_table.pop_scope(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn gather_platform_function_definition( | ||||||
|  |     platform_function_declaration: &mut PlatformFunctionDeclaration, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     fqn_context: &mut FqnContext, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let declared_name = platform_function_declaration.identifier.name(); | ||||||
|  |     let fully_qualified_name = fqn_context.resolve(&declared_name); | ||||||
|  | 
 | ||||||
|  |     let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( | ||||||
|  |         &fully_qualified_name, | ||||||
|  |         &declared_name, | ||||||
|  |         platform_function_declaration.is_public, | ||||||
|  |         true, | ||||||
|  |         Some(&platform_function_declaration.identifier), | ||||||
|  |     )); | ||||||
|  | 
 | ||||||
|  |     if let Err(err) = insert_result { | ||||||
|  |         handle_insert_error( | ||||||
|  |             err, | ||||||
|  |             &declared_name, | ||||||
|  |             platform_function_declaration.identifier.file_id, | ||||||
|  |             platform_function_declaration.identifier.range, | ||||||
|  |             "(Platform-) Function", | ||||||
|  |             diagnostics, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let declared_name_as_string = platform_function_declaration.identifier.name().to_string(); | ||||||
|  | 
 | ||||||
|  |     platform_function_declaration | ||||||
|  |         .identifier | ||||||
|  |         .set_scope_id(symbol_table.current_scope_id()); | ||||||
|  | 
 | ||||||
|  |     symbol_table.push_scope(&format!("FunctionScope({})", declared_name_as_string)); | ||||||
|  |     gather_parameters( | ||||||
|  |         &mut platform_function_declaration.parameters, | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     symbol_table.pop_scope(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn gather_parameters( | fn gather_parameters( | ||||||
|     parameters: &mut Parameters, |     parameters: &mut Parameters, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     for parameter in &mut parameters.0 { |     for parameter in &mut parameters.0 { | ||||||
|         gather_parameter(parameter, symbol_table, fqn_context, diagnostics); |         gather_parameter(parameter, symbol_table, fqn_context, diagnostics); | ||||||
| @ -163,18 +406,14 @@ fn gather_parameter( | |||||||
|     parameter: &mut Parameter, |     parameter: &mut Parameter, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     let parameter_name = parameter.identifier.name(); |     let parameter_name = parameter.identifier.name(); | ||||||
| 
 | 
 | ||||||
|     let insert_result = symbol_table.insert( |     let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( | ||||||
|         ¶meter_name, |         ¶meter_name, | ||||||
|         Symbol::Variable(VariableSymbol::new( |         Some(¶meter.identifier), | ||||||
|             ¶meter_name, |     )); | ||||||
|             false, |  | ||||||
|             SourceDefinition::from_identifier(¶meter.identifier), |  | ||||||
|         )), |  | ||||||
|     ); |  | ||||||
| 
 | 
 | ||||||
|     if let Err(err) = insert_result { |     if let Err(err) = insert_result { | ||||||
|         handle_insert_error( |         handle_insert_error( | ||||||
| @ -190,13 +429,20 @@ fn gather_parameter( | |||||||
|     parameter |     parameter | ||||||
|         .identifier |         .identifier | ||||||
|         .set_scope_id(symbol_table.current_scope_id()); |         .set_scope_id(symbol_table.current_scope_id()); | ||||||
|  | 
 | ||||||
|  |     gather_type_use( | ||||||
|  |         &mut parameter.type_use, | ||||||
|  |         symbol_table, | ||||||
|  |         fqn_context, | ||||||
|  |         diagnostics, | ||||||
|  |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn gather_function_body( | fn gather_function_body( | ||||||
|     function_body: &mut FunctionBody, |     function_body: &mut FunctionBody, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     use crate::ast::FunctionBody::*; |     use crate::ast::FunctionBody::*; | ||||||
|     match function_body { |     match function_body { | ||||||
| @ -209,7 +455,7 @@ fn gather_block_statement( | |||||||
|     block: &mut BlockStatement, |     block: &mut BlockStatement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     symbol_table.push_scope("BlockStatementScope"); |     symbol_table.push_scope("BlockStatementScope"); | ||||||
|     gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics); |     gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics); | ||||||
| @ -220,7 +466,7 @@ fn gather_block_statement_inner( | |||||||
|     block: &mut BlockStatement, |     block: &mut BlockStatement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     for statement in &mut block.statements { |     for statement in &mut block.statements { | ||||||
|         gather_statement(statement, symbol_table, fqn_context, diagnostics); |         gather_statement(statement, symbol_table, fqn_context, diagnostics); | ||||||
| @ -234,7 +480,7 @@ fn gather_statement( | |||||||
|     statement: &mut Statement, |     statement: &mut Statement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     use crate::ast::Statement::*; |     use crate::ast::Statement::*; | ||||||
|     match statement { |     match statement { | ||||||
| @ -247,6 +493,9 @@ fn gather_statement( | |||||||
|         AssignStatement(assign_statement) => { |         AssignStatement(assign_statement) => { | ||||||
|             gather_assign_statement(assign_statement, symbol_table, fqn_context, diagnostics) |             gather_assign_statement(assign_statement, symbol_table, fqn_context, diagnostics) | ||||||
|         } |         } | ||||||
|  |         CallStatement(call_statement) => { | ||||||
|  |             gather_call_statement(call_statement, symbol_table, diagnostics) | ||||||
|  |         } | ||||||
|         _ => todo!(), |         _ => todo!(), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -254,18 +503,15 @@ fn gather_statement( | |||||||
| fn gather_variable_declaration( | fn gather_variable_declaration( | ||||||
|     variable_declaration: &mut VariableDeclarationStatement, |     variable_declaration: &mut VariableDeclarationStatement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     let variable_name = variable_declaration.identifier.name(); |     let variable_name = variable_declaration.identifier.name(); | ||||||
| 
 | 
 | ||||||
|     let insert_result = symbol_table.insert( |     let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new( | ||||||
|         &variable_name, |         &variable_name, | ||||||
|         Symbol::Variable(VariableSymbol::new( 
 |         variable_declaration.is_mutable, | ||||||
|             &variable_name, |         Some(&variable_declaration.identifier), | ||||||
|             variable_declaration.is_mutable, |     )); | ||||||
|             SourceDefinition::from_identifier(&variable_declaration.identifier), |  | ||||||
|         )), |  | ||||||
|     ); |  | ||||||
| 
 | 
 | ||||||
|     if let Err(err) = insert_result { |     if let Err(err) = insert_result { | ||||||
|         handle_insert_error( |         handle_insert_error( | ||||||
| @ -291,29 +537,156 @@ fn gather_assign_statement( | |||||||
|     assign_statement: &mut AssignStatement, |     assign_statement: &mut AssignStatement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     fqn_context: &mut FqnContext, |     fqn_context: &mut FqnContext, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     gather_expression(&mut assign_statement.lhs, symbol_table, diagnostics); |     gather_expression(&mut assign_statement.lhs, symbol_table, diagnostics); | ||||||
|     gather_expression(&mut assign_statement.rhs, symbol_table, diagnostics); |     gather_expression(&mut assign_statement.rhs, symbol_table, diagnostics); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn gather_call_statement( | ||||||
|  |     call_statement: &mut CallStatement, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     gather_expression(&mut call_statement.0, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn gather_expression( | fn gather_expression( | ||||||
|     expression: &mut Expression, |     expression: &mut Expression, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     use crate::ast::Expression::*; |     use crate::ast::Expression::*; | ||||||
|     match expression { |     match expression { | ||||||
|  |         Ternary(ternary_expression) => { | ||||||
|  |             gather_ternary_expression(ternary_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         Binary(binary_expression) => { | ||||||
|  |             gather_binary_expression(binary_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         UnaryPrefix(prefix_expression) => { | ||||||
|  |             gather_prefix_expression(prefix_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         UnarySuffix(suffix_expression) => { | ||||||
|  |             gather_suffix_expression(suffix_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         Call(call_expression) => { | ||||||
|  |             gather_call_expression(call_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         ObjectAccess(object_access) => { | ||||||
|  |             gather_object_access(object_access, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         Literal(literal) => { | ||||||
|  |             gather_literal(literal, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|         FullyQualifiedName(fully_qualified_name) => { |         FullyQualifiedName(fully_qualified_name) => { | ||||||
|             gather_fully_qualified_name(fully_qualified_name, symbol_table); |             gather_fully_qualified_name(fully_qualified_name, symbol_table); | ||||||
|         } |         } | ||||||
|         _ => {} |         Closure(closure) => { | ||||||
|  |             gather_closure(closure, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn gather_fully_qualified_name( | fn gather_ternary_expression( | ||||||
|     fully_qualified_name: &mut FullyQualifiedName, |     ternary_expression: &mut TernaryExpression, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     fully_qualified_name.set_scope_id(symbol_table.current_scope_id()); |     gather_expression(&mut ternary_expression.condition, symbol_table, diagnostics); | ||||||
|  |     gather_expression( | ||||||
|  |         &mut ternary_expression.true_expression, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     gather_expression( | ||||||
|  |         &mut ternary_expression.false_expression, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_binary_expression( | ||||||
|  |     binary_expression: &mut BinaryExpression, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     gather_expression(&mut binary_expression.left, symbol_table, diagnostics); | ||||||
|  |     gather_expression(&mut binary_expression.right, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_prefix_expression( | ||||||
|  |     prefix_expression: &mut PrefixExpression, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     gather_expression(&mut prefix_expression.expression, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_suffix_expression( | ||||||
|  |     suffix_expression: &mut SuffixExpression, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     gather_expression(&mut suffix_expression.expression, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_call_expression( | ||||||
|  |     call_expression: &mut CallExpression, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     gather_expression(&mut call_expression.callee, symbol_table, diagnostics); | ||||||
|  |     if let Some(turbo_fish) = &mut call_expression.turbo_fish { | ||||||
|  |         gather_turbo_fish(turbo_fish, symbol_table, diagnostics); | ||||||
|  |     } | ||||||
|  |     for call_argument in &mut call_expression.arguments.0 { | ||||||
|  |         gather_expression(&mut call_argument.0, symbol_table, diagnostics); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_turbo_fish( | ||||||
|  |     turbo_fish: &mut TurboFish, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_closure( | ||||||
|  |     closure: &mut Closure, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_object_access( | ||||||
|  |     object_access: &mut ObjectAccess, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     gather_expression(&mut object_access.receiver, symbol_table, diagnostics); | ||||||
|  |     for object_navigation in &mut object_access.navigations.0 { | ||||||
|  |         match object_navigation { | ||||||
|  |             ObjectNavigation::Index(index_expression) => { | ||||||
|  |                 gather_expression(index_expression, symbol_table, diagnostics); | ||||||
|  |             } | ||||||
|  |             ObjectNavigation::Identifier(identifier) => { | ||||||
|  |                 identifier.set_scope_id(symbol_table.current_scope_id()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn gather_literal( | ||||||
|  |     literal: &mut Literal, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     match literal { | ||||||
|  |         Literal::DString(d_string) => todo!(), | ||||||
|  |         Literal::BacktickString(backtick_string) => todo!(), | ||||||
|  |         _ => {} | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,12 +1,9 @@ | |||||||
| use crate::ast::named::Named; | use crate::ast::named::Named; | ||||||
| use crate::ast::{CompilationUnit, Identifier}; | use crate::ast::CompilationUnit; | ||||||
| use crate::diagnostic::DmDiagnostic; | use crate::diagnostic::DmDiagnostic; | ||||||
| use crate::name_analysis::fqn_context::FqnContext; | use crate::name_analysis::gather::gather_compilation_unit; | ||||||
| use crate::name_analysis::gather::gather_module_level_declaration; | use crate::name_analysis::resolve::resolve_compilation_unit; | ||||||
| use crate::name_analysis::resolve::resolve_module_level_declaration; |  | ||||||
| use crate::name_analysis::symbol_table::SymbolTable; | use crate::name_analysis::symbol_table::SymbolTable; | ||||||
| use codespan_reporting::diagnostic::{Diagnostic, Label}; |  | ||||||
| use log::debug; |  | ||||||
| 
 | 
 | ||||||
| mod fqn_context; | mod fqn_context; | ||||||
| mod gather; | mod gather; | ||||||
| @ -14,63 +11,20 @@ mod resolve; | |||||||
| pub mod symbol; | pub mod symbol; | ||||||
| pub mod symbol_table; | pub mod symbol_table; | ||||||
| 
 | 
 | ||||||
| pub(self) struct DiagnosticsContainer { |  | ||||||
|     file_id: usize, |  | ||||||
|     diagnostics: Vec<DmDiagnostic>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl DiagnosticsContainer { |  | ||||||
|     pub fn new(file_id: usize) -> DiagnosticsContainer { |  | ||||||
|         DiagnosticsContainer { |  | ||||||
|             file_id, |  | ||||||
|             diagnostics: vec![], |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn add(&mut self, diagnostic: DmDiagnostic) { |  | ||||||
|         self.diagnostics.push(diagnostic); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn add_error_at_identifier(&mut self, msg: &str, identifier: &Identifier) { |  | ||||||
|         self.diagnostics.push( |  | ||||||
|             Diagnostic::error() |  | ||||||
|                 .with_message(msg) |  | ||||||
|                 .with_label(Label::primary(self.file_id, identifier.range)), |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Into<Vec<DmDiagnostic>> for DiagnosticsContainer { |  | ||||||
|     fn into(self) -> Vec<DmDiagnostic> { |  | ||||||
|         self.diagnostics |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn analyze_names( | pub fn analyze_names( | ||||||
|     file_id: usize, |     compilation_units: &mut Vec<CompilationUnit>, | ||||||
|     compilation_unit: &mut CompilationUnit, |  | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
| ) -> Vec<DmDiagnostic> { | ) -> Vec<DmDiagnostic> { | ||||||
|     let mut diagnostics = DiagnosticsContainer::new(file_id); |     let mut diagnostics = vec![]; | ||||||
| 
 | 
 | ||||||
|     let mut fqn_context = FqnContext::new(); |     // gather symbols
 | ||||||
|     if let Some(namespace) = &compilation_unit.namespace { |     for compilation_unit in compilation_units.iter_mut() { | ||||||
|         fqn_context.push(namespace.name().to_string()); |         gather_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for declaration in &mut compilation_unit.declarations { |     // resolve symbols
 | ||||||
|         gather_module_level_declaration( |     for compilation_unit in compilation_units.iter_mut() { | ||||||
|             declaration, |         resolve_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); | ||||||
|             symbol_table, |  | ||||||
|             &mut fqn_context, |  | ||||||
|             &mut diagnostics, |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     assert_eq!(symbol_table.current_scope_id(), 0); |  | ||||||
| 
 |  | ||||||
|     for declaration in &mut compilation_unit.declarations { |  | ||||||
|         resolve_module_level_declaration(declaration, symbol_table, &mut diagnostics); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     diagnostics.into() |     diagnostics.into() | ||||||
| @ -81,26 +35,36 @@ mod tests { | |||||||
|     use super::*; |     use super::*; | ||||||
|     use crate::ast::build::build_ast; |     use crate::ast::build::build_ast; | ||||||
|     use crate::parser::{DeimosParser, Rule}; |     use crate::parser::{DeimosParser, Rule}; | ||||||
|  |     use crate::std_core::add_std_core_symbols; | ||||||
|     use codespan_reporting::files::SimpleFiles; |     use codespan_reporting::files::SimpleFiles; | ||||||
|     use codespan_reporting::term; |     use codespan_reporting::term; | ||||||
|     use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; |     use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; | ||||||
|  |     use indoc::indoc; | ||||||
|     use pest::Parser; |     use pest::Parser; | ||||||
|  |     use std::collections::HashMap; | ||||||
| 
 | 
 | ||||||
|     fn assert_no_diagnostics(src: &str) { |     fn assert_no_diagnostics(sources: HashMap<&str, &str>) -> SymbolTable { | ||||||
|         let mut files = SimpleFiles::new(); |         let mut files = SimpleFiles::new(); | ||||||
|         let test_file_id = files.add("test.dm", src); |         let mut compilation_units = vec![]; | ||||||
| 
 | 
 | ||||||
|         let parse_result = DeimosParser::parse(Rule::CompilationUnit, src); |         for (file_name, source) in sources { | ||||||
|         if let Err(err) = &parse_result { |             let file_id = files.add(file_name, source); | ||||||
|             panic!("{:?}", err); |             let parse_result = DeimosParser::parse(Rule::CompilationUnit, source); | ||||||
|  |             if let Err(err) = &parse_result { | ||||||
|  |                 panic!("{}", err); | ||||||
|  |             } | ||||||
|  |             let mut pairs = parse_result.unwrap(); | ||||||
|  |             if pairs.as_str().trim() != source.trim() { | ||||||
|  |                 panic!("Parsing did not consume entire input."); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap())) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let compilation_unit_pair = parse_result.unwrap().next().unwrap(); |  | ||||||
|         let mut ast = build_ast(test_file_id, compilation_unit_pair); |  | ||||||
| 
 |  | ||||||
|         let mut symbol_table = SymbolTable::new(); |         let mut symbol_table = SymbolTable::new(); | ||||||
|  |         add_std_core_symbols(&mut symbol_table).expect("Failed to add std_core_symbols"); | ||||||
| 
 | 
 | ||||||
|         let diagnostics = analyze_names(test_file_id, &mut ast, &mut symbol_table); |         let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table); | ||||||
| 
 | 
 | ||||||
|         if !diagnostics.is_empty() { |         if !diagnostics.is_empty() { | ||||||
|             let writer = StandardStream::stderr(ColorChoice::Always); |             let writer = StandardStream::stderr(ColorChoice::Always); | ||||||
| @ -113,16 +77,50 @@ mod tests { | |||||||
|             eprintln!("{}", symbol_table); |             eprintln!("{}", symbol_table); | ||||||
|             panic!("Diagnostics was not empty!"); |             panic!("Diagnostics was not empty!"); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         for compilation_unit in &compilation_units { | ||||||
|  |             dbg!(compilation_unit); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         symbol_table | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn params_seen() { |     fn params_seen() { | ||||||
|         assert_no_diagnostics( |         let sources: HashMap<&str, &str> = HashMap::from([( | ||||||
|             r#" |             "main.dm", | ||||||
|  |             indoc! {" | ||||||
|             fn main(args: Array<String>) { |             fn main(args: Array<String>) { | ||||||
|                 let x = args; |                 let x = args; | ||||||
|             } |             }"},
 | ||||||
|             "#,
 |         )]); | ||||||
|         ) | 
 | ||||||
|  |         assert_no_diagnostics(sources); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn two_files() { | ||||||
|  |         let sources: HashMap<&str, &str> = HashMap::from([ | ||||||
|  |             ( | ||||||
|  |                 "main.dm", | ||||||
|  |                 indoc! {" | ||||||
|  |                 use test::Greeter; | ||||||
|  | 
 | ||||||
|  |                 fn main(args: Array<String>) { | ||||||
|  |                     println(\"Hello, World!\");
 | ||||||
|  |                 } | ||||||
|  |             "},
 | ||||||
|  |             ), | ||||||
|  |             ( | ||||||
|  |                 "deps.dm", | ||||||
|  |                 indoc! {" | ||||||
|  |                 ns test; | ||||||
|  | 
 | ||||||
|  |                 pub class Greeter {} | ||||||
|  |             "},
 | ||||||
|  |             ), | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |         assert_no_diagnostics(sources); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,19 +1,229 @@ | |||||||
| use crate::ast::named::Named; | use crate::ast::named::Named; | ||||||
| use crate::ast::*; | use crate::ast::*; | ||||||
|  | use crate::diagnostic::DmDiagnostic; | ||||||
| use crate::name_analysis::symbol_table::SymbolTable; | use crate::name_analysis::symbol_table::SymbolTable; | ||||||
| use crate::name_analysis::DiagnosticsContainer; |  | ||||||
| use codespan_reporting::diagnostic::{Diagnostic, Label}; | use codespan_reporting::diagnostic::{Diagnostic, Label}; | ||||||
| 
 | 
 | ||||||
|  | fn resolve_fully_qualified_name( | ||||||
|  |     fully_qualified_name: &mut FullyQualifiedName, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     let lookup_result = symbol_table.lookup( | ||||||
|  |         fully_qualified_name.name().as_ref(), | ||||||
|  |         fully_qualified_name.scope_id().expect(&format!( | ||||||
|  |             "FullyQualifiedName has no scope_id set: {:?}", | ||||||
|  |             fully_qualified_name | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  |     match lookup_result { | ||||||
|  |         Ok(symbol) => { | ||||||
|  |             fully_qualified_name.set_symbol(symbol.clone()); | ||||||
|  |         } | ||||||
|  |         Err(e) => diagnostics.push( | ||||||
|  |             Diagnostic::error() | ||||||
|  |                 .with_message(format!( | ||||||
|  |                     "No symbol with name '{}' found in current scope.", | ||||||
|  |                     fully_qualified_name.name() | ||||||
|  |                 )) | ||||||
|  |                 .with_label(Label::primary( | ||||||
|  |                     fully_qualified_name.file_id, | ||||||
|  |                     fully_qualified_name.range, | ||||||
|  |                 )), | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_type_use( | ||||||
|  |     type_use: &mut TypeUse, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     match type_use { | ||||||
|  |         TypeUse::Void => {} | ||||||
|  |         TypeUse::InterfaceOrClass(interface_or_class_type_use) => { | ||||||
|  |             resolve_interface_or_class_type_use( | ||||||
|  |                 interface_or_class_type_use, | ||||||
|  |                 symbol_table, | ||||||
|  |                 diagnostics, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         TypeUse::Tuple(tuple_type_use) => { | ||||||
|  |             resolve_tuple_type_use(tuple_type_use, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         TypeUse::Function(function_type_use) => { | ||||||
|  |             resolve_function_type_use(function_type_use, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_interface_or_class_type_use( | ||||||
|  |     interface_or_class_type_use: &mut InterfaceOrClassTypeUse, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_fully_qualified_name( | ||||||
|  |         &mut interface_or_class_type_use.fqn, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     resolve_generic_arguments( | ||||||
|  |         &mut interface_or_class_type_use.generics, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_tuple_type_use( | ||||||
|  |     tuple_type_use: &mut TupleTypeUse, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_tuple_arguments(&mut tuple_type_use.arguments, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_function_type_use( | ||||||
|  |     function_type_use: &mut FunctionTypeUse, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_parameters(&mut function_type_use.parameters, symbol_table, diagnostics); | ||||||
|  |     resolve_return_type( | ||||||
|  |         &mut function_type_use.return_type, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_generic_arguments( | ||||||
|  |     generic_arguments: &mut GenericArguments, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     for generic_argument in &mut generic_arguments.0 { | ||||||
|  |         resolve_type_use(generic_argument, symbol_table, diagnostics); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_tuple_arguments( | ||||||
|  |     tuple_type_use: &mut TupleArguments, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     for type_use in &mut tuple_type_use.0 { | ||||||
|  |         resolve_type_use(type_use, symbol_table, diagnostics); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_implements_list( | ||||||
|  |     implements_list: &mut ImplementsList, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_parameters( | ||||||
|  |     parameters: &mut Parameters, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     for parameter in &mut parameters.0 { | ||||||
|  |         resolve_type_use(&mut parameter.type_use, symbol_table, diagnostics); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_return_type( | ||||||
|  |     return_type: &mut ReturnType, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_type_use(&mut return_type.declared_type, symbol_table, diagnostics); | ||||||
|  |     resolve_references(&mut return_type.references, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_references( | ||||||
|  |     references: &mut References, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     for reference in &mut references.0 { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_use_statement( | ||||||
|  |     use_statement: &mut UseStatement, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     if use_statement.is_star() { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let base_name = use_statement.base_name().to_string(); | ||||||
|  | 
 | ||||||
|  |     match &use_statement.last { | ||||||
|  |         UseStatementLast::Identifier(identifier) => { | ||||||
|  |             let borrowed_identifier = identifier.borrow(); | ||||||
|  |             let declared_name = borrowed_identifier.name().to_string(); | ||||||
|  |             let fqn = format!("{}::{}", &base_name, &declared_name); | ||||||
|  |             let lookup_result = | ||||||
|  |                 symbol_table.lookup_usable_by_fqn(&fqn, borrowed_identifier.scope_id().unwrap()); | ||||||
|  |             drop(borrowed_identifier); | ||||||
|  | 
 | ||||||
|  |             if let Err(_) = lookup_result { | ||||||
|  |                 diagnostics.push( | ||||||
|  |                     Diagnostic::error() | ||||||
|  |                         .with_message(&format!("Unable to find symbol '{}'.", fqn)) | ||||||
|  |                         .with_label(Label::primary(use_statement.file_id, use_statement.range)), | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 let mut mutable_borrowed_identifier = identifier.borrow_mut(); | ||||||
|  |                 let use_statement_symbol = mutable_borrowed_identifier | ||||||
|  |                     .symbol_mut() | ||||||
|  |                     .unwrap() | ||||||
|  |                     .unwrap_use_statement_symbol(); | ||||||
|  |                 let mut mutable_borrowed_use_statement_symbol = use_statement_symbol.borrow_mut(); | ||||||
|  |                 mutable_borrowed_use_statement_symbol.set_referenced_symbol(lookup_result.unwrap()) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         UseStatementLast::Identifiers(identifiers) => {} | ||||||
|  |         UseStatementLast::Star => panic!(), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(super) fn resolve_compilation_unit( | ||||||
|  |     compilation_unit: &mut CompilationUnit, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     for use_statement in &mut compilation_unit.use_statements { | ||||||
|  |         resolve_use_statement(use_statement, symbol_table, diagnostics); | ||||||
|  |     } | ||||||
|  |     for declaration in &mut compilation_unit.declarations { | ||||||
|  |         resolve_module_level_declaration(declaration, symbol_table, diagnostics); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub(super) fn resolve_module_level_declaration( | pub(super) fn resolve_module_level_declaration( | ||||||
|     declaration: &mut ModuleLevelDeclaration, |     declaration: &mut ModuleLevelDeclaration, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     use crate::ast::ModuleLevelDeclaration::*; |     use crate::ast::ModuleLevelDeclaration::*; | ||||||
|     match declaration { |     match declaration { | ||||||
|         Function(function_definition) => { |         Function(function_definition) => { | ||||||
|             resolve_function_definition(function_definition, symbol_table, diagnostics) |             resolve_function_definition(function_definition, symbol_table, diagnostics) | ||||||
|         } |         } | ||||||
|  |         PlatformFunction(platform_function_declaration) => resolve_platform_function_declaration( | ||||||
|  |             platform_function_declaration, | ||||||
|  |             symbol_table, | ||||||
|  |             diagnostics, | ||||||
|  |         ), | ||||||
|  |         Class(class_declaration) => { | ||||||
|  |             // todo
 | ||||||
|  |         } | ||||||
|         _ => todo!(), |         _ => todo!(), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -21,15 +231,42 @@ pub(super) fn resolve_module_level_declaration( | |||||||
| fn resolve_function_definition( | fn resolve_function_definition( | ||||||
|     function_definition: &mut FunctionDefinition, |     function_definition: &mut FunctionDefinition, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|  |     resolve_parameters( | ||||||
|  |         &mut function_definition.parameters, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     resolve_return_type( | ||||||
|  |         &mut function_definition.return_type, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|     resolve_function_body(&mut function_definition.body, symbol_table, diagnostics); |     resolve_function_body(&mut function_definition.body, symbol_table, diagnostics); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn resolve_platform_function_declaration( | ||||||
|  |     platform_function_declaration: &mut PlatformFunctionDeclaration, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_parameters( | ||||||
|  |         &mut platform_function_declaration.parameters, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  |     resolve_return_type( | ||||||
|  |         &mut platform_function_declaration.return_type, | ||||||
|  |         symbol_table, | ||||||
|  |         diagnostics, | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn resolve_function_body( | fn resolve_function_body( | ||||||
|     function_body: &mut FunctionBody, |     function_body: &mut FunctionBody, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     use crate::ast::FunctionBody::*; |     use crate::ast::FunctionBody::*; | ||||||
|     match function_body { |     match function_body { | ||||||
| @ -41,7 +278,7 @@ fn resolve_function_body( | |||||||
| fn resolve_block( | fn resolve_block( | ||||||
|     block_statement: &mut BlockStatement, |     block_statement: &mut BlockStatement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     for statement in block_statement.statements.iter_mut() { |     for statement in block_statement.statements.iter_mut() { | ||||||
|         resolve_statement(statement, symbol_table, diagnostics); |         resolve_statement(statement, symbol_table, diagnostics); | ||||||
| @ -54,7 +291,7 @@ fn resolve_block( | |||||||
| fn resolve_statement( | fn resolve_statement( | ||||||
|     statement: &mut Statement, |     statement: &mut Statement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     use crate::ast::Statement::*; |     use crate::ast::Statement::*; | ||||||
|     match statement { |     match statement { | ||||||
| @ -75,7 +312,7 @@ fn resolve_statement( | |||||||
| fn resolve_variable_declaration( | fn resolve_variable_declaration( | ||||||
|     variable_declaration: &mut VariableDeclarationStatement, |     variable_declaration: &mut VariableDeclarationStatement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     if let Some(initializer) = &mut variable_declaration.initializer { |     if let Some(initializer) = &mut variable_declaration.initializer { | ||||||
|         resolve_expression(initializer, symbol_table, diagnostics) |         resolve_expression(initializer, symbol_table, diagnostics) | ||||||
| @ -85,7 +322,7 @@ fn resolve_variable_declaration( | |||||||
| fn resolve_assign_statement( | fn resolve_assign_statement( | ||||||
|     assign_statement: &mut AssignStatement, |     assign_statement: &mut AssignStatement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     resolve_expression(&mut assign_statement.lhs, symbol_table, diagnostics); |     resolve_expression(&mut assign_statement.lhs, symbol_table, diagnostics); | ||||||
|     resolve_expression(&mut assign_statement.rhs, symbol_table, diagnostics); |     resolve_expression(&mut assign_statement.rhs, symbol_table, diagnostics); | ||||||
| @ -94,7 +331,7 @@ fn resolve_assign_statement( | |||||||
| fn resolve_call_statement( | fn resolve_call_statement( | ||||||
|     call_statement: &mut CallStatement, |     call_statement: &mut CallStatement, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     resolve_expression(&mut call_statement.0, symbol_table, diagnostics) |     resolve_expression(&mut call_statement.0, symbol_table, diagnostics) | ||||||
| } | } | ||||||
| @ -102,42 +339,151 @@ fn resolve_call_statement( | |||||||
| fn resolve_expression( | fn resolve_expression( | ||||||
|     expression: &mut Expression, |     expression: &mut Expression, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     use crate::ast::Expression::*; |     use crate::ast::Expression::*; | ||||||
|     match expression { |     match expression { | ||||||
|  |         Ternary(ternary_expression) => { | ||||||
|  |             resolve_ternary_expression(ternary_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         Binary(binary_expression) => { | ||||||
|  |             resolve_binary_expression(binary_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         UnaryPrefix(prefix_expression) => { | ||||||
|  |             resolve_prefix_expression(prefix_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         UnarySuffix(suffix_expression) => { | ||||||
|  |             resolve_suffix_expression(suffix_expression, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         Call(call_expression) => { | ||||||
|  |             resolve_call_expression(call_expression, symbol_table, diagnostics) | ||||||
|  |         } | ||||||
|  |         ObjectAccess(object_access) => { | ||||||
|  |             resolve_object_access(object_access, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|         FullyQualifiedName(fqn) => resolve_fully_qualified_name(fqn, symbol_table, diagnostics), |         FullyQualifiedName(fqn) => resolve_fully_qualified_name(fqn, symbol_table, diagnostics), | ||||||
|         Literal(_) => {} |         Literal(literal) => { | ||||||
|         _ => todo!(), |             resolve_literal(literal, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|  |         Closure(closure) => { | ||||||
|  |             resolve_closure(closure, symbol_table, diagnostics); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn resolve_fully_qualified_name( | fn resolve_ternary_expression( | ||||||
|     fully_qualified_name: &mut FullyQualifiedName, |     ternary_expression: &mut TernaryExpression, | ||||||
|     symbol_table: &mut SymbolTable, |     symbol_table: &mut SymbolTable, | ||||||
|     diagnostics: &mut DiagnosticsContainer, |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
| ) { | ) { | ||||||
|     let lookup_result = symbol_table.lookup( |     resolve_expression(&mut ternary_expression.condition, symbol_table, diagnostics); | ||||||
|         fully_qualified_name.name().as_ref(), |     resolve_expression( | ||||||
|         fully_qualified_name.scope_id().expect(&format!( |         &mut ternary_expression.true_expression, | ||||||
|             "FullyQualifiedName has no scope_id set: {:?}", |         symbol_table, | ||||||
|             fully_qualified_name |         diagnostics, | ||||||
|         )), |  | ||||||
|     ); |     ); | ||||||
|     match lookup_result { |     resolve_expression( | ||||||
|         Ok(symbol) => { |         &mut ternary_expression.false_expression, | ||||||
|             fully_qualified_name.set_symbol(symbol.clone()); |         symbol_table, | ||||||
|         } |         diagnostics, | ||||||
|         Err(e) => diagnostics.add( |     ); | ||||||
|             Diagnostic::error() | } | ||||||
|                 .with_message(format!( | 
 | ||||||
|                     "No symbol with name '{}' found in current scope.", | fn resolve_binary_expression( | ||||||
|                     fully_qualified_name.name() |     binary_expression: &mut BinaryExpression, | ||||||
|                 )) |     symbol_table: &mut SymbolTable, | ||||||
|                 .with_label(Label::primary( |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|                     fully_qualified_name.file_id, | ) { | ||||||
|                     fully_qualified_name.range, |     resolve_expression(&mut binary_expression.left, symbol_table, diagnostics); | ||||||
|                 )), |     resolve_expression(&mut binary_expression.right, symbol_table, diagnostics); | ||||||
|         ), | } | ||||||
|  | 
 | ||||||
|  | fn resolve_prefix_expression( | ||||||
|  |     prefix_expression: &mut PrefixExpression, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_expression(&mut prefix_expression.expression, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_suffix_expression( | ||||||
|  |     suffix_expression: &mut SuffixExpression, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_expression(&mut suffix_expression.expression, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_call_expression( | ||||||
|  |     call_expression: &mut CallExpression, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_expression(&mut call_expression.callee, symbol_table, diagnostics); | ||||||
|  |     if let Some(turbo_fish) = &mut call_expression.turbo_fish { | ||||||
|  |         resolve_turbo_fish(turbo_fish, symbol_table, diagnostics); | ||||||
|  |     } | ||||||
|  |     resolve_call_arguments(&mut call_expression.arguments, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_turbo_fish( | ||||||
|  |     turbo_fish: &mut TurboFish, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_call_arguments( | ||||||
|  |     call_arguments: &mut CallArguments, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     for argument in &mut call_arguments.0 { | ||||||
|  |         resolve_call_argument(argument, symbol_table, diagnostics); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | fn resolve_call_argument( | ||||||
|  |     call_argument: &mut CallArgument, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     resolve_expression(&mut call_argument.0, symbol_table, diagnostics); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_closure( | ||||||
|  |     closure: &mut Closure, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_object_access( | ||||||
|  |     object_access: &mut ObjectAccess, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_literal( | ||||||
|  |     literal: &mut Literal, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     match literal { | ||||||
|  |         Literal::DString(d_string) => resolve_d_string(d_string, symbol_table, diagnostics), | ||||||
|  |         Literal::BacktickString(d_string) => resolve_d_string(d_string, symbol_table, diagnostics), | ||||||
|  |         _ => {} | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn resolve_d_string( | ||||||
|  |     d_string: &mut DString, | ||||||
|  |     symbol_table: &mut SymbolTable, | ||||||
|  |     diagnostics: &mut Vec<DmDiagnostic>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| use crate::ast::Identifier; | use std::cell::RefCell; | ||||||
|  | use crate::ast::{Identifier, UseStatement}; | ||||||
| use std::fmt::Display; | use std::fmt::Display; | ||||||
| use std::range::Range; | use std::range::Range; | ||||||
|  | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Debug)] | #[derive(Clone, Debug)] | ||||||
| pub struct SourceDefinition { | pub struct SourceDefinition { | ||||||
| @ -15,6 +17,22 @@ impl SourceDefinition { | |||||||
|             range: identifier.range, |             range: identifier.range, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     
 | ||||||
|  |     pub fn from_identifier_rc(identifier: Rc<RefCell<Identifier>>) -> Self { | ||||||
|  |         let borrowed = identifier.borrow(); | ||||||
|  |         SourceDefinition { | ||||||
|  |             file_id: borrowed.file_id, | ||||||
|  |             range: borrowed.range, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[deprecated(note = "Use identifier instead.")] | ||||||
|  |     pub fn from_use_statement(use_statement: &UseStatement) -> Self { | ||||||
|  |         SourceDefinition { | ||||||
|  |             file_id: use_statement.file_id, | ||||||
|  |             range: use_statement.range, | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     pub fn file_id(&self) -> usize { |     pub fn file_id(&self) -> usize { | ||||||
|         self.file_id |         self.file_id | ||||||
| @ -25,27 +43,39 @@ impl SourceDefinition { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub trait SymbolInner { | ||||||
|  |     fn declared_name(&self) -> &str; | ||||||
|  |     fn definition(&self) -> Option<SourceDefinition>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Symbol */ | ||||||
|  | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub enum Symbol { | pub enum Symbol { | ||||||
|     Function(FunctionSymbol), |     UseStatement(Rc<RefCell<UseStatementSymbol>>), | ||||||
|     Variable(VariableSymbol), |     Module(Rc<ModuleSymbol>), | ||||||
|     Module(ModuleSymbol), |     Type(Rc<TypeSymbol>), | ||||||
|  |     Function(Rc<FunctionSymbol>), | ||||||
|  |     Parameter(Rc<ParameterSymbol>), | ||||||
|  |     Variable(Rc<VariableSymbol>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Symbol { | impl Symbol { | ||||||
|     pub fn name(&self) -> &str { |     pub fn definition(&self) -> Option<SourceDefinition> { | ||||||
|         match self { |         match self { | ||||||
|             Symbol::Function(s) => s.declared_name.as_str(), |             Symbol::UseStatement(s) => s.borrow().definition.clone(), | ||||||
|             Symbol::Variable(s) => s.name.as_str(), |             Symbol::Module(s) => s.definition(), | ||||||
|             Symbol::Module(s) => s.declared_name.as_str(), |             Symbol::Type(s) => s.definition(), | ||||||
|  |             Symbol::Function(s) => s.definition(), | ||||||
|  |             Symbol::Parameter(s) => s.definition(), | ||||||
|  |             Symbol::Variable(s) => s.definition(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |     
 | ||||||
|     pub fn definition(&self) -> &SourceDefinition { |     pub fn unwrap_use_statement_symbol(&self) -> Rc<RefCell<UseStatementSymbol>> { | ||||||
|         match self { |         match self { | ||||||
|             Symbol::Function(s) => s.definition(), |             Symbol::UseStatement(s) => s.clone(), | ||||||
|             Symbol::Module(s) => s.definition(), |             _ => panic!("unwrap_use_statement_symbol called on non-use statement symbol"), | ||||||
|             Symbol::Variable(s) => s.definition(), |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -54,19 +84,170 @@ impl Display for Symbol { | |||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|         use Symbol::*; |         use Symbol::*; | ||||||
|         match self { |         match self { | ||||||
|             Function(function_symbol) => write!(f, "{}", function_symbol), |             UseStatement(use_statement_symbol) => write!(f, "{}", use_statement_symbol.borrow()), | ||||||
|             Variable(variable_symbol) => write!(f, "{}", variable_symbol), |  | ||||||
|             Module(module_symbol) => write!(f, "{}", module_symbol), |             Module(module_symbol) => write!(f, "{}", module_symbol), | ||||||
|  |             Type(class_symbol) => write!(f, "{}", class_symbol), | ||||||
|  |             Function(function_symbol) => write!(f, "{}", function_symbol), | ||||||
|  |             Parameter(parameter_symbol) => write!(f, "{}", parameter_symbol), | ||||||
|  |             Variable(variable_symbol) => write!(f, "{}", variable_symbol), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* Use-statement */ | ||||||
|  | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub struct FunctionSymbol { | pub struct UseStatementSymbol { | ||||||
|     pub fqn: String, |     pub fqn: String, | ||||||
|     pub declared_name: String, |     pub declared_name: String, | ||||||
|     pub is_public: bool, |     definition: Option<SourceDefinition>, | ||||||
|     definition: SourceDefinition, |     referenced_symbol: Option<Box<Symbol>> | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl UseStatementSymbol { | ||||||
|  |     pub fn new(fqn: &str, declared_name: &str, identifier: Option<Rc<RefCell<Identifier>>>) -> Self { | ||||||
|  |         UseStatementSymbol { | ||||||
|  |             fqn: fqn.to_string(), | ||||||
|  |             declared_name: declared_name.to_string(), | ||||||
|  |             definition: identifier.map(SourceDefinition::from_identifier_rc), | ||||||
|  |             referenced_symbol: None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn set_referenced_symbol(&mut self, referenced_symbol: Symbol) { | ||||||
|  |         self.referenced_symbol = Some(Box::new(referenced_symbol)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn referenced_symbol(&self) -> Option<Box<Symbol>> { | ||||||
|  |         self.referenced_symbol.clone() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SymbolInner for UseStatementSymbol { | ||||||
|  |     fn declared_name(&self) -> &str { | ||||||
|  |         &self.declared_name | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn definition(&self) -> Option<SourceDefinition> { | ||||||
|  |         self.definition.clone() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Display for UseStatementSymbol { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|  |         write!( | ||||||
|  |             f, | ||||||
|  |             "UseStatementSymbol(fqn = {}, declared_name = {})", | ||||||
|  |             self.fqn, self.declared_name | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* Module */ | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct ModuleSymbol { | ||||||
|  |     fqn: String, | ||||||
|  |     declared_name: String, | ||||||
|  |     is_public: bool, | ||||||
|  |     definition: Option<SourceDefinition>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ModuleSymbol { | ||||||
|  |     pub fn new( | ||||||
|  |         fqn: &str, | ||||||
|  |         declared_name: &str, | ||||||
|  |         is_public: bool, | ||||||
|  |         identifier: Option<&Identifier>, | ||||||
|  |     ) -> ModuleSymbol { | ||||||
|  |         ModuleSymbol { | ||||||
|  |             fqn: fqn.to_string(), | ||||||
|  |             declared_name: declared_name.to_string(), | ||||||
|  |             is_public, | ||||||
|  |             definition: identifier.map(SourceDefinition::from_identifier), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SymbolInner for ModuleSymbol { | ||||||
|  |     fn declared_name(&self) -> &str { | ||||||
|  |         self.declared_name.as_str() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn definition(&self) -> Option<SourceDefinition> { | ||||||
|  |         self.definition.clone() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Display for ModuleSymbol { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|  |         write!( | ||||||
|  |             f, | ||||||
|  |             "ModuleSymbol(name = {}, is_public = {})", | ||||||
|  |             self.fqn, self.is_public | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Class */ | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct TypeSymbol { | ||||||
|  |     fqn: String, | ||||||
|  |     declared_name: String, | ||||||
|  |     is_public: bool, | ||||||
|  |     definition: Option<SourceDefinition>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl TypeSymbol { | ||||||
|  |     pub fn new(fqn: &str, declared_name: &str, is_public: bool, identifier: Option<&Identifier>) -> Self { | ||||||
|  |         TypeSymbol { | ||||||
|  |             fqn: fqn.to_string(), | ||||||
|  |             declared_name: declared_name.to_string(), | ||||||
|  |             is_public, | ||||||
|  |             definition: identifier.map(SourceDefinition::from_identifier), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn fqn(&self) -> &str { | ||||||
|  |         &self.fqn | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn is_public(&self) -> bool { | ||||||
|  |         self.is_public | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SymbolInner for TypeSymbol { | ||||||
|  |     fn declared_name(&self) -> &str { | ||||||
|  |         &self.declared_name | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn definition(&self) -> Option<SourceDefinition> { | ||||||
|  |         self.definition.clone() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Display for TypeSymbol { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|  |         write!( | ||||||
|  |             f, | ||||||
|  |             "TypeSymbol(fqn = {}, declared_name = {})", | ||||||
|  |             self.fqn, self.declared_name | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Function */ | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct FunctionSymbol { | ||||||
|  |     fqn: String, | ||||||
|  |     declared_name: String, | ||||||
|  |     is_public: bool, | ||||||
|  |     is_platform: bool, | ||||||
|  |     definition: Option<SourceDefinition>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl FunctionSymbol { | impl FunctionSymbol { | ||||||
| @ -74,18 +255,30 @@ impl FunctionSymbol { | |||||||
|         fqn: &str, |         fqn: &str, | ||||||
|         declared_name: &str, |         declared_name: &str, | ||||||
|         is_public: bool, |         is_public: bool, | ||||||
|         identifier: &Identifier, |         is_platform: bool, | ||||||
|  |         identifier: Option<&Identifier>, | ||||||
|     ) -> FunctionSymbol { |     ) -> FunctionSymbol { | ||||||
|         FunctionSymbol { |         FunctionSymbol { | ||||||
|             fqn: fqn.to_string(), |             fqn: fqn.to_string(), | ||||||
|             declared_name: declared_name.to_string(), |             declared_name: declared_name.to_string(), | ||||||
|             is_public, |             is_public, | ||||||
|             definition: SourceDefinition::from_identifier(identifier), |             is_platform, | ||||||
|  |             definition: identifier.map(SourceDefinition::from_identifier), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     
 | ||||||
|  |     pub fn fqn(&self) -> &str { | ||||||
|  |         &self.fqn | ||||||
|  |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     fn definition(&self) -> &SourceDefinition { | impl SymbolInner for FunctionSymbol { | ||||||
|         &self.definition |     fn declared_name(&self) -> &str { | ||||||
|  |         self.declared_name.as_str() | ||||||
|  |     } | ||||||
|  |     
 | ||||||
|  |     fn definition(&self) -> Option<SourceDefinition> { | ||||||
|  |         self.definition.clone() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -99,24 +292,69 @@ impl Display for FunctionSymbol { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | /* Parameter */ | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct ParameterSymbol { | ||||||
|  |     declared_name: String, | ||||||
|  |     definition: Option<SourceDefinition>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ParameterSymbol { | ||||||
|  |     pub fn new(declared_name: &str, identifier: Option<&Identifier>) -> Self { | ||||||
|  |         ParameterSymbol { | ||||||
|  |             declared_name: declared_name.to_string(), | ||||||
|  |             definition: identifier.map(SourceDefinition::from_identifier), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SymbolInner for ParameterSymbol { | ||||||
|  |     fn declared_name(&self) -> &str { | ||||||
|  |         &self.declared_name | ||||||
|  |     } | ||||||
|  |     
 | ||||||
|  |     fn definition(&self) -> Option<SourceDefinition> { | ||||||
|  |         self.definition.clone() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Display for ParameterSymbol { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|  |         write!( | ||||||
|  |             f, | ||||||
|  |             "ParameterSymbol({})", | ||||||
|  |             self.declared_name | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Variable */ | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
| pub struct VariableSymbol { | pub struct VariableSymbol { | ||||||
|     pub name: String, |     declared_name: String, | ||||||
|     pub is_mutable: bool, |     is_mutable: bool, | ||||||
|     definition: SourceDefinition, |     definition: Option<SourceDefinition>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl VariableSymbol { | impl VariableSymbol { | ||||||
|     pub fn new(name: &str, is_mutable: bool, definition: SourceDefinition) -> Self { |     pub fn new(declared_name: &str, is_mutable: bool, identifier: Option<&Identifier>) -> Self { | ||||||
|         VariableSymbol { |         VariableSymbol { | ||||||
|             name: name.to_string(), |             declared_name: declared_name.to_string(), | ||||||
|             is_mutable, |             is_mutable, | ||||||
|             definition, |             definition: identifier.map(SourceDefinition::from_identifier), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     pub fn definition(&self) -> &SourceDefinition { | impl SymbolInner for VariableSymbol { | ||||||
|         &self.definition |     fn declared_name(&self) -> &str { | ||||||
|  |         self.declared_name.as_str() | ||||||
|  |     } | ||||||
|  |     
 | ||||||
|  |     fn definition(&self) -> Option<SourceDefinition> { | ||||||
|  |         self.definition.clone() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -125,45 +363,7 @@ impl Display for VariableSymbol { | |||||||
|         write!( |         write!( | ||||||
|             f, |             f, | ||||||
|             "VariableSymbol(name = {}, is_mutable = {})", |             "VariableSymbol(name = {}, is_mutable = {})", | ||||||
|             self.name, self.is_mutable |             self.declared_name, self.is_mutable | ||||||
|         ) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct ModuleSymbol { |  | ||||||
|     pub fqn: String, |  | ||||||
|     pub declared_name: String, |  | ||||||
|     pub is_public: bool, |  | ||||||
|     definition: SourceDefinition, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl ModuleSymbol { |  | ||||||
|     pub fn new( |  | ||||||
|         fqn: &str, |  | ||||||
|         declared_name: &str, |  | ||||||
|         is_public: bool, |  | ||||||
|         identifier: &Identifier, |  | ||||||
|     ) -> ModuleSymbol { |  | ||||||
|         ModuleSymbol { |  | ||||||
|             fqn: fqn.to_string(), |  | ||||||
|             declared_name: declared_name.to_string(), |  | ||||||
|             is_public, |  | ||||||
|             definition: SourceDefinition::from_identifier(identifier), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn definition(&self) -> &SourceDefinition { |  | ||||||
|         &self.definition |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Display for ModuleSymbol { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |  | ||||||
|         write!( |  | ||||||
|             f, |  | ||||||
|             "ModuleSymbol(name = {}, is_public = {})", |  | ||||||
|             self.fqn, self.is_public |  | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,13 +1,24 @@ | |||||||
| use crate::name_analysis::symbol::Symbol; | use std::cell::RefCell; | ||||||
| use std::collections::HashMap; | use crate::name_analysis::symbol::{ | ||||||
| use std::fmt::Display; |     FunctionSymbol, ModuleSymbol, ParameterSymbol, Symbol, SymbolInner, TypeSymbol, | ||||||
|  |     UseStatementSymbol, VariableSymbol, | ||||||
|  | }; | ||||||
| use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; | use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; | ||||||
| use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; | use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; | ||||||
|  | use std::collections::HashMap; | ||||||
|  | use std::fmt::Display; | ||||||
|  | use std::rc::Rc; | ||||||
|  | /* Scope */ | ||||||
| 
 | 
 | ||||||
| pub struct Scope { | #[derive(Debug)] | ||||||
|  | struct Scope { | ||||||
|     parent: Option<usize>, |     parent: Option<usize>, | ||||||
|     function_and_variable_symbols: HashMap<String, Symbol>, |     use_statement_symbols: HashMap<String, Rc<RefCell<UseStatementSymbol>>>, | ||||||
|     type_and_module_symbols: HashMap<String, Symbol>, |     module_symbols: HashMap<String, Rc<ModuleSymbol>>, | ||||||
|  |     type_symbols: HashMap<String, Rc<TypeSymbol>>, | ||||||
|  |     function_symbols: HashMap<String, Rc<FunctionSymbol>>, | ||||||
|  |     parameter_symbols: HashMap<String, Rc<ParameterSymbol>>, | ||||||
|  |     variable_symbols: HashMap<String, Rc<VariableSymbol>>, | ||||||
|     debug_name: String, |     debug_name: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -15,21 +26,91 @@ impl Scope { | |||||||
|     pub fn new(parent: Option<usize>, debug_name: String) -> Scope { |     pub fn new(parent: Option<usize>, debug_name: String) -> Scope { | ||||||
|         Scope { |         Scope { | ||||||
|             parent, |             parent, | ||||||
|             function_and_variable_symbols: HashMap::new(), |             use_statement_symbols: HashMap::new(), | ||||||
|             type_and_module_symbols: HashMap::new(), |             module_symbols: HashMap::new(), | ||||||
|  |             type_symbols: HashMap::new(), | ||||||
|  |             function_symbols: HashMap::new(), | ||||||
|  |             parameter_symbols: HashMap::new(), | ||||||
|  |             variable_symbols: HashMap::new(), | ||||||
|             debug_name, |             debug_name, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     fn get_any_symbol(&self, name: &str) -> Option<Symbol> { | ||||||
|  |         self.variable_symbols.get(name) | ||||||
|  |             .map(|s| Symbol::Variable(s.clone())) | ||||||
|  |             .or_else(|| self.parameter_symbols.get(name).map(|s| Symbol::Parameter(s.clone()))) | ||||||
|  |             .or_else(|| self.function_symbols.get(name).map(|s| Symbol::Function(s.clone()))) | ||||||
|  |             .or_else(|| self.type_symbols.get(name).map(|ts| Symbol::Type(ts.clone()))) | ||||||
|  |             .or_else(|| self.module_symbols.get(name).map(|ms| Symbol::Module(ms.clone()))) | ||||||
|  |             .or_else(|| self.use_statement_symbols.get(name).map(|us| Symbol::UseStatement(us.clone()))) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_module_symbol_by_declared_name(&self, name: &str) -> Option<Rc<ModuleSymbol>> { | ||||||
|  |         for module_symbol in self.module_symbols.values() { | ||||||
|  |             if module_symbol.declared_name() == name { | ||||||
|  |                 return Some(module_symbol.clone()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         None | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_usable_symbol_by_fqn(&self, fqn: &str) -> Option<Symbol> { | ||||||
|  |         for function_symbol in self.function_symbols.values() { | ||||||
|  |             if function_symbol.fqn() == fqn { | ||||||
|  |                 return Some(Symbol::Function(function_symbol.clone())); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         for type_symbol in self.type_symbols.values() { | ||||||
|  |             if type_symbol.fqn() == fqn { | ||||||
|  |                 return Some(Symbol::Type(type_symbol.clone())); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         None | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_usable_symbol_by_declared_name(&self, declared_name: &str) -> Option<Symbol> { | ||||||
|  |         for function_symbol in self.function_symbols.values() { | ||||||
|  |             if function_symbol.declared_name() == declared_name { | ||||||
|  |                 return Some(Symbol::Function(function_symbol.clone())); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         for type_symbol in self.type_symbols.values() { | ||||||
|  |             if type_symbol.declared_name() == declared_name { | ||||||
|  |                 return Some(Symbol::Type(type_symbol.clone())); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         None | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_value_symbol_by_declared_name(&self, declared_name: &str) -> Option<Symbol> { | ||||||
|  |         for variable_symbol in self.variable_symbols.values() { | ||||||
|  |             if variable_symbol.declared_name() == declared_name { | ||||||
|  |                 return Some(Symbol::Variable(variable_symbol.clone())); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         for parameter_symbol in self.parameter_symbols.values() { | ||||||
|  |             if parameter_symbol.declared_name() == declared_name { | ||||||
|  |                 return Some(Symbol::Parameter(parameter_symbol.clone())); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         None | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* Symbol table */ | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
| pub enum SymbolInsertError { | pub enum SymbolInsertError { | ||||||
|     SymbolAlreadyDefined(Symbol), |     SymbolAlreadyDefined(Symbol), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
| pub enum SymbolLookupError { | pub enum SymbolLookupError { | ||||||
|     NoDefinition |     NoDefinition, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
| pub struct SymbolTable { | pub struct SymbolTable { | ||||||
|     scopes: Vec<Scope>, |     scopes: Vec<Scope>, | ||||||
|     current_scope_id: usize, |     current_scope_id: usize, | ||||||
| @ -49,10 +130,16 @@ impl SymbolTable { | |||||||
|         self.current_scope_id |         self.current_scope_id | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn scopes(&self) -> &Vec<Scope> { | ||||||
|  |         &self.scopes | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn push_scope(&mut self, debug_name: &str) { |     pub fn push_scope(&mut self, debug_name: &str) { | ||||||
|         let id = self.scopes.len(); |         let id = self.scopes.len(); | ||||||
|         self.scopes |         self.scopes.push(Scope::new( | ||||||
|             .push(Scope::new(Some(self.current_scope_id), debug_name.to_string())); |             Some(self.current_scope_id), | ||||||
|  |             debug_name.to_string(), | ||||||
|  |         )); | ||||||
|         self.current_scope_id = id; |         self.current_scope_id = id; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -62,47 +149,115 @@ impl SymbolTable { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn insert(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { |     pub fn insert_use_statement_symbol( | ||||||
|         match symbol { |         &mut self, | ||||||
|             Symbol::Function(_) | Symbol::Variable(_) => { |         use_statement_symbol: UseStatementSymbol, | ||||||
|                 self.insert_function_or_variable(name, symbol) |     ) -> Result<(), SymbolInsertError> { | ||||||
|             } |         let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); | ||||||
|             Symbol::Module(_) => self.insert_module_or_type(name, symbol), |         if let Some(defined_symbol) = | ||||||
|         } |             current_scope.get_usable_symbol_by_declared_name(use_statement_symbol.declared_name()) | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn insert_function_or_variable(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { |  | ||||||
|         if let Some(defined_symbol) = self.scopes[self.current_scope_id] |  | ||||||
|             .function_and_variable_symbols |  | ||||||
|             .get(name) |  | ||||||
|         { |         { | ||||||
|             Err(SymbolAlreadyDefined(defined_symbol.clone())) |             Err(SymbolAlreadyDefined(defined_symbol)) | ||||||
|         } else { |         } else { | ||||||
|             self.scopes[self.current_scope_id] |             current_scope.use_statement_symbols.insert( | ||||||
|                 .function_and_variable_symbols |                 use_statement_symbol.declared_name().to_string(), | ||||||
|                 .insert(name.to_string(), symbol); |                 Rc::new(RefCell::new(use_statement_symbol)), | ||||||
|  |             ); | ||||||
|             Ok(()) |             Ok(()) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn insert_module_or_type(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { |     pub fn insert_module_symbol( | ||||||
|         if let Some(defined_symbol) = self.scopes[self.current_scope_id] |         &mut self, | ||||||
|             .type_and_module_symbols |         module_symbol: ModuleSymbol, | ||||||
|             .get(name) |     ) -> Result<(), SymbolInsertError> { | ||||||
|  |         let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); | ||||||
|  |         if let Some(defined_symbol) = | ||||||
|  |             current_scope.get_module_symbol_by_declared_name(module_symbol.declared_name()) | ||||||
|         { |         { | ||||||
|             Err(SymbolAlreadyDefined(defined_symbol.clone())) |             Err(SymbolAlreadyDefined(Symbol::Module(defined_symbol.clone()))) | ||||||
|         } else { |         } else { | ||||||
|             self.scopes[self.current_scope_id] |             current_scope.module_symbols.insert( | ||||||
|                 .type_and_module_symbols |                 module_symbol.declared_name().to_string(), | ||||||
|                 .insert(name.to_string(), symbol); |                 Rc::new(module_symbol), | ||||||
|  |             ); | ||||||
|             Ok(()) |             Ok(()) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn lookup(&self, name: &str, scope_id: usize) -> Result<&Symbol, SymbolLookupError> { |     pub fn insert_type_symbol(&mut self, type_symbol: TypeSymbol) -> Result<(), SymbolInsertError> { | ||||||
|  |         let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); | ||||||
|  |         if let Some(defined_symbol) = | ||||||
|  |             current_scope.get_usable_symbol_by_declared_name(type_symbol.declared_name()) | ||||||
|  |         { | ||||||
|  |             Err(SymbolAlreadyDefined(defined_symbol)) | ||||||
|  |         } else { | ||||||
|  |             current_scope.type_symbols.insert( | ||||||
|  |                 type_symbol.declared_name().to_string(), | ||||||
|  |                 Rc::new(type_symbol), | ||||||
|  |             ); | ||||||
|  |             Ok(()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn insert_function_symbol( | ||||||
|  |         &mut self, | ||||||
|  |         function_symbol: FunctionSymbol, | ||||||
|  |     ) -> Result<(), SymbolInsertError> { | ||||||
|  |         let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); | ||||||
|  |         if let Some(defined_symbol) = | ||||||
|  |             current_scope.get_usable_symbol_by_declared_name(function_symbol.declared_name()) | ||||||
|  |         { | ||||||
|  |             Err(SymbolAlreadyDefined(defined_symbol)) | ||||||
|  |         } else { | ||||||
|  |             current_scope.function_symbols.insert( | ||||||
|  |                 function_symbol.declared_name().to_string(), | ||||||
|  |                 Rc::new(function_symbol), | ||||||
|  |             ); | ||||||
|  |             Ok(()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn insert_parameter_symbol( | ||||||
|  |         &mut self, | ||||||
|  |         parameter_symbol: ParameterSymbol, | ||||||
|  |     ) -> Result<(), SymbolInsertError> { | ||||||
|  |         let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); | ||||||
|  |         if let Some(defined_symbol) = | ||||||
|  |             current_scope.get_value_symbol_by_declared_name(parameter_symbol.declared_name()) | ||||||
|  |         { | ||||||
|  |             Err(SymbolAlreadyDefined(defined_symbol)) | ||||||
|  |         } else { | ||||||
|  |             current_scope.parameter_symbols.insert( | ||||||
|  |                 parameter_symbol.declared_name().to_string(), | ||||||
|  |                 Rc::new(parameter_symbol), | ||||||
|  |             ); | ||||||
|  |             Ok(()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn insert_variable_symbol( | ||||||
|  |         &mut self, | ||||||
|  |         variable_symbol: VariableSymbol, | ||||||
|  |     ) -> Result<(), SymbolInsertError> { | ||||||
|  |         let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap(); | ||||||
|  |         if let Some(defined_symbol) = | ||||||
|  |             current_scope.get_value_symbol_by_declared_name(variable_symbol.declared_name()) | ||||||
|  |         { | ||||||
|  |             Err(SymbolAlreadyDefined(defined_symbol)) | ||||||
|  |         } else { | ||||||
|  |             current_scope.variable_symbols.insert( | ||||||
|  |                 variable_symbol.declared_name().to_string(), | ||||||
|  |                 Rc::new(variable_symbol), | ||||||
|  |             ); | ||||||
|  |             Ok(()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn lookup(&self, name: &str, scope_id: usize) -> Result<Symbol, SymbolLookupError> { | ||||||
|         let mut scope_opt = Some(&self.scopes[scope_id]); |         let mut scope_opt = Some(&self.scopes[scope_id]); | ||||||
|         while let Some(scope) = scope_opt { |         while let Some(scope) = scope_opt { | ||||||
|             if let Some(symbol) = scope.function_and_variable_symbols.get(name) { |             if let Some(symbol) = scope.get_any_symbol(name) { | ||||||
|                 return Ok(symbol); |                 return Ok(symbol); | ||||||
|             } |             } | ||||||
|             scope_opt = if let Some(parent_id) = scope.parent { |             scope_opt = if let Some(parent_id) = scope.parent { | ||||||
| @ -113,6 +268,19 @@ impl SymbolTable { | |||||||
|         } |         } | ||||||
|         Err(NoDefinition) |         Err(NoDefinition) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn lookup_usable_by_fqn( | ||||||
|  |         &self, | ||||||
|  |         fully_qualified_name: &str, | ||||||
|  |         scope_id: usize, | ||||||
|  |     ) -> Result<Symbol, SymbolLookupError> { | ||||||
|  |         for scope in &self.scopes { | ||||||
|  |             if let Some(symbol) = scope.get_usable_symbol_by_fqn(fully_qualified_name) { | ||||||
|  |                 return Ok(symbol); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Err(NoDefinition) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Display for SymbolTable { | impl Display for SymbolTable { | ||||||
| @ -120,7 +288,19 @@ impl Display for SymbolTable { | |||||||
|         writeln!(f, "SymbolTable(current_scope = {})", self.current_scope_id)?; |         writeln!(f, "SymbolTable(current_scope = {})", self.current_scope_id)?; | ||||||
|         for (i, scope) in self.scopes.iter().enumerate() { |         for (i, scope) in self.scopes.iter().enumerate() { | ||||||
|             writeln!(f, "Scope {} {}", i, scope.debug_name)?; |             writeln!(f, "Scope {} {}", i, scope.debug_name)?; | ||||||
|             for (name, symbol) in &scope.function_and_variable_symbols { |             for (name, symbol) in &scope.use_statement_symbols { | ||||||
|  |                 writeln!(f, "  {}({})", name, symbol.borrow())?; | ||||||
|  |             } | ||||||
|  |             for (name, symbol) in &scope.module_symbols { | ||||||
|  |                 writeln!(f, "  {}({})", name, symbol)?; | ||||||
|  |             } | ||||||
|  |             for (name, symbol) in &scope.type_symbols { | ||||||
|  |                 writeln!(f, "  {}({})", name, symbol)?; | ||||||
|  |             } | ||||||
|  |             for (name, symbol) in &scope.function_symbols { | ||||||
|  |                 writeln!(f, "  {}({})", name, symbol)?; | ||||||
|  |             } | ||||||
|  |             for (name, symbol) in &scope.variable_symbols { | ||||||
|                 writeln!(f, "  {}({})", name, symbol)?; |                 writeln!(f, "  {}({})", name, symbol)?; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ Move = { "move" } | |||||||
| Alias = { "alias" } | Alias = { "alias" } | ||||||
| True = { "true" } | True = { "true" } | ||||||
| False = { "false" } | False = { "false" } | ||||||
|  | Use = { "use" } | ||||||
| 
 | 
 | ||||||
| // Keywords as a rule (for preventing identifiers with keywords, etc.) | // Keywords as a rule (for preventing identifiers with keywords, etc.) | ||||||
| Keyword = { | Keyword = { | ||||||
| @ -64,6 +65,7 @@ Keyword = { | |||||||
|     | Alias |     | Alias | ||||||
|     | True |     | True | ||||||
|     | False |     | False | ||||||
|  |     | Use | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Symbols | // Symbols | ||||||
| @ -280,7 +282,8 @@ RefList = { | |||||||
| 
 | 
 | ||||||
| CompilationUnit = { | CompilationUnit = { | ||||||
|       SOI |       SOI | ||||||
|     ~ Namespace? |     ~ ( Namespace ~ Semicolon )? | ||||||
|  |     ~ ( UseStatement ~ Semicolon )* | ||||||
|     ~ ModuleLevelDeclaration* |     ~ ModuleLevelDeclaration* | ||||||
|     ~ EOI |     ~ EOI | ||||||
| } | } | ||||||
| @ -382,6 +385,7 @@ PlatformFunction = { | |||||||
|     ~ Identifier |     ~ Identifier | ||||||
|     ~ Parameters |     ~ Parameters | ||||||
|     ~ ReturnType |     ~ ReturnType | ||||||
|  |     ~ ";" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| InterfaceFunction = { | InterfaceFunction = { | ||||||
| @ -479,6 +483,20 @@ Field = { | |||||||
| 
 | 
 | ||||||
| // Statements | // Statements | ||||||
| 
 | 
 | ||||||
|  | UseStatement = { | ||||||
|  |       Use | ||||||
|  |     ~ Identifier | ||||||
|  |     ~ ( "::" ~ Identifier )* | ||||||
|  |     ~ ( "::" ~ ( Star | UseList ) )? | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | UseList = { | ||||||
|  |       "{" | ||||||
|  |     ~ Identifier | ||||||
|  |     ~ ( "," ~ Identifier )* | ||||||
|  |     ~ "}" | ||||||
|  | } | ||||||
|  | 
 | ||||||
| BlockStatement = { | BlockStatement = { | ||||||
|       "{" |       "{" | ||||||
|     ~ Statement* |     ~ Statement* | ||||||
| @ -492,6 +510,7 @@ Statement = { | |||||||
|         | AssignmentStatement |         | AssignmentStatement | ||||||
|         | CallStatement |         | CallStatement | ||||||
|         | ReturnStatement |         | ReturnStatement | ||||||
|  |         | UseStatement | ||||||
|       ) |       ) | ||||||
|     ~ Semicolon |     ~ Semicolon | ||||||
|     | ( |     | ( | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ pub struct DeimosParser; | |||||||
| mod deimos_parser_tests { | mod deimos_parser_tests { | ||||||
|     use crate::parser::{DeimosParser, Rule}; |     use crate::parser::{DeimosParser, Rule}; | ||||||
|     use indoc::indoc; |     use indoc::indoc; | ||||||
|     use pest::{parses_to, Parser}; |     use pest::Parser; | ||||||
| 
 | 
 | ||||||
|     macro_rules! fail_rule { |     macro_rules! fail_rule { | ||||||
|         ($pair: expr; $rule:path) => {{ |         ($pair: expr; $rule:path) => {{ | ||||||
| @ -147,37 +147,58 @@ mod deimos_parser_tests { | |||||||
|             }"},
 |             }"},
 | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|     
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn while_statement() { |     fn while_statement() { | ||||||
|         parses_to(Rule::WhileStatement, "while (foo) { bar() }"); |         parses_to(Rule::WhileStatement, "while (foo) { bar() }"); | ||||||
|     } |     } | ||||||
|     
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn for_statement() { |     fn for_statement() { | ||||||
|         parses_to(Rule::ForStatement, "for (foo in bar) { baz(foo); }"); |         parses_to(Rule::ForStatement, "for (foo in bar) { baz(foo); }"); | ||||||
|     } |     } | ||||||
|     
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn if_statement_with_call_condition() { |     fn if_statement_with_call_condition() { | ||||||
|         parses_to(Rule::IfStatement, indoc! {" |         parses_to( | ||||||
|  |             Rule::IfStatement, | ||||||
|  |             indoc! {" | ||||||
|             if (foo()) { |             if (foo()) { | ||||||
|                 bar() |                 bar() | ||||||
|             } |             } | ||||||
|         "})
 |         "},
 | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
|     
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn while_statement_with_call_condition() { |     fn while_statement_with_call_condition() { | ||||||
|         parses_to(Rule::WhileStatement, "while (foo()) { bar(); }") |         parses_to(Rule::WhileStatement, "while (foo()) { bar(); }") | ||||||
|     } |     } | ||||||
|     
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn for_statement_with_call_iterator() { |     fn for_statement_with_call_iterator() { | ||||||
|         parses_to(Rule::ForStatement, indoc! {" |         parses_to( | ||||||
|  |             Rule::ForStatement, | ||||||
|  |             indoc! {" | ||||||
|             for (foo in bar()) { |             for (foo in bar()) { | ||||||
|                 baz(foo); |                 baz(foo); | ||||||
|             } |             } | ||||||
|         "})
 |         "},
 | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn use_statement() { | ||||||
|  |         parses_to(Rule::UseStatement, "use std::core::println"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn use_star() { | ||||||
|  |         parses_to(Rule::UseStatement, "use std::core::*") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn use_list() { | ||||||
|  |         parses_to(Rule::UseStatement, "use std::core::{print, println}"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										23
									
								
								src/std_core/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/std_core/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | use crate::name_analysis::symbol::{FunctionSymbol, TypeSymbol}; | ||||||
|  | use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; | ||||||
|  | 
 | ||||||
|  | pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), SymbolInsertError> { | ||||||
|  |     symbol_table.insert_type_symbol(TypeSymbol::new("std::core:Array", "Array", true, None))?; | ||||||
|  |     // todo: make this primitive
 | ||||||
|  |     symbol_table.insert_type_symbol(TypeSymbol::new("std::core::String", "String", true, None))?; | ||||||
|  |     symbol_table.insert_function_symbol(FunctionSymbol::new( | ||||||
|  |         "std::core::println", | ||||||
|  |         "println", | ||||||
|  |         true, | ||||||
|  |         true, | ||||||
|  |         None, | ||||||
|  |     ))?; | ||||||
|  |     symbol_table.insert_function_symbol(FunctionSymbol::new( | ||||||
|  |         "std::core::print", | ||||||
|  |         "print", | ||||||
|  |         true, | ||||||
|  |         true, | ||||||
|  |         None, | ||||||
|  |     ))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user