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