Browse Source

Starting to add matchers

main
Dustin Wilson 3 years ago
parent
commit
7a3d0e5d2e
  1. 33
      lib/Scope/Composite.php
  2. 2
      lib/Scope/Expression.php
  3. 30
      lib/Scope/Filter.php
  4. 5
      lib/Scope/Group.php
  5. 39
      lib/Scope/Parser.php
  6. 17
      lib/Scope/Path.php
  7. 5
      lib/Scope/Scope.php
  8. 15
      lib/Scope/Selector.php

33
lib/Scope/Composite.php

@ -26,6 +26,39 @@ class Composite extends Node {
return true;
}
public function matches(Path $path): bool {
$result = false;
foreach ($this->_expressions as $expression) {
$operator = $expression->operator;
if ($result && $operator === Expression::OPERATOR_OR) {
continue;
} elseif (!$result && $operator === Expression::OPERATOR_AND) {
continue;
} elseif (!$result && $operator === Expression::OPERATOR_NOT) {
continue;
}
$local = $expression->child->matches($path);
if ($expression->negate) {
$local = !$local;
}
switch ($operator) {
case Expression::OPERATOR_NONE: $result = $local;
break;
case Expression::OPERATOR_OR: $result = $result || $local;
break;
case Expression::OPERATOR_AND: $result = $result && $local;
break;
case Expression::OPERATOR_NOT: $result = $result && !$local;
break;
}
}
return $result;
}
public function __toString(): string {
return implode(' ', $this->_expressions);
}

2
lib/Scope/Expression.php

@ -23,7 +23,7 @@ class Expression extends Node {
$this->_operator = $operator;
$this->_parent = \WeakReference::create($parent);
}
public function __set(string $name, $value) {
if ($name !== 'child') {

30
lib/Scope/Filter.php

@ -9,26 +9,34 @@ namespace dW\Lit\Scope;
class Filter extends Node {
protected Group|Path $_child;
protected bool $frozen = false;
protected int $_side;
protected int $_prefix;
const SIDE_LEFT = 0;
const SIDE_RIGHT = 1;
const SIDE_BOTH = 2;
public function __construct(Expression $parent, string $side) {
public function __construct(Expression $parent, string $prefix) {
$this->_parent = \WeakReference::create($parent);
switch ($side) {
case 'L': $this->_side = self::SIDE_LEFT;
switch ($prefix) {
case 'L': $this->_prefix = self::SIDE_LEFT;
break;
case 'R': $this->_side = self::SIDE_RIGHT;
case 'R': $this->_prefix = self::SIDE_RIGHT;
break;
case 'B': $this->_side = self::SIDE_BOTH;
case 'B': $this->_prefix = self::SIDE_BOTH;
break;
}
}
public function matches(Path $path): bool {
// No idea if prefixes are supposed to affect matches. Appears to in the
// TextMate original but not in Atom's implementation...
return $this->_child->matches($path);
}
public function __set(string $name, $value) {
if ($name !== 'child') {
$trace = debug_backtrace();
@ -47,15 +55,15 @@ class Filter extends Node {
public function __toString(): string {
switch ($this->_side) {
case self::SIDE_LEFT: $side = 'L';
switch ($this->_prefix) {
case self::SIDE_LEFT: $prefix = 'L';
break;
case self::SIDE_RIGHT: $side = 'R';
case self::SIDE_RIGHT: $prefix = 'R';
break;
case self::SIDE_BOTH: $side = 'B';
case self::SIDE_BOTH: $prefix = 'B';
break;
}
return "$side:{$this->_child}";
return "$prefix:{$this->_child}";
}
}

5
lib/Scope/Group.php

@ -16,6 +16,11 @@ class Group extends Node {
}
public function matches(Path $path): bool {
return $this->_child->matches($path);
}
public function __set(string $name, $value) {
if ($name !== 'child') {
$trace = debug_backtrace();

39
lib/Scope/Parser.php

@ -28,14 +28,33 @@ class Parser {
$this->data = new Data($selector);
}
/** Static method entry point for the class. Parses the string. */
public static function parse(string $string): Selector {
/** Parses strings into Selectors */
public static function parseSelector(string $string): Selector {
if (isset(self::$cache[$string])) {
return self::$cache[$string];
}
self::$instance = new self($string);
$result = self::parseSelector();
$result = self::_parseSelector();
// If not at the end of input throw an exception.
$token = self::$instance->data->consume();
if ($token !== false) {
self::throw(false, $token);
}
self::$cache[$string] = $result;
return $result;
}
/** Parses strings into Selectors */
public static function parsePath(string $string): Path {
if (isset(self::$cache[$string])) {
return self::$cache[$string];
}
self::$instance = new self($string);
$result = self::_parsePath();
// If not at the end of input throw an exception.
$token = self::$instance->data->consume();
@ -95,7 +114,7 @@ class Parser {
} elseif ($peek === '(') {
$result->child = self::parseGroup($result);
} else {
$result->child = self::parsePath($result);
$result->child = self::_parsePath($result);
}
assert((fn() => self::debugResult($result))());
@ -103,15 +122,15 @@ class Parser {
return $result;
}
protected static function parseFilter(Expression $parent, string $side): Filter {
protected static function parseFilter(Expression $parent, string $prefix): Filter {
assert((fn() => self::debug())());
$result = new Filter($parent, $side);
$result = new Filter($parent, $prefix);
$peek = self::$instance->data->peek();
if ($peek === '(') {
$result->child = self::parseGroup($result);
} else {
$result->child = self::parsePath($result);
$result->child = self::_parsePath($result);
}
assert((fn() => self::debugResult($result))());
@ -129,7 +148,7 @@ class Parser {
self::throw('"("', $token);
}
$result->child = self::parseSelector($result);
$result->child = self::_parseSelector($result);
$token = self::$instance->data->consume();
if ($token !== ')') {
@ -141,7 +160,7 @@ class Parser {
return $result;
}
protected static function parsePath(Expression $parent): Path {
protected static function _parsePath(Expression $parent): Path {
assert((fn() => self::debug())());
$result = new Path($parent);
@ -193,7 +212,7 @@ class Parser {
return $result;
}
protected static function parseSelector(?Group $parent = null): Selector {
protected static function _parseSelector(?Group $parent = null): Selector {
assert((fn() => self::debug())());
$result = new Selector($parent);

17
lib/Scope/Path.php

@ -27,6 +27,23 @@ class Path extends Node {
}
public function matches(Path $path): bool {
$start = reset($this->_scopes);
$bt = end($this->_scopes);
$node = $this;
if ($this->_anchor === self::ANCHOR_END || $this->_anchor === self::ANCHOR_BOTH) {
while ($node && $node->isAuxiliary()) {
$node = $node->parent->get();
}
$bt = $start;
}
return false;
}
public function add(Scope ...$scopes): bool {
if ($this->frozen['add']) {
return false;

5
lib/Scope/Scope.php

@ -28,6 +28,11 @@ class Scope extends Node {
return true;
}
public function isAuxiliary(): bool {
$serialized = (string)$this;
return(strncmp($serialized, 'attr.', 5) === 0 || strncmp($serialized, 'dyn.', 4) === 0);
}
public function __toString(): string {
$result = '';

15
lib/Scope/Selector.php

@ -26,6 +26,21 @@ class Selector extends Node {
return true;
}
public function matches(Path|string $path, &$match = null): bool {
if (is_string($selector)) {
$path = Parser::parsePath($path);
}
foreach ($this->_composites as $composite) {
if ($composite->matches($path)) {
$match = $composite;
return true;
}
}
return false;
}
public function __toString(): string {
return implode(', ', $this->_composites);

Loading…
Cancel
Save