9.5.1
FossilOrigin-Name: e6003611fc9c7f22e8ab96c338f79c3f8a0ddd7ff15b21a37568b4b6c3f54329
diff --git a/ruby/lib/lox/parser.rb b/ruby/lib/lox/parser.rb
index cfec840..0f6ce9f 100644
--- a/ruby/lib/lox/parser.rb
+++ b/ruby/lib/lox/parser.rb
@@ -46,6 +46,7 @@ module Lox
end
def statement
+ return for_stmt if match?(:FOR)
return if_stmt if match?(:IF)
return print if match?(:PRINT)
return while_stmt if match?(:WHILE)
@@ -54,6 +55,44 @@ module Lox
expression_stmt
end
+ def for_stmt
+ consume!(:LEFT_PAREN, "Expect '(' after 'if'.")
+
+ initializer = if match?(:SEMICOLON)
+ nil
+ elsif match?(:VAR)
+ var_declaration
+ else
+ expression_stmt
+ end
+
+ condition = !check?(:SEMICOLON) ? expression : Expr::Literal(true)
+ consume!(:SEMICOLON, "Expect ';' after loop condition.")
+
+ increment = !check?(:RIGHT_PAREN) ? expression : nil
+ consume!(:RIGHT_PAREN, "Expect ')' after for clauses.")
+
+ body = statement
+
+ if increment
+ body = Stmt::Block.new([
+ body,
+ Stmt::Expr.new(increment),
+ ])
+ end
+
+ body = Stmt::While.new(condition, body);
+
+ if initializer
+ body = Stmt::Block.new([
+ initializer,
+ body,
+ ])
+ end
+
+ body
+ end
+
def if_stmt
consume!(:LEFT_PAREN, "Expect '(' after 'if'.")
cond = expression
diff --git a/ruby/test/lox/test_interpreter.rb b/ruby/test/lox/test_interpreter.rb
index e7ce24b..21a1258 100644
--- a/ruby/test/lox/test_interpreter.rb
+++ b/ruby/test/lox/test_interpreter.rb
@@ -200,6 +200,30 @@ class TestInterpreter < Lox::Test
SRC
end
+ def test_for
+ assert_interpreted <<~EXPECTED.chomp, <<~SRC
+ 0
+ 1
+ 1
+ 2
+ 3
+ 5
+ 8
+ 13
+ 21
+ 34
+ EXPECTED
+ var a = 0;
+ var temp;
+
+ for (var b = 1; a < 50; b = temp + b) {
+ print a;
+ temp = a;
+ a = b;
+ }
+ SRC
+ end
+
private
def assert_interpreted(expected, src)