summaryrefslogtreecommitdiff
path: root/src/Parser
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2025-01-03 12:41:41 +0100
committerDaniel Weipert <git@mail.dweipert.de>2025-01-03 12:41:41 +0100
commit57e8f84c1465c0fd8daf78d4178c6b18a65e9158 (patch)
tree48de6696c719a3ce0a016753a87cf8702f3e5ec3 /src/Parser
parentba1bcfa811fe8eab5a2c71ef4a360e8b846ae32b (diff)
parser
Diffstat (limited to 'src/Parser')
-rw-r--r--src/Parser/Parser.php167
1 files changed, 106 insertions, 61 deletions
diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php
index 41c8a14..05d3726 100644
--- a/src/Parser/Parser.php
+++ b/src/Parser/Parser.php
@@ -43,27 +43,29 @@ class Parser
$currentStatement = new CommentNode($currentToken);
$this->advance(1);
}
-
+
else {
- $currentStatement = $this->parseFunctionCall();
+ #$currentStatement = $this->parseFunctionCall();
+ $error = sprintf("Unexpected %s at %d:%d" . PHP_EOL, $currentToken->value, $currentToken->line, $currentToken->column);
+ $this->addError($error);
+
+ exit;
}
$nextToken = $this->getCurrentToken();
-
+
if ($nextToken->literal == "=>") {
$this->advance(1);
-
+
$currentStatement = new PipeExpression($currentStatement, $this->parseExpression(shouldBeFunction: true));
}
-
+
// unknown token
if ($this->position == $lastPosition) {
$error = sprintf("Unknown token %s at position %d,%d" . PHP_EOL, $currentToken, $currentToken->line, $currentToken->column);
- $this->errors[] = $error;
+ $this->addError($error);
$this->advance(1);
-
- echo $error;
}
$this->nodes[] = $currentStatement;
@@ -87,7 +89,7 @@ class Parser
echo sprintf(str_repeat("> ", $level) . "%s: %s" . PHP_EOL, $propertyKey, (new \ReflectionClass($propertyValue))->getShortName());
$this->printNodeRecursive($propertyValue, $level + 1);
}
-
+
else if (is_array($propertyValue)) {
$length = count($propertyValue);
@@ -122,15 +124,15 @@ class Parser
return $this->tokens[$this->position];
}
- private function getNextToken(): ?Token
+ private function getNextToken(int $steps = 1): ?Token
{
- return $this->tokens[$this->position + 1] ?? null;
+ return $this->tokens[$this->position + $steps] ?? null;
}
private function advance(int $steps): void
{
$lastToken = $this->getCurrentToken();
-
+
if ($this->position + $steps > count($this->tokens)) {
if (! empty($this->errors)) {
exit;
@@ -141,7 +143,7 @@ class Parser
"Parser Implementation Error: Can't advance. Position out of bounds."
);
}
-
+
$this->position += $steps;
}
@@ -161,15 +163,20 @@ class Parser
if ($currentToken->value != $value) {
$error = sprintf("Expected %s but got %s instead at %d:%d" . PHP_EOL, $value, $currentToken->value, $currentToken->line, $currentToken->column);
- $this->errors[] = $error;
-
- echo $error;
+ $this->addError($error);
}
-
+
$this->advance(1);
}
}
+ private function addError(string $error): void
+ {
+ $this->errors[] = $error;
+
+ echo $error;
+ }
+
private function parseConst(): Node
{
// skip const
@@ -185,7 +192,7 @@ class Parser
// skip =
$this->anticipateTokenAndSkip("=");
-
+
$expression = $this->parseExpression(
shouldBeMap: $type instanceof MapTypeDeclaration,
shouldBeFunction: $type instanceof TypeDeclaration and $type->left->literal == "function",
@@ -199,7 +206,7 @@ class Parser
}
private function parseType(): Node
- {
+ {
$currentToken = $this->getCurrentToken();
$nextToken = $this->getNextToken();
@@ -209,13 +216,13 @@ class Parser
else if (in_array($nextToken->literal, ["and", "or"])) {
$this->advance(2);
-
+
return new TypeDeclaration($currentToken, $nextToken, $this->parseType());
}
else {
$this->advance(1);
-
+
return new TypeDeclaration($currentToken);
}
}
@@ -224,7 +231,7 @@ class Parser
{
// skip first [
$this->anticipateTokenAndSkip("[");
-
+
$key = $this->parseType();
$currentToken = $this->getCurrentToken();
@@ -233,7 +240,7 @@ class Parser
if ($currentToken->literal == "]" && $nextToken->literal == "[") {
// skip to first type
$this->advance(2);
-
+
$value = $this->parseType();
// skip last ]
@@ -252,14 +259,27 @@ class Parser
{
$currentToken = $this->getCurrentToken();
$currentExpression = $currentToken;
-
+
if ($currentToken->literal == "[") {
$currentExpression = $this->parseArrayOrMap($shouldBeMap);
}
else if ($currentToken->type == TokenType::Identifier) {
- $currentExpression = new IdentifierNode($currentToken);
- $this->advance(1);
+ if (in_array($currentToken->literal, ["true", "false"])) {
+ $currentExpression = new BoolNode($currentToken);
+ $this->advance(1);
+ }
+ else {
+ $currentExpression = new IdentifierNode($currentToken);
+ $this->advance(1);
+
+ if ($this->getCurrentToken()->literal == "(") {
+ // step back to parse function call fully
+ $this->stepBack(1);
+
+ $currentExpression = $this->parseFunctionCall();
+ }
+ }
}
else if ($currentToken->type == TokenType::Number) {
@@ -272,11 +292,11 @@ class Parser
}
else if ($currentToken->literal == "(") {
- #if ($shouldBeFunction) {
+ if ($this->getNextToken(2)->literal == ":") {
$currentExpression = $this->parseFunctionDefinition();
- #}
-
- # TODO: parse normal ()
+ } else {
+ $currentExpression = $this->parseParenthesis();
+ }
}
else {
@@ -288,7 +308,7 @@ class Parser
if (in_array($nextToken->literal, ["+", "-", "*", "**", "/"])) {
$this->advance(1);
-
+
return new OperatorExpression($currentExpression, $nextToken, $this->parseExpression(shouldBeMap: $shouldBeMap));
}
@@ -297,7 +317,7 @@ class Parser
return new CompareExpression($currentExpression, $nextToken, $this->parseExpression(shouldBeMap: $shouldBeMap));
}
-
+
else if (in_array($nextToken->literal, ["and", "or"])) {
$this->advance(1);
@@ -306,17 +326,10 @@ class Parser
else if ($nextToken->literal == "=>") {
$this->advance(1);
-
+
return new PipeExpression($currentExpression, $this->parseExpression(shouldBeFunction: true));
}
- else if ($currentToken->type == TokenType::Identifier and $nextToken->literal == "(") {
- // step back to parse function call fully
- $this->stepBack(1);
-
- return $this->parseFunctionCall();
- }
-
else {
return $currentExpression;
}
@@ -334,7 +347,7 @@ class Parser
$tokenShouldBeComma = false;
while ($this->getCurrentToken()->literal != "]") {
$currentToken = $this->getCurrentToken();
-
+
// skip ,
if ($tokenShouldBeComma) {
if ($currentToken->literal == ",") {
@@ -358,7 +371,7 @@ class Parser
break;
}
}
-
+
// nested array or map
if ($currentToken->literal == "[") {
$values[] = $this->parseArrayOrMap();
@@ -379,7 +392,7 @@ class Parser
// skip last ]
$this->advance(1);
-
+
if ((count($values) > 0 and $values[0] instanceof MapItemNode) or $shouldBeMap) {
return new MapNode($values);
} else {
@@ -394,7 +407,7 @@ class Parser
// is map item
if ($this->getCurrentToken()->literal == "=") {
$this->advance(1);
-
+
$value = $this->parseExpression();
return new MapItemNode($key, $value);
@@ -409,7 +422,7 @@ class Parser
private function parseNumber(): Node
{
$currentToken = $this->getCurrentToken();
-
+
$value = $currentToken->value;
if (str_contains($value, ".")) {
$value = floatval($value);
@@ -449,14 +462,14 @@ class Parser
}
$parameters = [];
-
+
while ($this->getCurrentToken()->literal != ")") {
// skip ,
if ($this->getCurrentToken()->literal == ",") {
$this->advance(1);
continue;
}
-
+
$identifier = $this->getCurrentToken();
$this->advance(1);
@@ -464,7 +477,7 @@ class Parser
$this->anticipateTokenAndSkip(":");
$type = $this->parseType();
-
+
// skip potential , instead default value
if ($this->getCurrentToken()->literal == ",") {
$this->advance(1);
@@ -496,12 +509,12 @@ class Parser
$this->anticipateTokenAndSkip("{");
$body = [];
-
+
while ($this->getCurrentToken()->literal != "}") {
$currentToken = $this->getCurrentToken();
-
+
if ($currentToken->literal == "const") {
- $body[] = $this->parseConst();
+ $body[] = $this->parseConst();
}
else if ($currentToken->literal == "return") {
@@ -512,14 +525,20 @@ class Parser
$body[] = $this->parseIf();
}
- // skip comments
else if ($currentToken->type == TokenType::Comment) {
+ $body[] = new CommentNode($currentToken);
$this->advance(1);
- continue;
}
- else {
+ /*else if ($currentToken->type == TokenType::Identifier) {
$body[] = $this->parseFunctionCall();
+ }*/
+
+ else {
+ $error = sprintf("Unexpected %s at %d:%d" . PHP_EOL, $currentToken->value, $currentToken->line, $currentToken->column);
+ $this->addError($error);
+
+ exit;
}
}
@@ -562,19 +581,18 @@ class Parser
$parameters = [];
-
while ($this->getCurrentToken()->literal != ")") {
// skip ,
if ($this->getCurrentToken()->literal == ",") {
$this->advance(1);
continue;
}
-
+
// if "=" then identifier is name
if ($this->getNextToken()->literal == "=") {
$identifier = $this->getCurrentToken();
$this->advance(2);
-
+
$value = $this->parseExpression();
$parameters[] = new FunctionCallParameter(
@@ -616,7 +634,7 @@ class Parser
private function parseIfArm(): Node
{
$isElseBlock = false;
-
+
if ($this->getCurrentToken()->literal == "if") {
$this->advance(1);
}
@@ -641,12 +659,25 @@ class Parser
}
$body = $this->parseFunctionBody();
-
+
return new IfArm(
$condition,
$body,
);
}
+
+ private function parseParenthesis(): Node
+ {
+ // skip first (
+ $this->anticipateTokenAndSkip("(");
+
+ $content = $this->parseExpression();
+
+ // skip last )
+ $this->anticipateTokenAndSkip(")");
+
+ return new Parenthesis($content);
+ }
}
class Node
@@ -677,7 +708,7 @@ class TypeDeclaration extends Node
public Token $left,
public ?Token $operator = null,
public Token|TypeDeclaration|null $right = null,
- ) {}
+ ) {}
}
class ArrayTypeDeclaration extends Node
@@ -727,7 +758,7 @@ class OperatorExpression extends Node
public Token|Node $left,
public Token $operator,
public Token|Node $right,
- ) {}
+ ) {}
}
class CompareExpression extends Node
@@ -770,6 +801,13 @@ class StringNode extends Node
) {}
}
+class BoolNode extends Node
+{
+ public function __construct(
+ public Token $token,
+ ) {}
+}
+
class CommentNode extends Node
{
public function __construct(
@@ -852,3 +890,10 @@ class PipeExpression extends Node
public Token|Node $right,
) {}
}
+
+class Parenthesis extends Node
+{
+ public function __construct(
+ public Node $content,
+ ) {}
+}