/** * Declare a {@link Rule} for the syntax. * * @param string $name Name of the rule. * * @return RuleBuilder */ public function rule($name) { $rule = new Rule($this->syntax); $rule->name = (string) $name; $this->syntax->addChild($rule); return new RuleBuilder($rule, $this); }
protected function visitSyntax(Syntax $syntax) { if ($this->isSyntaxDefined()) { throw new ValidaorException("You can specify a syntax only once!", ValidaorException::SYNTAXT_REDECLARATION); } $this->representative[$syntax->getNodeName()] = array("meta" => $syntax->meta, "title" => $syntax->title, "rule" => array()); }
private function assertEquivalentSyntax(Syntax $expected, Syntax $actual) { $n = new Notification(); $expected->probeEquivalence($actual, $n); $this->assertNotificationOk($n); $n = new Notification(); $actual->probeEquivalence($expected, $n); $this->assertNotificationOk($n); }
/** * @todo use ast builder */ public function testGenerateXml() { $visitor = new Xml(); $this->assertEquals('<?xml version="1.0" encoding="utf-8"?>', $visitor->getXmlString()); $syntax = new Syntax(); $syntax->meta = "EBNF defined in itself."; $syntax->title = "xis/ebnf v2.0 http://wiki.karmin.ch/ebnf/ gpl3"; $visitor = new Xml(); $syntax->accept($visitor); $xml = file_get_contents(EBNF_TESTS_FIXTURS . "/visitor/syntax.xml"); $this->assertEquals('<?xml version="1.0" encoding="utf-8"?>' . "\n" . '<syntax title="xis/ebnf v2.0 http://wiki.karmin.ch/ebnf/ gpl3" meta="EBNF defined in itself."/>', $visitor->getXmlString()); $syntax = new Syntax(); $syntax->title = "EBNF defined in itself."; $syntax->meta = "xis/ebnf v2.0 http://wiki.karmin.ch/ebnf/ gpl3"; $syntaxRule = new Rule($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $syntaxRule->name = "syntax"; $seq = new Sequence($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $opt = new Option($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "title"; $opt->addChild($ident); $seq->addChild($opt); $terminal = new Terminal($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $terminal->value = "{"; $seq->addChild($terminal); $loop = new Loop($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "rule"; $loop->addChild($ident); $seq->addChild($loop); $terminal = new Terminal($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $terminal->value = "}"; $seq->addChild($terminal); $opt = new Option($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "comment"; $opt->addChild($ident); $seq->addChild($opt); $syntaxRule->addChild($seq); $syntax->addChild($syntaxRule); $ruleRule = new Rule($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ruleRule->name = "rule"; $seq = new Sequence($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "identifier"; $seq->addChild($ident); $choice = new Choice($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); foreach (array("=", ":", ":==") as $literal) { $terminal = new Terminal($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $terminal->value = $literal; $choice->addChild($terminal); } $seq->addChild($choice); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "expression"; $seq->addChild($ident); $choice = new Choice($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); foreach (array(".", ";") as $literal) { $terminal = new Terminal($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $terminal->value = $literal; $choice->addChild($terminal); } $seq->addChild($choice); $ruleRule->addChild($seq); $syntax->addChild($ruleRule); $literalRule = new Rule($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $literalRule->name = "literal"; $choice = new Choice($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $seq = new Sequence($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $terminal = new Terminal($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $terminal->value = "'"; $seq->addChild($terminal); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "character"; $seq->addChild($ident); $loop = new Loop($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "character"; $loop->addChild($ident); $seq->addChild($loop); $seq->addChild($terminal); $choice->addChild($seq); $seq = new Sequence($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $terminal = new Terminal($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $terminal->value = '"'; $seq->addChild($terminal); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "character"; $seq->addChild($ident); $loop = new Loop($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident = new Identifier($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ident->value = "character"; $loop->addChild($ident); $seq->addChild($loop); $seq->addChild($terminal); $choice->addChild($seq); $literalRule->addChild($choice); $syntax->addChild($literalRule); $visitor = new Xml(); $syntax->accept($visitor); $xml = file_get_contents(EBNF_TESTS_FIXTURS . "/visitor/syntax.xml"); $this->assertEquals($xml, $visitor->getXmlString()); }
public function testProbeEquivalenceSyntaxWithRules() { $syntax1 = new Syntax(); $syntax1->title = "foo"; $syntax1->meta = "bar"; $syntax2 = new Syntax(); $syntax2->title = "foo"; $syntax2->meta = "bar"; $syntax3 = new Syntax(); $syntax3->title = "foo"; $syntax3->meta = "bar"; $rule1 = new Rule($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $rule1->name = "rule1"; $syntax1->addChild($rule1); $syntax2->addChild($rule1); $n = new Notification(); $syntax1->probeEquivalence($syntax2, $n); $this->assertTrue($n->isOk(), $n->report()); $this->assertEquals("", $n->report()); $n = new Notification(); $syntax2->probeEquivalence($syntax1, $n); $this->assertTrue($n->isOk(), $n->report()); $this->assertEquals("", $n->report()); $rule2 = new Rule($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $rule2->name = "rule2"; $syntax1->addChild($rule2); $error = "Node syntax has different child count than other: 2 != 1!\n"; $error .= "Other node has not the expected subnode!"; $n = new Notification(); $syntax1->probeEquivalence($syntax2, $n); $this->assertFalse($n->isOk()); $this->assertEquals($error, $n->report()); $error = "Node syntax has different child count than other: 1 != 2!"; $n = new Notification(); $syntax2->probeEquivalence($syntax1, $n); $this->assertFalse($n->isOk()); $this->assertEquals($error, $n->report()); $syntax2->addChild($rule2); $n = new Notification(); $syntax1->probeEquivalence($syntax2, $n); $this->assertTrue($n->isOk(), $n->report()); $this->assertEquals("", $n->report()); $n = new Notification(); $syntax2->probeEquivalence($syntax1, $n); $this->assertTrue($n->isOk(), $n->report()); $this->assertEquals("", $n->report()); $rule3 = new Rule($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $rule3->name = "rule3"; $syntax3->addChild($rule1); $syntax3->addChild($rule3); $n = new Notification(); $syntax1->probeEquivalence($syntax3, $n); $this->assertFalse($n->isOk()); $this->assertEquals("Names of rule differs: 'rule2' != 'rule3'!", $n->report()); }
/** * Parses the EBNF tokens and returns a syntax tree as DOMDocument object on success. * * On semantic syntax errors a SyntaxtException will be thrown. * * @throws SyntaxtException * @return DOMDocument */ public function parse() { $syntax = $this->dom->createElement(Type::SYNTAX); $this->scanner->nextToken(); if ($this->scanner->currentToken()->isType(Token::LITERAL)) { $syntax->setAttribute('title', $this->scanner->currentToken()->getValue(true)); $this->ast->title = $this->scanner->currentToken()->getValue(true); $this->scanner->nextToken(); } if (!$this->assertToken($this->scanner->currentToken(), Token::OPERATOR, '{')) { $this->raiseError("Syntax must start with '{'"); } $this->scanner->nextToken(); while ($this->scanner->hasNextToken() && $this->scanner->currentToken()->isType(Token::IDENTIFIER)) { $rules = $this->parseRule(); $syntax->appendChild($rules[0]); $this->ast->addChild($rules[1]); $this->scanner->nextToken(); } if (!$this->assertToken($this->scanner->currentToken(), Token::OPERATOR, '}')) { $this->raiseError("Syntax must end with '}' but saw {$this->scanner->currentToken()}"); } $this->scanner->nextToken(); if ($this->scanner->hasNextToken()) { if ($this->scanner->currentToken()->isType(Token::LITERAL)) { $syntax->setAttribute('meta', $this->scanner->currentToken()->getValue(true)); $this->ast->meta = $this->scanner->currentToken()->getValue(true); } else { $this->raiseError("Literal expected as syntax comment"); } } else { $syntax->setAttribute('meta', self::DEFAULT_META); $this->ast->meta = self::DEFAULT_META; } $this->dom->appendChild($syntax); return $this->dom; }
public function testValidateRule() { $syntax = new Syntax(); $syntax->meta = "foo meta"; $syntax->title = "bar title"; $ruleFoo = new Rule($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ruleFoo->name = "foo"; $syntax->addChild($ruleFoo); $ruleBar = new Rule($this->getMock('de\\weltraumschaf\\ebnf\\ast\\Node')); $ruleBar->name = "bar"; $syntax->addChild($ruleBar); $tester = new Validator(); $syntax->accept($tester); $this->assertEquals(array("syntax" => array("meta" => "foo meta", "title" => "bar title", "rule" => array("foo" => array(), "bar" => array()))), $tester->getRepresentative()); }