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}; | ||||
							
								
								
									
										139
									
								
								src/ast/build.rs
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								src/ast/build.rs
									
									
									
									
									
								
							| @ -15,8 +15,12 @@ fn expect_and_use<T>( | ||||
|     f(file_id, pair) | ||||
| } | ||||
| 
 | ||||
| pub fn build_ast(file_id: usize, compilation_unit_pair: Pair<Rule>) -> CompilationUnit { | ||||
|     build_compilation_unit(file_id, compilation_unit_pair) | ||||
| pub fn build_ast( | ||||
|     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 { | ||||
| @ -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 use_statements = vec![]; | ||||
|     let mut declarations = vec![]; | ||||
| 
 | ||||
|     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 => { | ||||
|                 namespace = Some(build_namespace(file_id, inner_pair)); | ||||
|             } | ||||
|             Rule::UseStatement => { | ||||
|                 use_statements.push(build_use_statement(file_id, inner_pair)); | ||||
|             } | ||||
|             Rule::ModuleLevelDeclaration => { | ||||
|                 declarations.push(build_module_level_declaration(file_id, inner_pair)); | ||||
|             } | ||||
|             Rule::EOI => {} | ||||
|             Rule::Semicolon | Rule::EOI => {} | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     CompilationUnit { | ||||
|         file_name: file_name.to_string(), | ||||
|         file_id, | ||||
|         namespace, | ||||
|         use_statements, | ||||
|         declarations, | ||||
|     } | ||||
| } | ||||
| @ -579,7 +594,46 @@ fn build_platform_function_declaration( | ||||
|     file_id: usize, | ||||
|     platform_function_pair: Pair<Rule>, | ||||
| ) -> 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( | ||||
| @ -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 { | ||||
|     let mut statements = vec![]; | ||||
|     let mut expression = None; | ||||
| @ -1558,7 +1665,7 @@ mod tests { | ||||
|             if pairs.as_str().trim() != src.trim() { | ||||
|                 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()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -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 pest::Parser; | ||||
| use std::borrow::Cow; | ||||
| use std::cell::RefCell; | ||||
| use std::range::Range; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| pub mod build; | ||||
| pub mod named; | ||||
| @ -87,6 +91,10 @@ impl Identifier { | ||||
|     pub fn symbol(&self) -> &Option<Symbol> { | ||||
|         &self.symbol | ||||
|     } | ||||
| 
 | ||||
|     pub fn symbol_mut(&mut self) -> Option<Symbol> { | ||||
|         self.symbol.clone() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| @ -287,7 +295,10 @@ impl Default for References { | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct CompilationUnit { | ||||
|     pub file_name: String, | ||||
|     pub file_id: usize, | ||||
|     pub namespace: Option<FullyQualifiedName>, | ||||
|     pub use_statements: Vec<UseStatement>, | ||||
|     pub declarations: Vec<ModuleLevelDeclaration>, | ||||
| } | ||||
| 
 | ||||
| @ -448,6 +459,91 @@ pub struct FieldDeclaration { | ||||
| 
 | ||||
| // 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)] | ||||
| pub struct BlockStatement { | ||||
|     pub statements: Vec<Statement>, | ||||
| @ -556,8 +652,8 @@ pub struct PrefixExpression { | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct SuffixExpression { | ||||
|     expression: Box<Expression>, | ||||
|     operator: SuffixUnaryOperator, | ||||
|     pub expression: Box<Expression>, | ||||
|     pub operator: SuffixUnaryOperator, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
|  | ||||
| @ -282,6 +282,9 @@ impl PrettyPrint for CompilationUnit { | ||||
|             namespace.pretty_print(writer)?; | ||||
|             writer.decrease_indent(); | ||||
|         } | ||||
|         for use_statement in &self.use_statements { | ||||
|             use_statement.pretty_print(writer)?; | ||||
|         } | ||||
|         for declaration in &self.declarations { | ||||
|             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 { | ||||
|     fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { | ||||
|         writer.writeln_indented("BlockStatement")?; | ||||
|  | ||||
| @ -373,7 +373,11 @@ impl Unparse for CompilationUnit { | ||||
|         if let Some(namespace) = &self.namespace { | ||||
|             writer.write("ns ")?; | ||||
|             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))?; | ||||
|         Ok(()) | ||||
| @ -570,6 +574,7 @@ impl Unparse for PlatformFunctionDeclaration { | ||||
|         self.parameters.unparse(writer)?; | ||||
|         writer.write(" ")?; | ||||
|         self.return_type.unparse(writer)?; | ||||
|         writer.write(";")?; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| @ -722,6 +727,41 @@ impl Unparse for FieldDeclaration { | ||||
| 
 | ||||
| /* 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 { | ||||
|     fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { | ||||
|         writer.writeln_indented("{")?; | ||||
|  | ||||
| @ -45,11 +45,9 @@ fn main() { | ||||
|             } | ||||
|         } | ||||
|         Commands::NameAnalysis { paths } => { | ||||
|             for path in paths { | ||||
|                 let result = name_analysis(&path); | ||||
|             let result = name_analysis(&paths); | ||||
|             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::parser::{DeimosParser, Rule}; | ||||
| 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 mut compilation_units = vec![]; | ||||
|     let mut files = SimpleFiles::new(); | ||||
|     
 | ||||
|     for path in paths { | ||||
|         let src = std::fs::read_to_string(path).unwrap(); | ||||
|         let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src); | ||||
|     let mut files = SimpleFiles::new(); | ||||
|     let file_id = files.add(path.display().to_string(), &src); | ||||
|         let file_id = files.add(path.display().to_string(), src.clone()); // I don't love this clone
 | ||||
| 
 | ||||
|         match parse_result { | ||||
|             Ok(mut pairs) => { | ||||
|                 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); | ||||
|                 compilation_units.push(compilation_unit); | ||||
|                 Ok::<(), Box<dyn std::error::Error>>(()) | ||||
|             } | ||||
|             Err(e) => Err(e.into()), | ||||
|         }?; | ||||
|     } | ||||
| 
 | ||||
|     let mut symbol_table = SymbolTable::new(); | ||||
|             let diagnostics = analyze_names(file_id, &mut compilation_unit, &mut symbol_table); | ||||
|     
 | ||||
|     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); | ||||
|                 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()), | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -11,7 +11,7 @@ pub fn pretty_print_parse(path: &PathBuf) { | ||||
|     match parse_result { | ||||
|         Ok(mut pairs) => { | ||||
|             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())); | ||||
|             compilation_unit | ||||
|                 .pretty_print(&mut indent_writer) | ||||
|  | ||||
| @ -11,7 +11,7 @@ pub fn unparse(path: &PathBuf) { | ||||
|     match parse_result { | ||||
|         Ok(mut pairs) => { | ||||
|             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())); | ||||
|             compilation_unit | ||||
|                 .unparse(&mut writer) | ||||
|  | ||||
| @ -6,5 +6,6 @@ pub mod module; | ||||
| pub mod name_analysis; | ||||
| pub mod object_file; | ||||
| pub mod parser; | ||||
| mod std_core; | ||||
| pub mod util; | ||||
| pub mod vm; | ||||
|  | ||||
| @ -1,11 +1,13 @@ | ||||
| use crate::ast::named::Named; | ||||
| use crate::ast::*; | ||||
| use crate::diagnostic::DmDiagnostic; | ||||
| 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::DiagnosticsContainer; | ||||
| use codespan_reporting::diagnostic::{Diagnostic, Label}; | ||||
| use std::cell::RefCell; | ||||
| use std::range::Range; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| fn handle_insert_error( | ||||
|     err: SymbolInsertError, | ||||
| @ -13,14 +15,11 @@ fn handle_insert_error( | ||||
|     error_file_id: usize, | ||||
|     error_range: Range<usize>, | ||||
|     symbol_types: &str, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     match err { | ||||
|         SymbolInsertError::SymbolAlreadyDefined(s) => { | ||||
|             let already_defined_definition = s.definition(); | ||||
| 
 | ||||
|             diagnostics.add( | ||||
|                 Diagnostic::error() | ||||
|             let mut diagnostic = Diagnostic::error() | ||||
|                 .with_message(format!( | ||||
|                     "{} symbol '{}' already defined in the current scope.", | ||||
|                     symbol_types, error_symbol_name, | ||||
| @ -28,33 +27,209 @@ fn handle_insert_error( | ||||
|                 .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."), | ||||
|                     ), | ||||
|                 ); | ||||
| 
 | ||||
|             if let Some(source_definition) = s.definition() { | ||||
|                 diagnostic = diagnostic.with_label( | ||||
|                     Label::secondary(source_definition.file_id(), source_definition.range()) | ||||
|                         .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, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     use ModuleLevelDeclaration::*; | ||||
|     match declaration { | ||||
|         Module(module_declaration) => { | ||||
|             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) => { | ||||
|             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!(), | ||||
|     } | ||||
| } | ||||
| @ -63,7 +238,7 @@ fn gather_module_declaration( | ||||
|     declaration: &mut ModuleDeclaration, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     // 1. Add mod identifier symbol
 | ||||
|     // 2. Update fqn context
 | ||||
| @ -73,15 +248,12 @@ fn gather_module_declaration( | ||||
| 
 | ||||
|     let module_name = declaration.identifier.name(); | ||||
| 
 | ||||
|     let insert_result = symbol_table.insert( | ||||
|         &module_name, | ||||
|         Symbol::Module(ModuleSymbol::new( | ||||
|     let insert_result = symbol_table.insert_module_symbol(ModuleSymbol::new( | ||||
|         &fqn_context.resolve(&module_name), | ||||
|         &module_name, | ||||
|         declaration.is_public, | ||||
|             &declaration.identifier, | ||||
|         )), | ||||
|     ); | ||||
|         Some(&declaration.identifier), | ||||
|     )); | ||||
| 
 | ||||
|     if let Err(err) = insert_result { | ||||
|         handle_insert_error( | ||||
| @ -96,31 +268,58 @@ fn gather_module_declaration( | ||||
| 
 | ||||
|     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 { | ||||
|         gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics); | ||||
|     } | ||||
|     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( | ||||
|     function: &mut FunctionDefinition, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     let declared_name = function.identifier.name(); | ||||
|     let resolved_name = fqn_context.resolve(&declared_name); | ||||
| 
 | ||||
|     let insert_result = symbol_table.insert( | ||||
|         &declared_name, | ||||
|         Symbol::Function(FunctionSymbol::new( | ||||
|     let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( | ||||
|         &resolved_name, | ||||
|         &declared_name, | ||||
|         function.is_public, | ||||
|             &function.identifier, | ||||
|         )), | ||||
|     ); | ||||
|         false, | ||||
|         Some(&function.identifier), | ||||
|     )); | ||||
| 
 | ||||
|     if let Err(err) = insert_result { | ||||
|         handle_insert_error( | ||||
| @ -148,11 +347,55 @@ fn gather_function_definition( | ||||
|     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( | ||||
|     parameters: &mut Parameters, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     for parameter in &mut parameters.0 { | ||||
|         gather_parameter(parameter, symbol_table, fqn_context, diagnostics); | ||||
| @ -163,18 +406,14 @@ fn gather_parameter( | ||||
|     parameter: &mut Parameter, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     let parameter_name = parameter.identifier.name(); | ||||
| 
 | ||||
|     let insert_result = symbol_table.insert( | ||||
|     let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( | ||||
|         ¶meter_name, | ||||
|         Symbol::Variable(VariableSymbol::new( | ||||
|             ¶meter_name, | ||||
|             false, | ||||
|             SourceDefinition::from_identifier(¶meter.identifier), | ||||
|         )), | ||||
|     ); | ||||
|         Some(¶meter.identifier), | ||||
|     )); | ||||
| 
 | ||||
|     if let Err(err) = insert_result { | ||||
|         handle_insert_error( | ||||
| @ -190,13 +429,20 @@ fn gather_parameter( | ||||
|     parameter | ||||
|         .identifier | ||||
|         .set_scope_id(symbol_table.current_scope_id()); | ||||
| 
 | ||||
|     gather_type_use( | ||||
|         &mut parameter.type_use, | ||||
|         symbol_table, | ||||
|         fqn_context, | ||||
|         diagnostics, | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| fn gather_function_body( | ||||
|     function_body: &mut FunctionBody, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     use crate::ast::FunctionBody::*; | ||||
|     match function_body { | ||||
| @ -209,7 +455,7 @@ fn gather_block_statement( | ||||
|     block: &mut BlockStatement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     symbol_table.push_scope("BlockStatementScope"); | ||||
|     gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics); | ||||
| @ -220,7 +466,7 @@ fn gather_block_statement_inner( | ||||
|     block: &mut BlockStatement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     for statement in &mut block.statements { | ||||
|         gather_statement(statement, symbol_table, fqn_context, diagnostics); | ||||
| @ -234,7 +480,7 @@ fn gather_statement( | ||||
|     statement: &mut Statement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     fqn_context: &mut FqnContext, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     use crate::ast::Statement::*; | ||||
|     match statement { | ||||
| @ -247,6 +493,9 @@ fn gather_statement( | ||||
|         AssignStatement(assign_statement) => { | ||||
|             gather_assign_statement(assign_statement, symbol_table, fqn_context, diagnostics) | ||||
|         } | ||||
|         CallStatement(call_statement) => { | ||||
|             gather_call_statement(call_statement, symbol_table, diagnostics) | ||||
|         } | ||||
|         _ => todo!(), | ||||
|     } | ||||
| } | ||||
| @ -254,18 +503,15 @@ fn gather_statement( | ||||
| fn gather_variable_declaration( | ||||
|     variable_declaration: &mut VariableDeclarationStatement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     let variable_name = variable_declaration.identifier.name(); | ||||
| 
 | ||||
|     let insert_result = symbol_table.insert( | ||||
|         &variable_name, | ||||
|         Symbol::Variable(VariableSymbol::new( 
 | ||||
|     let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new( | ||||
|         &variable_name, | ||||
|         variable_declaration.is_mutable, | ||||
|             SourceDefinition::from_identifier(&variable_declaration.identifier), | ||||
|         )), | ||||
|     ); | ||||
|         Some(&variable_declaration.identifier), | ||||
|     )); | ||||
| 
 | ||||
|     if let Err(err) = insert_result { | ||||
|         handle_insert_error( | ||||
| @ -291,29 +537,156 @@ fn gather_assign_statement( | ||||
|     assign_statement: &mut AssignStatement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     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.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( | ||||
|     expression: &mut Expression, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     use crate::ast::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) => { | ||||
|             gather_fully_qualified_name(fully_qualified_name, symbol_table); | ||||
|         } | ||||
|         _ => {} | ||||
|         Closure(closure) => { | ||||
|             gather_closure(closure, symbol_table, diagnostics); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn gather_fully_qualified_name( | ||||
|     fully_qualified_name: &mut FullyQualifiedName, | ||||
| fn gather_ternary_expression( | ||||
|     ternary_expression: &mut TernaryExpression, | ||||
|     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::{CompilationUnit, Identifier}; | ||||
| use crate::ast::CompilationUnit; | ||||
| use crate::diagnostic::DmDiagnostic; | ||||
| use crate::name_analysis::fqn_context::FqnContext; | ||||
| use crate::name_analysis::gather::gather_module_level_declaration; | ||||
| use crate::name_analysis::resolve::resolve_module_level_declaration; | ||||
| use crate::name_analysis::gather::gather_compilation_unit; | ||||
| use crate::name_analysis::resolve::resolve_compilation_unit; | ||||
| use crate::name_analysis::symbol_table::SymbolTable; | ||||
| use codespan_reporting::diagnostic::{Diagnostic, Label}; | ||||
| use log::debug; | ||||
| 
 | ||||
| mod fqn_context; | ||||
| mod gather; | ||||
| @ -14,63 +11,20 @@ mod resolve; | ||||
| pub mod symbol; | ||||
| 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( | ||||
|     file_id: usize, | ||||
|     compilation_unit: &mut CompilationUnit, | ||||
|     compilation_units: &mut Vec<CompilationUnit>, | ||||
|     symbol_table: &mut SymbolTable, | ||||
| ) -> Vec<DmDiagnostic> { | ||||
|     let mut diagnostics = DiagnosticsContainer::new(file_id); | ||||
|     let mut diagnostics = vec![]; | ||||
| 
 | ||||
|     let mut fqn_context = FqnContext::new(); | ||||
|     if let Some(namespace) = &compilation_unit.namespace { | ||||
|         fqn_context.push(namespace.name().to_string()); | ||||
|     // gather symbols
 | ||||
|     for compilation_unit in compilation_units.iter_mut() { | ||||
|         gather_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); | ||||
|     } | ||||
| 
 | ||||
|     for declaration in &mut compilation_unit.declarations { | ||||
|         gather_module_level_declaration( | ||||
|             declaration, | ||||
|             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); | ||||
|     // resolve symbols
 | ||||
|     for compilation_unit in compilation_units.iter_mut() { | ||||
|         resolve_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); | ||||
|     } | ||||
| 
 | ||||
|     diagnostics.into() | ||||
| @ -81,26 +35,36 @@ mod tests { | ||||
|     use super::*; | ||||
|     use crate::ast::build::build_ast; | ||||
|     use crate::parser::{DeimosParser, Rule}; | ||||
|     use crate::std_core::add_std_core_symbols; | ||||
|     use codespan_reporting::files::SimpleFiles; | ||||
|     use codespan_reporting::term; | ||||
|     use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; | ||||
|     use indoc::indoc; | ||||
|     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 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 { | ||||
|             let file_id = files.add(file_name, source); | ||||
|             let parse_result = DeimosParser::parse(Rule::CompilationUnit, source); | ||||
|             if let Err(err) = &parse_result { | ||||
|             panic!("{:?}", err); | ||||
|                 panic!("{}", err); | ||||
|             } | ||||
|             let mut pairs = parse_result.unwrap(); | ||||
|             if pairs.as_str().trim() != source.trim() { | ||||
|                 panic!("Parsing did not consume entire input."); | ||||
|             } | ||||
| 
 | ||||
|         let compilation_unit_pair = parse_result.unwrap().next().unwrap(); | ||||
|         let mut ast = build_ast(test_file_id, compilation_unit_pair); | ||||
|             compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap())) | ||||
|         } | ||||
| 
 | ||||
|         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() { | ||||
|             let writer = StandardStream::stderr(ColorChoice::Always); | ||||
| @ -113,16 +77,50 @@ mod tests { | ||||
|             eprintln!("{}", symbol_table); | ||||
|             panic!("Diagnostics was not empty!"); | ||||
|         } | ||||
| 
 | ||||
|         for compilation_unit in &compilation_units { | ||||
|             dbg!(compilation_unit); | ||||
|         } | ||||
| 
 | ||||
|         symbol_table | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn params_seen() { | ||||
|         assert_no_diagnostics( | ||||
|             r#" | ||||
|         let sources: HashMap<&str, &str> = HashMap::from([( | ||||
|             "main.dm", | ||||
|             indoc! {" | ||||
|             fn main(args: Array<String>) { | ||||
|                 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::*; | ||||
| use crate::diagnostic::DmDiagnostic; | ||||
| use crate::name_analysis::symbol_table::SymbolTable; | ||||
| use crate::name_analysis::DiagnosticsContainer; | ||||
| 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( | ||||
|     declaration: &mut ModuleLevelDeclaration, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     use crate::ast::ModuleLevelDeclaration::*; | ||||
|     match declaration { | ||||
|         Function(function_definition) => { | ||||
|             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!(), | ||||
|     } | ||||
| } | ||||
| @ -21,15 +231,42 @@ pub(super) fn resolve_module_level_declaration( | ||||
| fn resolve_function_definition( | ||||
|     function_definition: &mut FunctionDefinition, | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
| 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( | ||||
|     function_body: &mut FunctionBody, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     use crate::ast::FunctionBody::*; | ||||
|     match function_body { | ||||
| @ -41,7 +278,7 @@ fn resolve_function_body( | ||||
| fn resolve_block( | ||||
|     block_statement: &mut BlockStatement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     for statement in block_statement.statements.iter_mut() { | ||||
|         resolve_statement(statement, symbol_table, diagnostics); | ||||
| @ -54,7 +291,7 @@ fn resolve_block( | ||||
| fn resolve_statement( | ||||
|     statement: &mut Statement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     use crate::ast::Statement::*; | ||||
|     match statement { | ||||
| @ -75,7 +312,7 @@ fn resolve_statement( | ||||
| fn resolve_variable_declaration( | ||||
|     variable_declaration: &mut VariableDeclarationStatement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     if let Some(initializer) = &mut variable_declaration.initializer { | ||||
|         resolve_expression(initializer, symbol_table, diagnostics) | ||||
| @ -85,7 +322,7 @@ fn resolve_variable_declaration( | ||||
| fn resolve_assign_statement( | ||||
|     assign_statement: &mut AssignStatement, | ||||
|     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.rhs, symbol_table, diagnostics); | ||||
| @ -94,7 +331,7 @@ fn resolve_assign_statement( | ||||
| fn resolve_call_statement( | ||||
|     call_statement: &mut CallStatement, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     resolve_expression(&mut call_statement.0, symbol_table, diagnostics) | ||||
| } | ||||
| @ -102,42 +339,151 @@ fn resolve_call_statement( | ||||
| fn resolve_expression( | ||||
|     expression: &mut Expression, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     use crate::ast::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), | ||||
|         Literal(_) => {} | ||||
|         _ => todo!(), | ||||
|         Literal(literal) => { | ||||
|             resolve_literal(literal, symbol_table, diagnostics); | ||||
|         } | ||||
|         Closure(closure) => { | ||||
|             resolve_closure(closure, symbol_table, diagnostics); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn resolve_fully_qualified_name( | ||||
|     fully_qualified_name: &mut FullyQualifiedName, | ||||
| fn resolve_ternary_expression( | ||||
|     ternary_expression: &mut TernaryExpression, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut DiagnosticsContainer, | ||||
|     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 | ||||
|         )), | ||||
|     resolve_expression(&mut ternary_expression.condition, symbol_table, diagnostics); | ||||
|     resolve_expression( | ||||
|         &mut ternary_expression.true_expression, | ||||
|         symbol_table, | ||||
|         diagnostics, | ||||
|     ); | ||||
|     match lookup_result { | ||||
|         Ok(symbol) => { | ||||
|             fully_qualified_name.set_symbol(symbol.clone()); | ||||
|     resolve_expression( | ||||
|         &mut ternary_expression.false_expression, | ||||
|         symbol_table, | ||||
|         diagnostics, | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| fn resolve_binary_expression( | ||||
|     binary_expression: &mut BinaryExpression, | ||||
|     symbol_table: &mut SymbolTable, | ||||
|     diagnostics: &mut Vec<DmDiagnostic>, | ||||
| ) { | ||||
|     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); | ||||
|     } | ||||
|         Err(e) => diagnostics.add( | ||||
|             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, | ||||
|                 )), | ||||
|         ), | ||||
|     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::range::Range; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct SourceDefinition { | ||||
| @ -16,6 +18,22 @@ impl SourceDefinition { | ||||
|         } | ||||
|     } | ||||
|     
 | ||||
|     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 { | ||||
|         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)] | ||||
| pub enum Symbol { | ||||
|     Function(FunctionSymbol), | ||||
|     Variable(VariableSymbol), | ||||
|     Module(ModuleSymbol), | ||||
|     UseStatement(Rc<RefCell<UseStatementSymbol>>), | ||||
|     Module(Rc<ModuleSymbol>), | ||||
|     Type(Rc<TypeSymbol>), | ||||
|     Function(Rc<FunctionSymbol>), | ||||
|     Parameter(Rc<ParameterSymbol>), | ||||
|     Variable(Rc<VariableSymbol>), | ||||
| } | ||||
| 
 | ||||
| impl Symbol { | ||||
|     pub fn name(&self) -> &str { | ||||
|     pub fn definition(&self) -> Option<SourceDefinition> { | ||||
|         match self { | ||||
|             Symbol::Function(s) => s.declared_name.as_str(), | ||||
|             Symbol::Variable(s) => s.name.as_str(), | ||||
|             Symbol::Module(s) => s.declared_name.as_str(), | ||||
|             Symbol::UseStatement(s) => s.borrow().definition.clone(), | ||||
|             Symbol::Module(s) => s.definition(), | ||||
|             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 { | ||||
|             Symbol::Function(s) => s.definition(), | ||||
|             Symbol::Module(s) => s.definition(), | ||||
|             Symbol::Variable(s) => s.definition(), | ||||
|             Symbol::UseStatement(s) => s.clone(), | ||||
|             _ => panic!("unwrap_use_statement_symbol called on non-use statement symbol"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -54,19 +84,170 @@ impl Display for Symbol { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||
|         use Symbol::*; | ||||
|         match self { | ||||
|             Function(function_symbol) => write!(f, "{}", function_symbol), | ||||
|             Variable(variable_symbol) => write!(f, "{}", variable_symbol), | ||||
|             UseStatement(use_statement_symbol) => write!(f, "{}", use_statement_symbol.borrow()), | ||||
|             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)] | ||||
| pub struct FunctionSymbol { | ||||
| pub struct UseStatementSymbol { | ||||
|     pub fqn: String, | ||||
|     pub declared_name: String, | ||||
|     pub is_public: bool, | ||||
|     definition: SourceDefinition, | ||||
|     definition: Option<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 { | ||||
| @ -74,18 +255,30 @@ impl FunctionSymbol { | ||||
|         fqn: &str, | ||||
|         declared_name: &str, | ||||
|         is_public: bool, | ||||
|         identifier: &Identifier, | ||||
|         is_platform: bool, | ||||
|         identifier: Option<&Identifier>, | ||||
|     ) -> FunctionSymbol { | ||||
|         FunctionSymbol { | ||||
|             fqn: fqn.to_string(), | ||||
|             declared_name: declared_name.to_string(), | ||||
|             is_public, | ||||
|             definition: SourceDefinition::from_identifier(identifier), | ||||
|             is_platform, | ||||
|             definition: identifier.map(SourceDefinition::from_identifier), | ||||
|         } | ||||
|     } | ||||
|     
 | ||||
|     fn definition(&self) -> &SourceDefinition { | ||||
|         &self.definition | ||||
|     pub fn fqn(&self) -> &str { | ||||
|         &self.fqn | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl SymbolInner for FunctionSymbol { | ||||
|     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 name: String, | ||||
|     pub is_mutable: bool, | ||||
|     definition: SourceDefinition, | ||||
|     declared_name: String, | ||||
|     is_mutable: bool, | ||||
|     definition: Option<SourceDefinition>, | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|             name: name.to_string(), | ||||
|             declared_name: declared_name.to_string(), | ||||
|             is_mutable, | ||||
|             definition, | ||||
|             definition: identifier.map(SourceDefinition::from_identifier), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl SymbolInner for VariableSymbol { | ||||
|     fn declared_name(&self) -> &str { | ||||
|         self.declared_name.as_str() | ||||
|     } | ||||
|     
 | ||||
|     pub fn definition(&self) -> &SourceDefinition { | ||||
|         &self.definition | ||||
|     fn definition(&self) -> Option<SourceDefinition> { | ||||
|         self.definition.clone() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -125,45 +363,7 @@ impl Display for VariableSymbol { | ||||
|         write!( | ||||
|             f, | ||||
|             "VariableSymbol(name = {}, is_mutable = {})", | ||||
|             self.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 | ||||
|             self.declared_name, self.is_mutable | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,13 +1,24 @@ | ||||
| use crate::name_analysis::symbol::Symbol; | ||||
| use std::collections::HashMap; | ||||
| use std::fmt::Display; | ||||
| use std::cell::RefCell; | ||||
| use crate::name_analysis::symbol::{ | ||||
|     FunctionSymbol, ModuleSymbol, ParameterSymbol, Symbol, SymbolInner, TypeSymbol, | ||||
|     UseStatementSymbol, VariableSymbol, | ||||
| }; | ||||
| use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; | ||||
| 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>, | ||||
|     function_and_variable_symbols: HashMap<String, Symbol>, | ||||
|     type_and_module_symbols: HashMap<String, Symbol>, | ||||
|     use_statement_symbols: HashMap<String, Rc<RefCell<UseStatementSymbol>>>, | ||||
|     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, | ||||
| } | ||||
| 
 | ||||
| @ -15,21 +26,91 @@ impl Scope { | ||||
|     pub fn new(parent: Option<usize>, debug_name: String) -> Scope { | ||||
|         Scope { | ||||
|             parent, | ||||
|             function_and_variable_symbols: HashMap::new(), | ||||
|             type_and_module_symbols: HashMap::new(), | ||||
|             use_statement_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, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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 { | ||||
|     SymbolAlreadyDefined(Symbol), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum SymbolLookupError { | ||||
|     NoDefinition | ||||
|     NoDefinition, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct SymbolTable { | ||||
|     scopes: Vec<Scope>, | ||||
|     current_scope_id: usize, | ||||
| @ -49,10 +130,16 @@ impl SymbolTable { | ||||
|         self.current_scope_id | ||||
|     } | ||||
| 
 | ||||
|     pub fn scopes(&self) -> &Vec<Scope> { | ||||
|         &self.scopes | ||||
|     } | ||||
| 
 | ||||
|     pub fn push_scope(&mut self, debug_name: &str) { | ||||
|         let id = self.scopes.len(); | ||||
|         self.scopes | ||||
|             .push(Scope::new(Some(self.current_scope_id), debug_name.to_string())); | ||||
|         self.scopes.push(Scope::new( | ||||
|             Some(self.current_scope_id), | ||||
|             debug_name.to_string(), | ||||
|         )); | ||||
|         self.current_scope_id = id; | ||||
|     } | ||||
| 
 | ||||
| @ -62,47 +149,115 @@ impl SymbolTable { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn insert(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { | ||||
|         match symbol { | ||||
|             Symbol::Function(_) | Symbol::Variable(_) => { | ||||
|                 self.insert_function_or_variable(name, symbol) | ||||
|             } | ||||
|             Symbol::Module(_) => self.insert_module_or_type(name, symbol), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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) | ||||
|     pub fn insert_use_statement_symbol( | ||||
|         &mut self, | ||||
|         use_statement_symbol: UseStatementSymbol, | ||||
|     ) -> 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(use_statement_symbol.declared_name()) | ||||
|         { | ||||
|             Err(SymbolAlreadyDefined(defined_symbol.clone())) | ||||
|             Err(SymbolAlreadyDefined(defined_symbol)) | ||||
|         } else { | ||||
|             self.scopes[self.current_scope_id] | ||||
|                 .function_and_variable_symbols | ||||
|                 .insert(name.to_string(), symbol); | ||||
|             current_scope.use_statement_symbols.insert( | ||||
|                 use_statement_symbol.declared_name().to_string(), | ||||
|                 Rc::new(RefCell::new(use_statement_symbol)), | ||||
|             ); | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn insert_module_or_type(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> { | ||||
|         if let Some(defined_symbol) = self.scopes[self.current_scope_id] | ||||
|             .type_and_module_symbols | ||||
|             .get(name) | ||||
|     pub fn insert_module_symbol( | ||||
|         &mut self, | ||||
|         module_symbol: ModuleSymbol, | ||||
|     ) -> 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 { | ||||
|             self.scopes[self.current_scope_id] | ||||
|                 .type_and_module_symbols | ||||
|                 .insert(name.to_string(), symbol); | ||||
|             current_scope.module_symbols.insert( | ||||
|                 module_symbol.declared_name().to_string(), | ||||
|                 Rc::new(module_symbol), | ||||
|             ); | ||||
|             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]); | ||||
|         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); | ||||
|             } | ||||
|             scope_opt = if let Some(parent_id) = scope.parent { | ||||
| @ -113,6 +268,19 @@ impl SymbolTable { | ||||
|         } | ||||
|         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 { | ||||
| @ -120,7 +288,19 @@ impl Display for SymbolTable { | ||||
|         writeln!(f, "SymbolTable(current_scope = {})", self.current_scope_id)?; | ||||
|         for (i, scope) in self.scopes.iter().enumerate() { | ||||
|             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)?; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -30,6 +30,7 @@ Move = { "move" } | ||||
| Alias = { "alias" } | ||||
| True = { "true" } | ||||
| False = { "false" } | ||||
| Use = { "use" } | ||||
| 
 | ||||
| // Keywords as a rule (for preventing identifiers with keywords, etc.) | ||||
| Keyword = { | ||||
| @ -64,6 +65,7 @@ Keyword = { | ||||
|     | Alias | ||||
|     | True | ||||
|     | False | ||||
|     | Use | ||||
| } | ||||
| 
 | ||||
| // Symbols | ||||
| @ -280,7 +282,8 @@ RefList = { | ||||
| 
 | ||||
| CompilationUnit = { | ||||
|       SOI | ||||
|     ~ Namespace? | ||||
|     ~ ( Namespace ~ Semicolon )? | ||||
|     ~ ( UseStatement ~ Semicolon )* | ||||
|     ~ ModuleLevelDeclaration* | ||||
|     ~ EOI | ||||
| } | ||||
| @ -382,6 +385,7 @@ PlatformFunction = { | ||||
|     ~ Identifier | ||||
|     ~ Parameters | ||||
|     ~ ReturnType | ||||
|     ~ ";" | ||||
| } | ||||
| 
 | ||||
| InterfaceFunction = { | ||||
| @ -479,6 +483,20 @@ Field = { | ||||
| 
 | ||||
| // Statements | ||||
| 
 | ||||
| UseStatement = { | ||||
|       Use | ||||
|     ~ Identifier | ||||
|     ~ ( "::" ~ Identifier )* | ||||
|     ~ ( "::" ~ ( Star | UseList ) )? | ||||
| } | ||||
| 
 | ||||
| UseList = { | ||||
|       "{" | ||||
|     ~ Identifier | ||||
|     ~ ( "," ~ Identifier )* | ||||
|     ~ "}" | ||||
| } | ||||
| 
 | ||||
| BlockStatement = { | ||||
|       "{" | ||||
|     ~ Statement* | ||||
| @ -492,6 +510,7 @@ Statement = { | ||||
|         | AssignmentStatement | ||||
|         | CallStatement | ||||
|         | ReturnStatement | ||||
|         | UseStatement | ||||
|       ) | ||||
|     ~ Semicolon | ||||
|     | ( | ||||
|  | ||||
| @ -8,7 +8,7 @@ pub struct DeimosParser; | ||||
| mod deimos_parser_tests { | ||||
|     use crate::parser::{DeimosParser, Rule}; | ||||
|     use indoc::indoc; | ||||
|     use pest::{parses_to, Parser}; | ||||
|     use pest::Parser; | ||||
| 
 | ||||
|     macro_rules! fail_rule { | ||||
|         ($pair: expr; $rule:path) => {{ | ||||
| @ -160,11 +160,14 @@ mod deimos_parser_tests { | ||||
| 
 | ||||
|     #[test] | ||||
|     fn if_statement_with_call_condition() { | ||||
|         parses_to(Rule::IfStatement, indoc! {" | ||||
|         parses_to( | ||||
|             Rule::IfStatement, | ||||
|             indoc! {" | ||||
|             if (foo()) { | ||||
|                 bar() | ||||
|             } | ||||
|         "})
 | ||||
|         "},
 | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
| @ -174,10 +177,28 @@ mod deimos_parser_tests { | ||||
| 
 | ||||
|     #[test] | ||||
|     fn for_statement_with_call_iterator() { | ||||
|         parses_to(Rule::ForStatement, indoc! {" | ||||
|         parses_to( | ||||
|             Rule::ForStatement, | ||||
|             indoc! {" | ||||
|             for (foo in bar()) { | ||||
|                 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