From 01b036b2842665ba726d77d977e01b4a15cf2b55 Mon Sep 17 00:00:00 2001 From: Adam Pippin Date: Tue, 16 Feb 2021 15:39:57 -0800 Subject: [PATCH] Move cfnpp code out from under engine namespace --- app/{Engine => }/Cfnpp/Compiler.php | 72 ++++++++++++++----- .../Cfnpp/Expression/Expression.php | 5 +- app/{Engine => }/Cfnpp/Expression/Parser.php | 2 +- app/{Engine => }/Cfnpp/Expression/Token.php | 2 +- .../Cfnpp/Expression/TokenFunction.php | 2 +- .../Cfnpp/Expression/TokenNumericLiteral.php | 2 +- .../Cfnpp/Expression/TokenOperator.php | 5 +- .../Cfnpp/Expression/TokenStringLiteral.php | 2 +- .../Cfnpp/Expression/TokenVariable.php | 2 +- app/{Engine => }/Cfnpp/Functions.php | 19 ++++- app/{Engine => }/Cfnpp/Options.php | 2 +- app/Commands/Stack/Compile.php | 4 +- 12 files changed, 85 insertions(+), 34 deletions(-) rename app/{Engine => }/Cfnpp/Compiler.php (85%) rename app/{Engine => }/Cfnpp/Expression/Expression.php (97%) rename app/{Engine => }/Cfnpp/Expression/Parser.php (96%) rename app/{Engine => }/Cfnpp/Expression/Token.php (93%) rename app/{Engine => }/Cfnpp/Expression/TokenFunction.php (97%) rename app/{Engine => }/Cfnpp/Expression/TokenNumericLiteral.php (97%) rename app/{Engine => }/Cfnpp/Expression/TokenOperator.php (97%) rename app/{Engine => }/Cfnpp/Expression/TokenStringLiteral.php (97%) rename app/{Engine => }/Cfnpp/Expression/TokenVariable.php (97%) rename app/{Engine => }/Cfnpp/Functions.php (89%) rename app/{Engine => }/Cfnpp/Options.php (98%) diff --git a/app/Engine/Cfnpp/Compiler.php b/app/Cfnpp/Compiler.php similarity index 85% rename from app/Engine/Cfnpp/Compiler.php rename to app/Cfnpp/Compiler.php index 9c1307b..2986f66 100644 --- a/app/Engine/Cfnpp/Compiler.php +++ b/app/Cfnpp/Compiler.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp; +namespace App\Cfnpp; use App\Dom\Document; use App\Dom\Node; @@ -171,8 +171,8 @@ class Compiler implements \App\Engine\ICompile } /** - * Compiler Pass 1 - Grab all variables, build dependency graph of - * dependencies between variable values, resolve variables values. Then + * Compiler Pass 1 - Grab all variables and parameters, build dependency + * graph of dependencies between values, resolve values. Then * set them on $options to include them in program state. * * @param Document $document @@ -182,32 +182,61 @@ class Compiler implements \App\Engine\ICompile protected function pass_1(Document $document, IOptions $options): void { $variables_node = $document->getChildByPath('cfnpp.variables'); - // If there are no variables, we're done here. - if (!isset($variables_node)) + $parameters_node = $document->getChildByPath('cfnpp.parameters'); + // If there are no variables or parameters, we're done here. + if (!isset($variables_node) && !isset($parameters_node)) { return; } - $variables_raw = []; + $nodes = []; $graph = new DependencyGraph(); - foreach ($variables_node as $variable_node) + if (isset($parameters_node)) { - $variables_raw[$variable_node->getName()] = $variable_node; - $graph->add($variable_node->getName(), $this->pass_1_getVariableDependencies($variable_node)); + foreach ($parameters_node as $parameter_node) + { + $nodes[$parameter_node->getName()] = $parameter_node; + $graph->add($parameter_node->getName(), $this->pass_1_getDependencies($parameter_node)); + } + } + + if (isset($variables_node)) + { + foreach ($variables_node as $variable_node) + { + if (isset($nodes[$variable_node->getName()])) + { + 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)); + } } - $variables_ordered = $graph->solve(); + $nodes_ordered = $graph->solve(); - foreach ($variables_ordered as $variable) + foreach ($nodes_ordered as $node_name) { - $this->runFunctions($variables_raw[$variable]); - $variable_node = $variables_node->getChildByName($variable); - // By all accounts this _should_ still exist, but this accounts for the - // case where, say, someone had used !unset on a variable for some reason. - if (isset($variable_node)) + $this->runFunctions($nodes[$node_name]); + + $type = $nodes[$node_name]->getParent()->getName(); + + if ($type == 'parameters') + { + $parameter_node = $parameters_node->getChildByName($node_name); + if (isset($parameter_node)) + { + $options->setParameter($parameter_node->getName(), Node::toPhp($parameter_node)); + } + } + else if ($type == 'variables') { - $options->setVariable($variable, Node::toPhp($variable_node)); + $variable_node = $variables_node->getChildByName($node_name); + if (isset($variable_node)) + { + $options->setVariable($variable_node->getName(), Node::toPhp($variable_node)); + } } } } @@ -220,7 +249,7 @@ class Compiler implements \App\Engine\ICompile * @param Node $node * @return string[] */ - protected function pass_1_getVariableDependencies(Node $node): array + protected function pass_1_getDependencies(Node $node): array { $stack = [$node]; @@ -240,10 +269,15 @@ class Compiler implements \App\Engine\ICompile { $variables[] = $node->getValue(); } + else if ($node instanceof NodeFunctionValue && + $node->getName() == 'param') + { + $variables[] = $node->getValue(); + } elseif ($node instanceof NodeFunctionValue && $node->getName() == 'expr') { - $parser = new \App\Engine\Cfnpp\Expression\Parser(); + $parser = new \App\Cfnpp\Expression\Parser(); $expression = $parser->parse($node->getValue()); $variables = array_merge($variables, $expression->getReferencedVariables()); } diff --git a/app/Engine/Cfnpp/Expression/Expression.php b/app/Cfnpp/Expression/Expression.php similarity index 97% rename from app/Engine/Cfnpp/Expression/Expression.php rename to app/Cfnpp/Expression/Expression.php index f70d4b3..a04c460 100644 --- a/app/Engine/Cfnpp/Expression/Expression.php +++ b/app/Cfnpp/Expression/Expression.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp\Expression; +namespace App\Cfnpp\Expression; /** * Expression that can be evaluated. @@ -158,6 +158,9 @@ class Expression $var2 = $this->pop(); $this->push($var1 || $var2); break; + case 'not': + $this->push(!$this->pop()); + break; default: throw new \Exception('Unhandled comparison operator: '.$token->getOperator()); } diff --git a/app/Engine/Cfnpp/Expression/Parser.php b/app/Cfnpp/Expression/Parser.php similarity index 96% rename from app/Engine/Cfnpp/Expression/Parser.php rename to app/Cfnpp/Expression/Parser.php index f7122c4..c87d3aa 100644 --- a/app/Engine/Cfnpp/Expression/Parser.php +++ b/app/Cfnpp/Expression/Parser.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp\Expression; +namespace App\Cfnpp\Expression; /** * Parse a string into a series of expression tokens. diff --git a/app/Engine/Cfnpp/Expression/Token.php b/app/Cfnpp/Expression/Token.php similarity index 93% rename from app/Engine/Cfnpp/Expression/Token.php rename to app/Cfnpp/Expression/Token.php index 75eb65d..a47573a 100644 --- a/app/Engine/Cfnpp/Expression/Token.php +++ b/app/Cfnpp/Expression/Token.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp\Expression; +namespace App\Cfnpp\Expression; /** * Token representing a distinct part of an expression. diff --git a/app/Engine/Cfnpp/Expression/TokenFunction.php b/app/Cfnpp/Expression/TokenFunction.php similarity index 97% rename from app/Engine/Cfnpp/Expression/TokenFunction.php rename to app/Cfnpp/Expression/TokenFunction.php index 0b99cef..b597a96 100644 --- a/app/Engine/Cfnpp/Expression/TokenFunction.php +++ b/app/Cfnpp/Expression/TokenFunction.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp\Expression; +namespace App\Cfnpp\Expression; /** * Token representing a function. diff --git a/app/Engine/Cfnpp/Expression/TokenNumericLiteral.php b/app/Cfnpp/Expression/TokenNumericLiteral.php similarity index 97% rename from app/Engine/Cfnpp/Expression/TokenNumericLiteral.php rename to app/Cfnpp/Expression/TokenNumericLiteral.php index 1aec30c..32fcfde 100644 --- a/app/Engine/Cfnpp/Expression/TokenNumericLiteral.php +++ b/app/Cfnpp/Expression/TokenNumericLiteral.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp\Expression; +namespace App\Cfnpp\Expression; /** * Token representing a numeric (integer or float) literal. diff --git a/app/Engine/Cfnpp/Expression/TokenOperator.php b/app/Cfnpp/Expression/TokenOperator.php similarity index 97% rename from app/Engine/Cfnpp/Expression/TokenOperator.php rename to app/Cfnpp/Expression/TokenOperator.php index 9d90b28..5d3bce3 100644 --- a/app/Engine/Cfnpp/Expression/TokenOperator.php +++ b/app/Cfnpp/Expression/TokenOperator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp\Expression; +namespace App\Cfnpp\Expression; /** * Token representing a comparison operator. @@ -23,7 +23,8 @@ class TokenOperator extends Token 'lt', 'lte', 'and', - 'or' + 'or', + 'not' ]; /** diff --git a/app/Engine/Cfnpp/Expression/TokenStringLiteral.php b/app/Cfnpp/Expression/TokenStringLiteral.php similarity index 97% rename from app/Engine/Cfnpp/Expression/TokenStringLiteral.php rename to app/Cfnpp/Expression/TokenStringLiteral.php index 252b997..0ea6ec6 100644 --- a/app/Engine/Cfnpp/Expression/TokenStringLiteral.php +++ b/app/Cfnpp/Expression/TokenStringLiteral.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp\Expression; +namespace App\Cfnpp\Expression; /** * Token representing a string literal. diff --git a/app/Engine/Cfnpp/Expression/TokenVariable.php b/app/Cfnpp/Expression/TokenVariable.php similarity index 97% rename from app/Engine/Cfnpp/Expression/TokenVariable.php rename to app/Cfnpp/Expression/TokenVariable.php index ed78f29..b17cca2 100644 --- a/app/Engine/Cfnpp/Expression/TokenVariable.php +++ b/app/Cfnpp/Expression/TokenVariable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp\Expression; +namespace App\Cfnpp\Expression; /** * Expression token referencing a variable. diff --git a/app/Engine/Cfnpp/Functions.php b/app/Cfnpp/Functions.php similarity index 89% rename from app/Engine/Cfnpp/Functions.php rename to app/Cfnpp/Functions.php index bf9395c..debea51 100644 --- a/app/Engine/Cfnpp/Functions.php +++ b/app/Cfnpp/Functions.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp; +namespace App\Cfnpp; use App\Dom\Node; use App\Dom\NodeValue; @@ -112,6 +112,18 @@ class Functions return new NodeValue(null, $node->hasName() ? $node->getName() : null, $value); } + public function f_param(Node $node, NodeFunction $function): ?Node + { + if (!($function instanceof NodeFunctionValue)) + { + throw new \Exception('!param requires scalar argument'); + } + $node = new Node(null, $node->hasName() ? $node->getName() : null); + $ref = new NodeValue($node, 'Ref', $function->getValue()); + $node->addChild($ref); + return $node; + } + /** * Conditionally include part of the file. * @@ -137,7 +149,7 @@ class Functions $if_true = $nodes[1]; $if_false = sizeof($nodes) == 3 ? $nodes[2] : null; - $parser = new \App\Engine\Cfnpp\Expression\Parser(); + $parser = new \App\Cfnpp\Expression\Parser(); $expression = $parser->parse($condition->getValue()); $result = $expression->evaluate($this->options->getVariables()); @@ -173,7 +185,7 @@ class Functions throw new \Exception('!if requires scalar argument'); } - $parser = new \App\Engine\Cfnpp\Expression\Parser(); + $parser = new \App\Cfnpp\Expression\Parser(); $expression = $parser->parse($function->getValue()); $result = $expression->evaluate($this->options->getVariables()); @@ -182,4 +194,5 @@ class Functions return $result; } + } diff --git a/app/Engine/Cfnpp/Options.php b/app/Cfnpp/Options.php similarity index 98% rename from app/Engine/Cfnpp/Options.php rename to app/Cfnpp/Options.php index 81495ca..f1cf1fc 100644 --- a/app/Engine/Cfnpp/Options.php +++ b/app/Cfnpp/Options.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Engine\Cfnpp; +namespace App\Cfnpp; /** * Options for controlling the Cfnpp compilation process. diff --git a/app/Commands/Stack/Compile.php b/app/Commands/Stack/Compile.php index c305a57..a6c151c 100644 --- a/app/Commands/Stack/Compile.php +++ b/app/Commands/Stack/Compile.php @@ -39,8 +39,8 @@ class Compile extends Command $serializer = $this->getSerializer(); $unserializer = $this->getUnserializer(); - $engine->setSerializer($serializer)->setUnserializer($unserializer)->setCompiler(new \App\Engine\Cfnpp\Compiler()); - $options = new \App\Engine\Cfnpp\Options(); + $engine->setSerializer($serializer)->setUnserializer($unserializer)->setCompiler(new \App\Cfnpp\Compiler()); + $options = new \App\Cfnpp\Options(); $output = $engine->process($this->argument('in_file'), $options);