diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 1dd5c9a..e418616 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,6 +1,6 @@ +use crate::name_analysis::symbol::Symbol; use pest::Parser; use std::range::Range; -use crate::name_analysis::symbol::Symbol; pub mod build; pub mod named; @@ -241,8 +241,8 @@ impl Default for Parameters { #[derive(Debug)] pub struct Parameter { - identifier: Identifier, - type_use: TypeUse, + pub identifier: Identifier, + pub type_use: TypeUse, } /* Return Type */ diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather.rs index b6d7fdc..f666541 100644 --- a/src/name_analysis/gather.rs +++ b/src/name_analysis/gather.rs @@ -50,11 +50,50 @@ fn gather_function_definition( .set_scope_id(symbol_table.current_scope_id()); symbol_table.push_scope(&format!("FunctionScope({})", resolved_name)); - // TODO: params + gather_parameters( + &mut function.parameters, + symbol_table, + fqn_context, + diagnostics, + ); gather_function_body(&mut function.body, 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, +) { + for parameter in &mut parameters.0 { + gather_parameter(parameter, symbol_table, fqn_context, diagnostics); + } +} + +fn gather_parameter( + parameter: &mut Parameter, + symbol_table: &mut SymbolTable, + fqn_context: &mut FqnContext, + diagnostics: &mut DiagnosticsContainer, +) { + let parameter_name = parameter.identifier.name(); + + let insert_result = symbol_table.insert( + parameter_name.to_string(), + Symbol::Variable(VariableSymbol { + name: parameter_name.to_string(), + is_mutable: false, + }), + ); + + if let Err(msg) = insert_result { + diagnostics.add_error_at_identifier(&msg, ¶meter.identifier); + } + + parameter.identifier.set_scope_id(symbol_table.current_scope_id()); +} + fn gather_function_body( function_body: &mut FunctionBody, symbol_table: &mut SymbolTable, @@ -63,7 +102,7 @@ fn gather_function_body( ) { use crate::ast::FunctionBody::*; match function_body { - Block(block) => gather_block_statement(block, symbol_table, fqn_context, diagnostics), + Block(block) => gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics), _ => todo!(), } } @@ -75,10 +114,22 @@ fn gather_block_statement( diagnostics: &mut DiagnosticsContainer, ) { symbol_table.push_scope("BlockStatementScope"); + gather_block_statement(block, symbol_table, fqn_context, diagnostics); + symbol_table.pop_scope(); +} + +fn gather_block_statement_inner( + block: &mut BlockStatement, + symbol_table: &mut SymbolTable, + fqn_context: &mut FqnContext, + diagnostics: &mut DiagnosticsContainer, +) { for statement in &mut block.statements { gather_statement(statement, symbol_table, fqn_context, diagnostics); } - symbol_table.pop_scope(); + if let Some(expression) = &mut block.expression { + gather_expression(expression, symbol_table, diagnostics); + } } fn gather_statement( @@ -124,6 +175,10 @@ fn gather_variable_declaration( variable_declaration .identifier .set_scope_id(symbol_table.current_scope_id()); + + if let Some(initializer) = &mut variable_declaration.initializer { + gather_expression(initializer, symbol_table, diagnostics); + } } fn gather_assign_statement( @@ -132,11 +187,15 @@ fn gather_assign_statement( fqn_context: &mut FqnContext, diagnostics: &mut DiagnosticsContainer, ) { - gather_expression(&mut assign_statement.lhs, symbol_table); - gather_expression(&mut assign_statement.rhs, symbol_table); + gather_expression(&mut assign_statement.lhs, symbol_table, diagnostics); + gather_expression(&mut assign_statement.rhs, symbol_table, diagnostics); } -fn gather_expression(expression: &mut Expression, symbol_table: &mut SymbolTable) { +fn gather_expression( + expression: &mut Expression, + symbol_table: &mut SymbolTable, + diagnostics: &mut DiagnosticsContainer, +) { use crate::ast::Expression::*; match expression { FullyQualifiedName(fully_qualified_name) => { diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index beac2bf..3c3b8b1 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -74,3 +74,53 @@ pub fn analyze_names( diagnostics.into() } + +#[cfg(test)] +mod tests { + use super::*; + use crate::ast::build::build_ast; + use crate::parser::{DeimosParser, Rule}; + use codespan_reporting::files::SimpleFiles; + use codespan_reporting::term; + use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; + use pest::Parser; + + fn assert_no_diagnostics(src: &str) { + let parse_result = DeimosParser::parse(Rule::CompilationUnit, src); + if let Err(err) = &parse_result { + panic!("{:?}", err); + } + let compilation_unit_pair = parse_result.unwrap().next().unwrap(); + let mut ast = build_ast(compilation_unit_pair); + + let mut files = SimpleFiles::new(); + let test_file_id = files.add("test.dm", src); + + let mut symbol_table = SymbolTable::new(); + + let diagnostics = analyze_names(test_file_id, &mut ast, &mut symbol_table); + + if !diagnostics.is_empty() { + let writer = StandardStream::stderr(ColorChoice::Always); + let config = term::Config::default(); + + for diagnostic in &diagnostics { + term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap(); + } + + eprintln!("{}", symbol_table); + panic!("Diagnostics was not empty!"); + } + } + + #[test] + fn params_seen() { + assert_no_diagnostics( + r#" + fn main(args: Array) { + let x = args; + } + "#, + ) + } +}