commit 64de5b2dfcfcfcf12ed646909756c050a2ce5670
parent 9c63719d0882f86e13849257b99b33784c8e0ec3
Author: Jan Dankert <develop@jandankert.de>
Date: Sun, 26 Jun 2022 15:46:54 +0200
Fix: Another, little better, hack for parameterless functions. Shunting yard seems to be unable to handle empty parentheses.
Diffstat:
8 files changed, 39 insertions(+), 37 deletions(-)
diff --git a/modules/dsl/DslAstParser.class.php b/modules/dsl/DslAstParser.class.php
@@ -18,11 +18,7 @@ class DslAstParser
*/
public function parse($tokens ) {
- //echo "<h1>Token:</h1><pre>"; var_export( $tokens ); echo "</pre>";
-
$this->rootStatement = new DslStatementList( $tokens );
-
- //echo "<h1>AST:</h1><pre>"; var_export( $this->rootStatement ); echo "</pre>";
}
diff --git a/modules/dsl/DslLexer.class.php b/modules/dsl/DslLexer.class.php
@@ -175,7 +175,7 @@ class DslLexer
}
// Numbers
- if ( $char >= '0' && $char <= '9' || $char == '-') {
+ if ( $char >= '0' && $char <= '9' ) {
$value = $char;
while( true ) {
$char = array_shift( $chars );
@@ -222,11 +222,16 @@ class DslLexer
elseif ( $char == '(' ) {
if ( end( $this->token)->type == DslToken::T_STRING)
+ // if string is followed by "(" it is a function or a function call
$this->addToken( $line, DslToken::T_OPERATOR,'$'); // function call
$this->addToken( $line,DslToken::T_BRACKET_OPEN,$char);
}
- elseif ( $char == ')' )
- $this->addToken( $line,DslToken::T_BRACKET_CLOSE,$char);
+ elseif ( $char == ')' ) {
+ if (end($this->token)->type == DslToken::T_BRACKET_OPEN)
+ // if there is an empty parenthesis, make it contain something, otherwise the shunting yard algo will fail.
+ $this->addToken($line, DslToken::T_NONE ); //
+ $this->addToken($line, DslToken::T_BRACKET_CLOSE, $char);
+ }
elseif ( $char == '{' )
$this->addToken( $line,DslToken::T_BLOCK_BEGIN,$char);
elseif ( $char == '}' )
diff --git a/modules/dsl/DslToken.class.php b/modules/dsl/DslToken.class.php
@@ -48,4 +48,15 @@ class DslToken
{
return '#'.$this->lineNumber.':'.$this->type.':"'.$this->value.'"';
}
+
+
+ /**
+ * @return bool
+ */
+ public function isOperator( $value = null ) {
+ if ( ! $value )
+ return $this->type == self::T_OPERATOR;
+
+ return $this->type == self::T_OPERATOR && $this->value == $value;
+ }
}
\ No newline at end of file
diff --git a/modules/dsl/ast/DslExpression.class.php b/modules/dsl/ast/DslExpression.class.php
@@ -106,8 +106,8 @@ class DslExpression extends DslElement implements DslStatement
$precedence['('] = 0;
$precedence[')'] = 0;
- $output_queue = array();
- $operator_stack = array();
+ $output_queue = [];
+ $operator_stack = [];
if ( $tokens instanceof DslStatement ) {
@@ -118,14 +118,15 @@ class DslExpression extends DslElement implements DslStatement
if ( $tokens instanceof DslToken )
$tokens = [$tokens];
- if ( ! is_array($tokens)) echo "tokens ist kein array, aber ".get_class($tokens);
+ if ( ! is_array($tokens))
+ throw new DslParserException("tokens must be an array, but it is ".get_class($tokens));
// while there are tokens to be read:
- while ($tokens) {
+ while ( $tokens ) {
// read a token.
$token = array_shift($tokens);
- if ($token->type == DslToken::T_OPERATOR) {
+ if ($token->isOperator() ) {
// while there is an operator at the top of the operator stack with
// greater than or equal to precedence:
@@ -157,7 +158,7 @@ class DslExpression extends DslElement implements DslStatement
// /* if the stack runs out without finding a left bracket, then there are
// mismatched parentheses. */
if (!$operator_stack) {
- throw new DslParserException("Mismatched parentheses!");
+ throw new DslParserException("Mismatched ')' parentheses");
}
}
@@ -182,7 +183,7 @@ class DslExpression extends DslElement implements DslStatement
// if the operator token on the top of the stack is a bracket, then
// there are mismatched parentheses.
if ($token->type == DslToken::T_OPERATOR && $token->value == '(') {
- throw new DslParserException( "Mismatched parentheses");
+ throw new DslParserException( "Mismatched '(' parentheses");
}
// pop the operator onto the output queue.
$left = array_pop( $output_queue );
@@ -190,8 +191,6 @@ class DslExpression extends DslElement implements DslStatement
$output_queue[] = $this->createNode( $token,$left,$right );
}
-
- //echo "<h5>Output queue:</h5><pre>"; var_export( $output_queue ); echo "</pre>";
$this->value = $output_queue[0];
}
@@ -221,6 +220,8 @@ class DslExpression extends DslElement implements DslStatement
private function tokenToStatement($token)
{
switch( $token->type ) {
+ case DslToken::T_NONE:
+ return new DslInteger( 0 );
case DslToken::T_NUMBER:
return new DslInteger( $token->value );
case DslToken::T_TEXT:
diff --git a/modules/dsl/ast/DslFunction.class.php b/modules/dsl/ast/DslFunction.class.php
@@ -40,14 +40,13 @@ class DslFunction extends DslElement implements DslStatement
*/
public function __construct( $functionParameter, $functionBody )
{
- //$this->parameters = $functionParameter;
-
$this->parameters = [];
- //var_export($this->splitByComma( $functionParameter ));
foreach( $this->splitByComma( $functionParameter ) as $parameter ) {
if ( sizeof($parameter) != 1 )
throw new DslParserException('function parameter must be a single name');
$nameToken = $parameter[0];
+ if ( $nameToken->type == DslToken::T_NONE ) // no parameter
+ continue;
if ( $nameToken->type != DslToken::T_STRING )
throw new DslParserException('function parameter must be a name');
diff --git a/modules/dsl/ast/DslFunctionCall.class.php b/modules/dsl/ast/DslFunctionCall.class.php
@@ -17,14 +17,6 @@ class DslFunctionCall implements DslStatement
*/
public function __construct($name, $parameters)
{
- //echo "name:";var_export( $name );
- //echo "params:";var_export( $parameters );
-
- // Parameterless function calls are not correctly detected by the AST parser
- if ( $name==null) {
- $name = $parameters;
- $parameters = null;
- }
$this->name = $name;
$this->parameters = $parameters;
}
@@ -35,15 +27,11 @@ class DslFunctionCall implements DslStatement
*/
public function execute(& $context ) {
- //var_export($this->name);
$function = $this->name->execute( $context );
- //echo "name is $name";
//if ( ! array_key_exists( $name, $context ) )
// throw new DslRuntimeException('function \''.$this->name.'\' does not exist.');
-//
-// $function = $context[$name];
if ( $this->parameters == null )
$parameterValues = []; // parameterless functions.
@@ -63,9 +51,8 @@ class DslFunctionCall implements DslStatement
elseif ( $function instanceof DslFunction ) {
$parameters = $function->parameters;
- //var_export( $function->parameters);
- if ( sizeof($parameters) != sizeof($parameterValues) )
+ if ( sizeof($parameters) > sizeof($parameterValues) )
throw new DslRuntimeException('function call has '.sizeof($parameterValues).' parameters but the function has '.sizeof($parameters).' parameters');
// Put all function parameters to the function context.
diff --git a/modules/dsl/ast/DslOperation.class.php b/modules/dsl/ast/DslOperation.class.php
@@ -21,8 +21,8 @@ class DslOperation implements DslStatement
public function __construct($operator, $left, $right)
{
$this->operator = $operator;
- $this->left = new DslExpression( $left );
- $this->right = new DslExpression($right );
+ $this->left = new DslExpression( $left );
+ $this->right = new DslExpression( $right );
}
@@ -83,6 +83,5 @@ class DslOperation implements DslStatement
public function parse($tokens)
{
- // TODO: Implement parse() method.
}
}
\ No newline at end of file
diff --git a/modules/dsl/ast/DslStatementList.class.php b/modules/dsl/ast/DslStatementList.class.php
@@ -80,10 +80,14 @@ class DslStatementList extends DslElement implements DslStatement
$name = $nameToken->value;
$functionCallOp = array_shift($tokens);
+ if ( $functionCallOp->type != DslToken::T_OPERATOR || $functionCallOp->value != '$' )
+ throw new DslParserException('function \''.$name.'\' must have a function signature');
+
$functionParameter = $this->getGroup($tokens);
- $functionBlock = $this->getBlock($tokens);
+ $functionBlock = $this->getBlock($tokens);
$this->functions[ $name ] = new DslFunction( $functionParameter, $functionBlock );
+
break;
case DslToken::T_IF: