diff --git a/ruby/lib/lox/resolver.rb b/ruby/lib/lox/resolver.rb
index 7cdf3b6..c52819c 100644
--- a/ruby/lib/lox/resolver.rb
+++ b/ruby/lib/lox/resolver.rb
@@ -8,6 +8,7 @@ module Lox
@scopes = []
@current_func = :NONE
+ @current_class = :NONE
end
def resolve(*resolvees)
@@ -25,16 +26,18 @@ module Lox
end
def visit_class(stmt)
- declare(stmt.name)
+ with_current_class(:CLASS) do
+ declare(stmt.name)
- with_scope do
- @scopes.last["this"] = true
+ with_scope do
+ @scopes.last["this"] = true
- stmt.methods.each do |method|
- resolve_function(method, :METHOD)
- end
+ stmt.methods.each do |method|
+ resolve_function(method, :METHOD)
+ end
- define(stmt.name)
+ define(stmt.name)
+ end
end
nil
@@ -104,6 +107,8 @@ module Lox
end
def visit_this(expr)
+ raise ResolverError.new(expr.keyword, "Can't use 'this' outside of a class.") if @current_class == :NONE
+
resolve_local(expr, expr.keyword)
nil
end
@@ -163,5 +168,14 @@ module Lox
@current_func = enclosing_func
end
+ def with_current_class(type)
+ enclosing_class = @current_class
+ @current_class = type
+
+ yield
+
+ @current_class = enclosing_class
+ end
+
end
end
diff --git a/ruby/test/lox/test_interpreter.rb b/ruby/test/lox/test_interpreter.rb
index 6463058..73e42df 100644
--- a/ruby/test/lox/test_interpreter.rb
+++ b/ruby/test/lox/test_interpreter.rb
@@ -402,6 +402,20 @@ class TestInterpreter < Lox::Test
SRC
end
+ def test_invalid_this
+ assert_raises Lox::ResolverError, "Can't use 'this' outside of a class." do
+ interpret("print this;")
+ end
+
+ assert_raises Lox::ResolverError, "Can't use 'this' outside of a class." do
+ interpret(<<~SRC)
+ fun notAMethod() {
+ print this;
+ }
+ SRC
+ end
+ end
+
private
def assert_interpreted(expected, src)