From 1cb62101d814fafdb31f38762e71a3a139ac9925 Mon Sep 17 00:00:00 2001 From: alpha Date: Tue, 9 Aug 2022 21:43:35 +0000 Subject: [PATCH] 8.4.2 FossilOrigin-Name: 0d44d8a3a62b9bd884f12a5497f7b085c6727ae0861100ca22488b67564750df --- ruby/lib/lox/ast_printer.rb | 19 +++++++++++++------ ruby/lib/lox/environment.rb | 8 ++++++++ ruby/lib/lox/interpreter.rb | 6 ++++++ ruby/lib/lox/parser.rb | 4 ++-- ruby/test/lox/test_interpreter.rb | 9 +++++++++ ruby/test/lox/test_parser.rb | 3 ++- 6 files changed, 40 insertions(+), 9 deletions(-) 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