Bunch of rewrites to scope resolver

This commit is contained in:
Greg Shuflin 2021-10-24 00:08:26 -07:00
parent d8f6c41f04
commit ba09919aa1
5 changed files with 198 additions and 147 deletions

View File

@ -8,7 +8,7 @@ mod visitor;
mod operators; mod operators;
pub use operators::{PrefixOp, BinOp}; 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::derivative::Derivative;
use crate::tokenizing::Location; use crate::tokenizing::Location;

View File

@ -1,18 +1,19 @@
use crate::ast::*; use crate::ast::*;
#[derive(Debug)]
pub enum Recursion {
Continue,
Stop
}
pub trait ASTVisitor: Sized { pub trait ASTVisitor: Sized {
fn expression(&mut self, _expression: &Expression) {} fn expression(&mut self, _expression: &Expression) -> Recursion { Recursion::Continue }
fn expression_post(&mut self, _expression: &Expression) {} fn declaration(&mut self, _declaration: &Declaration) -> Recursion { Recursion::Continue }
fn declaration(&mut self, _declaration: &Declaration) {} fn import(&mut self, _import: &ImportSpecifier) -> Recursion { Recursion::Continue }
fn declaration_post(&mut self, _declaration: &Declaration) {} fn module(&mut self, _module: &ModuleSpecifier) -> Recursion { Recursion::Continue }
fn import(&mut self, _import: &ImportSpecifier) {} fn pattern(&mut self, _pat: &Pattern) -> Recursion { Recursion::Continue }
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) {}
} }
pub fn walk_ast<V: ASTVisitor>(v: &mut V, ast: &AST) { pub fn walk_ast<V: ASTVisitor>(v: &mut V, ast: &AST) {
@ -29,11 +30,13 @@ pub fn walk_block<V: ASTVisitor>(v: &mut V, block: &Block) {
Declaration(ref decl) => { Declaration(ref decl) => {
walk_declaration(v, 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) => { Module(ref module_spec) => {
v.module(module_spec); if let Recursion::Continue = v.module(module_spec) {
walk_block(v, &module_spec.contents); walk_block(v, &module_spec.contents);
v.module_post(module_spec); }
} }
} }
} }
@ -42,103 +45,101 @@ 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) {
use Declaration::*; use Declaration::*;
v.declaration(decl); if let Recursion::Continue = v.declaration(decl) {
match decl {
match decl { FuncDecl(_sig, block) => {
FuncDecl(_sig, block) => { walk_block(v, block);
walk_block(v, block); }
} Binding {
Binding { name: _,
name: _, constant: _,
constant: _, type_anno: _,
type_anno: _, expr,
expr, } => {
} => { walk_expression(v, expr);
walk_expression(v, expr); }
} _ => (),
_ => (), };
}; }
v.declaration_post(decl);
} }
fn walk_expression<V: ASTVisitor>(v: &mut V, expr: &Expression) { fn walk_expression<V: ASTVisitor>(v: &mut V, expr: &Expression) {
use ExpressionKind::*; use ExpressionKind::*;
v.expression(expr); if let Recursion::Continue = v.expression(expr) {
match &expr.kind {
match &expr.kind { NatLiteral(_) | FloatLiteral(_) | StringLiteral(_) | BoolLiteral(_) | Value(_) => (),
NatLiteral(_) | FloatLiteral(_) | StringLiteral(_) | BoolLiteral(_) | Value(_) => (), BinExp(_, lhs, rhs) => {
BinExp(_, lhs, rhs) => { walk_expression(v, &lhs);
walk_expression(v, &lhs); walk_expression(v, &rhs);
walk_expression(v, &rhs);
}
PrefixExp(_, arg) => {
walk_expression(v, &arg);
}
TupleLiteral(exprs) => {
for expr in exprs {
walk_expression(v, &expr);
} }
} PrefixExp(_, arg) => {
NamedStruct { name: _, fields } => { walk_expression(v, &arg);
for (_, expr) in fields.iter() {
walk_expression(v, expr);
} }
} TupleLiteral(exprs) => {
Call { f, arguments } => { for expr in exprs {
walk_expression(v, &f); walk_expression(v, &expr);
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
_ => (),
} }
} }
} NamedStruct { name: _, fields } => {
Index { indexee, indexers } => { for (_, expr) in fields.iter() {
walk_expression(v, &indexee); walk_expression(v, expr);
for indexer in indexers.iter() { }
walk_expression(v, indexer);
} }
} Call { f, arguments } => {
IfExpression { walk_expression(v, &f);
discriminator, for arg in arguments.iter() {
body, match arg {
} => { InvocationArgument::Positional(expr) => walk_expression(v, expr),
if let Some(d) = discriminator.as_ref() { InvocationArgument::Keyword { expr, .. } => walk_expression(v, expr), //TODO maybe I can combine this pattern
walk_expression(v, &d); _ => (),
}
}
} }
walk_if_expr_body(v, &body.as_ref()); Index { indexee, indexers } => {
} walk_expression(v, &indexee);
WhileExpression { condition, body } => { for indexer in indexers.iter() {
if let Some(d) = condition.as_ref() { walk_expression(v, indexer);
walk_expression(v, d); }
} }
walk_block(v, &body); IfExpression {
} discriminator,
ForExpression { enumerators, body } => { body,
for enumerator in enumerators { } => {
walk_expression(v, &enumerator.generator); if let Some(d) = discriminator.as_ref() {
walk_expression(v, &d);
}
walk_if_expr_body(v, &body.as_ref());
} }
match body.as_ref() { WhileExpression { condition, body } => {
ForBody::MonadicReturn(expr) => walk_expression(v, expr), if let Some(d) = condition.as_ref() {
ForBody::StatementBlock(block) => walk_block(v, block), walk_expression(v, d);
}; }
} walk_block(v, &body);
Lambda {
params: _,
type_anno: _,
body,
} => {
walk_block(v, &body);
}
ListLiteral(exprs) => {
for expr in exprs {
walk_expression(v, &expr);
} }
} ForExpression { enumerators, body } => {
}; for enumerator in enumerators {
v.expression_post(expr); 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: ASTVisitor>(v: &mut V, body: &IfExpressionBody) { fn walk_if_expr_body<V: ASTVisitor>(v: &mut V, body: &IfExpressionBody) {
@ -187,26 +188,24 @@ fn walk_if_expr_body<V: ASTVisitor>(v: &mut V, body: &IfExpressionBody) {
fn walk_pattern<V: ASTVisitor>(v: &mut V, pat: &Pattern) { fn walk_pattern<V: ASTVisitor>(v: &mut V, pat: &Pattern) {
use Pattern::*; use Pattern::*;
v.pattern(pat); if let Recursion::Continue = v.pattern(pat) {
match pat {
match pat { TuplePattern(patterns) => {
TuplePattern(patterns) => { for pat in patterns {
for pat in patterns { walk_pattern(v, pat);
walk_pattern(v, pat); }
} }
} TupleStruct(_, patterns) => {
TupleStruct(_, patterns) => { for pat in patterns {
for pat in patterns { walk_pattern(v, pat);
walk_pattern(v, pat); }
} }
} Record(_, name_and_patterns) => {
Record(_, name_and_patterns) => { for (_, pat) in name_and_patterns {
for (_, pat) in name_and_patterns { walk_pattern(v, pat);
walk_pattern(v, pat); }
} }
} _ => (),
_ => (), };
}; }
v.pattern_post(pat);
} }

View File

@ -125,7 +125,7 @@ impl<'a> Reducer<'a> {
arity: *arity, arity: *arity,
}, },
SymbolSpec::Func(_) => Expr::Sym(local_name.clone()), 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
} }
} }

View File

@ -189,6 +189,7 @@ impl SymbolTable {
self.id_to_symbol.get(id).map(|s| s.as_ref()) 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> { pub fn lookup_symbol_by_def(&self, def: &DefId) -> Option<&Symbol> {
self.id_to_symbol.iter().find(|(_, sym)| sym.def_id == *def) self.id_to_symbol.iter().find(|(_, sym)| sym.def_id == *def)
.map(|(_, sym)| sym.as_ref()) .map(|(_, sym)| sym.as_ref())
@ -223,7 +224,7 @@ pub enum SymbolSpec {
members: HashMap<Rc<String>, TypeName>, members: HashMap<Rc<String>, TypeName>,
type_name: 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 { impl fmt::Display for SymbolSpec {
@ -283,13 +284,14 @@ impl SymbolTable {
/// up name tables that will be used by further parts of the compiler /// up name tables that will be used by further parts of the compiler
fn populate_name_tables(&mut self, ast: &ast::AST) -> Vec<SymbolError> { fn populate_name_tables(&mut self, ast: &ast::AST) -> Vec<SymbolError> {
let mut scope_stack = 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>( fn add_from_scope<'a>(
&'a mut self, &'a mut self,
statements: &[Statement], statements: &[Statement],
scope_stack: &mut Vec<Scope>, scope_stack: &mut Vec<Scope>,
function_scope: bool,
) -> Vec<SymbolError> { ) -> Vec<SymbolError> {
let mut errors = vec![]; let mut errors = vec![];
@ -300,7 +302,7 @@ impl SymbolTable {
location, location,
} = statement; //TODO I'm not sure if I need to do anything with this ID } = statement; //TODO I'm not sure if I need to do anything with this ID
let location = *location; 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); errors.push(err);
} else { } else {
// If there's an error with a name, don't recurse into subscopes of that name // 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)) => { StatementKind::Declaration(Declaration::FuncDecl(signature, body)) => {
let new_scope = Scope::Name(signature.name.clone()); let new_scope = Scope::Name(signature.name.clone());
scope_stack.push(new_scope); 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(); scope_stack.pop();
output output
} }
StatementKind::Module(ModuleSpecifier { name, contents }) => { StatementKind::Module(ModuleSpecifier { name, contents }) => {
let new_scope = Scope::Name(name.clone()); let new_scope = Scope::Name(name.clone());
scope_stack.push(new_scope); 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(); scope_stack.pop();
output output
} }
@ -339,6 +341,7 @@ impl SymbolTable {
kind: &StatementKind, kind: &StatementKind,
location: Location, location: Location,
scope_stack: &[Scope], scope_stack: &[Scope],
function_scope: bool,
) -> Result<(), SymbolError> { ) -> Result<(), SymbolError> {
match kind { match kind {
StatementKind::Declaration(Declaration::FuncSig(signature)) => { StatementKind::Declaration(Declaration::FuncSig(signature)) => {
@ -407,12 +410,13 @@ impl SymbolTable {
kind: NameKind::Binding, kind: NameKind::Binding,
}, },
)?; )?;
println!("Adding Binding symbol: {:?}", fq_binding); if !function_scope {
self.add_symbol( self.add_symbol(
id, id,
fq_binding, fq_binding,
SymbolSpec::Binding, SymbolSpec::GlobalBinding,
); );
}
} }
StatementKind::Module(ModuleSpecifier { name, .. }) => { StatementKind::Module(ModuleSpecifier { name, .. }) => {
let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone()); let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone());

View File

@ -1,24 +1,45 @@
use std::rc::Rc; use std::rc::Rc;
use crate::ast::*; use crate::ast::*;
use crate::symbol_table::{Fqsn, Scope, SymbolTable}; use crate::symbol_table::{Fqsn, Scope, SymbolTable, DefId};
use crate::util::ScopeStack; use crate::util::ScopeStack;
type FqsnPrefix = Vec<Scope>; type FqsnPrefix = Vec<Scope>;
#[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<String>
},
//TODO add some notion of a let-like scope?
}
pub struct ScopeResolver<'a> { pub struct ScopeResolver<'a> {
symbol_table: &'a mut super::SymbolTable, 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<String>, FqsnPrefix>, name_scope_stack: ScopeStack<'a, Rc<String>, FqsnPrefix>,
lexical_scopes: ScopeStack<'a, Rc<String>, NameType, ScopeType>
} }
impl<'a> ScopeResolver<'a> { impl<'a> ScopeResolver<'a> {
pub fn new(symbol_table: &'a mut SymbolTable) -> Self { pub fn new(symbol_table: &'a mut SymbolTable) -> Self {
let name_scope_stack: ScopeStack<'a, Rc<String>, FqsnPrefix> = ScopeStack::new(None); let name_scope_stack = ScopeStack::new(None);
let lexical_scopes = ScopeStack::new(None);
Self { Self {
symbol_table, symbol_table,
name_scope_stack, name_scope_stack,
lexical_scopes,
} }
} }
pub fn resolve(&mut self, ast: &AST) { pub fn resolve(&mut self, ast: &AST) {
walk_ast(self, 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); println!("Handling qualified_name in resolver.rs: {:?}", name);
let fqsn = self.lookup_name_in_scope(name); let fqsn = self.lookup_name_in_scope(name);
println!("Computed FQSN: {:?}", fqsn);
let symbol = self.symbol_table.fqsn_to_symbol.get(&fqsn); let symbol = self.symbol_table.fqsn_to_symbol.get(&fqsn);
if let Some(symbol) = symbol { if let Some(symbol) = symbol {
self.symbol_table.id_to_symbol.insert(name.id.clone(), symbol.clone()); 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> { impl<'a> ASTVisitor for ScopeResolver<'a> {
//TODO need to un-insert these - maybe need to rethink visitor // Import statements bring in a bunch of local names that all map to a specific FQSN.
fn import(&mut self, import_spec: &ImportSpecifier) { // 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 { let ImportSpecifier {
ref path_components, ref path_components,
ref imported_names, ref imported_names,
@ -99,22 +123,45 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
} }
} }
}; };
Recursion::Continue
} }
fn expression(&mut self, expression: &Expression) { fn declaration(&mut self, declaration: &Declaration) -> Recursion {
use ExpressionKind::*; if let Declaration::FuncDecl(signature, block) = declaration {
match &expression.kind { let param_names = signature.params.iter().map(|param| param.name.clone());
Value(name) => { let mut new_scope = self.lexical_scopes.new_scope(Some(ScopeType::Function { name: signature.name.clone() }));
self.qualified_name(name);
}, for (n, param) in param_names.enumerate().into_iter() {
NamedStruct { name, fields: _ } => { new_scope.insert(param, NameType::Param(n as u8));
self.qualified_name(name); }
},
_ => (), 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::*; use Pattern::*;
match pat { match pat {
@ -122,8 +169,9 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
TuplePattern(_) => (), TuplePattern(_) => (),
Literal(_) | Ignored => (), Literal(_) | Ignored => (),
TupleStruct(name, _) | Record(name, _) | VarOrName(name) => { TupleStruct(name, _) | Record(name, _) | VarOrName(name) => {
self.qualified_name(name); self.handle_qualified_name(name);
} }
}; };
Recursion::Continue
} }
} }