Browse Source

Use assertions for debugging scope parsing

main
Dustin Wilson 3 years ago
parent
commit
8d6c51a2d0
  1. 2
      lib/FauxReadOnly.php
  2. 5
      lib/Scope/Expression.php
  3. 2
      lib/Scope/Filter.php
  4. 2
      lib/Scope/Group.php
  5. 106
      lib/Scope/Parser.php
  6. 4
      lib/Scope/Selector.php

2
lib/FauxReadOnly.php

@ -15,6 +15,6 @@ trait FauxReadOnly {
return null; return null;
} }
return (!is_array($this->$prop)) ? $this->$prop : clone $this->prop; return $this->$prop;
} }
} }

5
lib/Scope/Expression.php

@ -9,17 +9,12 @@ namespace dW\Lit\Scope;
class Expression extends Node { class Expression extends Node {
protected Filter|Group|Path $_child; protected Filter|Group|Path $_child;
protected bool $frozen = false; protected bool $frozen = false;
protected bool $_negate = false;
protected ?string $_operator; protected ?string $_operator;
public function __construct(Composite $parent, ?string $operator = null) { public function __construct(Composite $parent, ?string $operator = null) {
$this->_operator = $operator; $this->_operator = $operator;
$this->_parent = \WeakReference::create($parent); $this->_parent = \WeakReference::create($parent);
if ($operator === '-') {
$this->negate = true;
}
} }

2
lib/Scope/Filter.php

@ -13,7 +13,7 @@ class Filter extends Node {
protected string $_side; protected string $_side;
public function __construct(Selector $parent, string $side) { public function __construct(Expression $parent, string $side) {
$this->_parent = \WeakReference::create($parent); $this->_parent = \WeakReference::create($parent);
$this->_side = $side; $this->_side = $side;
} }

2
lib/Scope/Group.php

@ -11,7 +11,7 @@ class Group extends Node {
protected bool $frozen = false; protected bool $frozen = false;
public function __construct(Expression $parent) { public function __construct(Expression|Filter $parent) {
$this->_parent = \WeakReference::create($parent); $this->_parent = \WeakReference::create($parent);
} }

106
lib/Scope/Parser.php

@ -11,10 +11,6 @@ class Parser {
// Used to cache parsed selectors // Used to cache parsed selectors
protected static array $cache = []; protected static array $cache = [];
// When true prints out detailed data about the construction of the matcher
// tree.
public static bool $debug = false;
// The tokenized scope string // The tokenized scope string
protected Data $data; protected Data $data;
// Used for incrementing the blocks of debug information; useful for creating // Used for incrementing the blocks of debug information; useful for creating
@ -45,31 +41,27 @@ class Parser {
} }
protected static function parseComposite(?Selector $parent = null): Matcher { protected static function parseComposite(?Selector $parent = null): Composite {
if (self::$debug) { assert((fn() => self::debug())());
self::debug();
}
$result = new Composite($parent); $result = new Composite($parent);
$expressions = [ self::parseExpression($result) ]; $expressions = [ self::parseExpression($result) ];
while ($peek = self::$instance->data->peek() && in_array($peek, [ '&', '|', '-' ])) { $peek = self::$instance->data->peek();
while ($peek !== false && in_array($peek, [ '&', '|', '-' ])) {
$expressions[] = self::parseExpression($result, self::$instance->data->consume()); $expressions[] = self::parseExpression($result, self::$instance->data->consume());
$peek = self::$instance->data->peek();
} }
$result->add(...$expressions); $result->add(...$expressions);
if (self::$debug) { assert((fn() => self::debugResult($result))());
self::debugResult($result);
}
return $result; return $result;
} }
protected static function parseExpression(Composite $parent, ?string $operator = null): Expression { protected static function parseExpression(Composite $parent, ?string $operator = null): Expression {
if (self::$debug) { assert((fn() => self::debug())());
self::debug();
}
$result = new Expression($parent, $operator); $result = new Expression($parent, $operator);
@ -82,17 +74,13 @@ class Parser {
$result->child = self::parsePath($result); $result->child = self::parsePath($result);
} }
if (self::$debug) { assert((fn() => self::debugResult($result))());
self::debugResult($result);
}
return $result; return $result;
} }
protected static function parseFilter(Expression $parent, string $side): Filter { protected static function parseFilter(Expression $parent, string $side): Filter {
if (self::$debug) { assert((fn() => self::debug())());
self::debug();
}
$result = new Filter($parent, $side); $result = new Filter($parent, $side);
$peek = self::$instance->data->peek(); $peek = self::$instance->data->peek();
@ -102,17 +90,13 @@ class Parser {
$result->child = self::parsePath($result); $result->child = self::parsePath($result);
} }
if (self::$debug) { assert((fn() => self::debugResult($result))());
self::debugResult($result);
}
return $result; return $result;
} }
protected static function parseGroup(Expression $parent): Group { protected static function parseGroup(Expression|Filter $parent): Group {
if (self::$debug) { assert((fn() => self::debug())());
self::debug();
}
$result = new Group($parent); $result = new Group($parent);
@ -121,26 +105,20 @@ class Parser {
self::throw('"("', $token); self::throw('"("', $token);
} }
if (!$group->child = self::parseSelector($result)) { $result->child = self::parseSelector($result);
return false;
}
$token = self::$instance->data->consume(); $token = self::$instance->data->consume();
if ($token !== ')') { if ($token !== ')') {
self::throw('")"', $token); self::throw('")"', $token);
} }
if (self::$debug) { assert((fn() => self::debugResult($result))());
self::debugResult($result);
}
return $result; return $result;
} }
protected static function parsePath(Expression $parent): Path { protected static function parsePath(Expression $parent): Path {
if (self::$debug) { assert((fn() => self::debug())());
self::debug();
}
$result = new Path($parent); $result = new Path($parent);
@ -156,14 +134,16 @@ class Parser {
} }
$scopes = [ $first ]; $scopes = [ $first ];
while ($peek = self::$instance->data->peek() && strspn($peek, self::SCOPE_MASK) === strlen($peek)) { $peek = self::$instance->data->peek();
while ($peek !== false && $peek !== '-' && strspn($peek, self::SCOPE_MASK) === strlen($peek)) {
$scopes[] = self::parseScope($result); $scopes[] = self::parseScope($result);
$peek = self::$instance->data->peek();
} }
$result->add(...$scopes); $result->add(...$scopes);
$anchorEnd = false; $anchorEnd = false;
if (self::$instance->data->peek() === '$') { if ($peek === '$') {
$anchorEnd = true; $anchorEnd = true;
self::$instance->data->consume(); self::$instance->data->consume();
} }
@ -172,43 +152,39 @@ class Parser {
$result->anchor = Path::ANCHOR_BOTH; $result->anchor = Path::ANCHOR_BOTH;
} elseif ($anchorStart) { } elseif ($anchorStart) {
$result->anchor = Path::ANCHOR_START; $result->anchor = Path::ANCHOR_START;
} else { } elseif ($anchorEnd) {
$result->anchor = Path::ANCHOR_END; $result->anchor = Path::ANCHOR_END;
} else {
$result->anchor = Path::ANCHOR_NONE;
} }
if (self::$debug) { assert((fn() => self::debugResult($result))());
self::debugResult($result);
}
return $result; return $result;
} }
protected static function parseSelector(?Group $parent = null): Matcher { protected static function parseSelector(?Group $parent = null): Selector {
if (self::$debug) { assert((fn() => self::debug())());
self::debug();
}
$result = new Selector($parent); $result = new Selector($parent);
$composites = [ self::parseComposite($result) ]; $composites = [ self::parseComposite($result) ];
while ($peek = self::$instance->data->peek() && $peek === ',') { $peek = self::$instance->data->peek();
while ($peek === ',') {
self::$instance->data->consume(); self::$instance->data->consume();
$composites[] = self::parseComposite($result); $composites[] = self::parseComposite($result);
$peek = self::$instance->data->peek();
} }
$result->add(...$composites); $result->add(...$composites);
if (self::$debug) { assert((fn() => self::debugResult($result))());
self::debugResult($result);
}
return $result; return $result;
} }
protected static function parseScope(Path $parent): Scope { protected static function parseScope(Path $parent): Scope {
if (self::$debug) { assert((fn() => self::debug())());
self::debug();
}
$peek = self::$instance->data->peek(); $peek = self::$instance->data->peek();
if ($peek === '>') { if ($peek === '>') {
@ -225,7 +201,7 @@ class Parser {
} }
$peek = self::$instance->data->peek(); $peek = self::$instance->data->peek();
if (strspn($peek, self::SCOPE_MASK) !== strlen($peek)) { if ($peek !== false && strspn($peek, self::SCOPE_MASK) !== strlen($peek)) {
self::throw([ 'A-Z', 'a-z', '0-9', '-', '+', '_', '*' ], $peek); self::throw([ 'A-Z', 'a-z', '0-9', '-', '+', '_', '*' ], $peek);
} }
@ -235,14 +211,12 @@ class Parser {
$result->add(...$atoms); $result->add(...$atoms);
if (self::$debug) { assert((fn() => self::debugResult($result))());
self::debugResult($result);
}
return $result; return $result;
} }
protected static function debug() { protected static function debug(): bool {
$message = <<<DEBUG $message = <<<DEBUG
------------------------------ ------------------------------
%s %s
@ -254,7 +228,10 @@ class Parser {
$methodTree = ''; $methodTree = '';
$backtrace = debug_backtrace(); $backtrace = debug_backtrace();
// Shift two off because it's executed in an assert closure
array_shift($backtrace);
array_shift($backtrace); array_shift($backtrace);
// And, pop this method off the backtrace
array_pop($backtrace); array_pop($backtrace);
foreach ($backtrace as $b) { foreach ($backtrace as $b) {
$methodTree = "->{$b['function']}$methodTree"; $methodTree = "->{$b['function']}$methodTree";
@ -266,13 +243,16 @@ class Parser {
self::$instance->data->position + 1, self::$instance->data->position + 1,
var_export(self::$instance->data->peek(), true) var_export(self::$instance->data->peek(), true)
); );
return true;
} }
protected static function debugResult($result) { protected static function debugResult($result): bool {
printf("%s Result: %s\n", printf("%s Result: %s\n",
debug_backtrace()[1]['function'], debug_backtrace()[2]['function'],
// Removes bullshit from printed classes for easier reading // Removes bullshit from var_exported classes for easier reading
str_replace([ '::__set_state(array', __NAMESPACE__, '))' ], [ '', '', ')' ], var_export($result, true))); str_replace([ '::__set_state(array', __NAMESPACE__.'\\', '))' ], [ '', '', ')' ], var_export($result, true)));
return true;
} }
protected static function throw(array|string $expected, string|bool $found) { protected static function throw(array|string $expected, string|bool $found) {

4
lib/Scope/Selector.php

@ -7,7 +7,7 @@ declare(strict_types=1);
namespace dW\Lit\Scope; namespace dW\Lit\Scope;
class Selector extends Node { class Selector extends Node {
protected array $composites = []; protected array $_composites = [];
protected bool $frozen = false; protected bool $frozen = false;
@ -21,7 +21,7 @@ class Selector extends Node {
return false; return false;
} }
$this->composites = $this->composites; $this->_composites = $composites;
$this->frozen = true; $this->frozen = true;
return true; return true;
} }

Loading…
Cancel
Save