diff --git a/lib/Scope/Composite.php b/lib/Scope/Composite.php index 26348ef..38c2c84 100644 --- a/lib/Scope/Composite.php +++ b/lib/Scope/Composite.php @@ -7,7 +7,7 @@ declare(strict_types=1); namespace dW\Lit\Scope; class Composite extends Node { - protected array $expressions = []; + protected array $_expressions = []; protected bool $frozen = false; @@ -21,8 +21,13 @@ class Composite extends Node { return false; } - $this->expressions = $expressions; + $this->_expressions = $expressions; $this->frozen = true; return true; } + + + public function __toString(): string { + return implode(' ', $this->_expressions); + } } diff --git a/lib/Scope/Expression.php b/lib/Scope/Expression.php index 442feb6..e56f995 100644 --- a/lib/Scope/Expression.php +++ b/lib/Scope/Expression.php @@ -9,10 +9,15 @@ namespace dW\Lit\Scope; class Expression extends Node { protected Filter|Group|Path $_child; protected bool $frozen = false; - protected ?string $_operator; + protected int $_operator; + const OPERATOR_NONE = 0; + const OPERATOR_AND = 1; + const OPERATOR_OR = 2; + const OPERATOR_NOT = 3; - public function __construct(Composite $parent, ?string $operator = null) { + + public function __construct(Composite $parent, int $operator = self::OPERATOR_NONE) { $this->_operator = $operator; $this->_parent = \WeakReference::create($parent); } @@ -33,4 +38,19 @@ class Expression extends Node { $this->frozen = true; $this->_child = $value; } + + + public function __toString(): string { + switch ($this->_operator) { + case OPERATOR_NONE: $operator = ''; + break; + case OPERATOR_AND: $operator = '& '; + break; + case OPERATOR_OR: $operator = '| '; + break; + case OPERATOR_NOT: $operator = '- '; + } + + return "$operator${$this->_child}"; + } } diff --git a/lib/Scope/Filter.php b/lib/Scope/Filter.php index 433265f..51bef90 100644 --- a/lib/Scope/Filter.php +++ b/lib/Scope/Filter.php @@ -9,7 +9,6 @@ namespace dW\Lit\Scope; class Filter extends Node { protected Group|Path $_child; protected bool $frozen = false; - protected string $_operator; protected string $_side; @@ -34,4 +33,9 @@ class Filter extends Node { $this->frozen = true; $this->_child = $value; } + + + public function __toString(): string { + return "${$this->side}: ${$this->_child}"; + } } diff --git a/lib/Scope/Group.php b/lib/Scope/Group.php index 171d3ce..18567fe 100644 --- a/lib/Scope/Group.php +++ b/lib/Scope/Group.php @@ -31,4 +31,9 @@ class Group extends Node { $this->frozen = true; $this->_child = $value; } + + + public function __toString(): string { + return "({$this->_child})"; + } } diff --git a/lib/Scope/Parser.php b/lib/Scope/Parser.php index ff48c91..57f0405 100644 --- a/lib/Scope/Parser.php +++ b/lib/Scope/Parser.php @@ -49,7 +49,17 @@ class Parser { $peek = self::$instance->data->peek(); while ($peek !== false && in_array($peek, [ '&', '|', '-' ])) { - $expressions[] = self::parseExpression($result, self::$instance->data->consume()); + self::$instance->data->consume(); + switch ($peek) { + case '&': $operator = Expression::OPERATOR_AND; + break; + case '|': $operator = Expression::OPERATOR_OR; + break; + case '-': $operator = Expression::OPERATOR_NOT; + break; + } + + $expressions[] = self::parseExpression($result, $operator); $peek = self::$instance->data->peek(); } @@ -60,7 +70,7 @@ class Parser { return $result; } - protected static function parseExpression(Composite $parent, ?string $operator = null): Expression { + protected static function parseExpression(Composite $parent, int $operator = Expression::OPERATOR_NONE): Expression { assert((fn() => self::debug())()); $result = new Expression($parent, $operator); @@ -135,8 +145,14 @@ class Parser { $scopes = [ $first ]; $peek = self::$instance->data->peek(); - while ($peek !== false && $peek !== '-' && strspn($peek, self::SCOPE_MASK) === strlen($peek)) { - $scopes[] = self::parseScope($result); + while ($peek !== false && $peek !== '-' && ($peek === '>' || strspn($peek, self::SCOPE_MASK) === strlen($peek))) { + $anchorToPrevious = false; + if ($peek === '>') { + self::$instance->data->consume(); + $peek = self::$instance->data->peek(); + $anchorToPrevious = true; + } + $scopes[] = self::parseScope($result, $anchorToPrevious); $peek = self::$instance->data->peek(); } diff --git a/lib/Scope/Path.php b/lib/Scope/Path.php index 82cd4fb..b7d5e79 100644 --- a/lib/Scope/Path.php +++ b/lib/Scope/Path.php @@ -53,4 +53,20 @@ class Path extends Node { $this->frozen['anchor'] = true; $this->_anchor = $value; } + + public function __toString(): string { + $result = ''; + + if ($this->_anchor === self::ANCHOR_START || $this->_anchor === self::ANCHOR_BOTH) { + $result .= '^'; + } + + $result .= implode(' ', $this->_scopes); + + if ($this->_anchor === self::ANCHOR_END || $this->_anchor === self::ANCHOR_BOTH) { + $result .= '$'; + } + + return $result; + } } diff --git a/lib/Scope/Scope.php b/lib/Scope/Scope.php index 99fc920..b34704f 100644 --- a/lib/Scope/Scope.php +++ b/lib/Scope/Scope.php @@ -27,4 +27,17 @@ class Scope extends Node { $this->frozen = true; return true; } + + + public function __toString(): string { + $result = ''; + + if ($this->_anchorToPrevious) { + $result .= '< '; + } + + $result .= implode('.', $this->_atoms); + + return $result; + } } diff --git a/lib/Scope/Selector.php b/lib/Scope/Selector.php index e4367bc..ca62030 100644 --- a/lib/Scope/Selector.php +++ b/lib/Scope/Selector.php @@ -25,4 +25,9 @@ class Selector extends Node { $this->frozen = true; return true; } + + + public function __toString(): string { + return implode(', ', $this->_composites); + } }