Beispiel #1
0
    function it_should_create_an_extended_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', 'Acme\\BaseFile'));
        $grammarNode->setBase('BaseFile');
        $grammarCode = <<<EOS
namespace Acme\\Factory;

use Acme\\FactoryInterface;
use Acme\\BaseFile;

class FooFile extends BaseFile
{
    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;
    }
}
EOS;
        $grammarNode->accept($this->getWrappedObject());
        $this->getResult()->shouldBe($grammarCode);
    }
Beispiel #2
0
    public function visitGrammar(GrammarNode $node)
    {
        $result = '';
        if ($node->getNamespace() !== null) {
            $result .= "namespace {$node->getNamespace()};\n\n";
        }
        if (count($node->getImports()) > 0) {
            foreach ($node->getImports() as $import) {
                $result .= "use {$import};\n";
            }
            $result .= "\n";
        }
        if ($node->getBase() === null) {
            $result .= <<<EOS
class {$node->getName()}
{
    protected \$string;
    protected \$position;
    protected \$value;
    protected \$cache;
    protected \$cut;
    protected \$errors;
    protected \$warnings;

EOS;
        } else {
            $result .= <<<EOS
class {$node->getName()} extends {$node->getBase()}
{
EOS;
        }
        $pieces = $this->getResults($node->getLength());
        foreach ($pieces as $piece) {
            $result .= <<<EOS

    {$this->indent($piece)}

EOS;
        }
        if ($node->getStartSymbol() !== null) {
            $result .= <<<EOS

    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->parse{$node->getStartSymbol()}();

        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;
        }
        $result .= <<<EOS
}
EOS;
        $this->results[] = $result;
    }
Beispiel #3
0
 function it_should_parse_extended_grammars()
 {
     $tree = new GrammarNode('ExtendedFile', array(new RuleNode('Foo', "'Foo'", new LiteralNode('"foo"', false))));
     $tree->setBase('BaseFile');
     $this->parse('grammar ExtendedFile extends BaseFile { Foo = "foo"; }')->shouldBeLike($tree);
 }
Beispiel #4
0
 private function createClassFromTree(GrammarNode $tree)
 {
     $visitor = new ToClassVisitor();
     $tree->accept($visitor);
     return $visitor->getResult();
 }
Beispiel #5
0
 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;
 }