Compare commits
3 commits
f59e6a5fd5
...
7340601939
Author | SHA1 | Date | |
---|---|---|---|
7340601939 | |||
3cbeab3434 | |||
eefbcc8ae2 |
3 changed files with 90 additions and 8 deletions
|
@ -49,8 +49,11 @@ pub enum InterpreterError {
|
|||
/// Interpreter for the Lox language that executes statements and evaluates expressions.
|
||||
#[derive(Debug)]
|
||||
pub struct Interpreter {
|
||||
/// Global environment containing built-in functions and top-level variables
|
||||
pub globals: Rc<RefCell<Environment>>,
|
||||
/// Current environment for variable lookups and assignments
|
||||
environment: Rc<RefCell<Environment>>,
|
||||
/// Map of expressions to their lexical distance for variable resolution
|
||||
locals: HashMap<Expression, usize>,
|
||||
}
|
||||
|
||||
|
@ -76,7 +79,8 @@ impl Default for Interpreter {
|
|||
}
|
||||
|
||||
impl Interpreter {
|
||||
/// Try to evaluate an expression and return its result.
|
||||
/// Execute a list of statements in sequence.
|
||||
/// Log errors but continue execution.
|
||||
pub fn run(&mut self, statements: Vec<Statement>) -> Result<(), InterpreterError> {
|
||||
for stmt in statements {
|
||||
match self.execute(&stmt) {
|
||||
|
@ -88,11 +92,12 @@ impl Interpreter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Record the resolved lexical depth for a variable reference.
|
||||
pub fn resolve(&mut self, expression: Expression, depth: usize) {
|
||||
self.locals.insert(expression, depth);
|
||||
}
|
||||
|
||||
///Execute a statement.
|
||||
/// Execute a statement and return its result value, if any.
|
||||
fn execute(&mut self, statement: &Statement) -> Result<Option<Value>, InterpreterError> {
|
||||
match statement {
|
||||
Statement::Block(statements) => {
|
||||
|
@ -154,6 +159,8 @@ impl Interpreter {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
/// Define a new class with methods and optional inheritance.
|
||||
/// Handle superclass setup and method capturing.
|
||||
fn class(
|
||||
&mut self,
|
||||
name: &Token,
|
||||
|
@ -259,6 +266,7 @@ impl Interpreter {
|
|||
|
||||
/// Call a callable if it is one (meaning it starts with a LeftParen after an identifier),
|
||||
/// otherwise evaluate the expression.
|
||||
/// Evaluate the callee and all arguments before making the call.
|
||||
fn call(
|
||||
&mut self,
|
||||
callee: &Expression,
|
||||
|
@ -280,6 +288,8 @@ impl Interpreter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get a property from an object instance.
|
||||
/// Properties can be fields or methods.
|
||||
fn get(&mut self, object: &Expression, name: &Token) -> Result<Value, InterpreterError> {
|
||||
match self.evaluate(object)? {
|
||||
Value::Instance(instance) => Ok(instance.borrow().get(name, instance.clone())?),
|
||||
|
@ -287,6 +297,7 @@ impl Interpreter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set a property on an object instance to a new value.
|
||||
fn set(
|
||||
&mut self,
|
||||
object: &Expression,
|
||||
|
@ -304,6 +315,7 @@ impl Interpreter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Handle super expressions to access methods from a superclass.
|
||||
fn super_expr(
|
||||
&mut self,
|
||||
expression: &Expression,
|
||||
|
@ -423,7 +435,7 @@ impl Interpreter {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
/// Execute the body as long as the condition evaluates to true.
|
||||
/// Execute the body as long as the loop condition evaluates to true.
|
||||
fn while_statement(
|
||||
&mut self,
|
||||
condition: &Expression,
|
||||
|
@ -513,7 +525,7 @@ impl Interpreter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the value of a variable.
|
||||
/// Evaluate a variable reference expression.
|
||||
fn var_expression(
|
||||
&mut self,
|
||||
name: &Token,
|
||||
|
@ -522,6 +534,8 @@ impl Interpreter {
|
|||
self.lookup_var(name, expression)
|
||||
}
|
||||
|
||||
/// Look up a variable's value using static analysis information.
|
||||
/// Use the resolved lexical distance if available, otherwise check globals.
|
||||
fn lookup_var(
|
||||
&mut self,
|
||||
name: &Token,
|
||||
|
|
|
@ -81,6 +81,7 @@ struct Parser {
|
|||
|
||||
impl Parser {
|
||||
/// Create a new parser instance, fail if the tokens vector is empty.
|
||||
/// Initialize the current token to the first token in the list.
|
||||
fn new(tokens: Vec<Token>) -> Result<Self, ParserError> {
|
||||
let current_token = tokens.first().ok_or(ParserError::NoTokens)?.clone();
|
||||
|
||||
|
@ -92,6 +93,8 @@ impl Parser {
|
|||
}
|
||||
|
||||
/// Parse all tokens to a list of statements for execution.
|
||||
/// Continue parsing until reaching the end of the token stream.
|
||||
/// Handle errors by logging them and synchronizing to continue parsing.
|
||||
fn run(&mut self) -> Result<Vec<Statement>, ParserError> {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
|
@ -110,7 +113,8 @@ impl Parser {
|
|||
|
||||
/// Check if any of the provided types match the type of the current token.
|
||||
///
|
||||
/// If so, advance the current token.
|
||||
/// If so, advance the current token and return true.
|
||||
/// Otherwise, return false without advancing.
|
||||
fn matches(&mut self, types: &[TokenType]) -> bool {
|
||||
let matches = types.iter().any(|x| self.check(x));
|
||||
matches.then(|| self.advance());
|
||||
|
@ -151,7 +155,7 @@ impl Parser {
|
|||
}
|
||||
|
||||
/// Consume the current token if its token type matches the provided token_type and advance the
|
||||
/// current token. Otherwise return None..
|
||||
/// current token. Otherwise return None.
|
||||
fn consume(&mut self, token_type: &TokenType) -> Option<&Token> {
|
||||
if self.check(token_type) {
|
||||
self.advance().ok()
|
||||
|
@ -185,6 +189,7 @@ impl Parser {
|
|||
self.assignment()
|
||||
}
|
||||
|
||||
/// Parse a declaration.
|
||||
fn declaration(&mut self) -> Result<Statement, ParserError> {
|
||||
if self.matches(&[Class]) {
|
||||
self.class_declaration()
|
||||
|
@ -197,6 +202,7 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a statement.
|
||||
fn statement(&mut self) -> Result<Statement, ParserError> {
|
||||
if self.matches(&[For]) {
|
||||
self.for_statement()
|
||||
|
@ -215,7 +221,7 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
/// Build up a while statement from a for statement.
|
||||
/// Parse a for statement by desugaring it into a while loop.
|
||||
fn for_statement(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
self.consume(&LeftParen)
|
||||
|
@ -264,6 +270,8 @@ impl Parser {
|
|||
Ok(body)
|
||||
}
|
||||
|
||||
/// Parse an if statement with a condition, then branch, and optional else branch.
|
||||
/// The condition must be enclosed in parentheses.
|
||||
fn if_statement(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
self.consume(&LeftParen)
|
||||
|
@ -288,6 +296,8 @@ impl Parser {
|
|||
})
|
||||
}
|
||||
|
||||
/// Parse a print statement, which consists of an expression followed by a semicolon.
|
||||
/// The expression's value will be printed during execution.
|
||||
fn print_statement(&mut self) -> Result<Statement, ParserError> {
|
||||
let value = self.expression()?;
|
||||
let line = self.current_token.line;
|
||||
|
@ -297,6 +307,8 @@ impl Parser {
|
|||
Ok(Statement::Print(value))
|
||||
}
|
||||
|
||||
/// Parse a return statement, which may include a return value expression.
|
||||
/// The return value is optional - if not provided, nil is returned implicitly.
|
||||
fn return_statement(&mut self) -> Result<Statement, ParserError> {
|
||||
let keyword = self.previous()?.clone();
|
||||
let value = if self.check(&Semicolon) {
|
||||
|
@ -311,6 +323,8 @@ impl Parser {
|
|||
Ok(Statement::Return { keyword, value })
|
||||
}
|
||||
|
||||
/// Parse a class declaration with a name, optional superclass, and methods.
|
||||
/// A class can inherit from a superclass using the '<' operator.
|
||||
fn class_declaration(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
let name = self
|
||||
|
@ -347,6 +361,8 @@ impl Parser {
|
|||
})
|
||||
}
|
||||
|
||||
/// Parse a variable declaration with a name and optional initializer.
|
||||
/// If no initializer is provided, the variable is initialized to nil.
|
||||
fn var_declaration(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
let name = self
|
||||
|
@ -369,6 +385,8 @@ impl Parser {
|
|||
})
|
||||
}
|
||||
|
||||
/// Parse a while statement with a condition and body.
|
||||
/// The condition must be enclosed in parentheses.
|
||||
fn while_statement(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
self.consume(&LeftParen)
|
||||
|
@ -387,6 +405,8 @@ impl Parser {
|
|||
})
|
||||
}
|
||||
|
||||
/// Parse an expression statement, which is an expression followed by a semicolon.
|
||||
/// The expression is evaluated for its side effects.
|
||||
fn expression_statement(&mut self) -> Result<Statement, ParserError> {
|
||||
let expr = self.expression()?;
|
||||
let line = self.current_token.line;
|
||||
|
@ -396,6 +416,8 @@ impl Parser {
|
|||
Ok(Statement::Expression(expr))
|
||||
}
|
||||
|
||||
/// Parse a function declaration with a name, parameters, and body.
|
||||
/// Used for both standalone functions and class methods.
|
||||
fn function(&mut self) -> Result<Statement, ParserError> {
|
||||
let line = self.current_token.line;
|
||||
let name = self
|
||||
|
@ -433,6 +455,8 @@ impl Parser {
|
|||
Ok(Statement::Function { name, params, body })
|
||||
}
|
||||
|
||||
/// Parse a block of statements enclosed in braces.
|
||||
/// A block creates a new scope for variable declarations.
|
||||
fn block(&mut self) -> Result<Vec<Statement>, ParserError> {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
|
@ -447,6 +471,8 @@ impl Parser {
|
|||
Ok(statements)
|
||||
}
|
||||
|
||||
/// Parse an assignment expression, which can assign to a variable or object property.
|
||||
/// Assignment is right-associative, so we recursively parse the right side.
|
||||
fn assignment(&mut self) -> Result<Expression, ParserError> {
|
||||
let expr = self.or()?;
|
||||
|
||||
|
@ -473,6 +499,7 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a logical expression with a specific operator (AND or OR).
|
||||
fn logical_operator<F>(
|
||||
&mut self,
|
||||
operator: TokenType,
|
||||
|
@ -497,10 +524,12 @@ impl Parser {
|
|||
Ok(expr)
|
||||
}
|
||||
|
||||
/// Parse a logical OR expression.
|
||||
fn or(&mut self) -> Result<Expression, ParserError> {
|
||||
self.logical_operator(Or, Self::and)
|
||||
}
|
||||
|
||||
/// Parse a logical AND expression.
|
||||
fn and(&mut self) -> Result<Expression, ParserError> {
|
||||
self.logical_operator(And, Self::equality)
|
||||
}
|
||||
|
@ -540,6 +569,7 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a call expression or property access.
|
||||
fn call(&mut self) -> Result<Expression, ParserError> {
|
||||
let mut expr = self.primary()?;
|
||||
|
||||
|
@ -565,6 +595,8 @@ impl Parser {
|
|||
Ok(expr)
|
||||
}
|
||||
|
||||
/// Complete parsing a function call after seeing the opening parenthesis.
|
||||
/// Parse the arguments and closing parenthesis.
|
||||
fn finish_call(&mut self, callee: Expression) -> Result<Expression, ParserError> {
|
||||
let mut args = Vec::new();
|
||||
|
||||
|
@ -643,6 +675,8 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
/// Synchronize the parser after an error by advancing to the next statement boundary.
|
||||
/// This allows parsing to continue after encountering a syntax error.
|
||||
fn synchronize(&mut self) {
|
||||
let _ = self.advance();
|
||||
while !self.is_at_end()
|
||||
|
|
|
@ -37,7 +37,7 @@ enum ClassType {
|
|||
Subclass,
|
||||
}
|
||||
|
||||
/// Resolve variable references and performs static analysis before interpretation.
|
||||
/// Resolve variable references and perform static analysis before interpretation.
|
||||
#[derive(Debug)]
|
||||
pub struct Resolver<'a> {
|
||||
scopes: Vec<HashMap<String, bool>>,
|
||||
|
@ -47,6 +47,7 @@ pub struct Resolver<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
/// Create a new resolver with a reference to the interpreter
|
||||
pub fn new(interpreter: &'a mut Interpreter) -> Self {
|
||||
Self {
|
||||
scopes: Vec::default(),
|
||||
|
@ -56,6 +57,7 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Resolve all statements in a program
|
||||
pub fn resolve(&mut self, statements: &[Statement]) -> Result<(), ResolverError> {
|
||||
for stm in statements {
|
||||
self.resolve_statement(stm)?;
|
||||
|
@ -63,6 +65,7 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a single statement.
|
||||
fn resolve_statement(&mut self, statement: &Statement) -> Result<(), ResolverError> {
|
||||
match statement {
|
||||
Statement::Block(statements) => self.resolve_block(statements),
|
||||
|
@ -91,6 +94,7 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Resolve an expression.
|
||||
fn resolve_expression(&mut self, expr: &Expression) -> Result<(), ResolverError> {
|
||||
match expr {
|
||||
Expression::Assign { name, value } => self.resolve_assign_expr(expr, name, value),
|
||||
|
@ -132,14 +136,19 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new scope for variable declarations.
|
||||
fn begin_scope(&mut self) {
|
||||
self.scopes.push(HashMap::new());
|
||||
}
|
||||
|
||||
/// Remove the current scope.
|
||||
fn end_scope(&mut self) {
|
||||
self.scopes.pop();
|
||||
}
|
||||
|
||||
/// Declare a variable in the current scope and mark it as not initialized yet (false).
|
||||
///
|
||||
/// Error if the variable is already declared in this scope.
|
||||
fn declare(&mut self, name: &Token) -> Result<(), ResolverError> {
|
||||
if let Some(scope) = self.scopes.last_mut() {
|
||||
if scope.contains_key(&name.lexeme) {
|
||||
|
@ -152,12 +161,15 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Mark a variable as initialized (true) in the current scope.
|
||||
fn define(&mut self, name: &Token) {
|
||||
if let Some(scope) = self.scopes.last_mut() {
|
||||
scope.insert(name.lexeme.clone(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve a block statement by creating a new scope.
|
||||
/// Resolve all statements in the block, then remove the scope.
|
||||
fn resolve_block(&mut self, statements: &[Statement]) -> Result<(), ResolverError> {
|
||||
self.begin_scope();
|
||||
self.resolve(statements)?;
|
||||
|
@ -166,6 +178,8 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a class declaration with methods and optional inheritance.
|
||||
/// Handle special cases for 'this', 'super', and initializers.
|
||||
fn resolve_class_stmt(
|
||||
&mut self,
|
||||
name: &Token,
|
||||
|
@ -225,6 +239,7 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a return statement, checking for invalid returns (top-level code and value returns from initializers).
|
||||
fn resolve_return_stmt(
|
||||
&mut self,
|
||||
keyword: &Token,
|
||||
|
@ -243,6 +258,7 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Declare the variable, resolve its initializer if any, then define it.
|
||||
fn resolve_var(
|
||||
&mut self,
|
||||
name: &Token,
|
||||
|
@ -258,6 +274,8 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a variable reference expression.
|
||||
/// Check that the variable is not being used in its own initializer.
|
||||
fn resolve_var_expr(&mut self, expr: &Expression, name: &Token) -> Result<(), ResolverError> {
|
||||
if let Some(scope) = self.scopes.last() {
|
||||
if !scope.get(&name.lexeme).unwrap_or(&true) {
|
||||
|
@ -268,6 +286,8 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve an assignment expression.
|
||||
/// Resolve the value being assigned, then resolve the variable being assigned to.
|
||||
fn resolve_assign_expr(
|
||||
&mut self,
|
||||
expr: &Expression,
|
||||
|
@ -279,6 +299,7 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a binary expression by resolving both operands.
|
||||
fn resolve_binary_expr(
|
||||
&mut self,
|
||||
left: &Expression,
|
||||
|
@ -289,6 +310,8 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a function declaration.
|
||||
/// Declare and define the function name, then resolve the function body.
|
||||
fn resolve_function_stmt(
|
||||
&mut self,
|
||||
name: &Token,
|
||||
|
@ -302,6 +325,8 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a function call expression.
|
||||
/// Resolve the callee and all arguments.
|
||||
fn resolve_call_expr(
|
||||
&mut self,
|
||||
callee: &Expression,
|
||||
|
@ -316,6 +341,8 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a property assignment expression.
|
||||
/// Resolve both the object and the value being assigned.
|
||||
fn resolve_set_expression(
|
||||
&mut self,
|
||||
object: &Expression,
|
||||
|
@ -327,6 +354,7 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a super expression, checking for invalid uses (outside of classes, classes with no superclass).
|
||||
fn resolve_super_expression(
|
||||
&mut self,
|
||||
keyword: &Token,
|
||||
|
@ -341,6 +369,7 @@ impl<'a> Resolver<'a> {
|
|||
self.resolve_local(expression, keyword)
|
||||
}
|
||||
|
||||
/// Resolve an if statement by resolving the condition and both branches.
|
||||
fn resolve_if_stmt(
|
||||
&mut self,
|
||||
condition: &Expression,
|
||||
|
@ -357,6 +386,7 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a while statement by resolving the condition and body.
|
||||
fn resolve_while_stmt(
|
||||
&mut self,
|
||||
condition: &Expression,
|
||||
|
@ -368,6 +398,8 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a function definition with parameters and body.
|
||||
/// Create a new scope for the function body and declare all parameters.
|
||||
fn resolve_function(
|
||||
&mut self,
|
||||
params: &[Token],
|
||||
|
@ -392,6 +424,8 @@ impl<'a> Resolver<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a local variable reference by finding its scope.
|
||||
/// Tell the interpreter the number of scopes between the reference and definition.
|
||||
fn resolve_local(
|
||||
&mut self,
|
||||
expression: &Expression,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue