diff --git a/lib/Highlight.php b/lib/Highlight.php index 56efb6c..3a42957 100644 --- a/lib/Highlight.php +++ b/lib/Highlight.php @@ -25,8 +25,8 @@ class Highlight { foreach ($tokenList as $lineNumber => $tokens) { if ($lineNumber === 26) { - var_export($tokens); - echo "\n"; + //var_export($tokens); + //echo "\n"; die(); } } diff --git a/lib/Scope/Parser.php b/lib/Scope/Parser.php index 6722ae8..fc816d4 100644 --- a/lib/Scope/Parser.php +++ b/lib/Scope/Parser.php @@ -8,6 +8,11 @@ namespace dW\Lit\Scope; /** Parses strings into a scope selector */ class Parser { + // Flag for turning on debugging on the class. Assertions must be enabled for + // it to work. This allows for parsing of scopes to be debugged separately from + // tokenization of input text. + public static bool $debug = false; + // Used to cache parsed scopes and selectors protected static array $cache = [ 'selector' => [], @@ -71,7 +76,7 @@ class Parser { protected static function parseComposite(): Composite { - assert((fn() => self::debug())()); + assert((fn() => self::debugStart())()); $expressions = [ self::parseExpression() ]; @@ -97,7 +102,7 @@ class Parser { } protected static function parseExpression(int $operator = Expression::OPERATOR_NONE): Expression { - assert((fn() => self::debug())()); + assert((fn() => self::debugStart())()); $peek = self::$instance->data->peek(); $negate = false; @@ -121,7 +126,7 @@ class Parser { } protected static function parseFilter(string $prefix): Filter { - assert((fn() => self::debug())()); + assert((fn() => self::debugStart())()); $peek = self::$instance->data->peek(); if ($peek === '(') { @@ -136,7 +141,7 @@ class Parser { } protected static function parseGroup(): Group { - assert((fn() => self::debug())()); + assert((fn() => self::debugStart())()); $token = self::$instance->data->consume(); if ($token !== '(') { @@ -156,7 +161,7 @@ class Parser { } protected static function parsePath(): Path { - assert((fn() => self::debug())()); + assert((fn() => self::debugStart())()); $anchorStart = false; if (self::$instance->data->peek() === '^') { @@ -204,7 +209,7 @@ class Parser { } protected static function _parseSelector(): Selector { - assert((fn() => self::debug())()); + assert((fn() => self::debugStart())()); $composites = [ self::parseComposite() ]; $peek = self::$instance->data->peek(); @@ -220,7 +225,7 @@ class Parser { } protected static function _parseScope(?Scope $parent = null, bool $anchorToPrevious = false): Scope { - assert((fn() => self::debug())()); + assert((fn() => self::debugStart())()); $atoms = []; $first = true; @@ -244,43 +249,48 @@ class Parser { return $result; } - protected static function debug(): bool { - $message = <<debugCount++, - ltrim($methodTree, '->'), - self::$instance->data->position + 1, - var_export(self::$instance->data->peek(), true) - ); + private static function debugStart(): bool { + if (self::$debug) { + $message = <<debugCount++, + ltrim($methodTree, '->'), + self::$instance->data->position + 1, + var_export(self::$instance->data->peek(), true) + ); + } return true; } - protected static function debugResult($result): bool { - printf("%s Result: %s\n", - debug_backtrace()[2]['function'], - // Removes bullshit from var_exported classes for easier reading - str_replace([ '::__set_state(array', __NAMESPACE__.'\\', '))' ], [ '', '', ')' ], var_export($result, true)) - ); + private static function debugResult($result): bool { + if (self::$debug) { + printf("%s Result: %s\n", + debug_backtrace()[2]['function'], + // Removes bullshit from var_exported classes for easier reading + str_replace([ '::__set_state(array', __NAMESPACE__.'\\', '))' ], [ '', '', ')' ], var_export($result, true)) + ); + } return true; } diff --git a/lib/Tokenizer.php b/lib/Tokenizer.php index d1ea8c3..35dad45 100644 --- a/lib/Tokenizer.php +++ b/lib/Tokenizer.php @@ -18,6 +18,8 @@ use dW\Lit\Scope\{ class Tokenizer { + public static bool $debug = false; + protected Data $data; protected Grammar $grammar; protected int $offset = 0; @@ -26,7 +28,7 @@ class Tokenizer { protected array $scopeStack; protected const SCOPE_RESOLVE_REGEX = '/\$(\d+)|\${(\d+):\/(downcase|upcase)}/S'; - protected const ANCHOR_CHECK_REGEX = '/(?data->get() as $lineNumber => $line) { + assert($this->debugLine($lineNumber, $line)); + $this->offset = 0; $lineLength = strlen($line); @@ -60,6 +64,8 @@ class Tokenizer { ]; } + assert($this->debugTokens($tokens)); + yield $lineNumber => $tokens; } } @@ -172,6 +178,8 @@ class Tokenizer { } } + assert($this->debugClosestMatch($closestMatch)); + // If there were a match above... if ($closestMatch !== null) { $match = $closestMatch['match']; @@ -414,4 +422,67 @@ class Tokenizer { return $tokens; } + + + private function debugClosestMatch(?array $closestMatch): bool { + if (self::$debug) { + $message = <<match ?? 'NULL', + $closestMatch['pattern']->name ?? 'NULL', + var_export($closestMatch['pattern']->beginPattern ?? null, true), + var_export($closestMatch['pattern']->endPattern ?? null, true), + var_export($closestMatch['match'] ?? null, true) + ); + + echo $this->debug_indentLines($message) . "\n\n"; + } + + return true; + } + + private function debug_indentLines(string $message): string { + $backtrace = debug_backtrace(); + array_shift($backtrace); + array_shift($backtrace); + + $count = -1; + foreach ($backtrace as $b) { + if ($b['function'] === 'tokenizeLine') { + $count++; + } + } + + return ($count > 0) ? preg_replace('/^/m', str_repeat('|', $count) . ' ', $message) : $message; + } + + private function debugLine(int $lineNumber, string $line): bool { + if (self::$debug) { + $message = <<