Skip to content

Commit

Permalink
fix Continues Statements in for loops
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Weber committed Jan 29, 2024
1 parent e6752f3 commit 43badb2
Show file tree
Hide file tree
Showing 20 changed files with 319 additions and 90 deletions.
4 changes: 4 additions & 0 deletions for.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
for(var inc = 0; inc < 10; inc=inc+1){
print(inc)
break
}
9 changes: 9 additions & 0 deletions plox.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@
/** @var Lox $lox */
$lox = dependency(Lox::class);
if (isset($argv[1])) {
if (isset($argv[2]) && $argv[2] == "--print") {
$result = $lox->reverseAST($argv[1]);
echo $result;
return;
} else if (isset($argv[2]) && $argv[2] == "--json") {
$result = $lox->jsonAST($argv[1]);
echo $result;
return;
}
$lox->runFile($argv[1]);
} else {
$lox->runCli();
Expand Down
11 changes: 11 additions & 0 deletions src/AST/AstNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace src\AST;

class AstNode
{
public function copy()
{
return unserialize(serialize($this));
}
}
175 changes: 160 additions & 15 deletions src/AST/AstPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,193 @@

namespace src\AST;

use src\AST\Expressions\Assign;
use src\AST\Expressions\Binary;
use src\AST\Expressions\Expression;
use src\AST\Expressions\Call;
use src\AST\Expressions\FunctionExpression;
use src\AST\Expressions\Grouping;
use src\AST\Expressions\Literal;
use src\AST\Expressions\Logical;
use src\AST\Expressions\Ternary;
use src\AST\Expressions\Unary;
use src\AST\Expressions\Variable;
use src\AST\Statements\BlockStatement;
use src\AST\Statements\CompletionStatement;
use src\AST\Statements\ExpressionStatement;
use src\AST\Statements\IfStatement;
use src\AST\Statements\ReturnStatement;
use src\AST\Statements\VarStatement;
use src\AST\Statements\WhileStatement;
use src\Services\Dependency\Attributes\Singleton;

#[Singleton]
class AstPrinter implements ExpressionVisitor
class AstPrinter implements ExpressionVisitor, StatementVisitor
{
public function print(Expression $expression)
{
return $expression->accept($this);
}
public $indent = " ";
private $currentIndent = "";

#[\Override] public function visitBinaryExpr(Binary $expression)
{
return $this->parenthesize($expression->operator->lexeme, $expression->left, $expression->right);
$left = $expression->left->accept($this);
$right = $expression->right->accept($this);

return "$left {$expression->operator->lexeme} $right";
}

#[\Override] public function visitGroupingExpr(Grouping $expression)
{
return $this->parenthesize("group", $expression->expression);
return $this->indent("(".$expression->accept($this).")\n");
}

#[\Override] public function visitLiteralExpr(Literal $expression)
{
if ($expression->value == null) return "nil";
return strval($expression->value);
return strval($expression->value->value);
}

#[\Override] public function visitUnaryExpr(Unary $expression)
{
return $this->parenthesize($expression->operator->lexeme, $expression->right);
$right = $expression->right->accept($this);
return "{$expression->operator->lexeme}$right";
}

#[\Override] public function visitTernaryExpr(Ternary $expression)
{
$condition = $expression->condition->accept($this);
$then = $expression->then->accept($this);
$else = $expression->else->accept($this);

return "$condition ? $then : $else\n";
}

#[\Override] public function visitVariableExpr(Variable $expression)
{
return $expression->name->lexeme;
}

#[\Override] public function visitAssignExpr(Assign $expression)
{
return $this->indent("{$expression->name->lexeme} = ".$expression->value->accept($this)."\n");
}

#[\Override] public function visitLogicalExpr(Logical $expression)
{
$left = $expression->left->accept($this);
$right = $expression->right->accept($this);

return "$left {$expression->operator->lexeme} $right";
}

#[\Override] public function visitCallExpr(Call $call)
{
$arguments = [];
foreach ($call->arguments as $argument) {
$arguments[] = $argument->accept($this);
}

return $this->indent($call->callee->accept($this)."(".implode(', ', $arguments).")\n");
}

#[\Override] public function visitFunctionExpr(FunctionExpression $expression)
{
$parameters = [];
foreach ($expression->parameters as $parameter) {
$parameters[] = $parameter->lexeme;
}
$result = $this->indent("{$expression->name->lexeme}(".implode(', ', $parameters).") {");

$this->addIndent();
foreach ($expression->body as $item) {
$result .= $this->indent($item->accept($this)."\n");
}
$this->removeIndent();

$result .= $this->indent("}\n");
return $result;
}

#[\Override] public function visitExpressionStmt(ExpressionStatement $statement)
{
return $statement->expression->accept($this);
}

protected function parenthesize(string $name, Expression ...$expressions)
#[\Override] public function visitVarStmt(VarStatement $statement)
{
$str = "($name";
foreach ($expressions as $expression) {
$str .= " ".$expression->accept($this);
if ($statement->initializer == null) {
return $this->indent("var {$statement->name->lexeme}");
} else {
$initializer = $statement->initializer->accept($this);
return $this->indent("var {$statement->name->lexeme} = $initializer\n");
}
return "$str)";
}

#[\Override] public function visitBlockStmt(BlockStatement $statement)
{
$result = $this->indent("{\n");
$this->addIndent();
foreach ($statement->statements as $statement) {
$result .= $statement->accept($this)."\n";
}
$this->removeIndent();
$result .= $this->indent("}\n");

return $result;
}

#[\Override] public function visitIfStmt(IfStatement $statement)
{
$result = $this->indent("if(".$statement->condition->accept($this).") {\n");

$this->addIndent();
$result .= $this->indent($statement->thenBranch->accept($this)."\n");
$this->removeIndent();
$result .= $this->indent("}");
if ($statement->elseBranch != null) {
$result .= " else {\n";

$this->addIndent();
$result .= $this->indent($statement->elseBranch->accept($this)."\n");
$this->removeIndent();
$result .= $this->indent("}\n");
return $result;
}
return $result."\n";
}

#[\Override] public function visitWhileStmt(WhileStatement $statement)
{
$result = $this->indent("while(".$statement->condition->accept($this).") \n");
$result .= $statement->body->accept($this)."\n";

return $result;
}

#[\Override] public function visitCompletionStmt(CompletionStatement $statement)
{
return $this->indent("{$statement->operator->lexeme}\n");
}

#[\Override] public function visitReturnStmt(ReturnStatement $statement)
{
if ($statement->value == null) {
return $this->indent("return\n");
} else {
return $this->indent("return ".$statement->value->accept($this)."\n");
}
}

private function indent($str)
{
return $this->currentIndent.$str;
}

private function addIndent()
{
$this->currentIndent .= $this->indent;
}

private function removeIndent()
{
$this->currentIndent = substr($this->currentIndent, strlen($this->indent));
}
}
5 changes: 4 additions & 1 deletion src/AST/Expressions/Assign.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public function __construct(

#[\Override] public function jsonSerialize(): mixed
{
// TODO: Implement jsonSerialize() method.
return [
"name" => $this->name,
"value" => $this->value
];
}
}
3 changes: 2 additions & 1 deletion src/AST/Expressions/Expression.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

namespace src\AST\Expressions;

use src\AST\AstNode;
use src\AST\ExpressionVisitor;
use src\Scaner\Token;

abstract class Expression implements \JsonSerializable
abstract class Expression extends AstNode implements \JsonSerializable
{

public function __construct(
Expand Down
2 changes: 1 addition & 1 deletion src/AST/Statements/BlockStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function __construct(

#[\Override] function accept(StatementVisitor $visitor)
{
$visitor->visitBlockStmt($this);
return $visitor->visitBlockStmt($this);
}

#[\Override] public function jsonSerialize(): mixed
Expand Down
2 changes: 1 addition & 1 deletion src/AST/Statements/CompletionStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function __construct(

#[\Override] function accept(StatementVisitor $visitor)
{
$visitor->visitCompletionStmt($this);
return $visitor->visitCompletionStmt($this);
}

#[\Override] public function jsonSerialize(): mixed
Expand Down
2 changes: 1 addition & 1 deletion src/AST/Statements/ExpressionStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function __construct(

#[\Override] function accept(StatementVisitor $visitor)
{
$visitor->visitExpressionStmt($this);
return $visitor->visitExpressionStmt($this);
}

#[\Override] public function jsonSerialize(): mixed
Expand Down
2 changes: 1 addition & 1 deletion src/AST/Statements/IfStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function __construct(

#[\Override] function accept(StatementVisitor $visitor)
{
$visitor->visitIfStmt($this);
return $visitor->visitIfStmt($this);
}

#[\Override] public function jsonSerialize(): mixed
Expand Down
2 changes: 1 addition & 1 deletion src/AST/Statements/ReturnStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function __construct(

#[\Override] function accept(StatementVisitor $visitor)
{
$visitor->visitReturnStmt($this);
return $visitor->visitReturnStmt($this);
}

#[\Override] public function jsonSerialize(): mixed
Expand Down
3 changes: 2 additions & 1 deletion src/AST/Statements/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

namespace src\AST\Statements;

use src\AST\AstNode;
use src\AST\StatementVisitor;
use src\Scaner\Token;

abstract class Statement implements \JsonSerializable
abstract class Statement extends AstNode implements \JsonSerializable
{
public function __construct(
public readonly Token $tokenStart,
Expand Down
2 changes: 1 addition & 1 deletion src/AST/Statements/VarStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function __construct(

#[\Override] function accept(StatementVisitor $visitor)
{
$visitor->visitVarStmt($this);
return $visitor->visitVarStmt($this);
}

#[\Override] public function jsonSerialize(): mixed
Expand Down
2 changes: 1 addition & 1 deletion src/AST/Statements/WhileStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function __construct(

#[\Override] function accept(StatementVisitor $visitor)
{
$visitor->visitWhileStmt($this);
return $visitor->visitWhileStmt($this);
}

#[\Override] public function jsonSerialize(): mixed
Expand Down
28 changes: 28 additions & 0 deletions src/Lox.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace src;


use src\AST\AstPrinter;
use src\Interpreter\Interpreter;
use src\Interpreter\Runtime\LoxType;
use src\Parser\Parser;
Expand All @@ -28,6 +29,33 @@ public function __construct(
{
}

public function reverseAST(string $file) {
$source = file_get_contents($file);

$tokens = $this->scanner->scanTokens($source);
$statements = $this->parser->parse($tokens);
$this->resolver->resolveAll($statements);

$astPrinter = new AstPrinter();
$serialized = "";

foreach ($statements as $statement) {
$serialized .= $statement->accept($astPrinter);
}

return $serialized;
}

public function jsonAST(string $file) {
$source = file_get_contents($file);

$tokens = $this->scanner->scanTokens($source);
$statements = $this->parser->parse($tokens);
$this->resolver->resolveAll($statements);

return json_encode($statements, JSON_PRETTY_PRINT);
}

public function runString(string $source)
{
[$result, $expression] = $this->run($source);
Expand Down
Loading

0 comments on commit 43badb2

Please sign in to comment.