Handle local variables and function params in symbol table

This commit is contained in:
Greg Shuflin 2021-10-24 02:02:04 -07:00
parent 9540dc70f2
commit 82de5c6e27
3 changed files with 28 additions and 5 deletions

View File

@ -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,
}
}

View File

@ -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<String>,
pub local_name: Rc<String>, //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<TypeName>),
@ -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),
}
}
}

View File

@ -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<Scope>;
@ -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));