diff --git a/lib/Scope/Data.php b/lib/Scope/Data.php index 186c7ed..261e2ce 100644 --- a/lib/Scope/Data.php +++ b/lib/Scope/Data.php @@ -14,7 +14,7 @@ class Data { public function __construct(string $data) { $this->data = $data; - $this->endPosition = strlen($data) - 1; + $this->endPosition = strlen($data); } public function consume(int $length = 1): string|bool { @@ -39,19 +39,6 @@ class Data { return $this->consumeWhile($match, 1); } - public function consumeUntil(string $match, $limit = null): string|bool { - if ($this->_position === $this->endPosition) { - return false; - } - - $length = strcspn($this->data, $match, $this->_position, $limit); - if ($length === 0) { - return ''; - } - - return $this->consume($length); - } - public function consumeWhile(string $match, $limit = null): string|bool { if ($this->_position === $this->endPosition) { return false; @@ -83,6 +70,15 @@ class Data { return $output; } + public function unconsumeTo(int $position = 1): bool { + if ($position < 0 || $position > $this->endPosition) { + return false; + } + + $this->_position = $position; + return true; + } + public function __get(string $name) { if ($name === 'position') { return $this->_position; diff --git a/lib/Scope/Exception.php b/lib/Scope/Exception.php index 1201220..41d7f36 100644 --- a/lib/Scope/Exception.php +++ b/lib/Scope/Exception.php @@ -9,7 +9,7 @@ namespace dW\Highlighter\Scope; class Exception extends \Exception { const MESSAGE = '%s expected; found %s'; - public function __construct(string $expected, string $found) { + public function __construct(string $expected, string|bool $found) { $strlen = strlen($expected); if ($strlen > 1) { $temp = []; diff --git a/lib/Scope/Matchers/AndMatcher.php b/lib/Scope/Matchers/AndMatcher.php new file mode 100644 index 0000000..54bb906 --- /dev/null +++ b/lib/Scope/Matchers/AndMatcher.php @@ -0,0 +1,17 @@ +left = $left; + $this->right = $right; + } +} diff --git a/lib/Scope/Matchers/CompositeMatcher.php b/lib/Scope/Matchers/CompositeMatcher.php index 02ea865..dc7e03e 100644 --- a/lib/Scope/Matchers/CompositeMatcher.php +++ b/lib/Scope/Matchers/CompositeMatcher.php @@ -7,5 +7,19 @@ declare(strict_types=1); namespace dW\Highlighter\Scope; class CompositeMatcher extends Matcher { - public function __construct(Matcher $left, string $operator, Matcher $right) {} + protected Matcher $matcher; + + public function __construct(Matcher $left, string $operator, Matcher $right) { + switch ($operator) { + case '|': + $this->matcher = new OrMatcher($left, $right); + break; + case '&': + $this->matcher = new AndMatcher($left, $right); + break; + case '-': + $this->matcher = new AndMatcher($left, new NegateMatcher($right)); + break; + } + } } diff --git a/lib/Scope/Matchers/GroupMatcher.php b/lib/Scope/Matchers/GroupMatcher.php index fcc979f..96afcf1 100644 --- a/lib/Scope/Matchers/GroupMatcher.php +++ b/lib/Scope/Matchers/GroupMatcher.php @@ -7,5 +7,11 @@ declare(strict_types=1); namespace dW\Highlighter\Scope; class GroupMatcher extends Matcher { - public function __construct(string $prefix, Matcher $selector) {} + protected string|null $prefix; + protected Matcher $selector; + + public function __construct(string|null $prefix, Matcher $selector) { + $this->prefix = ($prefix !== null) ? $prefix[0] : null; + $this->selector = $selector; + } } diff --git a/lib/Scope/Matchers/NegateMatcher.php b/lib/Scope/Matchers/NegateMatcher.php index d71f904..7d575a5 100644 --- a/lib/Scope/Matchers/NegateMatcher.php +++ b/lib/Scope/Matchers/NegateMatcher.php @@ -7,5 +7,9 @@ declare(strict_types=1); namespace dW\Highlighter\Scope; class NegateMatcher extends Matcher { - public function __construct(Matcher $groupOrPath) {} + protected Matcher $matcher; + + public function __construct(Matcher $matcher) { + $this->matcher = $matcher; + } } diff --git a/lib/Scope/Matchers/OrMatcher.php b/lib/Scope/Matchers/OrMatcher.php index 6e4bd29..baa7491 100644 --- a/lib/Scope/Matchers/OrMatcher.php +++ b/lib/Scope/Matchers/OrMatcher.php @@ -7,5 +7,11 @@ declare(strict_types=1); namespace dW\Highlighter\Scope; class OrMatcher extends Matcher { - public function __construct(Matcher $left, Matcher $right) {} + protected Matcher $left; + protected Matcher $right; + + public function __construct(Matcher $left, Matcher $right) { + $this->left = $left; + $this->right = $right; + } } diff --git a/lib/Scope/Matchers/PathMatcher.php b/lib/Scope/Matchers/PathMatcher.php index cac3086..08d7662 100644 --- a/lib/Scope/Matchers/PathMatcher.php +++ b/lib/Scope/Matchers/PathMatcher.php @@ -11,7 +11,7 @@ class PathMatcher extends Matcher { protected array $matchers; public function __construct(string|null $prefix, Matcher ...$matchers) { - $this->prefix = $prefix; + $this->prefix = ($prefix !== null) ? $prefix[0] : null; $this->matchers = $matchers; } } diff --git a/lib/Scope/Parser.php b/lib/Scope/Parser.php index 08b7416..1ad13a0 100644 --- a/lib/Scope/Parser.php +++ b/lib/Scope/Parser.php @@ -30,16 +30,10 @@ class Parser { $s2 = self::parseSelector(); if ($s2 !== false) { $s3 = self::parseSpace(); - if ($s3 !== false) { - $result = $s2; - } + $result = $s2; } } - if (self::$debug === true) { - echo "------------------------------\n"; - } - if ($result === false && self::$instance->lastExceptionData !== []) { throw new Exception(self::$instance->lastExceptionData['expected'], self::$instance->lastExceptionData['found']); } @@ -53,6 +47,7 @@ class Parser { } $result = false; + $position = self::$instance->data->position; $s1 = self::parseExpression(); if ($s1 !== false) { @@ -77,11 +72,12 @@ class Parser { } if ($result === false) { + self::$instance->data->unconsumeTo($position); $result = self::parseExpression(); } if (self::$debug === true) { - echo "parseComposite Result: " . var_export($result, true) . "\n"; + self::debugResult($result); } return $result; @@ -142,7 +138,7 @@ class Parser { } if (self::$debug === true) { - echo "parseExpression Result: " . var_export($result, true) . "\n"; + self::debugResult($result); } return $result; @@ -174,29 +170,27 @@ class Parser { } } - if ($prefix !== null) { - $s2 = self::$instance->data->consumeIf('('); - if ($s2 === '' || $s2 === false) { - $s2 = false; - self::fail('('); - } + $s2 = self::$instance->data->consumeIf('('); + if ($s2 === '' || $s2 === false) { + $s2 = false; + self::fail('('); + } - if ($s2 !== false) { - $s3 = self::parse(); - if ($s3 !== false) { - $s4 = self::parseSelector(); - if ($s4 !== false) { - $s5 = self::parseSpace(); - if ($s5 !== false) { - $s6 = self::$instance->data->consumeIf(')'); - if ($s6 === '' || $s6 === false) { - $s6 = false; - self::fail(')'); - } - - if ($s6 !== false) { - $result = new GroupMatcher($prefix, $s4); - } + if ($s2 !== false) { + $s3 = self::parseSpace(); + if ($s3 !== false) { + $s4 = self::parseSelector(); + if ($s4 !== false) { + $s5 = self::parseSpace(); + if ($s5 !== false) { + $s6 = self::$instance->data->consumeIf(')'); + if ($s6 === '' || $s6 === false) { + $s6 = false; + self::fail(')'); + } + + if ($s6 !== false) { + $result = new GroupMatcher($prefix, $s4); } } } @@ -204,7 +198,7 @@ class Parser { } if (self::$debug === true) { - echo "parseGroup Result: " . var_export($result, true) . "\n"; + self::debugResult($result); } return $result; @@ -241,7 +235,7 @@ class Parser { $s3 = [$s2]; do { - $s4 = false; + $s6 = false; $s5 = self::parseSpace(); if ($s5 !== false) { $s6 = self::parseScope(); @@ -249,13 +243,13 @@ class Parser { $s3[] = $s6; } } - } while ($s4 !== false); + } while ($s6 !== false); $result = new PathMatcher($prefix, ...$s3); } if (self::$debug === true) { - echo "parsePath Result: " . var_export($result, true) . "\n"; + self::debugResult($result); } return $result; @@ -313,7 +307,7 @@ class Parser { } if (self::$debug === true) { - echo "parseSegment Result: " . var_export($result, true) . "\n"; + self::debugResult($result); } return $result; @@ -325,6 +319,7 @@ class Parser { } $result = false; + $position = self::$instance->data->position; $s1 = self::parseComposite(); if ($s1 !== false) { @@ -346,8 +341,13 @@ class Parser { } } + if ($result === false) { + self::$instance->data->unconsumeTo($position); + $result = self::parseComposite(); + } + if (self::$debug === true) { - echo "parseSelector Result: " . var_export($result, true) . "\n"; + self::debugResult($result); } return $result; @@ -384,7 +384,7 @@ class Parser { } if (self::$debug === true) { - echo "parseScope Result: " . var_export($result, true) . "\n"; + self::debugResult($result); } return $result; @@ -401,7 +401,7 @@ class Parser { } if (self::$debug === true) { - echo "parseSpace Result: " . var_export($result, true) . "\n"; + self::debugResult($result); } return $result; @@ -409,12 +409,16 @@ class Parser { protected static function debug() { + /*if (self::$debugCount === 2500) { + die(); + }*/ + $message = <<'), self::$instance->data->position, - self::$instance->data->peek() + var_export(self::$instance->data->peek(), true) ); } + protected static function debugResult($result) { + printf("%s Result: %s\n", + debug_backtrace()[1]['function'], + var_export($result, true)); + } + protected static function fail(string $expected) { self::$instance->lastExceptionData = [ 'expected' => $expected,