diff --git a/schala-lang/language/src/ast/mod.rs b/schala-lang/language/src/ast/mod.rs index c763b11..087e816 100644 --- a/schala-lang/language/src/ast/mod.rs +++ b/schala-lang/language/src/ast/mod.rs @@ -8,7 +8,7 @@ mod visitor; mod operators; pub use operators::{PrefixOp, BinOp}; -pub use visitor::{walk_ast, walk_block, ASTVisitor}; +pub use visitor::{walk_ast, walk_block, ASTVisitor, Recursion}; use crate::derivative::Derivative; use crate::tokenizing::Location; diff --git a/schala-lang/language/src/ast/visitor.rs b/schala-lang/language/src/ast/visitor.rs index 2948c82..b570cc1 100644 --- a/schala-lang/language/src/ast/visitor.rs +++ b/schala-lang/language/src/ast/visitor.rs @@ -1,18 +1,19 @@ use crate::ast::*; +#[derive(Debug)] +pub enum Recursion { + Continue, + Stop +} + pub trait ASTVisitor: Sized { - fn expression(&mut self, _expression: &Expression) {} - fn expression_post(&mut self, _expression: &Expression) {} + fn expression(&mut self, _expression: &Expression) -> Recursion { Recursion::Continue } + fn declaration(&mut self, _declaration: &Declaration) -> Recursion { Recursion::Continue } - fn declaration(&mut self, _declaration: &Declaration) {} - fn declaration_post(&mut self, _declaration: &Declaration) {} + fn import(&mut self, _import: &ImportSpecifier) -> Recursion { Recursion::Continue } + fn module(&mut self, _module: &ModuleSpecifier) -> Recursion { Recursion::Continue } - fn import(&mut self, _import: &ImportSpecifier) {} - fn module(&mut self, _module: &ModuleSpecifier) {} - fn module_post(&mut self, _module: &ModuleSpecifier) {} - - fn pattern(&mut self, _pat: &Pattern) {} - fn pattern_post(&mut self, _pat: &Pattern) {} + fn pattern(&mut self, _pat: &Pattern) -> Recursion { Recursion::Continue } } pub fn walk_ast(v: &mut V, ast: &AST) { @@ -29,11 +30,13 @@ pub fn walk_block(v: &mut V, block: &Block) { Declaration(ref decl) => { walk_declaration(v, decl); } - Import(ref import_spec) => v.import(import_spec), + Import(ref import_spec) => { + v.import(import_spec); + }, Module(ref module_spec) => { - v.module(module_spec); - walk_block(v, &module_spec.contents); - v.module_post(module_spec); + if let Recursion::Continue = v.module(module_spec) { + walk_block(v, &module_spec.contents); + } } } } @@ -42,103 +45,101 @@ pub fn walk_block(v: &mut V, block: &Block) { fn walk_declaration(v: &mut V, decl: &Declaration) { use Declaration::*; - v.declaration(decl); - - match decl { - FuncDecl(_sig, block) => { - walk_block(v, block); - } - Binding { - name: _, - constant: _, - type_anno: _, - expr, - } => { - walk_expression(v, expr); - } - _ => (), - }; - v.declaration_post(decl); + if let Recursion::Continue = v.declaration(decl) { + match decl { + FuncDecl(_sig, block) => { + walk_block(v, block); + } + Binding { + name: _, + constant: _, + type_anno: _, + expr, + } => { + walk_expression(v, expr); + } + _ => (), + }; + } } fn walk_expression(v: &mut V, expr: &Expression) { use ExpressionKind::*; - v.expression(expr); - - match &expr.kind { - NatLiteral(_) | FloatLiteral(_) | StringLiteral(_) | BoolLiteral(_) | Value(_) => (), - BinExp(_, lhs, rhs) => { - walk_expression(v, &lhs); - walk_expression(v, &rhs); - } - PrefixExp(_, arg) => { - walk_expression(v, &arg); - } - TupleLiteral(exprs) => { - for expr in exprs { - walk_expression(v, &expr); + if let Recursion::Continue = v.expression(expr) { + match &expr.kind { + NatLiteral(_) | FloatLiteral(_) | StringLiteral(_) | BoolLiteral(_) | Value(_) => (), + BinExp(_, lhs, rhs) => { + walk_expression(v, &lhs); + walk_expression(v, &rhs); } - } - NamedStruct { name: _, fields } => { - for (_, expr) in fields.iter() { - walk_expression(v, expr); + PrefixExp(_, arg) => { + walk_expression(v, &arg); } - } - Call { f, arguments } => { - walk_expression(v, &f); - for arg in arguments.iter() { - match arg { - InvocationArgument::Positional(expr) => walk_expression(v, expr), - InvocationArgument::Keyword { expr, .. } => walk_expression(v, expr), //TODO maybe I can combine this pattern - _ => (), + TupleLiteral(exprs) => { + for expr in exprs { + walk_expression(v, &expr); } } - } - Index { indexee, indexers } => { - walk_expression(v, &indexee); - for indexer in indexers.iter() { - walk_expression(v, indexer); + NamedStruct { name: _, fields } => { + for (_, expr) in fields.iter() { + walk_expression(v, expr); + } } - } - IfExpression { - discriminator, - body, - } => { - if let Some(d) = discriminator.as_ref() { - walk_expression(v, &d); + Call { f, arguments } => { + walk_expression(v, &f); + for arg in arguments.iter() { + match arg { + InvocationArgument::Positional(expr) => walk_expression(v, expr), + InvocationArgument::Keyword { expr, .. } => walk_expression(v, expr), //TODO maybe I can combine this pattern + _ => (), + } + } } - walk_if_expr_body(v, &body.as_ref()); - } - WhileExpression { condition, body } => { - if let Some(d) = condition.as_ref() { - walk_expression(v, d); + Index { indexee, indexers } => { + walk_expression(v, &indexee); + for indexer in indexers.iter() { + walk_expression(v, indexer); + } } - walk_block(v, &body); - } - ForExpression { enumerators, body } => { - for enumerator in enumerators { - walk_expression(v, &enumerator.generator); + IfExpression { + discriminator, + body, + } => { + if let Some(d) = discriminator.as_ref() { + walk_expression(v, &d); + } + walk_if_expr_body(v, &body.as_ref()); } - match body.as_ref() { - ForBody::MonadicReturn(expr) => walk_expression(v, expr), - ForBody::StatementBlock(block) => walk_block(v, block), - }; - } - Lambda { - params: _, - type_anno: _, - body, - } => { - walk_block(v, &body); - } - ListLiteral(exprs) => { - for expr in exprs { - walk_expression(v, &expr); + WhileExpression { condition, body } => { + if let Some(d) = condition.as_ref() { + walk_expression(v, d); + } + walk_block(v, &body); } - } - }; - v.expression_post(expr); + ForExpression { enumerators, body } => { + for enumerator in enumerators { + walk_expression(v, &enumerator.generator); + } + match body.as_ref() { + ForBody::MonadicReturn(expr) => walk_expression(v, expr), + ForBody::StatementBlock(block) => walk_block(v, block), + }; + } + Lambda { + params: _, + type_anno: _, + body, + } => { + walk_block(v, &body); + } + ListLiteral(exprs) => { + for expr in exprs { + walk_expression(v, &expr); + } + } + }; + } } fn walk_if_expr_body(v: &mut V, body: &IfExpressionBody) { @@ -187,26 +188,24 @@ fn walk_if_expr_body(v: &mut V, body: &IfExpressionBody) { fn walk_pattern(v: &mut V, pat: &Pattern) { use Pattern::*; - v.pattern(pat); - - match pat { - TuplePattern(patterns) => { - for pat in patterns { - walk_pattern(v, pat); + if let Recursion::Continue = v.pattern(pat) { + match pat { + TuplePattern(patterns) => { + for pat in patterns { + walk_pattern(v, pat); + } } - } - TupleStruct(_, patterns) => { - for pat in patterns { - walk_pattern(v, pat); + TupleStruct(_, patterns) => { + for pat in patterns { + walk_pattern(v, pat); + } } - } - Record(_, name_and_patterns) => { - for (_, pat) in name_and_patterns { - walk_pattern(v, pat); + Record(_, name_and_patterns) => { + for (_, pat) in name_and_patterns { + walk_pattern(v, pat); + } } - } - _ => (), - }; - - v.pattern_post(pat); + _ => (), + }; + } } diff --git a/schala-lang/language/src/reduced_ast/mod.rs b/schala-lang/language/src/reduced_ast/mod.rs index 4c247ae..8e0289a 100644 --- a/schala-lang/language/src/reduced_ast/mod.rs +++ b/schala-lang/language/src/reduced_ast/mod.rs @@ -125,7 +125,7 @@ impl<'a> Reducer<'a> { arity: *arity, }, SymbolSpec::Func(_) => Expr::Sym(local_name.clone()), - SymbolSpec::Binding => Expr::Sym(local_name.clone()), //TODO not sure if this is right, probably needs to eventually be fqsn + SymbolSpec::GlobalBinding => Expr::Sym(local_name.clone()), //TODO not sure if this is right, probably needs to eventually be fqsn } } diff --git a/schala-lang/language/src/symbol_table/mod.rs b/schala-lang/language/src/symbol_table/mod.rs index 6765020..7762789 100644 --- a/schala-lang/language/src/symbol_table/mod.rs +++ b/schala-lang/language/src/symbol_table/mod.rs @@ -189,6 +189,7 @@ impl SymbolTable { self.id_to_symbol.get(id).map(|s| s.as_ref()) } + //TODO optimize this pub fn lookup_symbol_by_def(&self, def: &DefId) -> Option<&Symbol> { self.id_to_symbol.iter().find(|(_, sym)| sym.def_id == *def) .map(|(_, sym)| sym.as_ref()) @@ -223,7 +224,7 @@ pub enum SymbolSpec { members: HashMap, TypeName>, type_name: TypeName, }, - Binding, + GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context } impl fmt::Display for SymbolSpec { @@ -283,13 +284,14 @@ impl SymbolTable { /// up name tables that will be used by further parts of the compiler fn populate_name_tables(&mut self, ast: &ast::AST) -> Vec { let mut scope_stack = vec![]; - self.add_from_scope(ast.statements.as_ref(), &mut scope_stack) + self.add_from_scope(ast.statements.as_ref(), &mut scope_stack, false) } fn add_from_scope<'a>( &'a mut self, statements: &[Statement], scope_stack: &mut Vec, + function_scope: bool, ) -> Vec { let mut errors = vec![]; @@ -300,7 +302,7 @@ impl SymbolTable { location, } = statement; //TODO I'm not sure if I need to do anything with this ID let location = *location; - if let Err(err) = self.add_single_statement(id, kind, location, scope_stack) { + if let Err(err) = self.add_single_statement(id, kind, location, scope_stack, function_scope) { errors.push(err); } else { // If there's an error with a name, don't recurse into subscopes of that name @@ -308,14 +310,14 @@ impl SymbolTable { StatementKind::Declaration(Declaration::FuncDecl(signature, body)) => { let new_scope = Scope::Name(signature.name.clone()); scope_stack.push(new_scope); - let output = self.add_from_scope(body.as_ref(), scope_stack); + let output = self.add_from_scope(body.as_ref(), scope_stack, true); scope_stack.pop(); output } StatementKind::Module(ModuleSpecifier { name, contents }) => { let new_scope = Scope::Name(name.clone()); scope_stack.push(new_scope); - let output = self.add_from_scope(contents.as_ref(), scope_stack); + let output = self.add_from_scope(contents.as_ref(), scope_stack, false); scope_stack.pop(); output } @@ -339,6 +341,7 @@ impl SymbolTable { kind: &StatementKind, location: Location, scope_stack: &[Scope], + function_scope: bool, ) -> Result<(), SymbolError> { match kind { StatementKind::Declaration(Declaration::FuncSig(signature)) => { @@ -407,12 +410,13 @@ impl SymbolTable { kind: NameKind::Binding, }, )?; - println!("Adding Binding symbol: {:?}", fq_binding); - self.add_symbol( - id, - fq_binding, - SymbolSpec::Binding, - ); + if !function_scope { + self.add_symbol( + id, + fq_binding, + SymbolSpec::GlobalBinding, + ); + } } StatementKind::Module(ModuleSpecifier { name, .. }) => { let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone()); diff --git a/schala-lang/language/src/symbol_table/resolver.rs b/schala-lang/language/src/symbol_table/resolver.rs index d7d8167..71e68d0 100644 --- a/schala-lang/language/src/symbol_table/resolver.rs +++ b/schala-lang/language/src/symbol_table/resolver.rs @@ -1,24 +1,45 @@ use std::rc::Rc; use crate::ast::*; -use crate::symbol_table::{Fqsn, Scope, SymbolTable}; +use crate::symbol_table::{Fqsn, Scope, SymbolTable, DefId}; use crate::util::ScopeStack; type FqsnPrefix = Vec; +#[derive(Debug)] +enum NameType { + //TODO eventually this needs to support closures + Param(u8), //TODO functions limited to 255 params + LocalVariable, + ImportedDefinition(DefId), +} + +#[derive(Debug)] +enum ScopeType { + Function { + name: Rc + }, + //TODO add some notion of a let-like scope? +} + pub struct ScopeResolver<'a> { symbol_table: &'a mut super::SymbolTable, + /// Used for import resolution. TODO maybe this can also use the lexical scope table. name_scope_stack: ScopeStack<'a, Rc, FqsnPrefix>, + lexical_scopes: ScopeStack<'a, Rc, NameType, ScopeType> } impl<'a> ScopeResolver<'a> { pub fn new(symbol_table: &'a mut SymbolTable) -> Self { - let name_scope_stack: ScopeStack<'a, Rc, FqsnPrefix> = ScopeStack::new(None); + let name_scope_stack = ScopeStack::new(None); + let lexical_scopes = ScopeStack::new(None); Self { symbol_table, name_scope_stack, + lexical_scopes, } } + pub fn resolve(&mut self, ast: &AST) { walk_ast(self, ast); } @@ -46,10 +67,11 @@ impl<'a> ScopeResolver<'a> { } } - fn qualified_name(&mut self, name: &QualifiedName) { + /// This method correctly modifies the id_to_symbol table (ItemId) to have the appropriate + /// mappings. + fn handle_qualified_name(&mut self, name: &QualifiedName) { println!("Handling qualified_name in resolver.rs: {:?}", name); let fqsn = self.lookup_name_in_scope(name); - println!("Computed FQSN: {:?}", fqsn); let symbol = self.symbol_table.fqsn_to_symbol.get(&fqsn); if let Some(symbol) = symbol { self.symbol_table.id_to_symbol.insert(name.id.clone(), symbol.clone()); @@ -58,8 +80,10 @@ impl<'a> ScopeResolver<'a> { } impl<'a> ASTVisitor for ScopeResolver<'a> { - //TODO need to un-insert these - maybe need to rethink visitor - fn import(&mut self, import_spec: &ImportSpecifier) { + // Import statements bring in a bunch of local names that all map to a specific FQSN. + // FQSNs map to a Symbol (or this is an error), Symbols have a DefId. So for every + // name we import, we map a local name (a string) to a NameType::ImportedDefinition(DefId). + fn import(&mut self, import_spec: &ImportSpecifier) -> Recursion { let ImportSpecifier { ref path_components, ref imported_names, @@ -99,22 +123,45 @@ impl<'a> ASTVisitor for ScopeResolver<'a> { } } }; + Recursion::Continue } - fn expression(&mut self, expression: &Expression) { - use ExpressionKind::*; - match &expression.kind { - Value(name) => { - self.qualified_name(name); - }, - NamedStruct { name, fields: _ } => { - self.qualified_name(name); - }, - _ => (), + fn declaration(&mut self, declaration: &Declaration) -> Recursion { + if let Declaration::FuncDecl(signature, block) = declaration { + let param_names = signature.params.iter().map(|param| param.name.clone()); + let mut new_scope = self.lexical_scopes.new_scope(Some(ScopeType::Function { name: signature.name.clone() })); + + for (n, param) in param_names.enumerate().into_iter() { + new_scope.insert(param, NameType::Param(n as u8)); + } + + let mut new_resolver = ScopeResolver { + symbol_table: self.symbol_table, + name_scope_stack: self.name_scope_stack.new_scope(None), + lexical_scopes: new_scope, + }; + walk_block(&mut new_resolver, block); + Recursion::Stop + } else { + Recursion::Continue } } - fn pattern(&mut self, pat: &Pattern) { + fn expression(&mut self, expression: &Expression) -> Recursion { + use ExpressionKind::*; + match &expression.kind { + Value(name) => { + self.handle_qualified_name(name); + }, + NamedStruct { name, fields: _ } => { + self.handle_qualified_name(name); + }, + _ => (), + } + Recursion::Continue + } + + fn pattern(&mut self, pat: &Pattern) -> Recursion { use Pattern::*; match pat { @@ -122,8 +169,9 @@ impl<'a> ASTVisitor for ScopeResolver<'a> { TuplePattern(_) => (), Literal(_) | Ignored => (), TupleStruct(name, _) | Record(name, _) | VarOrName(name) => { - self.qualified_name(name); + self.handle_qualified_name(name); } }; + Recursion::Continue } }