diff --git a/ruby/lib/lox/expr.rb b/ruby/lib/lox/expr.rb
index 52e2a82..1c1e7a8 100644
--- a/ruby/lib/lox/expr.rb
+++ b/ruby/lib/lox/expr.rb
@@ -18,6 +18,7 @@ module Lox
expr :Literal, :value
expr :Logical, :left, :op, :right
expr :Set, :object, :name, :value
+ expr :This, :keyword
expr :Unary, :op, :right
expr :Variable, :name
end
diff --git a/ruby/lib/lox/function.rb b/ruby/lib/lox/function.rb
index cc92c2f..f1f5475 100644
--- a/ruby/lib/lox/function.rb
+++ b/ruby/lib/lox/function.rb
@@ -6,6 +6,12 @@ module Lox
@decl, @closure = decl, closure
end
+ def bind(instance)
+ env = Environment.new(@closure)
+ env.define("this", instance)
+ Function.new(@decl, env)
+ end
+
def arity = @decl.params.size
def call(interpreter, args)
diff --git a/ruby/lib/lox/instance.rb b/ruby/lib/lox/instance.rb
index d6bd711..d149152 100644
--- a/ruby/lib/lox/instance.rb
+++ b/ruby/lib/lox/instance.rb
@@ -13,7 +13,7 @@ module Lox
return @fields.fetch(name.lexeme) if @fields.has_key?(name.lexeme)
method = @klass.find_method(name.lexeme)
- return method unless method.nil?
+ return method.bind(self) unless method.nil?
raise RuntimeError.new(name, "Undefined property '#{name.lexeme}'.")
end
diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb
index 39ee6b8..1774d51 100644
--- a/ruby/lib/lox/interpreter.rb
+++ b/ruby/lib/lox/interpreter.rb
@@ -136,6 +136,8 @@ module Lox
value
end
+ def visit_this(expr) = lookup_var(expr.keyword, expr)
+
def visit_unary(expr)
right = evaluate(expr.right)
diff --git a/ruby/lib/lox/parser.rb b/ruby/lib/lox/parser.rb
index 29f58b1..10e42b0 100644
--- a/ruby/lib/lox/parser.rb
+++ b/ruby/lib/lox/parser.rb
@@ -308,6 +308,7 @@ module Lox
return Expr::Literal.new(true) if match?(:TRUE)
return Expr::Literal.new(nil) if match?(:NIL)
return Expr::Literal.new(prev.literal) if match?(:NUMBER, :STRING)
+ return Expr::This.new(prev) if match?(:THIS)
return Expr::Variable.new(prev) if match?(:IDENTIFIER)
if match?(:LEFT_PAREN)
diff --git a/ruby/lib/lox/resolver.rb b/ruby/lib/lox/resolver.rb
index 2740876..7cdf3b6 100644
--- a/ruby/lib/lox/resolver.rb
+++ b/ruby/lib/lox/resolver.rb
@@ -27,11 +27,16 @@ module Lox
def visit_class(stmt)
declare(stmt.name)
- stmt.methods.each do |method|
- resolve_function(method, :METHOD)
+ with_scope do
+ @scopes.last["this"] = true
+
+ stmt.methods.each do |method|
+ resolve_function(method, :METHOD)
+ end
+
+ define(stmt.name)
end
- define(stmt.name)
nil
end
@@ -98,6 +103,11 @@ module Lox
nil
end
+ def visit_this(expr)
+ resolve_local(expr, expr.keyword)
+ nil
+ end
+
def visit_unary(expr) = resolve(expr.right)
private
diff --git a/ruby/test/lox/test_interpreter.rb b/ruby/test/lox/test_interpreter.rb
index 439bd5d..6463058 100644
--- a/ruby/test/lox/test_interpreter.rb
+++ b/ruby/test/lox/test_interpreter.rb
@@ -356,22 +356,50 @@ class TestInterpreter < Lox::Test
Bacon().eat(); // Prints "Crunch crunch crunch!".
SRC
- # assert_interpreted "", <<~SRC
- # class Person {
- # sayName() {
- # print this.name;
- # }
- # }
-
- # var jane = Person();
- # jane.name = "Jane";
-
- # var bill = Person();
- # bill.name = "Bill";
-
- # bill.sayName = jane.sayName;
- # bill.sayName(); // "Jane"
- # SRC
+ assert_interpreted "The German chocolate cake is delicious!", <<~SRC
+ class Cake {
+ taste() {
+ var adjective = "delicious";
+ print "The " + this.flavor + " cake is " + adjective + "!";
+ }
+ }
+
+ var cake = Cake();
+ cake.flavor = "German chocolate";
+ cake.taste(); // Prints "The German chocolate cake is delicious!".
+ SRC
+
+ assert_interpreted "Thing instance", <<~SRC
+ class Thing {
+ getCallback() {
+ fun localFunction() {
+ print this;
+ }
+
+ return localFunction;
+ }
+ }
+
+ var callback = Thing().getCallback();
+ callback();
+ SRC
+
+ assert_interpreted "Jane", <<~SRC
+ class Person {
+ sayName() {
+ print this.name;
+ }
+ }
+
+ var jane = Person();
+ jane.name = "Jane";
+
+ var bill = Person();
+ bill.name = "Bill";
+
+ bill.sayName = jane.sayName;
+ bill.sayName(); // "Jane"
+ SRC
end
private