diff --git a/lox-examples/closures.lox b/lox-examples/closures.lox new file mode 100644 index 0000000..5c69967 --- /dev/null +++ b/lox-examples/closures.lox @@ -0,0 +1,13 @@ +fun makeCounter() { + var i = 0; + fun count() { + i = i + 1; + print i; + } + return count; +} +var counter = makeCounter(); +counter(); +counter(); + +{ var a; var a; var a; } diff --git a/src/resolver.rs b/src/resolver.rs index 85c4e59..59ab62e 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -1,10 +1,14 @@ -use crate::ast::{Ast, Expr, Lval, Stmt}; -use crate::span::{Span, Spanned}; use std::collections::HashMap; +use crate::{ + ast::{Ast, Expr, Lval, Stmt}, + span::{Span, Spanned}, +}; + #[derive(Clone, Debug, Default)] pub struct Resolver { scopes: Vec, + function_types: Vec, } impl Resolver { @@ -29,6 +33,13 @@ impl Resolver { } } + fn last_scope_has_var(&self, name: &str) -> bool { + self.scopes + .last() + .map(|scope| scope.is_declared(name)) + .unwrap_or_default() + } + fn is_declared(&self, name: &str) -> bool { if let Some(scope) = self.scopes.last() { scope.is_declared(name) @@ -75,6 +86,8 @@ impl Resolver { self.define(name.clone()); self.begin_scope(); + self.function_types.push(FunctionType::Function); + for param in params { self.declare(param.clone()); self.define(param.clone()); @@ -82,9 +95,18 @@ impl Resolver { for stmt in body { self.resolve_stmt(stmt)?; } + self.end_scope(); + self.function_types.pop(); } Stmt::VarDecl { name, initializer } => { + if self.last_scope_has_var(name) { + return Err(ResolverError::RedefinedVar { + name: name.clone(), + second_def: stmt.span(), + }); + } + self.declare(name.clone()); if let Some(initializer) = initializer { self.resolve_expr(initializer)? @@ -110,6 +132,10 @@ impl Resolver { self.resolve_stmt(body)?; } Stmt::Return(expr) => { + if self.function_types.is_empty() { + return Err(ResolverError::ReturnFromGlobal { span: stmt.span() }); + } + if let Some(expr) = expr { self.resolve_expr(expr)?; } @@ -227,6 +253,18 @@ impl AsRef for MaybeResolved { } } +#[derive(Clone, Copy, Debug)] +enum FunctionType { + None, + Function, +} + +impl Default for FunctionType { + fn default() -> Self { + Self::None + } +} + #[derive(Clone, Debug, thiserror::Error, miette::Diagnostic)] pub enum ResolverError { #[error("Cannot reference variable in its own initializer")] @@ -235,4 +273,16 @@ pub enum ResolverError { #[label("`{name}` is being referenced here in its own declaration")] reference: Span, }, + #[error("Multiple definitions of the same variable")] + RedefinedVar { + name: String, + #[label("`{name}` is redefined here")] + second_def: Span, + }, + + #[error("Cannot return from top-level code")] + ReturnFromGlobal { + #[label("this return isn't in a function body")] + span: Span, + }, }