10.5
change rsuvptytylzklxxumuoywstlwxwlkowz
commit d5795dc1bd3d3466b8e48541adbc33cb1fffe7ad
author Alpha Chen <alpha@kejadlen.dev>
date
parent kzmqwztz
diff --git a/ruby/lib/lox/ast_printer.rb b/ruby/lib/lox/ast_printer.rb
index 154c9b9..ae8bdd1 100644
--- a/ruby/lib/lox/ast_printer.rb
+++ b/ruby/lib/lox/ast_printer.rb
@@ -40,6 +40,11 @@ module Lox
       parenthesize(call.callee.accept(self), *call.args)
     end
 
+    def visit_return(stmt)
+      exprs = stmt.value ? [stmt.value] : []
+      parenthesize("return", *exprs)
+    end
+
     private
 
     def parenthesize(name, *exprs)
diff --git a/ruby/lib/lox/parser.rb b/ruby/lib/lox/parser.rb
index 7ac47d3..0728bb4 100644
--- a/ruby/lib/lox/parser.rb
+++ b/ruby/lib/lox/parser.rb
@@ -50,6 +50,7 @@ module Lox
       return for_stmt if match?(:FOR)
       return if_stmt if match?(:IF)
       return print if match?(:PRINT)
+      return return_stmt if match?(:RETURN)
       return while_stmt if match?(:WHILE)
       return Stmt::Block.new(block) if match?(:LEFT_BRACE)
 
@@ -111,6 +112,13 @@ module Lox
       Stmt::Print.new(value)
     end
 
+    def return_stmt
+      keyword = prev
+      value = check?(:SEMICOLON) ? nil : expression
+      consume!(:SEMICOLON, "Expect ';' after return value.")
+      Stmt::Return.new(keyword, value)
+    end
+
     def expression_stmt
       value = expression
       consume!(:SEMICOLON, "Expect ';' after value.")
diff --git a/ruby/lib/lox/stmt.rb b/ruby/lib/lox/stmt.rb
index 2826c67..e4bfc54 100644
--- a/ruby/lib/lox/stmt.rb
+++ b/ruby/lib/lox/stmt.rb
@@ -17,6 +17,7 @@ module Lox
     stmt :Expr, :expr
     stmt :If, :cond, :then, :else
     stmt :Print, :expr
+    stmt :Return, :keyword, :value
     stmt :Var, :name, :initializer
     stmt :While, :cond, :body
   end
diff --git a/ruby/test/lox/test_parser.rb b/ruby/test/lox/test_parser.rb
index 11a7904..7aee4d2 100644
--- a/ruby/test/lox/test_parser.rb
+++ b/ruby/test/lox/test_parser.rb
@@ -81,6 +81,11 @@ class TestParser < Lox::Test
     assert_parsed "((var foo) (var bar) (var baz))", :statement, "foo(bar, baz);"
   end
 
+  def test_return
+    assert_parsed "(return)", :statement, "return;"
+    assert_parsed "(return (var foo))", :statement, "return foo;"
+  end
+
   private
 
   def assert_parsed(expected, name, src)