Browse Source

Specify some functions callable from expressions

master
Adam Pippin 3 years ago
parent
commit
400542bc12
  1. 64
      app/Engine/Cfnpp/Expression/Expression.php
  2. 1
      app/Engine/Cfnpp/Expression/Parser.php
  3. 90
      app/Engine/Cfnpp/Expression/TokenFunction.php

64
app/Engine/Cfnpp/Expression/Expression.php

@ -39,6 +39,25 @@ class Expression
$this->tokens = $tokens;
}
/**
* Find all referenced variables so we can do proper ordering of variable
* block evaluate.
*
* @return string[]
*/
public function getReferencedVariables(): array
{
$variables = [];
foreach ($this->tokens as $token)
{
if ($token instanceof TokenVariable)
{
$variables[] = $token->getName();
}
}
return array_values(array_unique($variables));
}
/**
* Evaluate the tokens contained in this expression.
*
@ -56,21 +75,12 @@ class Expression
$token = array_shift($tokens);
assert(isset($token));
if ($token instanceof TokenNumericLiteral)
{
$this->evaluateTokenNumericLiteral($token);
}
elseif ($token instanceof TokenStringLiteral)
{
$this->evaluateTokenStringLiteral($token);
}
elseif ($token instanceof TokenOperator)
$token_class = get_class($token);
$token_name = substr($token_class, strrpos($token_class, '\\') + 1);
$func = 'evaluate'.$token_name;
if (method_exists($this, $func))
{
$this->evaluateTokenOperator($token);
}
elseif ($token instanceof TokenVariable)
{
$this->evaluateTokenVariable($token);
$this->{$func}($token);
}
else
{
@ -148,6 +158,32 @@ class Expression
$var2 = $this->pop();
$this->push($var1 || $var2);
break;
default:
throw new \Exception('Unhandled comparison operator: '.$token->getOperator());
}
}
/**
* Evaluate and mutate the stack given a function token.
*
* @param TokenFunction $token
* @return void
*/
protected function evaluateTokenFunction(TokenFunction $token): void
{
switch ($token->getFunction())
{
case 'concat':
$this->push($this->pop(1).$this->pop());
break;
case 'concat*':
while (sizeof($this->stack) > 1)
{
$this->push($this->pop(1).$this->pop());
}
break;
default:
throw new \Exception('Unhandled function: '.$token->getFunction());
}
}

1
app/Engine/Cfnpp/Expression/Parser.php

@ -17,6 +17,7 @@ class Parser
* @var string[]
*/
public const TOKEN_TYPES = [
TokenFunction::class,
TokenNumericLiteral::class,
TokenOperator::class,
TokenStringLiteral::class,

90
app/Engine/Cfnpp/Expression/TokenFunction.php

@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
namespace App\Engine\Cfnpp\Expression;
/**
* Token representing a function.
*
* @author Adam Pippin <hello@adampippin.ca>
*/
class TokenFunction extends Token
{
/**
* List of valid functions this can parse.
* @var string[]
*/
public const FUNCTIONS = [
'concat*',
'concat'
];
/**
* Function this token represents.
* @var string
*/
protected $function;
/**
* Create a new function token.
*
* @param string $function
*/
public function __construct($function)
{
$this->function = $function;
}
/**
* Get the function this token represents.
*
* @return string
*/
public function getFunction(): string
{
return $this->function;
}
/**
* Determine whether a function token can be parsed from a stream.
*
* @param string $stream
* @return bool
*/
public static function isToken(string $stream): bool
{
foreach (static::FUNCTIONS as $function)
{
if (strlen($stream) > strlen($function) &&
substr($stream, 0, strlen($function)) == $function)
{
return true;
}
}
return false;
}
/**
* Parse a function token from a stream.
*
* Returns token, and modifies stream to remove all consumed characters
*
* @param string $stream
* @return Token
*/
public static function getToken(string &$stream): Token
{
foreach (static::FUNCTIONS as $function)
{
if (strlen($stream) > strlen($function) &&
substr($stream, 0, strlen($function)) == $function)
{
$function = substr($stream, 0, strlen($function));
$stream = substr($stream, strlen($function));
return new TokenFunction($function);
}
}
throw new \Exception('Could not parse function token!');
}
}
Loading…
Cancel
Save