Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/Interpreter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Lox\Expr\Visitor as VisitorExpr;
use Lox\Stmt\BlockStmt;
use Lox\Stmt\ExpressionStmt;
use Lox\Stmt\IfStmt;
use Lox\Stmt\PrintStmt;
use Lox\Stmt\Stmt;
use Lox\Stmt\VarStmt;
Expand Down Expand Up @@ -146,6 +147,16 @@ public function visitExpressionStmt(ExpressionStmt $stmt): void
$this->evaluate($stmt->expression());
}

#[\Override]
public function visitIfStmt(IfStmt $stmt): void
{
if ($this->isTruthy($this->evaluate($stmt->condition()))) {
$this->execute($stmt->thenBranch());
} elseif (null !== $stmt->elseBranch()) {
$this->execute($stmt->elseBranch());
}
}

#[\Override]
public function visitPrintStmt(PrintStmt $stmt): void
{
Expand Down
20 changes: 20 additions & 0 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Lox\Expr\Variable;
use Lox\Stmt\BlockStmt;
use Lox\Stmt\ExpressionStmt;
use Lox\Stmt\IfStmt;
use Lox\Stmt\PrintStmt;
use Lox\Stmt\Stmt;
use Lox\Stmt\VarStmt;
Expand Down Expand Up @@ -66,6 +67,10 @@ private function declaration(): ?Stmt

private function statement(): Stmt
{
if ($this->match(TokenType::IF)) {
return $this->ifStatement();
}

if ($this->match(TokenType::PRINT)) {
return $this->printStatement();
}
Expand All @@ -77,6 +82,21 @@ private function statement(): Stmt
return $this->expressionStatement();
}

private function ifStatement(): Stmt
{
$this->consume(TokenType::LEFT_PAREN, 'Expect "(" after "if".');
$condition = $this->expression();
$this->consume(TokenType::RIGHT_PAREN, 'Expect ")" after if condition.');

$thenBranch = $this->statement();
$elseBranch = null;
if ($this->match(TokenType::ELSE)) {
$elseBranch = $this->statement();
}

return new IfStmt($condition, $thenBranch, $elseBranch);
}

private function printStatement(): Stmt
{
$value = $this->expression();
Expand Down
46 changes: 46 additions & 0 deletions src/Stmt/IfStmt.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/**
* This file is auto-generated.
*/

declare(strict_types=1);

namespace Lox\Stmt;

use Lox\Expr\Expr;

final class IfStmt extends Stmt
{
private Expr $condition;
private Stmt $thenBranch;
private ?Stmt $elseBranch;

public function __construct(Expr $condition, Stmt $thenBranch, ?Stmt $elseBranch)
{
$this->condition = $condition;
$this->thenBranch = $thenBranch;
$this->elseBranch = $elseBranch;
}

public function condition(): Expr
{
return $this->condition;
}

public function thenBranch(): Stmt
{
return $this->thenBranch;
}

public function elseBranch(): ?Stmt
{
return $this->elseBranch;
}

#[\Override]
public function accept(Visitor $visitor)
{
return $visitor->visitIfStmt($this);
}
}
2 changes: 2 additions & 0 deletions src/Stmt/Visitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public function visitBlockStmt(BlockStmt $stmt): void;

public function visitExpressionStmt(ExpressionStmt $stmt): void;

public function visitIfStmt(IfStmt $stmt): void;

public function visitPrintStmt(PrintStmt $stmt): void;

public function visitVarStmt(VarStmt $stmt): void;
Expand Down
4 changes: 4 additions & 0 deletions tests/lox/block/empty.lox
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{} // By itself.

// In a statement.
if (true) {}
if (false) {} else {}

print "ok"; // expect: ok
3 changes: 3 additions & 0 deletions tests/lox/if/dangling_else.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// A dangling else binds to the right-most if.
if (true) if (false) print "bad"; else print "good"; // expect: good
if (false) if (true) print "bad"; else print "bad";
6 changes: 6 additions & 0 deletions tests/lox/if/else.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Evaluate the 'else' expression if the condition is false.
if (true) print "good"; else print "bad"; // expect: good
if (false) print "bad"; else print "good"; // expect: good

// Allow block body.
if (false) nil; else { print "block"; } // expect: block
10 changes: 10 additions & 0 deletions tests/lox/if/if.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Evaluate the 'then' expression if the condition is true.
if (true) print "good"; // expect: good
if (false) print "bad";

// Allow block body.
if (true) { print "block"; } // expect: block

// Assignment in if condition.
var a = false;
if (a = true) print a; // expect: true
8 changes: 8 additions & 0 deletions tests/lox/if/truth.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// False and nil are false.
if (false) print "bad"; else print "false"; // expect: false
if (nil) print "bad"; else print "nil"; // expect: nil

// Everything else is true.
if (true) print true; // expect: true
if (0) print 0; // expect: 0
if ("") print "empty"; // expect: empty
2 changes: 2 additions & 0 deletions tests/lox/if/var_in_else.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// [line 2] Error at "var": Expect expression.
if (true) "ok"; else var foo;
2 changes: 2 additions & 0 deletions tests/lox/if/var_in_then.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// [line 2] Error at "var": Expect expression.
if (true) var foo;
5 changes: 5 additions & 0 deletions tests/lox/variable/unreached_undefined.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
if (false) {
print notDefined;
}

print "ok"; // expect: ok
11 changes: 6 additions & 5 deletions tools/generate-ast
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ defineAst(EXPR_DIR, 'Expr', [

// Stmt classes must have Stmt suffix to be valid
defineAst(STMT_DIR, 'Stmt', [
'BlockStmt : List<Stmt> statements',
'BlockStmt : list<Stmt> statements',
'ExpressionStmt : Lox\Expr\Expr expression',
'IfStmt : Lox\Expr\Expr condition, Lox\Stmt\Stmt thenBranch, ?Lox\Stmt\Stmt elseBranch',
'PrintStmt : Lox\Expr\Expr expression',
'VarStmt : Lox\Token name, ?Lox\Expr\Expr initializer',
]);
Expand Down Expand Up @@ -107,10 +108,10 @@ function generateType(string $baseName, string $className, array $properties = [
$type = $parts[0];
$propertyName = $parts[1];

if (preg_match('/^List<.*>$/', $type)) {
$propertyComment = sprintf('@var %s', lcfirst($type));
$constructorComment = sprintf('@param %s $%s', lcfirst($type), $propertyName);
$returnComment = sprintf('@return %s', lcfirst($type));
if (preg_match('/^list<.*>$/', $type)) {
$propertyComment = sprintf('@var %s', $type);
$constructorComment = sprintf('@param %s $%s', $type, $propertyName);
$returnComment = sprintf('@return %s', $type);
$type = 'array';
}
} else {
Expand Down