diff --git a/app/Cfnpp/Compiler.php b/app/Cfnpp/Compiler.php index 558b7f9..051c593 100644 --- a/app/Cfnpp/Compiler.php +++ b/app/Cfnpp/Compiler.php @@ -216,7 +216,7 @@ class Compiler implements \App\Engine\ICompile foreach ($parameters_node as $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.'); } $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 * @return string[] */ - protected function pass_1_getDependencies(Node $node): array + protected function pass_1_getDependencies(Node $node, IOptions $options): array { $stack = [$node]; @@ -296,7 +296,7 @@ class Compiler implements \App\Engine\ICompile elseif ($node instanceof NodeFunctionValue && $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()); } } diff --git a/app/Cfnpp/Expression/Expression.php b/app/Cfnpp/Expression/Expression.php index 4f2a7e2..81ba21d 100644 --- a/app/Cfnpp/Expression/Expression.php +++ b/app/Cfnpp/Expression/Expression.php @@ -48,12 +48,15 @@ class Expression * @param string $expression * @param \App\Engine\IOptions $options */ - public function __construct(string $expression, \App\Engine\IOptions $options) + public function __construct(string $expression) { $tokens = static::tokenize($expression); - $nodes = static::parse($tokens); - $this->nodes = static::solve($nodes, $options->getVariables(), array_keys($options->getParameters())); - $this->options = $options; + $this->nodes = static::parse($tokens); + } + + 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); } + /** + * 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. * @@ -203,7 +227,7 @@ class Expression * @param string[] $parameters parameter names * @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(); foreach ($nodes as $node) diff --git a/app/Cfnpp/Functions.php b/app/Cfnpp/Functions.php index a4469e5..e5eb1a1 100644 --- a/app/Cfnpp/Functions.php +++ b/app/Cfnpp/Functions.php @@ -166,7 +166,8 @@ class Functions $if_true = $nodes[1]; $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 // if we want to convert to cloudformation. @@ -222,7 +223,8 @@ class Functions 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()) {