Resolver - Refactored entering/exiting scopes

This commit is contained in:
Emmanuel BENOîT 2023-01-07 10:51:34 +01:00
parent 6dceae73a0
commit 8d65c288a3

View file

@ -55,14 +55,16 @@ struct ResolverState {
} }
impl ResolverState { impl ResolverState {
/// Enter a new scope. /// Execute some function with a new scope. The scope will be disposed
fn begin_scope(&mut self) { /// of after the function has been executed.
fn with_scope<F>(&mut self, f: F) -> ResolverResult
where
F: FnOnce(&mut Self) -> ResolverResult,
{
self.scopes.push(HashMap::new()); self.scopes.push(HashMap::new());
} let result = f(self);
/// End the current scope.
fn end_scope(&mut self) {
self.scopes.pop(); self.scopes.pop();
result
} }
/// Try to declare a symbol. If the scope already contains a declaration /// Try to declare a symbol. If the scope already contains a declaration
@ -156,18 +158,13 @@ fn resolve_function(
params: &[Token], params: &[Token],
body: &Vec<ast::StmtNode>, body: &Vec<ast::StmtNode>,
) -> ResolverResult { ) -> ResolverResult {
rs.begin_scope();
for param in params { for param in params {
rs.declare(param, SymKind::Variable)?; rs.declare(param, SymKind::Variable)?;
rs.define(param); rs.define(param);
} }
// Unlike the original Lox, function arguments and function bodies do // Unlike the original Lox, function arguments and function bodies do
// not use the same environment. // not use the same environment.
rs.begin_scope(); rs.with_scope(|rs| body.resolve(rs))
let result = body.resolve(rs);
rs.end_scope();
rs.end_scope();
result
} }
/// Helper trait used to visit the various AST nodes with the resolver. /// Helper trait used to visit the various AST nodes with the resolver.
@ -194,12 +191,7 @@ impl VarResolver for Vec<ast::StmtNode> {
impl VarResolver for ast::StmtNode { impl VarResolver for ast::StmtNode {
fn resolve(&self, rs: &mut ResolverState) -> ResolverResult { fn resolve(&self, rs: &mut ResolverState) -> ResolverResult {
match self { match self {
ast::StmtNode::Block(stmts) => { ast::StmtNode::Block(stmts) => rs.with_scope(|rs| stmts.resolve(rs)),
rs.begin_scope();
let result = stmts.resolve(rs);
rs.end_scope();
result
}
ast::StmtNode::VarDecl(name, None) => { ast::StmtNode::VarDecl(name, None) => {
rs.declare(name, SymKind::Variable)?; rs.declare(name, SymKind::Variable)?;
@ -215,7 +207,7 @@ impl VarResolver for ast::StmtNode {
ast::StmtNode::FunDecl { name, params, body } => { ast::StmtNode::FunDecl { name, params, body } => {
rs.declare(name, SymKind::Function)?; rs.declare(name, SymKind::Function)?;
rs.define(name); rs.define(name);
resolve_function(rs, params, body) rs.with_scope(|rs| resolve_function(rs, params, body))
} }
ast::StmtNode::If { ast::StmtNode::If {
@ -270,16 +262,16 @@ impl VarResolver for ast::StmtNode {
impl VarResolver for ast::ExprNode { impl VarResolver for ast::ExprNode {
fn resolve(&self, rs: &mut ResolverState) -> ResolverResult { fn resolve(&self, rs: &mut ResolverState) -> ResolverResult {
match self { match self {
ast::ExprNode::Variable { name, id } => { ast::ExprNode::Variable { name, id } => rs.resolve_local(id, name, false),
rs.resolve_local(id, name, false)
}
ast::ExprNode::Assignment { name, value, id } => { ast::ExprNode::Assignment { name, value, id } => {
value.resolve(rs)?; value.resolve(rs)?;
rs.resolve_local(id, name, true) rs.resolve_local(id, name, true)
} }
ast::ExprNode::Lambda { params, body } => resolve_function(rs, params, body), ast::ExprNode::Lambda { params, body } => {
rs.with_scope(|rs| resolve_function(rs, params, body))
}
ast::ExprNode::Logical { ast::ExprNode::Logical {
left, left,