Alpha Chen 2 years ago
parent 952bd06dce
commit ec7a788377

@ -18,6 +18,7 @@ module Lox
expr :Literal, :value expr :Literal, :value
expr :Logical, :left, :op, :right expr :Logical, :left, :op, :right
expr :Set, :object, :name, :value expr :Set, :object, :name, :value
expr :This, :keyword
expr :Unary, :op, :right expr :Unary, :op, :right
expr :Variable, :name expr :Variable, :name
end end

@ -6,6 +6,12 @@ module Lox
@decl, @closure = decl, closure @decl, @closure = decl, closure
end end
def bind(instance)
env = Environment.new(@closure)
env.define("this", instance)
Function.new(@decl, env)
end
def arity = @decl.params.size def arity = @decl.params.size
def call(interpreter, args) def call(interpreter, args)

@ -13,7 +13,7 @@ module Lox
return @fields.fetch(name.lexeme) if @fields.has_key?(name.lexeme) return @fields.fetch(name.lexeme) if @fields.has_key?(name.lexeme)
method = @klass.find_method(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}'.") raise RuntimeError.new(name, "Undefined property '#{name.lexeme}'.")
end end

@ -136,6 +136,8 @@ module Lox
value value
end end
def visit_this(expr) = lookup_var(expr.keyword, expr)
def visit_unary(expr) def visit_unary(expr)
right = evaluate(expr.right) right = evaluate(expr.right)

@ -308,6 +308,7 @@ module Lox
return Expr::Literal.new(true) if match?(:TRUE) return Expr::Literal.new(true) if match?(:TRUE)
return Expr::Literal.new(nil) if match?(:NIL) return Expr::Literal.new(nil) if match?(:NIL)
return Expr::Literal.new(prev.literal) if match?(:NUMBER, :STRING) 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) return Expr::Variable.new(prev) if match?(:IDENTIFIER)
if match?(:LEFT_PAREN) if match?(:LEFT_PAREN)

@ -27,11 +27,16 @@ module Lox
def visit_class(stmt) def visit_class(stmt)
declare(stmt.name) declare(stmt.name)
with_scope do
@scopes.last["this"] = true
stmt.methods.each do |method| stmt.methods.each do |method|
resolve_function(method, :METHOD) resolve_function(method, :METHOD)
end end
define(stmt.name) define(stmt.name)
end
nil nil
end end
@ -98,6 +103,11 @@ module Lox
nil nil
end end
def visit_this(expr)
resolve_local(expr, expr.keyword)
nil
end
def visit_unary(expr) = resolve(expr.right) def visit_unary(expr) = resolve(expr.right)
private private

@ -356,22 +356,50 @@ class TestInterpreter < Lox::Test
Bacon().eat(); // Prints "Crunch crunch crunch!". Bacon().eat(); // Prints "Crunch crunch crunch!".
SRC SRC
# assert_interpreted "", <<~SRC assert_interpreted "The German chocolate cake is delicious!", <<~SRC
# class Person { class Cake {
# sayName() { taste() {
# print this.name; var adjective = "delicious";
# } print "The " + this.flavor + " cake is " + adjective + "!";
# } }
}
# var jane = Person();
# jane.name = "Jane"; var cake = Cake();
cake.flavor = "German chocolate";
# var bill = Person(); cake.taste(); // Prints "The German chocolate cake is delicious!".
# bill.name = "Bill"; SRC
# bill.sayName = jane.sayName; assert_interpreted "Thing instance", <<~SRC
# bill.sayName(); // "Jane" class Thing {
# SRC 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 end
private private

Loading…
Cancel
Save