openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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:
Mmodules/dsl/DslAstParser.class.php | 4----
Mmodules/dsl/DslLexer.class.php | 11++++++++---
Mmodules/dsl/DslToken.class.php | 11+++++++++++
Mmodules/dsl/ast/DslExpression.class.php | 19++++++++++---------
Mmodules/dsl/ast/DslFunction.class.php | 5++---
Mmodules/dsl/ast/DslFunctionCall.class.php | 15+--------------
Mmodules/dsl/ast/DslOperation.class.php | 5++---
Mmodules/dsl/ast/DslStatementList.class.php | 6+++++-
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: