/** * @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()); }
/** * Parses an EBNF factor: * factor = identifier * | literal * | "[" expression "]" * | "(" expression ")" * | "{" expression "}" . * * @param Node $parent Parent node. * * @throws SyntaxtException * @return DOMElement */ private function parseFactor(Node $parent) { if ($this->scanner->currentToken()->isType(Token::IDENTIFIER)) { $identifier = $this->dom->createElement(Type::IDENTIFIER); $identifier->setAttribute('value', $this->scanner->currentToken()->getValue()); $identifierNode = new Identifier($parent); $identifierNode->value = $this->scanner->currentToken()->getValue(); return array($identifier, $identifierNode); } if ($this->scanner->currentToken()->isType(Token::LITERAL)) { /*if ($this->assertToken($this->scanner->peekToken(), Token::OPERATOR, "::")) { echo "range"; $range = $this->dom->createElement(Type::RANGE); $range->setAttribute("from", $this->scanner->currentToken()->getValue(true)); $this->scanner->nextToken(); // Omit ".." literal. $this->scanner->nextToken(); $range->setAttribute("to", $this->scanner->currentToken()->getValue(true)); return $range; }*/ $literal = $this->dom->createElement(Type::TERMINAL); $literal->setAttribute('value', $this->scanner->currentToken()->getValue(true)); $literalNode = new Terminal($parent); $literalNode->value = $this->scanner->currentToken()->getValue(true); return array($literal, $literalNode); } if ($this->assertToken($this->scanner->currentToken(), Token::OPERATOR, '(')) { $this->scanner->nextToken(); $expression = $this->parseExpression($parent); if (!$this->assertToken($this->scanner->currentToken(), Token::OPERATOR, ')')) { $this->raiseError("Group must end with ')'"); } return $expression; } if ($this->assertToken($this->scanner->currentToken(), Token::OPERATOR, '[')) { $option = $this->dom->createElement(Type::OPTION); $this->scanner->nextToken(); $expression = $this->parseExpression($parent); $option->appendChild($expression[0]); $optionNode = new Option($parent); $optionNode->addChild($expression[1]); if (!$this->assertToken($this->scanner->currentToken(), Token::OPERATOR, ']')) { $this->raiseError("Option must end with ']'"); } return array($option, $optionNode); } if ($this->assertToken($this->scanner->currentToken(), Token::OPERATOR, '{')) { $loop = $this->dom->createElement(Type::LOOP); $this->scanner->nextToken(); $expression = $this->parseExpression($parent); $loop->appendChild($expression[0]); $loopNode = new Loop($parent); $loopNode->addChild($expression[1]); if (!$this->assertToken($this->scanner->currentToken(), Token::OPERATOR, '}')) { $this->raiseError("Loop must end with '}'"); } return array($loop, $loopNode); } $this->raiseError("Factor expected"); }