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)