8.4.2
FossilOrigin-Name: 0d44d8a3a62b9bd884f12a5497f7b085c6727ae0861100ca22488b67564750df
change pvqqwuqnrunurlsvtlynkrnmokukxryo
commit 9912feedbb9c89295c6b6670ace0dab45218742e
author alpha <alpha@kejadlen.dev>
date
parent lrqnquun
diff --git a/ruby/lib/lox/ast_printer.rb b/ruby/lib/lox/ast_printer.rb
index d394311..b79776b 100644
--- a/ruby/lib/lox/ast_printer.rb
+++ b/ruby/lib/lox/ast_printer.rb
@@ -10,17 +10,24 @@ module Lox
     def visit_print(expr)    = parenthesize("print", expr.expr)
 
     def visit_var(expr)
-      if init = expr.initializer
-        "(assign #{expr.name.lexeme} #{expr.initializer.value})"
-      else
-        "(var #{expr.name.lexeme})"
-      end
+      exprs = [expr.initializer].reject(&:nil?)
+      parenthesize("var #{expr.name.lexeme}", *exprs)
+    end
+
+    def visit_variable(expr)
+      "(var #{expr.name.lexeme})"
+    end
+
+    def visit_assign(expr)
+      parenthesize("assign #{expr.name.lexeme}", expr.value)
     end
 
     private
 
     def parenthesize(name, *exprs)
-      "(#{name} #{exprs.map {|expr| expr.accept(self) }.join(" ")})"
+      inside = [name]
+      inside.concat(exprs.map {|expr| expr.accept(self) })
+      "(#{inside.join(" ")})"
     end
   end
 end
diff --git a/ruby/lib/lox/environment.rb b/ruby/lib/lox/environment.rb
index 3f32be2..b568f69 100644
--- a/ruby/lib/lox/environment.rb
+++ b/ruby/lib/lox/environment.rb
@@ -1,3 +1,5 @@
+require_relative "error"
+
 module Lox
   class Environment
     def initialize
@@ -13,5 +15,11 @@ module Lox
 
       @values.fetch(name) { raise RuntimeError.new(token, "Undefined variable '#{name}'.") }
     end
+
+    def assign(name, value)
+      raise RuntimeError.new(name, "Undefined variable '#{name.lexeme}'.") unless @values.has_key?(name.lexeme)
+
+      @values[name.lexeme] = value
+    end
   end
 end
diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb
index c04c6e7..b712ffe 100644
--- a/ruby/lib/lox/interpreter.rb
+++ b/ruby/lib/lox/interpreter.rb
@@ -52,6 +52,12 @@ module Lox
       @env.get(expr.name)
     end
 
+    def visit_assign(expr)
+      value = evaluate(expr.value)
+      @env.assign(expr.name, value)
+      value
+    end
+
     def visit_binary(expr)
       left = evaluate(expr.left)
       right = evaluate(expr.right)
diff --git a/ruby/lib/lox/parser.rb b/ruby/lib/lox/parser.rb
index a2dc1dd..197cdef 100644
--- a/ruby/lib/lox/parser.rb
+++ b/ruby/lib/lox/parser.rb
@@ -63,13 +63,13 @@ module Lox
 
         raise ParseError.new(eq, "Invalid assignment target.") unless expr.instance_of?(Expr::Variable)
 
-        Expr::Assign.new(expr.name, value)
+        return Expr::Assign.new(expr.name, value)
       end
 
       expr
     end
 
-    def expression = equality
+    def expression = assignment
 
     def equality
       expr = comparison
diff --git a/ruby/test/lox/test_interpreter.rb b/ruby/test/lox/test_interpreter.rb
index af0eb94..fde7786 100644
--- a/ruby/test/lox/test_interpreter.rb
+++ b/ruby/test/lox/test_interpreter.rb
@@ -107,6 +107,15 @@ class TestInterpreter < Lox::Test
     SRC
   end
 
+  def test_assignment
+    assert_interpreted <<~EXPECTED.chomp, <<~SRC
+      2
+    EXPECTED
+      var a = 1;
+      print a = 2;
+    SRC
+  end
+
   private
 
   def assert_interpreted(expected, src)
diff --git a/ruby/test/lox/test_parser.rb b/ruby/test/lox/test_parser.rb
index 579676e..67b80ae 100644
--- a/ruby/test/lox/test_parser.rb
+++ b/ruby/test/lox/test_parser.rb
@@ -53,10 +53,11 @@ class TestParser < Lox::Test
 
   def test_var
     assert_parsed "(var foo)", :declaration, "var foo;"
+    assert_parsed "(var foo 42.0)", :declaration, "var foo = 42.0;"
   end
 
   def test_assign
-    assert_parsed "(assign foo 42.0)", :declaration, "var foo = 42.0;"
+    assert_parsed "(print (assign foo 42.0))", :declaration, "print foo = 42.0;"
   end
 
   private