Fix scope test bug

This involved fixing how the ScopeResolver handles local bindings. I
probably want to rewrite much of that code.
This commit is contained in:
Greg Shuflin 2021-10-25 01:02:19 -07:00
parent 9ec1e00afa
commit df41da84b4
5 changed files with 33 additions and 17 deletions

View File

@ -8,7 +8,7 @@ pub enum Recursion {
pub trait ASTVisitor: Sized { pub trait ASTVisitor: Sized {
fn expression(&mut self, _expression: &Expression) -> Recursion { Recursion::Continue } fn expression(&mut self, _expression: &Expression) -> Recursion { Recursion::Continue }
fn declaration(&mut self, _declaration: &Declaration) -> Recursion { Recursion::Continue } fn declaration(&mut self, _declaration: &Declaration, _id: &ItemId) -> Recursion { Recursion::Continue }
fn import(&mut self, _import: &ImportSpecifier) -> Recursion { Recursion::Continue } fn import(&mut self, _import: &ImportSpecifier) -> Recursion { Recursion::Continue }
fn module(&mut self, _module: &ModuleSpecifier) -> Recursion { Recursion::Continue } fn module(&mut self, _module: &ModuleSpecifier) -> Recursion { Recursion::Continue }
@ -28,7 +28,7 @@ pub fn walk_block<V: ASTVisitor>(v: &mut V, block: &Block) {
walk_expression(v, expr); walk_expression(v, expr);
} }
Declaration(ref decl) => { Declaration(ref decl) => {
walk_declaration(v, decl); walk_declaration(v, decl, &statement.id);
} }
Import(ref import_spec) => { Import(ref import_spec) => {
v.import(import_spec); v.import(import_spec);
@ -42,10 +42,10 @@ pub fn walk_block<V: ASTVisitor>(v: &mut V, block: &Block) {
} }
} }
fn walk_declaration<V: ASTVisitor>(v: &mut V, decl: &Declaration) { fn walk_declaration<V: ASTVisitor>(v: &mut V, decl: &Declaration, id: &ItemId) {
use Declaration::*; use Declaration::*;
if let Recursion::Continue = v.declaration(decl) { if let Recursion::Continue = v.declaration(decl, id) {
match decl { match decl {
FuncDecl(_sig, block) => { FuncDecl(_sig, block) => {
walk_block(v, block); walk_block(v, block);

View File

@ -91,6 +91,11 @@ impl<'a> Reducer<'a> {
self.insert_function_definition(item_id, statements); self.insert_function_definition(item_id, statements);
None None
}, },
ast::Declaration::Binding { constant, expr, ..} => {
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
Some(Statement::Binding { id: symbol.def_id.clone(), constant: *constant, expr: self.expression(&expr) })
},
_ => None _ => None
}, },
_ => None _ => None

View File

@ -283,11 +283,12 @@ impl SymbolTable {
/// Register a new mapping of a fully-qualified symbol name (e.g. `Option::Some`) /// Register a new mapping of a fully-qualified symbol name (e.g. `Option::Some`)
/// to a Symbol, a descriptor of what that name refers to. /// to a Symbol, a descriptor of what that name refers to.
fn add_symbol(&mut self, id: &ItemId, fqsn: Fqsn, spec: SymbolSpec) { fn add_symbol(&mut self, id: &ItemId, fqsn: Fqsn, spec: SymbolSpec) {
let def_id = self.def_id_store.fresh();
let symbol = Rc::new(Symbol { let symbol = Rc::new(Symbol {
local_name: fqsn.local_name(), local_name: fqsn.local_name(),
fully_qualified_name: fqsn.clone(), fully_qualified_name: fqsn.clone(),
spec, spec,
def_id: self.def_id_store.fresh(), def_id,
}); });
self.symbol_trie.insert(&fqsn); self.symbol_trie.insert(&fqsn);
self.fqsn_to_symbol.insert(fqsn, symbol.clone()); self.fqsn_to_symbol.insert(fqsn, symbol.clone());

View File

@ -8,14 +8,13 @@ use crate::util::ScopeStack;
enum NameType { enum NameType {
//TODO eventually this needs to support closures //TODO eventually this needs to support closures
Param(u8), //TODO handle implications of functions being limited to 255 params Param(u8), //TODO handle implications of functions being limited to 255 params
LocalVariable, LocalVariable(ItemId),
Import(Fqsn), Import(Fqsn),
} }
#[derive(Debug)] #[derive(Debug)]
enum ScopeType { enum ScopeType {
Function { Function {
#[allow(dead_code)]
name: Rc<String> name: Rc<String>
}, },
Lambda, Lambda,
@ -71,6 +70,8 @@ impl<'a> ScopeResolver<'a> {
fn lookup_name_in_scope(&mut self, name: &QualifiedName) { fn lookup_name_in_scope(&mut self, name: &QualifiedName) {
let QualifiedName { id, components } = name; let QualifiedName { id, components } = name;
//TODO handle a "partial" qualified name //TODO handle a "partial" qualified name
//TODO some of these if lets that look into the fqsn_to_symbol table should probaby fail
//with an error
if components.len() == 1 { if components.len() == 1 {
let local_name: Rc<String> = components[0].clone(); let local_name: Rc<String> = components[0].clone();
let name_type = self.lexical_scopes.lookup(&local_name); let name_type = self.lexical_scopes.lookup(&local_name);
@ -86,10 +87,11 @@ impl<'a> ScopeResolver<'a> {
let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] }; let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] };
self.symbol_table.add_symbol(id, fqsn, spec); self.symbol_table.add_symbol(id, fqsn, spec);
} }
Some(NameType::LocalVariable) => { Some(NameType::LocalVariable(item_id)) => {
let spec = SymbolSpec::LocalVariable; let symbol = self.symbol_table.id_to_symbol.get(&item_id).cloned();
let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] }; if let Some(symbol) = symbol {
self.symbol_table.add_symbol(id, fqsn, spec); self.symbol_table.id_to_symbol.insert(id.clone(), symbol);
}
}, },
None => { None => {
//TODO see if I can reduce this duplicate code //TODO see if I can reduce this duplicate code
@ -158,8 +160,12 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
Recursion::Continue Recursion::Continue
} }
fn declaration(&mut self, declaration: &Declaration) -> Recursion { fn declaration(&mut self, declaration: &Declaration, id: &ItemId) -> Recursion {
let is_function_scope = matches!(self.lexical_scopes.get_name(), Some(ScopeType::Function { .. })); let cur_function_name = match self.lexical_scopes.get_name() {
//TODO this needs to be a fqsn
Some(ScopeType::Function { name }) => Some(name.clone()),
_ => None
};
match declaration { match declaration {
Declaration::FuncDecl(signature, block) => { Declaration::FuncDecl(signature, block) => {
let param_names = signature.params.iter().map(|param| param.name.clone()); let param_names = signature.params.iter().map(|param| param.name.clone());
@ -178,8 +184,13 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
walk_block(&mut new_resolver, block); walk_block(&mut new_resolver, block);
Recursion::Stop Recursion::Stop
} }
Declaration::Binding { name, .. } if is_function_scope => { Declaration::Binding { name, .. } => {
self.lexical_scopes.insert(name.clone(), NameType::LocalVariable); if let Some(fn_name) = cur_function_name {
// We are within a function scope
let fqsn = Fqsn { scopes: vec![Scope::Name(fn_name.clone()), Scope::Name(name.clone())] };
self.symbol_table.add_symbol(id, fqsn, SymbolSpec::LocalVariable);
self.lexical_scopes.insert(name.clone(), NameType::LocalVariable(id.clone()));
}
Recursion::Continue Recursion::Continue
} }
_ => Recursion::Continue _ => Recursion::Continue

View File

@ -39,10 +39,10 @@ fn function_eval() {
#[test] #[test]
fn scopes() { fn scopes() {
/*
let scope_ok = r#" let scope_ok = r#"
let a = 20 let a = 20
fn haha() { fn haha() {
let something = 38
let a = 10 let a = 10
a a
} }
@ -60,6 +60,5 @@ fn scopes() {
a a
"#; "#;
eval_assert(scope_ok, "20"); eval_assert(scope_ok, "20");
*/
} }