Browse Source

Add compiler pass 1 -- resolve dependencies between variables and evaluate values

master
Adam Pippin 3 years ago
parent
commit
5a1b4f3402
  1. 81
      app/Engine/Cfnpp/Compiler.php

81
app/Engine/Cfnpp/Compiler.php

@ -7,7 +7,9 @@ namespace App\Engine\Cfnpp;
use App\Dom\Document;
use App\Dom\Node;
use App\Dom\NodeFunction;
use App\Dom\NodeFunctionValue;
use App\Engine\IOptions;
use App\Util\DependencyGraph;
/**
* Compiler that implements the cfnpp "language" and allows you to
@ -87,7 +89,10 @@ class Compiler implements \App\Engine\ICompile
$cfnpp_functions = new Functions($this, $options);
$cfnpp_functions->register($this);
return $this->pass_0($documents, $options);
$document = $this->pass_0($documents, $options);
$this->pass_1($document, $options);
return $document;
// Process each passed document
/*
@ -112,7 +117,7 @@ class Compiler implements \App\Engine\ICompile
{
// Build dependency graph
$graph = new \App\Util\DependencyGraph();
$graph = new DependencyGraph();
foreach ($documents as $doc)
{
$stack = [];
@ -146,7 +151,7 @@ class Compiler implements \App\Engine\ICompile
// Run our merge + merge functions
$document = new Document();
foreach ($documents as $next_document)
foreach ($ordered_documents as $next_document)
{
$this->runMergeFunctions($document, $next_document);
$this->merge($document, $next_document);
@ -164,6 +169,76 @@ class Compiler implements \App\Engine\ICompile
return $document;
}
/**
* Compiler Pass 1 - Grab all variables, build dependency graph of
* dependencies between variable values, resolve variables values. Then
* set them on $options to include them in program state.
*
* @param Document $document
* @param IOptions $options
* @return void
*/
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))
{
return;
}
$variables_raw = [];
$graph = new DependencyGraph();
foreach ($variables_node as $variable_node)
{
$variables_raw[$variable_node->getName()] = $variable_node;
$graph->add($variable_node->getName(), $this->pass_1_getVariableDependencies($variable_node));
}
$variables_ordered = $graph->solve();
foreach ($variables_ordered as $variable)
{
$this->runFunctions($variables_raw[$variable]);
$options->setVariable($variable, Node::toPhp($variables_node->getChildByName($variable)));
}
}
/**
* Given a node tree, get a list of variables that are referenced in that
* tree.
*
* @todo whenever we add expressions this will have to be extended/rewritten
* @param Node $node
* @return string[]
*/
protected function pass_1_getVariableDependencies(Node $node): array
{
$stack = [$node];
$variables = [];
while (sizeof($stack))
{
$node = array_shift($stack);
if ($node->hasChildren())
{
$stack = array_merge($stack, $node->getChildren());
}
// We're really only handling one case here right now
if ($node instanceof NodeFunctionValue &&
$node->getName() == 'var')
{
$variables[] = $node->getValue();
}
}
return $variables;
}
/**
* Performs a basic recursive merge of two dom trees with target overwriting
* original.

Loading…
Cancel
Save