Browse Source

Rework expression parser to not solve on creation; re-add dependency solving for variables in expressions in variables block

master
Adam Pippin 3 years ago
parent
commit
0265db1946
  1. 8
      app/Cfnpp/Compiler.php
  2. 34
      app/Cfnpp/Expression/Expression.php
  3. 6
      app/Cfnpp/Functions.php

8
app/Cfnpp/Compiler.php

@ -216,7 +216,7 @@ class Compiler implements \App\Engine\ICompile
foreach ($parameters_node as $parameter_node) foreach ($parameters_node as $parameter_node)
{ {
$nodes[$parameter_node->getName()] = $parameter_node; $nodes[$parameter_node->getName()] = $parameter_node;
$graph->add($parameter_node->getName(), $this->pass_1_getDependencies($parameter_node)); $graph->add($parameter_node->getName(), $this->pass_1_getDependencies($parameter_node, $options));
} }
} }
@ -229,7 +229,7 @@ class Compiler implements \App\Engine\ICompile
throw new \Exception('Variables and parameters cannot share the same name.'); throw new \Exception('Variables and parameters cannot share the same name.');
} }
$nodes[$variable_node->getName()] = $variable_node; $nodes[$variable_node->getName()] = $variable_node;
$graph->add($variable_node->getName(), $this->pass_1_getDependencies($variable_node)); $graph->add($variable_node->getName(), $this->pass_1_getDependencies($variable_node, $options));
} }
} }
@ -268,7 +268,7 @@ class Compiler implements \App\Engine\ICompile
* @param Node $node * @param Node $node
* @return string[] * @return string[]
*/ */
protected function pass_1_getDependencies(Node $node): array protected function pass_1_getDependencies(Node $node, IOptions $options): array
{ {
$stack = [$node]; $stack = [$node];
@ -296,7 +296,7 @@ class Compiler implements \App\Engine\ICompile
elseif ($node instanceof NodeFunctionValue && elseif ($node instanceof NodeFunctionValue &&
$node->getName() == 'expr') $node->getName() == 'expr')
{ {
$expression = new \App\Cfnpp\Expression\Expression($node->getValue()); $expression = new \App\Cfnpp\Expression\Expression($node->getValue(), $options);
$variables = array_merge($variables, $expression->getReferencedVariables()); $variables = array_merge($variables, $expression->getReferencedVariables());
} }
} }

34
app/Cfnpp/Expression/Expression.php

@ -48,12 +48,15 @@ class Expression
* @param string $expression * @param string $expression
* @param \App\Engine\IOptions $options * @param \App\Engine\IOptions $options
*/ */
public function __construct(string $expression, \App\Engine\IOptions $options) public function __construct(string $expression)
{ {
$tokens = static::tokenize($expression); $tokens = static::tokenize($expression);
$nodes = static::parse($tokens); $this->nodes = static::parse($tokens);
$this->nodes = static::solve($nodes, $options->getVariables(), array_keys($options->getParameters())); }
$this->options = $options;
public function solve(\App\Engine\IOptions $options)
{
$this->nodes = static::_solve($this->nodes, $options->getVariables(), array_keys($options->getParameters()));
} }
/** /**
@ -128,6 +131,27 @@ class Expression
return static::cloudformation($this->nodes); return static::cloudformation($this->nodes);
} }
/**
* Examine the expression to determine which variables are referenced so we
* can figure out the dependencies between them
*
* @return string[] names of variables referenced
*/
public function getReferencedVariables(): array
{
$variables = [];
foreach ($this->nodes as $node)
{
$node->walk(function($node) use (&$variables) {
if ($node->getValue() instanceof Token\Variable)
{
$variables[] = $node->getValue()->getName();
}
});
}
return array_values(array_unique($variables));
}
/** /**
* Convert an expression string into a series of tokens. * Convert an expression string into a series of tokens.
* *
@ -203,7 +227,7 @@ class Expression
* @param string[] $parameters parameter names * @param string[] $parameters parameter names
* @return GraphNode[] * @return GraphNode[]
*/ */
protected static function solve(array $nodes, array $variables = [], array $parameters = []): array protected static function _solve(array $nodes, array $variables = [], array $parameters = []): array
{ {
$root = new GraphNode(); $root = new GraphNode();
foreach ($nodes as $node) foreach ($nodes as $node)

6
app/Cfnpp/Functions.php

@ -166,7 +166,8 @@ class Functions
$if_true = $nodes[1]; $if_true = $nodes[1];
$if_false = sizeof($nodes) == 3 ? $nodes[2] : null; $if_false = sizeof($nodes) == 3 ? $nodes[2] : null;
$expression = new \App\Cfnpp\Expression\Expression($condition->getValue(), $this->options); $expression = new \App\Cfnpp\Expression\Expression($condition->getValue());
$expression->solve($this->options);
// We need a single resulting node as a final value either as a scalar or // We need a single resulting node as a final value either as a scalar or
// if we want to convert to cloudformation. // if we want to convert to cloudformation.
@ -222,7 +223,8 @@ class Functions
throw new \Exception('!expr requires scalar argument'); throw new \Exception('!expr requires scalar argument');
} }
$expression = new \App\Cfnpp\Expression\Expression($function->getValue(), $this->options); $expression = new \App\Cfnpp\Expression\Expression($function->getValue());
$expression->solve($this->options);
if ($expression->isComplete()) if ($expression->isComplete())
{ {

Loading…
Cancel
Save