main
Alpha Chen 2 years ago
parent dade99a51f
commit 009c22fa27

@ -55,11 +55,18 @@ module Lox
@env.define(stmt.name.lexeme, nil)
if superclass
@env = Environment.new(@env)
@env.define("super", superclass)
end
methods = stmt.methods.to_h {|method|
[method.name.lexeme, Function.new(method, @env, method.name.lexeme == "init")]
}
klass = LoxClass.new(stmt.name.lexeme, superclass, methods)
@env = @env.enclosing if superclass
@env.assign(stmt.name, klass)
nil
end
@ -144,6 +151,16 @@ module Lox
value
end
def visit_super(expr)
distance = @locals.fetch(expr)
superclass = @env.get_at(distance, "super")
object = @env.get_at(distance-1, "this")
method = superclass.find_method(expr.method.lexeme)
raise RuntimeError.new(expr.method, "Undefined property '#{expr.method.lexeme}'.") if method.nil?
method.bind(object)
end
def visit_this(expr) = lookup_var(expr.keyword, expr)
def visit_unary(expr)

@ -30,17 +30,20 @@ module Lox
declare(stmt.name)
define(stmt.name)
if stmt.superclass
raise ResolverError.new(stmt.superclass.name, "A class can't inherit from itself.") if stmt.name.lexeme == stmt.superclass.name.lexeme
resolve(stmt.superclass)
end
with_scope do
@scopes.last["this"] = true
stmt.methods.each do |method|
decl = method.name.lexeme == "init" ? :INIT : :METHOD
resolve_function(method, decl)
with_superclass_scope = if stmt.superclass
raise ResolverError.new(stmt.superclass.name, "A class can't inherit from itself.") if stmt.name.lexeme == stmt.superclass.name.lexeme
resolve(stmt.superclass)
->(&block) { with_scope(super: true) { block.call } }
else
->(&block) { block.call }
end
with_superclass_scope.call do
with_scope(this: true) do
stmt.methods.each do |method|
decl = method.name.lexeme == "init" ? :INIT : :METHOD
resolve_function(method, decl)
end
end
end
end
@ -117,6 +120,11 @@ module Lox
nil
end
def visit_super(expr)
resolve_local(expr, expr.keyword)
nil
end
def visit_this(expr)
raise ResolverError.new(expr.keyword, "Can't use 'this' outside of a class.") if @current_class == :NONE
@ -128,8 +136,8 @@ module Lox
private
def with_scope
@scopes.push({})
def with_scope(scope={})
@scopes.push(scope.transform_keys(&:to_s))
yield
@scopes.pop
end

@ -485,7 +485,7 @@ class TestInterpreter < Lox::Test
end
def test_calling_superclass_methods
assert_interpreted <<~OUT, <<~SRC
assert_interpreted <<~OUT.chomp, <<~SRC
Fry until golden brown.
Pipe full of custard and coat with chocolate.
OUT
@ -504,6 +504,28 @@ class TestInterpreter < Lox::Test
BostonCream().cook();
SRC
assert_interpreted "A method", <<~SRC
class A {
method() {
print "A method";
}
}
class B < A {
method() {
print "B method";
}
test() {
super.method();
}
}
class C < B {}
C().test();
SRC
end
private

Loading…
Cancel
Save