function it_should_parse_namespaces_and_imports() { $tree = new GrammarNode('TestFile', array(new RuleNode('File', "'File'", new LiteralNode('"foo"', false)))); $tree->setNamespace('Acme\\Test'); $tree->setImports(array('Acme\\Factory')); $tree->setStartSymbol('File'); $this->parse('namespace Acme\\Test; use Acme\\Factory; grammar TestFile { start File = "foo"; }')->shouldBeLike($tree); }
function it_should_create_a_grammar_from_a_node() { $grammarNode = new GrammarNode('FooFile', array(new RuleNode('Foo', '"Foo"', new RuleReferenceNode('Bar')))); $grammarNode->setNamespace('Acme\\Factory'); $grammarNode->setImports(array('Acme\\FactoryInterface')); $grammarNode->setStartSymbol('Foo'); $grammarCode = <<<EOS namespace Acme\\Factory; use Acme\\FactoryInterface; class FooFile { protected \$string; protected \$position; protected \$value; protected \$cache; protected \$cut; protected \$errors; protected \$warnings; protected function parseFoo() { \$_position = \$this->position; if (isset(\$this->cache['Foo'][\$_position])) { \$_success = \$this->cache['Foo'][\$_position]['success']; \$this->position = \$this->cache['Foo'][\$_position]['position']; \$this->value = \$this->cache['Foo'][\$_position]['value']; return \$_success; } \$_success = \$this->parseBar(); \$this->cache['Foo'][\$_position] = array( 'success' => \$_success, 'position' => \$this->position, 'value' => \$this->value ); if (!\$_success) { \$this->report(\$_position, "Foo"); } return \$_success; } private function line() { if (!empty(\$this->errors)) { \$positions = array_keys(\$this->errors); } else { \$positions = array_keys(\$this->warnings); } return count(explode("\\n", substr(\$this->string, 0, max(\$positions)))); } private function rest() { return '"' . substr(\$this->string, \$this->position) . '"'; } protected function report(\$position, \$expecting) { if (\$this->cut) { \$this->errors[\$position][] = \$expecting; } else { \$this->warnings[\$position][] = \$expecting; } } private function expecting() { if (!empty(\$this->errors)) { ksort(\$this->errors); return end(\$this->errors)[0]; } ksort(\$this->warnings); return implode(', ', end(\$this->warnings)); } public function parse(\$_string) { \$this->string = \$_string; \$this->position = 0; \$this->value = null; \$this->cache = array(); \$this->cut = false; \$this->errors = array(); \$this->warnings = array(); \$_success = \$this->parseFoo(); if (\$_success && \$this->position < strlen(\$this->string)) { \$_success = false; \$this->report(\$this->position, "end of file"); } if (!\$_success) { throw new \\InvalidArgumentException("Syntax error, expecting {\$this->expecting()} on line {\$this->line()}"); } return \$this->value; } } EOS; $grammarNode->accept($this->getWrappedObject()); $this->getResult()->shouldBe($grammarCode); }
protected function parseGrammar() { $_position = $this->position; if (isset($this->cache['Grammar'][$_position])) { $_success = $this->cache['Grammar'][$_position]['success']; $this->position = $this->cache['Grammar'][$_position]['position']; $this->value = $this->cache['Grammar'][$_position]['value']; return $_success; } $_value27 = array(); if (substr($this->string, $this->position, strlen("grammar")) === "grammar") { $_success = true; $this->value = substr($this->string, $this->position, strlen("grammar")); $this->position += strlen("grammar"); } else { $_success = false; $this->report($this->position, '"grammar"'); } if ($_success) { $_value27[] = $this->value; $_success = true; $this->value = null; $this->cut = true; } if ($_success) { $_value27[] = $this->value; $_success = $this->parse_(); } if ($_success) { $_value27[] = $this->value; $_success = $this->parseIdentifier(); if ($_success) { $name = $this->value; } } if ($_success) { $_value27[] = $this->value; $_position18 = $this->position; $_cut19 = $this->cut; $this->cut = false; $_value17 = array(); $_success = $this->parse_(); if ($_success) { $_value17[] = $this->value; if (substr($this->string, $this->position, strlen("extends")) === "extends") { $_success = true; $this->value = substr($this->string, $this->position, strlen("extends")); $this->position += strlen("extends"); } else { $_success = false; $this->report($this->position, '"extends"'); } } if ($_success) { $_value17[] = $this->value; $_success = $this->parse_(); } if ($_success) { $_value17[] = $this->value; $_success = $this->parseIdentifier(); if ($_success) { $base = $this->value; } } if ($_success) { $_value17[] = $this->value; $this->value = $_value17; } if (!$_success && !$this->cut) { $_success = true; $this->position = $_position18; $this->value = null; } $this->cut = $_cut19; } if ($_success) { $_value27[] = $this->value; $_success = $this->parse_(); } if ($_success) { $_value27[] = $this->value; if (substr($this->string, $this->position, strlen("{")) === "{") { $_success = true; $this->value = substr($this->string, $this->position, strlen("{")); $this->position += strlen("{"); } else { $_success = false; $this->report($this->position, '"{"'); } } if ($_success) { $_value27[] = $this->value; $_position21 = $this->position; $_cut22 = $this->cut; $this->cut = false; $_value20 = array(); $_success = $this->parse_(); if ($_success) { $_value20[] = $this->value; if (substr($this->string, $this->position, strlen("start")) === "start") { $_success = true; $this->value = substr($this->string, $this->position, strlen("start")); $this->position += strlen("start"); } else { $_success = false; $this->report($this->position, '"start"'); } } if ($_success) { $_value20[] = $this->value; $_success = true; $this->value = null; $this->cut = true; } if ($_success) { $_value20[] = $this->value; $_success = $this->parse_(); } if ($_success) { $_value20[] = $this->value; $_success = $this->parseRule(); if ($_success) { $startSymbol = $this->value; } } if ($_success) { $_value20[] = $this->value; $this->value = $_value20; } if (!$_success && !$this->cut) { $_success = true; $this->position = $_position21; $this->value = null; } $this->cut = $_cut22; } if ($_success) { $_value27[] = $this->value; $_value25 = array(); $_cut26 = $this->cut; while (true) { $_position24 = $this->position; $this->cut = false; $_value23 = array(); $_success = $this->parse_(); if ($_success) { $_value23[] = $this->value; $_success = $this->parseRule(); if ($_success) { $rule = $this->value; } } if ($_success) { $_value23[] = $this->value; $this->value = $_value23; } if ($_success) { $this->value = call_user_func(function () use(&$name, &$base, &$startSymbol, &$rule) { return $rule; }); } if (!$_success) { break; } $_value25[] = $this->value; } if (!$this->cut) { $_success = true; $this->position = $_position24; $this->value = $_value25; } $this->cut = $_cut26; if ($_success) { $rules = $this->value; } } if ($_success) { $_value27[] = $this->value; $_success = $this->parse_(); } if ($_success) { $_value27[] = $this->value; if (substr($this->string, $this->position, strlen("}")) === "}") { $_success = true; $this->value = substr($this->string, $this->position, strlen("}")); $this->position += strlen("}"); } else { $_success = false; $this->report($this->position, '"}"'); } } if ($_success) { $_value27[] = $this->value; $this->value = $_value27; } if ($_success) { $this->value = call_user_func(function () use(&$name, &$base, &$startSymbol, &$rule, &$rules) { $rules = array_merge(isset($startSymbol) ? array($startSymbol) : array(), $rules); $grammar = new GrammarNode($name, $rules); if (isset($base)) { $grammar->setBase($base); } if (isset($startSymbol)) { $grammar->setStartSymbol($startSymbol->getIdentifier()); } return $grammar; }); } $this->cache['Grammar'][$_position] = array('success' => $_success, 'position' => $this->position, 'value' => $this->value); if (!$_success) { $this->report($_position, 'Grammar'); } return $_success; }