diff --git a/src/resolver.rs b/src/resolver.rs index 9f24acc..036c5dd 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -6,8 +6,12 @@ use crate::{ tokens::Token, }; +/// Resolved variables. Pointers to the AST nodes using the variables are +/// associated with the relative depth at which the variable definition will be +/// found. pub type ResolvedVariables = HashMap<*const ast::ExprNode, usize>; +/// Resolve all variables in a program's AST. pub fn resolve_variables(program: &ast::ProgramNode) -> SloxResult { let mut state = ResolverState::default(); program.resolve(&mut state).map(|_| state.resolved) @@ -15,21 +19,29 @@ pub fn resolve_variables(program: &ast::ProgramNode) -> SloxResult; +/// The state of the resolver. #[derive(Default)] struct ResolverState { + /// The stack of scopes. Each scope maps variable names to a flag that + /// indicates whether the variable has been defined or not. scopes: Vec>, + /// The result of the resolver pass. resolved: ResolvedVariables, } impl ResolverState { + /// Enter a new scope. fn begin_scope(&mut self) { self.scopes.push(HashMap::new()); } + /// End the current scope. fn end_scope(&mut self) { self.scopes.pop(); } + /// Try to declare a variable. If the scope already contains a variable + /// declaration for the same name, return an error. fn declare(&mut self, name: &Token) -> ResolverResult { if !self.scopes.is_empty() { let idx = self.scopes.len() - 1; @@ -47,6 +59,7 @@ impl ResolverState { return Ok(()); } + /// Define a new variable. fn define(&mut self, name: &Token) { if !self.scopes.is_empty() { let idx = self.scopes.len() - 1; @@ -55,6 +68,7 @@ impl ResolverState { } } + /// Check for a variable in the current scope, if there is one. fn check(&self, name: &str) -> Option { if self.scopes.is_empty() { None @@ -64,6 +78,8 @@ impl ResolverState { } } + /// Try to resolve some access to a variable. If a local variable is found + /// matching the specified name, add it to the resolution map. fn resolve_local(&mut self, expr: &ast::ExprNode, name: &Token) { let mut i = self.scopes.len(); while i != 0 { @@ -75,6 +91,7 @@ impl ResolverState { } } + /// Add an entry to the resolution map for an AST node. fn mark_resolved(&mut self, expr: &ast::ExprNode, depth: usize) { self.resolved.insert(expr as *const ast::ExprNode, depth); } @@ -96,7 +113,9 @@ fn resolve_function(rs: &mut ResolverState, params: &[Token], body: &Vec ResolverResult; }