Initial commit
This commit is contained in:
commit
efa5624dab
687 changed files with 162710 additions and 0 deletions
188
kirby/src/Query/Visitors/DefaultVisitor.php
Normal file
188
kirby/src/Query/Visitors/DefaultVisitor.php
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Query\Visitors;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Kirby\Query\AST\ClosureNode;
|
||||
use Kirby\Query\Runners\Scope;
|
||||
|
||||
/**
|
||||
* Processes a query AST
|
||||
*
|
||||
* @package Kirby Query
|
||||
* @author Roman Steiner <roman@toastlab.ch>,
|
||||
* Nico Hoffmann <nico@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
* @since 5.1.0
|
||||
* @unstable
|
||||
*/
|
||||
class DefaultVisitor extends Visitor
|
||||
{
|
||||
/**
|
||||
* Processes list of arguments
|
||||
*/
|
||||
public function arguments(array $arguments): array
|
||||
{
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes arithmetic operation
|
||||
*/
|
||||
public function arithmetic(
|
||||
int|float $left,
|
||||
string $operator,
|
||||
int|float $right
|
||||
): mixed {
|
||||
return match ($operator) {
|
||||
'+' => $left + $right,
|
||||
'-' => $left - $right,
|
||||
'*' => $left * $right,
|
||||
'/' => $left / $right,
|
||||
'%' => $left % $right,
|
||||
default => throw new Exception("Unknown arithmetic operator: $operator")
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes array
|
||||
*/
|
||||
public function arrayList(array $elements): array
|
||||
{
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes node into actual closure
|
||||
*/
|
||||
public function closure(ClosureNode $node): Closure
|
||||
{
|
||||
$self = $this;
|
||||
|
||||
return function (...$params) use ($self, $node) {
|
||||
// [key1, key2] + [value1, value2] =>
|
||||
// [key1 => value1, key2 => value2]
|
||||
$arguments = array_combine(
|
||||
$node->arguments,
|
||||
$params
|
||||
);
|
||||
|
||||
// Create new nested visitor with combined
|
||||
// data context for resolving the closure body
|
||||
$visitor = new static(
|
||||
global: $self->global,
|
||||
context: [...$self->context, ...$arguments],
|
||||
interceptor: $self->interceptor
|
||||
);
|
||||
|
||||
return $node->body->resolve($visitor);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes coalescence operator
|
||||
*/
|
||||
public function coalescence(mixed $left, mixed $right): mixed
|
||||
{
|
||||
return $left ?? $right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes comparison operation
|
||||
*/
|
||||
public function comparison(
|
||||
mixed $left,
|
||||
string $operator,
|
||||
mixed $right
|
||||
): bool {
|
||||
return match ($operator) {
|
||||
'==' => $left == $right,
|
||||
'===' => $left === $right,
|
||||
'!=' => $left != $right,
|
||||
'!==' => $left !== $right,
|
||||
'<' => $left < $right,
|
||||
'<=' => $left <= $right,
|
||||
'>' => $left > $right,
|
||||
'>=' => $left >= $right,
|
||||
default => throw new Exception("Unknown comparison operator: $operator")
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes global function
|
||||
*/
|
||||
public function function(string $name, array $arguments = []): mixed
|
||||
{
|
||||
$function = $this->global[$name] ?? null;
|
||||
|
||||
if ($function === null) {
|
||||
throw new Exception("Invalid global function in query: $name");
|
||||
}
|
||||
|
||||
return $function(...$arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes literals
|
||||
*/
|
||||
public function literal(mixed $value): mixed
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes logical operation
|
||||
*/
|
||||
public function logical(
|
||||
mixed $left,
|
||||
string $operator,
|
||||
mixed $right
|
||||
): bool {
|
||||
return match ($operator) {
|
||||
'&&', 'AND' => $left && $right,
|
||||
'||', 'OR' => $left || $right,
|
||||
default => throw new Exception("Unknown logical operator: $operator")
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes member access
|
||||
*/
|
||||
public function memberAccess(
|
||||
mixed $object,
|
||||
string|int $member,
|
||||
array|null $arguments = null,
|
||||
bool $nullSafe = false
|
||||
): mixed {
|
||||
if ($this->interceptor !== null) {
|
||||
$object = ($this->interceptor)($object);
|
||||
}
|
||||
|
||||
return Scope::access($object, $member, $nullSafe, ...$arguments ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes ternary operator
|
||||
*/
|
||||
public function ternary(
|
||||
mixed $condition,
|
||||
mixed $true,
|
||||
mixed $false
|
||||
): mixed {
|
||||
if ($true === null) {
|
||||
return $condition ?: $false;
|
||||
}
|
||||
|
||||
return $condition ? $true : $false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get variable from context or global function
|
||||
*/
|
||||
public function variable(string $name): mixed
|
||||
{
|
||||
return Scope::get($name, $this->context, $this->global);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue