10.1
FossilOrigin-Name: c1d35386c76ad60362ec68d9e94a6e4fe9cfc02c39b7c2589668a214a3f22c43
diff --git a/ruby/lib/lox/ast_printer.rb b/ruby/lib/lox/ast_printer.rb
index a303c5f..154c9b9 100644
--- a/ruby/lib/lox/ast_printer.rb
+++ b/ruby/lib/lox/ast_printer.rb
@@ -36,6 +36,10 @@ module Lox
expr.expr.accept(self)
end
+ def visit_call(call)
+ parenthesize(call.callee.accept(self), *call.args)
+ end
+
private
def parenthesize(name, *exprs)
diff --git a/ruby/lib/lox/expr.rb b/ruby/lib/lox/expr.rb
index 2737930..a3f40a2 100644
--- a/ruby/lib/lox/expr.rb
+++ b/ruby/lib/lox/expr.rb
@@ -12,6 +12,7 @@ module Lox
expr :Assign, :name, :value
expr :Binary, :left, :op, :right
+ expr :Call, :callee, :paren, :args
expr :Grouping, :expr
expr :Literal, :value
expr :Logical, :left, :op, :right
diff --git a/ruby/lib/lox/parser.rb b/ruby/lib/lox/parser.rb
index 0f6ce9f..c6e8e24 100644
--- a/ruby/lib/lox/parser.rb
+++ b/ruby/lib/lox/parser.rb
@@ -215,13 +215,41 @@ module Lox
end
def unary
- return primary unless match?(:BANG, :MINUS)
+ return call unless match?(:BANG, :MINUS)
op = prev
right = unary
Expr::Unary.new(op, right)
end
+ def call
+ expr = primary
+
+ loop do
+ if match?(:LEFT_PAREN)
+ expr = finish_call(expr)
+ else
+ break
+ end
+ end
+
+ expr
+ end
+
+ def finish_call(callee)
+ args = []
+ if !check?(:RIGHT_PAREN)
+ loop do
+ args << expression
+ break unless match?(:COMMA)
+ end
+ end
+
+ paren = consume!(:RIGHT_PAREN, "Expect ')' after arguments.")
+
+ Expr::Call.new(callee, paren, args)
+ end
+
def primary
return Expr::Literal.new(false) if match?(:FALSE)
return Expr::Literal.new(true) if match?(:TRUE)
diff --git a/ruby/test/lox/test_parser.rb b/ruby/test/lox/test_parser.rb
index aaad61e..11a7904 100644
--- a/ruby/test/lox/test_parser.rb
+++ b/ruby/test/lox/test_parser.rb
@@ -75,6 +75,12 @@ class TestParser < Lox::Test
SRC
end
+ def test_call
+ assert_parsed "((var foo))", :statement, "foo();"
+ assert_parsed "((var foo) (var bar))", :statement, "foo(bar);"
+ assert_parsed "((var foo) (var bar) (var baz))", :statement, "foo(bar, baz);"
+ end
+
private
def assert_parsed(expected, name, src)