You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
4.4 KiB
193 lines
4.4 KiB
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Engine;
|
|
|
|
use App\Dom\Document;
|
|
use App\Dom\Node;
|
|
use App\Dom\NodeFunction;
|
|
use App\Dom\NodeFunctionValue;
|
|
use App\Dom\NodeValue;
|
|
|
|
class Cfnpp implements ICompile
|
|
{
|
|
/** @var Document */
|
|
protected $document;
|
|
|
|
/** @var array<string, callable> */
|
|
protected $functions;
|
|
|
|
/** @var array<string, callable> */
|
|
protected $merge_functions;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->document = new Document();
|
|
$this->functions = [];
|
|
|
|
$this->registerMergeFunction('Replace', static function(Node $orig_p, Node $tgt_p, Node $t) {
|
|
// todo: nodefunctionvalue
|
|
|
|
$repl = new Node(null, $tgt_p->hasName() ? $tgt_p->getName() : null);
|
|
$repl->setChildren($t->getChildren());
|
|
return $repl;
|
|
});
|
|
$this->registerFunction('Unset', static function(Node $node, Node $func) {
|
|
});
|
|
}
|
|
|
|
public function registerFunction(string $name, callable $callback): void
|
|
{
|
|
$this->functions[$name] = $callback;
|
|
}
|
|
|
|
public function registerMergeFunction(string $name, callable $callback): void
|
|
{
|
|
$this->merge_functions[$name] = $callback;
|
|
}
|
|
|
|
public function setDocument(Document $document): void
|
|
{
|
|
$this->document = $document;
|
|
}
|
|
|
|
public function getDocument(): Document
|
|
{
|
|
return $this->document;
|
|
}
|
|
|
|
public function compile(Document $document, IOptions $options): void
|
|
{
|
|
$this->runMergeFunctions($this->document, $document);
|
|
$this->merge($this->document, $document);
|
|
$this->runFunctions($this->document);
|
|
}
|
|
|
|
protected function merge(Node $original, Node $target): void
|
|
{
|
|
if ($original->isArray() && $target->isArray())
|
|
{
|
|
foreach ($target as $child)
|
|
{
|
|
$original->addChild($child);
|
|
$child->setParent($original);
|
|
}
|
|
}
|
|
elseif ($original->isMap() && $target->isMap())
|
|
{
|
|
foreach ($target as $child)
|
|
{
|
|
$orig_child = $original->getChildByName($child->getName());
|
|
// If the key doesn't exist on the source, just copy over and we're done
|
|
if (!isset($orig_child))
|
|
{
|
|
$original->addChild($child);
|
|
$child->setParent($original);
|
|
continue;
|
|
}
|
|
|
|
// If this is a map or array, we need to descend into it
|
|
if ($child->isMap() || $child->isArray())
|
|
{
|
|
$this->merge($orig_child, $child);
|
|
}
|
|
// Otherwise just replace it (nodefunction, nodevalue, whatever)
|
|
else
|
|
{
|
|
$original->removeChild($orig_child);
|
|
$original->addChild($child);
|
|
$child->setParent($original);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If it's anything else, overwrite
|
|
$original->remove();
|
|
$original->getParent()->addChild($target);
|
|
$target->setParent($original);
|
|
}
|
|
}
|
|
|
|
protected function runMergeFunctions(Node $original, Node $target): void
|
|
{
|
|
if ($target->isFunctionParent() && isset($this->merge_functions[$target[0]->getName()]))
|
|
{
|
|
$function_node = $target[0];
|
|
$result = $this->runMergeFunction($original, $target, $function_node);
|
|
|
|
$original->remove();
|
|
$target->remove();
|
|
|
|
if (isset($result))
|
|
{
|
|
$original_node = $result;
|
|
$original_node->setParent($original->getParent());
|
|
$original->getParent()->addChild($original_node);
|
|
$original = $original_node;
|
|
|
|
$target_node = clone $result;
|
|
$target_node->setParent($target->getParent());
|
|
$target->getParent()->addChild($target_node);
|
|
$target = $target_node;
|
|
}
|
|
}
|
|
|
|
foreach ($target as $node)
|
|
{
|
|
if ($node->hasName())
|
|
{
|
|
$orig_child = $original->getChildByName($node->getName());
|
|
if (!isset($orig_child))
|
|
{
|
|
$orig_child = new Node($original, $node->getName());
|
|
$original->addChild($orig_child);
|
|
}
|
|
|
|
$this->runMergeFunctions($orig_child, $node);
|
|
}
|
|
}
|
|
|
|
if (isset($result))
|
|
{
|
|
$target->remove();
|
|
}
|
|
}
|
|
|
|
protected function runFunctions(Node $node): void
|
|
{
|
|
if ($node->isFunctionParent() && isset($this->functions[$node[0]->getName()]))
|
|
{
|
|
$function_node = $node[0];
|
|
$result = $this->runFunction($node, $function_node);
|
|
|
|
$node->remove();
|
|
if (isset($result))
|
|
{
|
|
$node->getParent()->addChild($result);
|
|
$result->setParent($node->getParent());
|
|
$node = $result;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
foreach ($node as $child)
|
|
{
|
|
$this->runFunctions($child);
|
|
}
|
|
}
|
|
|
|
protected function runFunction(Node $node, NodeFunction $function): ?Node
|
|
{
|
|
return $this->functions[$function->getName()]($node, $function);
|
|
}
|
|
|
|
protected function runMergeFunction(Node $original, Node $target, NodeFunction $function): ?Node
|
|
{
|
|
return $this->merge_functions[$function->getName()]($original, $target, $function);
|
|
}
|
|
}
|
|
|