diff --git a/ruby/lib/lox/error.rb b/ruby/lib/lox/error.rb index 46897e5..8013f0d 100644 --- a/ruby/lib/lox/error.rb +++ b/ruby/lib/lox/error.rb @@ -1,5 +1,11 @@ module Lox + class Error < StandardError + attr_reader :token, :message + + def initialize(token, message) + @token, @message = token, message + end end class ParseError < Error @@ -8,16 +14,12 @@ module Lox error = "Error" error << " at #{where}" unless where.empty? - super("[line #{token.line}] #{error}: #{message}") + + super(token, "[line #{token.line}] #{error}: #{message}") end end - class RuntimeError < Error - attr_reader :token + RuntimeError = Class.new(Error) + ResolverError = Class.new(Error) - def initialize(token, message) - @token = token - super(message) - end - end end diff --git a/ruby/lib/lox/resolver.rb b/ruby/lib/lox/resolver.rb index fdd385a..d2d48f4 100644 --- a/ruby/lib/lox/resolver.rb +++ b/ruby/lib/lox/resolver.rb @@ -1,3 +1,5 @@ +require_relative "error" + module Lox class Resolver @@ -27,12 +29,21 @@ module Lox nil end + def visit_variable(expr) + if !@scopes.empty? && @scopes.last[expr.name.lexeme] == false + raise ResolverError.new(expr.name, "Can't read local variable in its own initializer.") + end + + resolve_local(expr, expr.name) + nil + end + private def with_block - @scopes.push({}) + @scopes.unshift({}) yield - @scopes.pop + @scopes.shift end def declare(name) @@ -49,5 +60,13 @@ module Lox scopes[name.lexeme] = true end + def resolve_local(expr, name) + scope_and_depth = @scopes.each.with_index.find {|scope, depth| scope.has_key?(name.lexeme) } + return unless scope_and_depth + + scope, depth = scope_and_depth + @interpreter.resolve(expr, depth) + end + end end