Browse Source

Fixes to references in grammars, adoption of new owner grammars

main
Dustin Wilson 3 years ago
parent
commit
a12ec9dbfc
  1. 18
      lib/Grammar.php
  2. 61
      lib/Grammar/ChildGrammarRegistry.php
  3. 26
      lib/Grammar/FauxReadOnly.php
  4. 2
      lib/Grammar/GrammarReference.php
  5. 7
      lib/Grammar/Pattern.php
  6. 21
      lib/Grammar/Reference.php
  7. 4
      lib/Grammar/RepositoryReference.php
  8. 15
      lib/Grammar/Rule.php
  9. 15
      lib/Grammar/SelfReference.php
  10. 44
      lib/GrammarRegistry.php
  11. 2
      lib/Tokenizer.php

18
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);
}

61
lib/Grammar/ChildGrammarRegistry.php

@ -0,0 +1,61 @@
<?php
/** @license MIT
* Copyright 2021 Dustin Wilson et al.
* See LICENSE file for details */
declare(strict_types=1);
namespace dW\Lit\Grammar;
use dW\Lit\Grammar;
/**
* Static storage for child grammars; a map of a scope string and a Grammar
* object and checked against an owner grammar. Exists to prevent multiple clones
* of the same grammar from being created and also to give weak references a
* place in memory to access.
*/
class ChildGrammarRegistry {
protected static array $storage = [];
public static function clear(): bool {
self::$storage = [];
return true;
}
public static function get(string $scopeName, Grammar $ownerGrammar): ?Grammar {
if (!array_key_exists($scopeName, self::$storage)) {
return null;
}
$grammars = self::$storage[$scopeName];
foreach ($grammars as $g) {
if ($g->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;
}
}

26
lib/Grammar/FauxReadOnly.php

@ -0,0 +1,26 @@
<?php
/** @license MIT
* Copyright 2021 Dustin Wilson et al.
* See LICENSE file for details */
declare(strict_types=1);
namespace dW\Lit\Grammar;
trait FauxReadOnly {
public function __get(string $name) {
$prop = "_$name";
$exists = property_exists($this, $prop);
if ($name === 'ownerGrammar' && $exists) {
return $this->_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;
}
}

2
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;
}
}

7
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;
}
}

21
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;
}
}
abstract class Reference extends Rule {}

4
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;

15
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;
}
}

15
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();
}
}

44
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;
}
}
}

2
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;

Loading…
Cancel
Save