diff --git a/ruby/lib/lox/ast_printer.rb b/ruby/lib/lox/ast_printer.rb index a073805..a303c5f 100644 --- a/ruby/lib/lox/ast_printer.rb +++ b/ruby/lib/lox/ast_printer.rb @@ -26,6 +26,16 @@ module Lox parenthesize("block", *expr.stmts) end + def visit_if(stmt) + exprs = [stmt.cond, stmt.then] + exprs << stmt.else if stmt.else + parenthesize("if", *exprs) + end + + def visit_expr(expr) + expr.expr.accept(self) + end + private def parenthesize(name, *exprs) diff --git a/ruby/lib/lox/interpreter.rb b/ruby/lib/lox/interpreter.rb index 0066043..494fe26 100644 --- a/ruby/lib/lox/interpreter.rb +++ b/ruby/lib/lox/interpreter.rb @@ -39,6 +39,15 @@ module Lox nil end + def visit_if(stmt) + if truthy?(evaluate(stmt.cond)) + evaluate(stmt.then) + elsif stmt.else + evaluate(stmt.else) + end + nil + end + def visit_print(expr) puts stringify(evaluate(expr.expr)) nil diff --git a/ruby/lib/lox/parser.rb b/ruby/lib/lox/parser.rb index bfece21..a30f4ff 100644 --- a/ruby/lib/lox/parser.rb +++ b/ruby/lib/lox/parser.rb @@ -37,12 +37,24 @@ module Lox end def statement + return if_stmt if match?(:IF) return print if match?(:PRINT) return Stmt::Block.new(block) if match?(:LEFT_BRACE) expression_stmt end + def if_stmt + consume!(:LEFT_PAREN, "Expect '(' after 'if'.") + cond = expression + consume!(:RIGHT_PAREN, "Expect ')' after 'if'.") + + then_stmt = statement + else_stmt = match?(:ELSE) ? statement : nil + + Stmt::If.new(cond, then_stmt, else_stmt) + end + def print value = expression consume!(:SEMICOLON, "Expect ';' after value.") diff --git a/ruby/lib/lox/stmt.rb b/ruby/lib/lox/stmt.rb index ba05b17..8f95201 100644 --- a/ruby/lib/lox/stmt.rb +++ b/ruby/lib/lox/stmt.rb @@ -10,6 +10,10 @@ module Lox include Visitable end + If = Struct.new(:cond, :then, :else) do + include Visitable + end + Print = Struct.new(:expr) do include Visitable end diff --git a/ruby/test/lox/test_interpreter.rb b/ruby/test/lox/test_interpreter.rb index 53b8113..5bc5e41 100644 --- a/ruby/test/lox/test_interpreter.rb +++ b/ruby/test/lox/test_interpreter.rb @@ -159,6 +159,23 @@ class TestInterpreter < Lox::Test SRC end + def test_if + assert_interpreted <<~EXPECTED.chomp, <<~SRC + true + false + EXPECTED + if (true) + print "true"; + else + print "false"; + + if (false) + print "true"; + else + print "false"; + SRC + end + private def assert_interpreted(expected, src) diff --git a/ruby/test/lox/test_parser.rb b/ruby/test/lox/test_parser.rb index e5ad65c..aaad61e 100644 --- a/ruby/test/lox/test_parser.rb +++ b/ruby/test/lox/test_parser.rb @@ -69,6 +69,12 @@ class TestParser < Lox::Test SRC end + def test_if + assert_parsed "(if (var first) (if (var second) true false))", :statement, <<~SRC + if (first) if (second) true; else false; + SRC + end + private def assert_parsed(expected, name, src)