diff --git a/lib/Grammar.php b/lib/Grammar.php index 6d5e568..6af9875 100644 --- a/lib/Grammar.php +++ b/lib/Grammar.php @@ -8,9 +8,12 @@ namespace dW\Lit; use dW\Lit\Grammar\{ BaseReference, CaptureList, + ChildGrammarRegistry, Exception, + FauxReadOnly, GrammarReference, InjectionList, + Node, Pattern, PatternList, Reference, @@ -26,7 +29,6 @@ use dW\Lit\Grammar\{ */ class Grammar { use FauxReadOnly; - protected ?string $_contentRegex; protected ?string $_firstLineMatch; protected ?InjectionList $_injections; @@ -49,9 +51,12 @@ class Grammar { $this->_ownerGrammar = (is_null($ownerGrammar)) ? null : \WeakReference::create($ownerGrammar); } + // Used when adopting to change the $ownerGrammar property. + public function withOwnerGrammar(Grammar $ownerGrammar): self { + if ($new = ChildGrammarRegistry::get($this->_scopeName, $ownerGrammar)) { + return $new; + } - /** Clones the supplied grammar with this grammar set as its owner grammar */ - public function adoptGrammar(self $grammar): self { $new = clone $this; if ($new->_patterns !== null) { $new->_patterns = $new->_patterns->withOwnerGrammar($new); @@ -65,7 +70,10 @@ class Grammar { $new->_repository = $new->_repository->withOwnerGrammar($new); } - return GrammarRegistry::cacheChild($new); + $new->_ownerGrammar = \WeakReference::create($ownerGrammar); + + ChildGrammarRegistry::set($this->_scopeName, $new); + return $new; } @@ -147,7 +155,7 @@ class Grammar { } elseif ($pattern['include'] === '$base') { return new BaseReference($this); } elseif ($pattern['include'] === '$self') { - return SelfReference::create($this); + return new SelfReference($this); } else { return new GrammarReference($pattern['include'], $this); } diff --git a/lib/Grammar/ChildGrammarRegistry.php b/lib/Grammar/ChildGrammarRegistry.php new file mode 100644 index 0000000..13fb84e --- /dev/null +++ b/lib/Grammar/ChildGrammarRegistry.php @@ -0,0 +1,61 @@ +ownerGrammar === $ownerGrammar) { + return $g; + } + } + + return null; + } + + public static function set(string $scopeName, Grammar $grammar): bool { + try { + if (!array_key_exists($scopeName, self::$storage)) { + self::$storage[$scopeName] = [ $grammar ]; + return true; + } + + $grammars = self::$storage[$scopeName]; + foreach ($grammars as $key => $value) { + if ($value->ownerGrammar === $grammar->ownerGrammar) { + return false; + } + } + + self::$storage[$scopeName][] = $grammar; + } catch (\Exception $e) { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/lib/Grammar/FauxReadOnly.php b/lib/Grammar/FauxReadOnly.php new file mode 100644 index 0000000..af4a6fd --- /dev/null +++ b/lib/Grammar/FauxReadOnly.php @@ -0,0 +1,26 @@ +_ownerGrammar->get(); + } + + if (!$exists) { + $trace = debug_backtrace(); + trigger_error("Cannot get undefined property $name in {$trace[0]['file']} on line {$trace[0]['line']}", E_USER_NOTICE); + return null; + } + + return $this->$prop; + } +} \ No newline at end of file diff --git a/lib/Grammar/GrammarReference.php b/lib/Grammar/GrammarReference.php index 812ab21..8c1c512 100644 --- a/lib/Grammar/GrammarReference.php +++ b/lib/Grammar/GrammarReference.php @@ -36,7 +36,7 @@ class GrammarReference extends Reference { return null; } - $this->object = $this->_ownerGrammar->get()->adoptGrammar($grammar); + $this->object = $grammar->withOwnerGrammar($this->_ownerGrammar->get()); return $this->object; } } \ No newline at end of file diff --git a/lib/Grammar/Pattern.php b/lib/Grammar/Pattern.php index 89b2856..976b8d6 100644 --- a/lib/Grammar/Pattern.php +++ b/lib/Grammar/Pattern.php @@ -36,11 +36,4 @@ class Pattern extends Rule { $this->_applyEndPatternLast = $applyEndPatternLast; $this->_ownerGrammar = ($ownerGrammar === null) ? null : \WeakReference::create($ownerGrammar); } - - // Used when adopting to change the $ownerGrammar property. - public function withOwnerGrammar(Grammar $ownerGrammar): self { - $new = clone $this; - $new->_ownerGrammar = \WeakReference::create($ownerGrammar); - return $new; - } } \ No newline at end of file diff --git a/lib/Grammar/Reference.php b/lib/Grammar/Reference.php index 5949474..6005654 100644 --- a/lib/Grammar/Reference.php +++ b/lib/Grammar/Reference.php @@ -5,26 +5,7 @@ declare(strict_types=1); namespace dW\Lit\Grammar; -use dW\Lit\{ - FauxReadOnly, - Grammar -}; /** Acts as a catch-all type for references */ -abstract class Reference extends Rule { - use FauxReadOnly; - protected \WeakReference $_ownerGrammar; - - - public function __construct(Grammar $ownerGrammar) { - $this->_ownerGrammar = \WeakReference::create($ownerGrammar); - } - - // Used when adopting to change the $ownerGrammar property. - public function withOwnerGrammar(Grammar $ownerGrammar): self { - $new = clone $this; - $new->_ownerGrammar = \WeakReference::create($ownerGrammar); - return $new; - } -} \ No newline at end of file +abstract class Reference extends Rule {} \ No newline at end of file diff --git a/lib/Grammar/RepositoryReference.php b/lib/Grammar/RepositoryReference.php index b6d3dd1..b2f7112 100644 --- a/lib/Grammar/RepositoryReference.php +++ b/lib/Grammar/RepositoryReference.php @@ -30,10 +30,6 @@ class RepositoryReference extends Reference { } $grammar = $this->_ownerGrammar->get(); - if (!isset($grammar->repository)) { - die(var_export($grammar)); - } - if (!isset($grammar->repository[$this->name])) { $this->object = false; return null; diff --git a/lib/Grammar/Rule.php b/lib/Grammar/Rule.php index 85324bd..a1abc0e 100644 --- a/lib/Grammar/Rule.php +++ b/lib/Grammar/Rule.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace dW\Lit\Grammar; -use dW\Lit\FauxReadOnly; +use dW\Lit\Grammar; /** @@ -13,4 +13,17 @@ use dW\Lit\FauxReadOnly; */ abstract class Rule { use FauxReadOnly; + protected \WeakReference $_ownerGrammar; + + + public function __construct(Grammar $ownerGrammar) { + $this->_ownerGrammar = \WeakReference::create($ownerGrammar); + } + + // Used when adopting to change the $ownerGrammar property. + public function withOwnerGrammar(Grammar $ownerGrammar): self { + $new = clone $this; + $new->_ownerGrammar = \WeakReference::create($ownerGrammar); + return $new; + } } \ No newline at end of file diff --git a/lib/Grammar/SelfReference.php b/lib/Grammar/SelfReference.php index e794f14..6a877c1 100644 --- a/lib/Grammar/SelfReference.php +++ b/lib/Grammar/SelfReference.php @@ -12,21 +12,12 @@ use dW\Lit\Grammar; * exists to maintain sanity when checking types. */ class SelfReference extends Reference { - protected ?Grammar $grammar; - - - public function __construct(Grammar $grammar, Grammar $ownerGrammar) { - $this->grammar = $grammar; - parent::__construct($ownerGrammar); - } - - public function __destruct() { - parent::__destruct(); - $this->grammar = null; + public function __construct(Grammar $grammar) { + parent::__construct($grammar); } public function get(): Grammar { - return $this->grammar; + return $this->_ownerGrammar->get(); } } \ No newline at end of file diff --git a/lib/GrammarRegistry.php b/lib/GrammarRegistry.php index 9cc32ee..76e286c 100644 --- a/lib/GrammarRegistry.php +++ b/lib/GrammarRegistry.php @@ -5,31 +5,17 @@ declare(strict_types=1); namespace dW\Lit; +use dW\Lit\Grammar\ChildGrammarRegistry; /** Static storage for grammars; a map of a scope string and a Grammar object */ -class GrammarRegistry implements \IteratorAggregate { +class GrammarRegistry { protected static array $storage = []; - protected static array $childStorage = []; - - public static function cacheChild(Grammar $grammar): Grammar { - self::$childStorage[] = $grammar; - return $grammar; - } public static function clear(): bool { + // Clear all the child grammars, too. + ChildGrammarRegistry::clear(); self::$storage = []; - self::$childStorage = []; - return true; - } - - public static function delete(string $scopeName): bool { - try { - unset(self::$storage[$scopeName]); - } catch (\Exception $e) { - return false; - } - return true; } @@ -48,22 +34,6 @@ class GrammarRegistry implements \IteratorAggregate { return false; } - public function getIterator(): \Traversable { - foreach (self::$storage as $scopeName => $grammar) { - yield $scopeName => $grammar; - } - } - - public static function has(string $scopeName): bool { - return (array_key_exists($scopeName, self::$storage)); - } - - public static function keys(): \Traversable { - foreach (self::$storage as $scopeName => $_) { - yield $scopeName; - } - } - public static function set(string $scopeName, Grammar $grammar): bool { try { self::$storage[$scopeName] = $grammar; @@ -73,10 +43,4 @@ class GrammarRegistry implements \IteratorAggregate { return true; } - - public function values(): \Traversable { - foreach (self::$storage as $grammar) { - yield $grammar; - } - } } \ No newline at end of file diff --git a/lib/Tokenizer.php b/lib/Tokenizer.php index 2bc65eb..84e8680 100644 --- a/lib/Tokenizer.php +++ b/lib/Tokenizer.php @@ -63,6 +63,8 @@ class Tokenizer { 'matches' => $match ]; + die(var_export($rule)); + if ($rule->begin !== null) { $this->ruleStack[] = $rule; $this->scopeStack[] = $scopeStack;