diff --git a/ruby/lib/lox/ast_printer.rb b/ruby/lib/lox/ast_printer.rb index ae8bdd1..f7578b4 100644 --- a/ruby/lib/lox/ast_printer.rb +++ b/ruby/lib/lox/ast_printer.rb @@ -48,9 +48,7 @@ module Lox private def parenthesize(name, *exprs) - inside = [name] - inside.concat(exprs.map {|expr| expr.accept(self) }) - "(#{inside.join(" ")})" + "(#{[name, *exprs.map { _1.accept(self) }].join(" ")})" end end end diff --git a/ruby/lib/lox/function.rb b/ruby/lib/lox/function.rb index 298a1a0..2f291a0 100644 --- a/ruby/lib/lox/function.rb +++ b/ruby/lib/lox/function.rb @@ -14,8 +14,9 @@ module Lox env.define(name, value) end - interpreter.execute_block(@decl.body, env) - nil + catch(:return) { + interpreter.execute_block(@decl.body, env) + } end def to_s = "" diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb index 8e9b305..1cd5536 100644 --- a/ruby/lib/lox/interpreter.rb +++ b/ruby/lib/lox/interpreter.rb @@ -69,6 +69,12 @@ module Lox nil end + def visit_return(stmt) + value = stmt.value ? evaluate(stmt.value) : nil + + throw(:return, value) + end + def visit_var(stmt) value = stmt.initializer&.yield_self { evaluate(_1) } @env.define(stmt.name.lexeme, value) diff --git a/ruby/test/lox/test_interpreter.rb b/ruby/test/lox/test_interpreter.rb index 7960957..3b89b2f 100644 --- a/ruby/test/lox/test_interpreter.rb +++ b/ruby/test/lox/test_interpreter.rb @@ -235,6 +235,28 @@ class TestInterpreter < Lox::Test sayHi("Dear", "Reader"); SRC end + + def test_function + assert_interpreted <<~EXPECTED.chomp, <<~SRC + 0 + 1 + 1 + 2 + 3 + 5 + 8 + EXPECTED + fun fib(n) { + if (n <= 1) return n; + return fib(n - 2) + fib(n - 1); + } + + for (var i = 0; i < 7; i = i + 1) { + print fib(i); + } + SRC + end + private def assert_interpreted(expected, src)