12.5
change wuklnrwtsukpsstlprtymnxuxzqrwksw
commit 26842170b785cb2f5785f6e77f31480941c461f8
author Alpha Chen <alpha@kejadlen.dev>
date
parent lqvzqoxz
diff --git a/ruby/lib/lox/instance.rb b/ruby/lib/lox/instance.rb
index 8b27905..d6bd711 100644
--- a/ruby/lib/lox/instance.rb
+++ b/ruby/lib/lox/instance.rb
@@ -10,9 +10,12 @@ module Lox
     end
 
     def get(name)
-      raise RuntimeError.new(name, "Undefined property '#{name.lexeme}'.") unless @fields.has_key?(name.lexeme)
+      return @fields.fetch(name.lexeme) if @fields.has_key?(name.lexeme)
 
-      @fields.fetch(name.lexeme)
+      method = @klass.find_method(name.lexeme)
+      return method unless method.nil?
+
+      raise RuntimeError.new(name, "Undefined property '#{name.lexeme}'.")
     end
 
     def set(name, value)
diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb
index c8fe02a..39ee6b8 100644
--- a/ruby/lib/lox/interpreter.rb
+++ b/ruby/lib/lox/interpreter.rb
@@ -46,7 +46,12 @@ module Lox
 
     def visit_class(stmt)
       @env.define(stmt.name.lexeme, nil)
-      klass = LoxClass.new(stmt.name.lexeme)
+
+      methods = stmt.methods.to_h {|method|
+        [method.name.lexeme, Function.new(method, @env)]
+      }
+
+      klass = LoxClass.new(stmt.name.lexeme, methods)
       @env.assign(stmt.name, klass)
       nil
     end
diff --git a/ruby/lib/lox/lox_class.rb b/ruby/lib/lox/lox_class.rb
index 170fa36..44a9f37 100644
--- a/ruby/lib/lox/lox_class.rb
+++ b/ruby/lib/lox/lox_class.rb
@@ -5,14 +5,13 @@ module Lox
 
     attr_reader :name
 
-    def initialize(name)
-      @name = name
+    def initialize(name, methods)
+      @name, @methods = name, methods
     end
 
+    def find_method(name) = @methods[name]
     def to_s = name
-
     def call(interpreter, args) = Instance.new(self)
-
     def arity = 0
 
   end
diff --git a/ruby/lib/lox/resolver.rb b/ruby/lib/lox/resolver.rb
index 2ea0471..2740876 100644
--- a/ruby/lib/lox/resolver.rb
+++ b/ruby/lib/lox/resolver.rb
@@ -26,6 +26,11 @@ module Lox
 
     def visit_class(stmt)
       declare(stmt.name)
+
+      stmt.methods.each do |method|
+        resolve_function(method, :METHOD)
+      end
+
       define(stmt.name)
       nil
     end
diff --git a/ruby/test/lox/test_interpreter.rb b/ruby/test/lox/test_interpreter.rb
index ad1fd14..439bd5d 100644
--- a/ruby/test/lox/test_interpreter.rb
+++ b/ruby/test/lox/test_interpreter.rb
@@ -345,6 +345,35 @@ class TestInterpreter < Lox::Test
     SRC
   end
 
+  def test_class_methods
+    assert_interpreted "Crunch crunch crunch!", <<~SRC
+      class Bacon {
+        eat() {
+          print "Crunch crunch crunch!";
+        }
+      }
+
+      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
+  end
+
   private
 
   def assert_interpreted(expected, src)