From 82de5c6e2766e2da1054d1c6bb87dddefcd48712 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sun, 24 Oct 2021 02:02:04 -0700 Subject: [PATCH] Handle local variables and function params in symbol table --- schala-lang/language/src/reduced_ast/mod.rs | 1 + schala-lang/language/src/symbol_table/mod.rs | 16 +++++++++++++++- .../language/src/symbol_table/resolver.rs | 16 ++++++++++++---- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/schala-lang/language/src/reduced_ast/mod.rs b/schala-lang/language/src/reduced_ast/mod.rs index 8e0289a..12ac4cd 100644 --- a/schala-lang/language/src/reduced_ast/mod.rs +++ b/schala-lang/language/src/reduced_ast/mod.rs @@ -126,6 +126,7 @@ impl<'a> Reducer<'a> { }, SymbolSpec::Func(_) => Expr::Sym(local_name.clone()), SymbolSpec::GlobalBinding => Expr::Sym(local_name.clone()), //TODO not sure if this is right, probably needs to eventually be fqsn + _ => Expr::UnimplementedSigilValue, } } diff --git a/schala-lang/language/src/symbol_table/mod.rs b/schala-lang/language/src/symbol_table/mod.rs index b958f61..a1e4aa4 100644 --- a/schala-lang/language/src/symbol_table/mod.rs +++ b/schala-lang/language/src/symbol_table/mod.rs @@ -16,6 +16,7 @@ use symbol_trie::SymbolTrie; mod test; +//TODO parameterize different types of ID /// ID used for definitions #[derive(Debug, PartialEq, Eq, Hash, Clone, Default)] pub struct DefId { @@ -199,7 +200,7 @@ impl SymbolTable { #[allow(dead_code)] #[derive(Debug, Clone)] pub struct Symbol { - pub local_name: Rc, + pub local_name: Rc, //TODO get rid of this, it can be computed from fqsn fully_qualified_name: Fqsn, pub spec: SymbolSpec, pub def_id: DefId, @@ -211,6 +212,15 @@ impl fmt::Display for Symbol { } } +//TODO - I think I eventually want to draw a distinction between true global items +//i.e. global vars, and items whose definitions are scoped. Right now there's a sense +//in which Func, DataConstructor, RecordConstructor, and GlobalBinding are "globals", +//whereas LocalVarible and FunctionParam have local scope. But right now, they all +//get put into a common table, and all get DefId's from a common source. +// +//It would be good if individual functions could in parallel look up their own +//local vars without interfering with other lookups. Also some type definitions +//should be scoped in a similar way. #[derive(Debug, Clone)] pub enum SymbolSpec { Func(Vec), @@ -225,6 +235,8 @@ pub enum SymbolSpec { type_name: TypeName, }, GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context + LocalVariable, + FunctionParam(u8), } impl fmt::Display for SymbolSpec { @@ -249,6 +261,8 @@ impl fmt::Display for SymbolSpec { index, type_name ), GlobalBinding => write!(f, "GlobalBinding"), + LocalVariable => write!(f, "Local variable"), + FunctionParam(n) => write!(f, "Function param: {}", n), } } } diff --git a/schala-lang/language/src/symbol_table/resolver.rs b/schala-lang/language/src/symbol_table/resolver.rs index 66c0b24..0458b13 100644 --- a/schala-lang/language/src/symbol_table/resolver.rs +++ b/schala-lang/language/src/symbol_table/resolver.rs @@ -1,7 +1,7 @@ use std::rc::Rc; use crate::ast::*; -use crate::symbol_table::{Fqsn, Scope, SymbolTable, DefId}; +use crate::symbol_table::{Fqsn, Scope, SymbolTable, Symbol, SymbolSpec, DefId}; use crate::util::ScopeStack; type FqsnPrefix = Vec; @@ -82,8 +82,16 @@ impl<'a> ScopeResolver<'a> { self.symbol_table.id_to_symbol.insert(id.clone(), symbol.clone()); } }, - Some(NameType::Param(n)) => (), - Some(NameType::LocalVariable) => (), + Some(NameType::Param(n)) => { + let spec = SymbolSpec::FunctionParam(*n); + let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] }; + self.symbol_table.add_symbol(id, fqsn, spec); + } + Some(NameType::LocalVariable) => { + let spec = SymbolSpec::LocalVariable; + let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] }; + self.symbol_table.add_symbol(id, fqsn, spec); + }, None => (), } } else { @@ -151,7 +159,7 @@ impl<'a> ASTVisitor for ScopeResolver<'a> { let param_names = signature.params.iter().map(|param| param.name.clone()); //TODO I'm 90% sure this is right, until I get to closures //let mut new_scope = self.lexical_scopes.new_scope(Some(ScopeType::Function { name: signature.name.clone() })); - let mut new_scope = ScopeStack::new(None); + let mut new_scope = ScopeStack::new(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));