From 4b48ef1a75165bfe98fb604bccf458fb37597605 Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 15 Aug 2022 23:17:37 +0000 Subject: [PATCH 1/4] 10.1 FossilOrigin-Name: c1d35386c76ad60362ec68d9e94a6e4fe9cfc02c39b7c2589668a214a3f22c43 --- ruby/lib/lox/ast_printer.rb | 4 ++++ ruby/lib/lox/expr.rb | 1 + ruby/lib/lox/parser.rb | 30 +++++++++++++++++++++++++++++- ruby/test/lox/test_parser.rb | 6 ++++++ 4 files changed, 40 insertions(+), 1 deletion(-) 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) From 2a5230c9251970c2d1a444281b20d354037550b9 Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 15 Aug 2022 23:19:49 +0000 Subject: [PATCH 2/4] 10.1.1 FossilOrigin-Name: c0a4d7dadf87d80ec3d0b6ef67e74d6c49d3ff2efa3179acf0ed90599b476efd --- ruby/lib/lox/parser.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ruby/lib/lox/parser.rb b/ruby/lib/lox/parser.rb index c6e8e24..1e14e53 100644 --- a/ruby/lib/lox/parser.rb +++ b/ruby/lib/lox/parser.rb @@ -16,6 +16,8 @@ module Lox statements << declaration end statements + rescue ParseError + synchronize! end private @@ -24,8 +26,6 @@ module Lox return var_declaration if match?(:VAR) statement - rescue ParseError - synchronize! end def var_declaration @@ -240,6 +240,8 @@ module Lox args = [] if !check?(:RIGHT_PAREN) loop do + raise ParseError.new(peek, "Can't have more than 255 arguments.") if args.size >= 255 + args << expression break unless match?(:COMMA) end From 28b9fd32d027a059b84f2d1cfe9d59dd950536cd Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 15 Aug 2022 23:22:11 +0000 Subject: [PATCH 3/4] 10.1.2 FossilOrigin-Name: fae7fe1a493cd7d2c31e140204cfd581080c6bf5a70ed967107a1a5237bed129 --- ruby/lib/lox/interpreter.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb index 90f087d..703389e 100644 --- a/ruby/lib/lox/interpreter.rb +++ b/ruby/lib/lox/interpreter.rb @@ -138,7 +138,13 @@ module Lox left * right else fail end + end + + def visit_call(expr) + callee = evaluate(expr.callee) + args = expr.args.map { evaluate(_1) } + callee.call(self, args) end private From fe7e9022117eb07a8d27965447741ae9712662fd Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 15 Aug 2022 23:25:36 +0000 Subject: [PATCH 4/4] 10.1.4 FossilOrigin-Name: f49d9465e02a773fe8b1add8537291fd03620b1c6f14f3b0846a4aa4d362ee5f --- ruby/lib/lox/interpreter.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb index 703389e..28904cc 100644 --- a/ruby/lib/lox/interpreter.rb +++ b/ruby/lib/lox/interpreter.rb @@ -141,10 +141,13 @@ module Lox end def visit_call(expr) - callee = evaluate(expr.callee) + func = evaluate(expr.callee) args = expr.args.map { evaluate(_1) } - callee.call(self, args) + raise RuntimeError.new(expr.paren, "Can only call functions and classes.") unless func.respond_to?(:call) + raise RuntimeError.new(expr.paren, "Expected #{func.arity} arguments but got #{args.size}.") unless args.size == func.arity + + func.call(self, args) end private