diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..7944e8e32 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "runtime/PHP"] + path = runtime/PHP + url = https://github.com/antlr/antlr-php-runtime.git diff --git a/.travis.yml b/.travis.yml index 880cf8907..0220f4ca2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -152,6 +152,13 @@ matrix: jdk: openjdk8 env: TARGET=csharp stage: main-test + - os: linux + language: php + php: + - 7.2 + jdk: openjdk8 + env: TARGET=php + stage: main-test - os: linux jdk: openjdk8 dist: trusty diff --git a/.travis/before-install-linux-php.sh b/.travis/before-install-linux-php.sh new file mode 100755 index 000000000..b95e3b31d --- /dev/null +++ b/.travis/before-install-linux-php.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -euo pipefail + +sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF +sudo apt-get update -qq + +php -v + +mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V \ No newline at end of file diff --git a/.travis/run-tests-php.sh b/.travis/run-tests-php.sh new file mode 100755 index 000000000..853efbd86 --- /dev/null +++ b/.travis/run-tests-php.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -euo pipefail + +php_path=$(which php) + +composer install -d ../runtime/PHP + +mvn -q -DPHP_PATH="${php_path}" -Dparallel=methods -DthreadCount=4 -Dtest=php.* test diff --git a/README.md b/README.md index d63bc4f66..ec5c21c62 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ ANTLR project lead and supreme dictator for life * [Janyou](https://github.com/janyou) (Swift target) * [Ewan Mellor](https://github.com/ewanmellor), [Hanzhou Shi](https://github.com/hanjoes) (Swift target merging) * [Ben Hamilton](https://github.com/bhamiltoncx) (Full Unicode support in serialized ATN and all languages' runtimes for code points > U+FFFF) +* [Marcos Passos](https://github.com/marcospassos) (PHP target) ## Useful information diff --git a/appveyor.yml b/appveyor.yml index 266eeebad..d58657c98 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,9 @@ cache: - '%USERPROFILE%\.nuget\packages -> **\project.json' image: Visual Studio 2017 build: off +install: + - git submodule update --init --recursive + - cinst -y php composer build_script: - mvn -DskipTests install --batch-mode - msbuild /target:restore /target:rebuild /property:Configuration=Release /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:detailed runtime/CSharp/runtime/CSharp/Antlr4.dotnet.sln @@ -11,7 +14,7 @@ build_script: after_build: - msbuild /target:pack /property:Configuration=Release /verbosity:detailed runtime/CSharp/runtime/CSharp/Antlr4.dotnet.sln test_script: - - mvn install -Dantlr-python2-python="C:\Python27\python.exe" -Dantlr-python3-python="C:\Python35\python.exe" -Dantlr-javascript-nodejs="C:\Program Files (x86)\nodejs\node.exe" --batch-mode + - mvn install -Dantlr-php-php="C:\tools\php73\php.exe" -Dantlr-python2-python="C:\Python27\python.exe" -Dantlr-python3-python="C:\Python35\python.exe" -Dantlr-javascript-nodejs="C:\Program Files (x86)\nodejs\node.exe" --batch-mode artifacts: - path: 'runtime\**\*.nupkg' name: NuGet \ No newline at end of file diff --git a/contributors.txt b/contributors.txt index f385aeeef..6ff7f398d 100644 --- a/contributors.txt +++ b/contributors.txt @@ -222,4 +222,7 @@ YYYY/MM/DD, github id, Full name, email 2019/07/16, abhijithneilabraham, Abhijith Neil Abraham, abhijithneilabrahampk@gmail.com 2019/07/26, Braavos96, Eric Hettiaratchi, erichettiaratchi@gmail.com 2019/09/10, ImanHosseini, Iman Hosseini, hosseini.iman@yahoo.com -2019/09/03, João Henrique, johnnyonflame@hotmail.com \ No newline at end of file +2019/09/03, João Henrique, johnnyonflame@hotmail.com +2019/09/10, yar3333, Yaroslav Sivakov, yar3333@gmail.com +2019/09/10, marcospassos, Marcos Passos, marcospassos.com@gmail.com +2019/09/10, amorimjuliana, Juliana Amorim, juu.amorim@gmail.com \ No newline at end of file diff --git a/doc/php-target.md b/doc/php-target.md new file mode 100644 index 000000000..75eae465c --- /dev/null +++ b/doc/php-target.md @@ -0,0 +1,111 @@ +# ANTLR4 Runtime for PHP + +### First steps + +#### 1. Install ANTLR4 + +[The getting started guide](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md) +should get you started. + +#### 2. Install the PHP ANTLR runtime + +Each target language for ANTLR has a runtime package for running parser +generated by ANTLR4. The runtime provides a common set of tools for using your parser. + +Install the runtime with Composer: + +```bash +composer install antlr/antlr4 +``` + +#### 3. Generate your parser + +You use the ANTLR4 "tool" to generate a parser. These will reference the ANTLR +runtime, installed above. + +Suppose you're using a UNIX system and have set up an alias for the ANTLR4 tool +as described in [the getting started guide](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md). +To generate your PHP parser, run the following command: + +```bash +antlr4 -Dlanguage=PHP MyGrammar.g4 +``` + +For a full list of antlr4 tool options, please visit the +[tool documentation page](https://github.com/antlr/antlr4/blob/master/doc/tool-options.md). + +### Complete example + +Suppose you're using the JSON grammar from https://github.com/antlr/grammars-v4/tree/master/json. + +Then, invoke `antlr4 -Dlanguage=PHP JSON.g4`. The result of this is a +collection of `.php` files in the `parser` directory including: +``` +JsonParser.php +JsonBaseListener.php +JsonLexer.php +JsonListener.php +``` + +Another common option to the ANTLR tool is `-visitor`, which generates a parse +tree visitor, but we won't be doing that here. For a full list of antlr4 tool +options, please visit the [tool documentation page](tool-options.md). + +We'll write a small main func to call the generated parser/lexer +(assuming they are separate). This one writes out the encountered +`ParseTreeContext`'s: + +```php +getText(); + } +} + +$input = InputStream::fromPath($argv[1]); +$lexer = new JSONLexer($input); +$tokens = new CommonTokenStream($lexer); +$parser = new JSONParser($tokens); +$parser->addErrorListener(new DiagnosticErrorListener()); +$parser->setBuildParseTree(true); +$tree = $parser->json(); + +ParseTreeWalker::default()->walk(new TreeShapeListener(), $tree); +``` + +Create a `example.json` file: +```json +{"a":1} +``` + +Parse the input file: + +``` +php json.php example.json +``` + +The expected output is: + +``` +{"a":1} +{"a":1} +"a":1 +1 +``` \ No newline at end of file diff --git a/doc/targets.md b/doc/targets.md index 418630bb1..c2341ec48 100644 --- a/doc/targets.md +++ b/doc/targets.md @@ -9,12 +9,13 @@ This page lists the available and upcoming ANTLR runtimes. Please note that you * [Go](go-target.md) * [C++](cpp-target.md) * [Swift](swift-target.md) +* [PHP](php-target.md) ## Target feature parity New features generally appear in the Java target and then migrate to the other targets, but these other targets don't always get updated in the same overall tool release. This section tries to identify features added to Java that have not been added to the other targets. -|Feature|Java|C♯|Python2|Python3|JavaScript|Go|C++|Swift| -|---|---|---|---|---|---|---|---|---| -|Ambiguous tree construction|4.5.1|-|-|-|-|-|-|-| +|Feature|Java|C♯|Python2|Python3|JavaScript|Go|C++|Swift|PHP +|---|---|---|---|---|---|---|---|---|---| +|Ambiguous tree construction|4.5.1|-|-|-|-|-|-|-|-| diff --git a/runtime-testsuite/pom.xml b/runtime-testsuite/pom.xml index ebfdbd723..b9e6bd936 100644 --- a/runtime-testsuite/pom.xml +++ b/runtime-testsuite/pom.xml @@ -109,14 +109,15 @@ -Dfile.encoding=UTF-8 - **/csharp/Test*.java - **/java/Test*.java - **/go/Test*.java - **/javascript/node/Test*.java - **/python2/Test*.java - **/python3/Test*.java - ${antlr.tests.swift} - + **/csharp/Test*.java + **/java/Test*.java + **/go/Test*.java + **/javascript/node/Test*.java + **/python2/Test*.java + **/python3/Test*.java + **/php/Test*.java + ${antlr.tests.swift} + diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/CSharp.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/CSharp.test.stg index 597248f2b..fb95440ce 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/CSharp.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/CSharp.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "(())" Append(a,b) ::= " + " +AppendStr(a,b) ::= <%%> + Concat(a,b) ::= "" DeclareLocal(s,v) ::= "Object = ;" @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <%int = ;%> InitBooleanMember(n,v) ::= <%bool = ;%> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "int " + +VarRef(n) ::= "" + GetMember(n) ::= <%this.%> SetMember(n,v) ::= <%this. = ;%> @@ -94,6 +102,8 @@ bool Property() { ParserPropertyCall(p, call) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << PositionAdjustingLexer.prototype.resetAcceptPosition = function(index, line, column) { diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Firefox.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Firefox.test.stg index c94be90e8..c8a6c1d57 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Firefox.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Firefox.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "" Append(a,b) ::= " + " +AppendStr(a,b) ::= <%%> + Concat(a,b) ::= "" DeclareLocal(s,v) ::= "var = ;" @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <%this. = ;%> InitBooleanMember(n,v) ::= <%this. = ;%> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "" + +VarRef(n) ::= "" + GetMember(n) ::= <%this.%> SetMember(n,v) ::= <%this. = ;%> @@ -100,6 +108,8 @@ this.Property = function() { ParserPropertyCall(p, call) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << PositionAdjustingLexer.prototype.resetAcceptPosition = function(index, line, column) { diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Go.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Go.test.stg index 37fe63441..b2909f4e1 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Go.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Go.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "()" Append(a,b) ::= " + fmt.Sprint()" +AppendStr(a,b) ::= " + " + Concat(a,b) ::= "" DeclareLocal(s, v) ::= "var = " @@ -26,6 +28,12 @@ InitIntMember(n, v) ::= <%var int = ; var _ int = ; %> InitBooleanMember(n, v) ::= <%var bool = ; var _ bool = ; %> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "int " + +VarRef(n) ::= "" + GetMember(n) ::= <%%> SetMember(n, v) ::= <% = ;%> @@ -94,6 +102,8 @@ func (p *TParser) Property() bool { ParserPropertyCall(p, call) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << func (p *PositionAdjustingLexer) NextToken() antlr.Token { if _, ok := p.Interpreter.(*PositionAdjustingLexerATNSimulator); !ok { diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Java.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Java.test.stg index 5012aa213..11f159743 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Java.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Java.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "(())" Append(a,b) ::= " + " +AppendStr(a,b) ::= <%%> + Concat(a,b) ::= "" DeclareLocal(s,v) ::= "Object = ;" @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <%int = ;%> InitBooleanMember(n,v) ::= <%boolean = ;%> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "int " + +VarRef(n) ::= "" + GetMember(n) ::= <%this.%> SetMember(n,v) ::= <%this. = ;%> @@ -94,6 +102,8 @@ boolean Property() { ParserPropertyCall(p, call) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << @Override diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Node.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Node.test.stg index 92cb1dbbb..81573d6c0 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Node.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Node.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "" Append(a,b) ::= " + " +AppendStr(a,b) ::= <%%> + Concat(a,b) ::= "" DeclareLocal(s,v) ::= "var = ;" @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <%this. = ;%> InitBooleanMember(n,v) ::= <%this. = ;%> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "" + +VarRef(n) ::= "" + GetMember(n) ::= <%this.%> SetMember(n,v) ::= <%this. = ;%> @@ -98,6 +106,8 @@ this.Property = function() { ParserPropertyCall(p, call) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << PositionAdjustingLexer.prototype.resetAcceptPosition = function(index, line, column) { diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/PHP.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/PHP.test.stg new file mode 100644 index 000000000..a2ea87466 --- /dev/null +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/PHP.test.stg @@ -0,0 +1,272 @@ +writeln(s) ::= < . \PHP_EOL;>> +write(s) ::= <;>> +writeList(s) ::= <;>> + +False() ::= "false" +True() ::= "true" +Not(v) ::= "!" +Assert(s) ::= <);>> +Cast(t,v) ::= "" +Append(a,b) ::= " . " +AppendStr(a,b) ::= <%%> +Concat(a,b) ::= "" + +DeclareLocal(s,v) ::= " = ;" + +AssertIsList(v) ::= "assert(\is_array());" // just use static type system +AssignLocal(s,v) ::= " = ;" + +InitIntMember(n,v) ::= <%public \$ = ;%> +InitBooleanMember(n,v) ::= <%public \$ = ;%> +InitIntVar(n,v) ::= <%\$ = ;%> +IntArg(n) ::= "int " +VarRef(n) ::= "$" + +GetMember(n) ::= <%\$this->%> +SetMember(n,v) ::= <%\$this-> = ;%> +AddMember(n,v) ::= <%\$this-> += ;%> +PlusMember(v,n) ::= <% + \$this->%> +MemberEquals(n,v) ::= <%\$this-> == %> +ModMemberEquals(n,m,v) ::= <%\$this-> % == %> +ModMemberNotEquals(n,m,v) ::= <%\$this-> % !== %> + +DumpDFA() ::= "\$this->dumpDFA();" +Pass() ::= "" + +StringList() ::= "" +BuildParseTrees() ::= "\$this->setBuildParseTree(true);" +BailErrorStrategy() ::= <%\$this->setErrorHandler(new Antlr\\Antlr4\\Runtime\\Error\\BailErrorStrategy());%> + +ToStringTree(s) ::= <%->toStringTree(\$this->getRuleNames())%> +Column() ::= "\$this->getCharPositionInLine()" +Text() ::= "\$this->getText()" +ValEquals(a,b) ::= <%===%> +TextEquals(a) ::= <%\$this->getText() === ""%> +PlusText(a) ::= <%"" . \$this->getText()%> +InputText() ::= "\$this->input->getText()" +LTEquals(i, v) ::= <%\$this->input->LT()->getText() === %> +LANotEquals(i, v) ::= <%\$this->input->LA() !== %> +TokenStartColumnEquals(i) ::= <%\$this->tokenStartCharPositionInLine === %> + +ImportListener(X) ::= "" + +GetExpectedTokenNames() ::= "\$this->getExpectedTokens()->toStringVocabulary(\$this->getVocabulary())" + +RuleInvocationStack() ::= "'[' . \implode(', ', \$this->getRuleInvocationStack()) . ']'" + +LL_EXACT_AMBIG_DETECTION() ::= <<\$this->interp->setPredictionMode(Antlr\\Antlr4\\Runtime\\Atn\\PredictionMode::LL_EXACT_AMBIG_DETECTION);>> + + +ParserToken(parser, token) ::= <%::%> + +Production(p) ::= <%

%> + +Result(r) ::= <%%> + +ParserPropertyMember() ::= << +@members { +public function Property() : bool +{ + return true; +} +} +>> + +ParserPropertyCall(p, call) ::= "

->" + +PositionAdjustingLexerDef() ::= << +class PositionAdjustingLexerATNSimulator extends LexerATNSimulator { + public function resetAcceptPosition(CharStream \$input, int \$index, int \$line, int \$charPositionInLine) : void { + \$input->seek(\$index); + \$this->line = \$line; + \$this->charPositionInLine = \$charPositionInLine; + \$this->consume(\$input); + } +} +>> + +PositionAdjustingLexer() ::= << +public function nextToken() : Antlr\\Antlr4\\Runtime\\Token +{ + if (!\$this->interp instanceof PositionAdjustingLexerATNSimulator) { + \$this->interp = new PositionAdjustingLexerATNSimulator(\$this, self::\$atn, self::\$decisionToDFA, self::\$sharedContextCache); + } + + return parent::nextToken(); +} + +public function emit() : Antlr\\Antlr4\\Runtime\\Token +{ + switch (\$this->type) { + case self::TOKENS: + \$this->handleAcceptPositionForKeyword('tokens'); + break; + + case self::LABEL: + \$this->handleAcceptPositionForIdentifier(); + break; + } + + return parent::emit(); +} + +private function handleAcceptPositionForIdentifier() : bool +{ + \$tokenText = \$this->getText(); + \$identifierLength = 0; + while (\$identifierLength \< \strlen(\$tokenText) && self::isIdentifierChar(\$tokenText[\$identifierLength])) { + \$identifierLength++; + } + + if (\$this->getInputStream()->getIndex() > \$this->tokenStartCharIndex + \$identifierLength) { + \$offset = \$identifierLength - 1; + \$this->getInterpreter()->resetAcceptPosition(\$this->getInputStream(), \$this->tokenStartCharIndex + \$offset, \$this->tokenStartLine, \$this->tokenStartCharPositionInLine + \$offset); + + return true; + } + + return false; +} + +private function handleAcceptPositionForKeyword(string \$keyword) : bool +{ + if (\$this->getInputStream()->getIndex() > \$this->tokenStartCharIndex + \strlen(\$keyword)) { + \$offset = \strlen(\$keyword) - 1; + \$this->getInterpreter()->resetAcceptPosition(\$this->getInputStream(), \$this->tokenStartCharIndex + \$offset, \$this->tokenStartLine, \$this->tokenStartCharPositionInLine + \$offset); + + return true; + } + + return false; +} + +private static function isIdentifierChar(string \$c) : bool +{ + return \ctype_alnum(\$c) || \$c === '_'; +} +>> + +BasicListener(X) ::= << +@parser::definitions { +class LeafListener extends TBaseListener +{ + public function visitTerminal(Antlr\\Antlr4\\Runtime\\Tree\\TerminalNode \$node) : void + { + echo \$node->getSymbol()->getText() . \PHP_EOL; + } +} +} +>> + +WalkListener(s) ::= << +\$walker = new Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeWalker(); +\$walker->walk(new LeafListener(), ); +>> + +TreeNodeWithAltNumField(X) ::= << +@parser::contexts { +class MyRuleNode extends ParserRuleContext +{ + public \$altNum; + + public function getAltNumber() : int + { + return \$this->altNum; + } + + public function setAltNumber(int \$altNum) : void + { + \$this->altNum = \$altNum; + } +} +} +>> + +TokenGetterListener(X) ::= << +@parser::definitions { +class LeafListener extends TBaseListener { + public function exitA(Context\\AContext \$ctx) : void { + if (\$ctx->getChildCount() === 2) { + echo \sprintf('%s %s [%s]',\$ctx->INT(0)->getSymbol()->getText(), \$ctx->INT(1)->getSymbol()->getText(), \implode(', ', \$ctx->INT())) . \PHP_EOL; + } else { + echo \$ctx->ID()->getSymbol() . \PHP_EOL; + } + } +} +} +>> + +RuleGetterListener(X) ::= << +@parser::definitions { +class LeafListener extends TBaseListener { + public function exitA(Context\\AContext \$ctx) : void + { + if (\$ctx->getChildCount() === 2) { + echo \sprintf('%s %s %s', \$ctx->b(0)->start->getText(), \$ctx->b(1)->start->getText(),\$ctx->b()[0]->start->getText()) . \PHP_EOL; + } else { + echo \$ctx->b(0)->start->getText() . \PHP_EOL; + } + } +} +} +>> + + +LRListener(X) ::= << +@parser::definitions { +class LeafListener extends TBaseListener { + public function exitE(Context\\EContext \$ctx) : void + { + if (\$ctx->getChildCount() === 3) { + echo \sprintf('%s %s %s', \$ctx->e(0)->start->getText(), \$ctx->e(1)->start->getText(), \$ctx->e()[0]->start->getText()) . \PHP_EOL; + } else { + echo \$ctx->INT()->getSymbol()->getText() . \PHP_EOL; + } + } +} +} +>> + +LRWithLabelsListener(X) ::= << +@parser::definitions { +class LeafListener extends TBaseListener +{ + public function exitCall(Context\\CallContext \$ctx) : void { + echo \sprintf('%s %s',\$ctx->e()->start->getText(),\$ctx->eList()) . \PHP_EOL; + } + + public function exitInt(Context\\IntContext \$ctx) : void { + echo \$ctx->INT()->getSymbol()->getText() . \PHP_EOL; + } +} +} +>> + +DeclareContextListGettersFunction() ::= << +public function foo() : void { + \$s = null; + \$a = \$s->a(); + \$b = \$s->b(); +} +>> + +Declare_foo() ::= << +public function foo() : void { + echo 'foo' . \PHP_EOL; +} +>> + +Invoke_foo() ::= "\$this->foo();" + +Declare_pred() ::= <pred()" + +ParserTokenType(t) ::= "Parser::" +ContextRuleFunction(ctx, rule) ::= "->" +StringType() ::= "" +ContextMember(ctx, subctx, member) ::= "->->" diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Python2.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Python2.test.stg index cc0d9d9c2..3102f4120 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Python2.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Python2.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "" Append(a,b) ::= " + str()" +AppendStr(a,b) ::= " + " + Concat(a,b) ::= "" DeclareLocal(s,v) ::= " = " @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <% = %> InitBooleanMember(n,v) ::= <% = %> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "" + +VarRef(n) ::= "" + GetMember(n) ::= <%self.%> SetMember(n,v) ::= <%self. = %> @@ -94,6 +102,8 @@ def Property(self): ParserPropertyCall(p, call) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << def resetAcceptPosition(self, index, line, column): diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Python3.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Python3.test.stg index c91563017..858b76113 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Python3.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Python3.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "" Append(a,b) ::= " + str()" +AppendStr(a,b) ::= " + " + Concat(a,b) ::= "" DeclareLocal(s,v) ::= " = " @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <% = %> InitBooleanMember(n,v) ::= <% = %> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "" + +VarRef(n) ::= "" + GetMember(n) ::= <%self.%> SetMember(n,v) ::= <%self. = %> @@ -99,6 +107,8 @@ def Property(self): ParserPropertyCall(p, call) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << def resetAcceptPosition(self, index, line, column): diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Safari.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Safari.test.stg index 71254e0f2..2a09970c2 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Safari.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Safari.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "" Append(a,b) ::= " + " +AppendStr(a,b) ::= <%%> + Concat(a,b) ::= "" DeclareLocal(s,v) ::= "var = ;" @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <%this. = ;%> InitBooleanMember(n,v) ::= <%this. = ;%> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "" + +VarRef(n) ::= "" + GetMember(n) ::= <%this.%> SetMember(n,v) ::= <%this. = ;%> @@ -98,6 +106,8 @@ this.Property = function() { ParserPropertyCall(p, call) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << PositionAdjustingLexer.prototype.resetAcceptPosition = function(index, line, column) { diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Swift.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Swift.test.stg index 100d6f3e7..d45168517 100755 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Swift.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Swift.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "(( as! ))" Append(a,b) ::= " + " +AppendStr(a,b) ::= <%%> + Concat(a,b) ::= "" DeclareLocal(s,v) ::= "var = " @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <%var = %> InitBooleanMember(n,v) ::= <%var = %> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "int " + +VarRef(n) ::= "" + GetMember(n) ::= <%self.%> SetMember(n,v) ::= <%self. = %> @@ -96,6 +104,8 @@ ParserPropertyCall(parser, property) ::= << . >> +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << override diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/BaseRuntimeTest.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/BaseRuntimeTest.java index 71cd1e34d..f7874d671 100644 --- a/runtime-testsuite/test/org/antlr/v4/test/runtime/BaseRuntimeTest.java +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/BaseRuntimeTest.java @@ -50,6 +50,7 @@ public abstract class BaseRuntimeTest { "Go", "CSharp", "Python2", "Python3", + "PHP", "Node", "Safari", "Firefox", "Explorer", "Chrome" }; public final static String[] JavaScriptTargets = { @@ -116,6 +117,7 @@ public abstract class BaseRuntimeTest { System.out.printf("Ignore "+descriptor); return; } + if ( descriptor.getTestType().contains("Parser") ) { testParser(descriptor); } diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/CompositeParsersDescriptors.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/CompositeParsersDescriptors.java index 435dcc977..6134b265b 100644 --- a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/CompositeParsersDescriptors.java +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/CompositeParsersDescriptors.java @@ -418,7 +418,7 @@ public class CompositeParsersDescriptors { parser grammar S; type_ : 'int' ; decl : type_ ID ';' - | type_ ID init_ ';' {}; + | type_ ID init_ ';' {}; init_ : '=' INT; */ @CommentHasStringValue @@ -532,7 +532,7 @@ public class CompositeParsersDescriptors { /** parser grammar S; - a @after {} : B; + a @after {} : B; */ @CommentHasStringValue public String slaveGrammarS; diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/FullContextParsingDescriptors.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/FullContextParsingDescriptors.java index 942d07be5..fb71b3863 100644 --- a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/FullContextParsingDescriptors.java +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/FullContextParsingDescriptors.java @@ -372,7 +372,7 @@ public class FullContextParsingDescriptors { : expr_or_assign*; expr_or_assign : expr '++' {} - | expr {} + | expr {} ; expr: expr_primary ('\<-' ID)?; expr_primary diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/LeftRecursionDescriptors.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/LeftRecursionDescriptors.java index 66dd5760d..01e868d6e 100644 --- a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/LeftRecursionDescriptors.java +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/LeftRecursionDescriptors.java @@ -529,8 +529,8 @@ public class LeftRecursionDescriptors { | e '+' e {$v = (0)}, {})> + (1)}, {})>;} # binary | INT {$v = $INT.int;} # anInt | '(' e ')' {$v = $e.v;} # parens - | left=e INC {$v = $left.v + 1;} # unary - | left=e DEC {$v = $left.v - 1;} # unary + | left=e INC {$v = $left.v + 1;} # unary + | left=e DEC {$v = $left.v - 1;} # unary | ID {} # anID ; ID : 'a'..'z'+ ; @@ -636,9 +636,9 @@ public class LeftRecursionDescriptors { grammar T; s : e {} ; e returns [ result] - : ID '=' e1=e {$result = "(" + $ID.text + "=" + $e1.result + ")";} + : ID '=' e1=e {$result = ;} | ID {$result = $ID.text;} - | e1=e '+' e2=e {$result = "(" + $e1.result + "+" + $e2.result + ")";} + | e1=e '+' e2=e {$result = ;} ; ID : 'a'..'z'+ ; INT : '0'..'9'+ ; diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/LexerExecDescriptors.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/LexerExecDescriptors.java index 60cb86cb4..7c74e74cb 100644 --- a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/LexerExecDescriptors.java +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/LexerExecDescriptors.java @@ -766,6 +766,10 @@ public class LexerExecDescriptors { /** lexer grammar PositionAdjustingLexer; + @definitions { + + } + @members { } diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/SemPredEvalParserDescriptors.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/SemPredEvalParserDescriptors.java index ed4f9a384..b09f07488 100644 --- a/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/SemPredEvalParserDescriptors.java +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/descriptors/SemPredEvalParserDescriptors.java @@ -144,8 +144,8 @@ public class SemPredEvalParserDescriptors { /** grammar T; s : b[2] ';' | b[2] '.' ; // decision in s drills down to ctx-dependent pred in a; - b[int i] : a[i] ; - a[int i] + b[] : a[] ; + a[] : {}? ID {} | {}? ID {} ; @@ -310,7 +310,7 @@ public class SemPredEvalParserDescriptors { grammar T; @parser::members {} primary - : ID {} + : ID {} | {}? 'enum' {} ; ID : [a-z]+ ; diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/BasePHPTest.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/BasePHPTest.java new file mode 100644 index 000000000..8f2cc5bcc --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/BasePHPTest.java @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.antlr.v4.Tool; +import org.antlr.v4.automata.LexerATNFactory; +import org.antlr.v4.automata.ParserATNFactory; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.ATNSerializer; +import org.antlr.v4.semantics.SemanticPipeline; +import org.antlr.v4.test.runtime.ErrorQueue; +import org.antlr.v4.test.runtime.RuntimeTestSupport; +import org.antlr.v4.test.runtime.StreamVacuum; +import org.antlr.v4.tool.Grammar; +import org.antlr.v4.tool.LexerGrammar; +import org.stringtemplate.v4.ST; + +import static org.antlr.v4.test.runtime.BaseRuntimeTest.antlrOnString; +import static org.antlr.v4.test.runtime.BaseRuntimeTest.writeFile; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class BasePHPTest implements RuntimeTestSupport { + public static final String newline = System.getProperty("line.separator"); + + public String tmpdir = null; + + /** + * If error during parser execution, store stderr here; can't return + * stdout and stderr. This doesn't trap errors from running antlr. + */ + protected String stderrDuringParse; + + /** + * Errors found while running antlr + */ + protected StringBuilder antlrToolErrors; + + private String getPropertyPrefix() { + return "antlr-php"; + } + + @Override + public void testSetUp() throws Exception { + // new output dir for each test + String propName = getPropertyPrefix() + "-test-dir"; + String prop = System.getProperty(propName); + + if (prop != null && prop.length() > 0) { + tmpdir = prop; + } else { + String classSimpleName = getClass().getSimpleName(); + String threadName = Thread.currentThread().getName(); + String childPath = String.format("%s-%s-%s", classSimpleName, threadName, System.currentTimeMillis()); + tmpdir = new File(System.getProperty("java.io.tmpdir"), childPath).getAbsolutePath(); + } + + antlrToolErrors = new StringBuilder(); + } + + @Override + public void testTearDown() throws Exception { + } + + @Override + public String getTmpDir() { + return tmpdir; + } + + @Override + public String getStdout() { + return null; + } + + @Override + public String getParseErrors() { + return stderrDuringParse; + } + + @Override + public String getANTLRToolErrors() { + if (antlrToolErrors.length() == 0) { + return null; + } + + return antlrToolErrors.toString(); + } + + protected ATN createATN(Grammar g, boolean useSerializer) { + if (g.atn == null) { + semanticProcess(g); + + assertEquals(0, g.tool.getNumErrors()); + + ParserATNFactory f; + + if (g.isLexer()) { + f = new LexerATNFactory((LexerGrammar) g); + } else { + f = new ParserATNFactory(g); + } + + g.atn = f.createATN(); + assertEquals(0, g.tool.getNumErrors()); + } + + ATN atn = g.atn; + + if (useSerializer) { + char[] serialized = ATNSerializer.getSerializedAsChars(atn); + + return new ATNDeserializer().deserialize(serialized); + } + + return atn; + } + + protected void semanticProcess(Grammar g) { + if (g.ast != null && !g.ast.hasErrors) { + Tool antlr = new Tool(); + SemanticPipeline sem = new SemanticPipeline(g); + sem.process(); + + if (g.getImportedGrammars() != null) { + for (Grammar imp: g.getImportedGrammars()) { + antlr.processNonCombinedGrammar(imp, false); + } + } + } + } + + protected String execLexer( + String grammarFileName, + String grammarStr, + String lexerName, + String input + ) { + return execLexer(grammarFileName, grammarStr, lexerName, input, false); + } + + @Override + public String execLexer( + String grammarFileName, + String grammarStr, + String lexerName, + String input, + boolean showDFA + ) { + boolean success = rawGenerateAndBuildRecognizer( + grammarFileName, + grammarStr, + null, + lexerName, + "-no-listener" + ); + assertTrue(success); + writeFile(tmpdir, "input", input); + writeLexerTestFile(lexerName, showDFA); + String output = execModule("Test.php"); + + return output; + } + + public String execParser( + String grammarFileName, + String grammarStr, + String parserName, + String lexerName, + String listenerName, + String visitorName, + String startRuleName, + String input, + boolean showDiagnosticErrors + ) { + return execParser_( + grammarFileName, + grammarStr, + parserName, + lexerName, + listenerName, + visitorName, + startRuleName, + input, + showDiagnosticErrors, + false + ); + } + + public String execParser_( + String grammarFileName, + String grammarStr, + String parserName, + String lexerName, + String listenerName, + String visitorName, + String startRuleName, + String input, + boolean debug, + boolean trace + ) { + boolean success = rawGenerateAndBuildRecognizer( + grammarFileName, + grammarStr, + parserName, + lexerName, + "-visitor" + ); + + assertTrue(success); + + writeFile(tmpdir, "input", input); + + rawBuildRecognizerTestFile( + parserName, + lexerName, + listenerName, + visitorName, + startRuleName, + debug, + trace + ); + + return execRecognizer(); + } + + /** + * Return true if all is well + */ + protected boolean rawGenerateAndBuildRecognizer( + String grammarFileName, + String grammarStr, + String parserName, + String lexerName, + String... extraOptions + ) { + return rawGenerateAndBuildRecognizer( + grammarFileName, + grammarStr, + parserName, + lexerName, + false, + extraOptions + ); + } + + /** + * Return true if all is well + */ + protected boolean rawGenerateAndBuildRecognizer( + String grammarFileName, + String grammarStr, + String parserName, + String lexerName, + boolean defaultListener, + String... extraOptions + ) { + ErrorQueue equeue = antlrOnString(getTmpDir(), "PHP", grammarFileName, grammarStr, defaultListener, extraOptions); + + if (!equeue.errors.isEmpty()) { + return false; + } + + List files = new ArrayList(); + + if (lexerName != null) { + files.add(lexerName + ".php"); + } + + if (parserName != null) { + files.add(parserName + ".php"); + Set optionsSet = new HashSet(Arrays.asList(extraOptions)); + + if (!optionsSet.contains("-no-listener")) { + files.add(grammarFileName.substring(0, grammarFileName.lastIndexOf('.')) + "Listener.php"); + } + + if (optionsSet.contains("-visitor")) { + files.add(grammarFileName.substring(0, grammarFileName.lastIndexOf('.')) + "Visitor.php"); + } + } + + return true; + } + + protected void rawBuildRecognizerTestFile( + String parserName, + String lexerName, + String listenerName, + String visitorName, + String parserStartRuleName, + boolean debug, + boolean trace + ) { + this.stderrDuringParse = null; + if (parserName == null) { + writeLexerTestFile(lexerName, false); + } else { + writeParserTestFile( + parserName, + lexerName, + listenerName, + visitorName, + parserStartRuleName, + debug, + trace + ); + } + } + + public String execRecognizer() { + return execModule("Test.php"); + } + + public String execModule(String fileName) { + String phpPath = locatePhp(); + String runtimePath = locateRuntime(); + + File tmpdirFile = new File(tmpdir); + String modulePath = new File(tmpdirFile, fileName).getAbsolutePath(); + String inputPath = new File(tmpdirFile, "input").getAbsolutePath(); + Path outputPath = tmpdirFile.toPath().resolve("output").toAbsolutePath(); + + try { + ProcessBuilder builder = new ProcessBuilder(phpPath, modulePath, inputPath, outputPath.toString()); + builder.environment().put("RUNTIME", runtimePath); + builder.directory(tmpdirFile); + Process process = builder.start(); + StreamVacuum stdoutVacuum = new StreamVacuum(process.getInputStream()); + StreamVacuum stderrVacuum = new StreamVacuum(process.getErrorStream()); + stdoutVacuum.start(); + stderrVacuum.start(); + process.waitFor(); + stdoutVacuum.join(); + stderrVacuum.join(); + String output = stdoutVacuum.toString(); + + if (output.length() == 0) { + output = null; + } + + if (stderrVacuum.toString().length() > 0) { + this.stderrDuringParse = stderrVacuum.toString(); + } + + return output; + } catch (Exception e) { + System.err.println("can't exec recognizer"); + e.printStackTrace(System.err); + } + return null; + } + + private String locateTool(String tool) { + final String phpPath = System.getProperty("PHP_PATH"); + + if (phpPath != null && new File(phpPath).exists()) { + return phpPath; + } + + String[] roots = {"/usr/local/bin/", "/opt/local/bin", "/usr/bin/"}; + + for (String root: roots) { + if (new File(root + tool).exists()) { + return root + tool; + } + } + + throw new RuntimeException("Could not locate " + tool); + } + + protected String locatePhp() { + String propName = getPropertyPrefix() + "-php"; + String prop = System.getProperty(propName); + + if (prop == null || prop.length() == 0) { + prop = locateTool("php"); + } + + File file = new File(prop); + + if (!file.exists()) { + throw new RuntimeException("Missing system property:" + propName); + } + + return file.getAbsolutePath(); + } + + protected String locateRuntime() { + String propName = "antlr-php-runtime"; + String prop = System.getProperty(propName); + + if (prop == null || prop.length() == 0) { + prop = "../runtime/PHP"; + } + + File file = new File(prop); + + if (!file.exists()) { + throw new RuntimeException("Missing system property:" + propName); + } + + try { + return file.getCanonicalPath(); + } catch (IOException e) { + return file.getAbsolutePath(); + } + } + + protected void mkdir(String dir) { + File f = new File(dir); + f.mkdirs(); + } + + protected void writeLexerTestFile(String lexerName, boolean showDFA) { + ST outputFileST = new ST( + "\\($input);\n" + + "$lexer->addErrorListener(new ConsoleErrorListener());" + + "$tokens = new CommonTokenStream($lexer);\n" + + "$tokens->fill();\n" + + "\n" + + "foreach ($tokens->getAllTokens() as $token) {\n" + + " echo $token . \\PHP_EOL;\n" + + "}" + + (showDFA + ? "echo $lexer->getInterpreter()->getDFA(Lexer::DEFAULT_MODE)->toLexerString();\n" + : "") + ); + + outputFileST.add("lexerName", lexerName); + + writeFile(tmpdir, "Test.php", outputFileST.render()); + } + + protected void writeParserTestFile( + String parserName, String lexerName, + String listenerName, String visitorName, + String parserStartRuleName, boolean debug, boolean trace + ) { + if (!parserStartRuleName.endsWith(")")) { + parserStartRuleName += "()"; + } + ST outputFileST = new ST( + "\\getChildCount(); $i \\< $count; $i++) {\n" + + " $parent = $ctx->getChild($i)->getParent();\n" + + "\n" + + " if (!($parent instanceof RuleNode) || $parent->getRuleContext() !== $ctx) {\n" + + " throw new RuntimeException('Invalid parse tree shape detected.');\n" + + " }\n" + + " }\n" + + " }\n" + + "}" + + "\n" + + "$input = InputStream::fromPath($argv[1]);\n" + + "$lexer = new ($input);\n" + + "$lexer->addErrorListener(new ConsoleErrorListener());" + + "$tokens = new CommonTokenStream($lexer);\n" + + "" + + "$parser->addErrorListener(new ConsoleErrorListener());" + + "$parser->setBuildParseTree(true);\n" + + "$tree = $parser->;\n\n" + + "ParseTreeWalker::default()->walk(new TreeShapeListener(), $tree);\n" + ); + + String stSource = "$parser = new ($tokens);\n"; + + if (debug) { + stSource += "$parser->addErrorListener(new DiagnosticErrorListener());\n"; + } + + if (trace) { + stSource += "$parser->setTrace(true);\n"; + } + + ST createParserST = new ST(stSource); + outputFileST.add("createParser", createParserST); + outputFileST.add("parserName", parserName); + outputFileST.add("lexerName", lexerName); + outputFileST.add("listenerName", listenerName); + outputFileST.add("visitorName", visitorName); + outputFileST.add("parserStartRuleName", parserStartRuleName); + + writeFile(tmpdir, "Test.php", outputFileST.render()); + } + + protected void eraseFiles(File dir) { + String[] files = dir.list(); + for (int i = 0; files != null && i < files.length; i++) { + new File(dir, files[i]).delete(); + } + } + + @Override + public void eraseTempDir() { + boolean doErase = true; + String propName = getPropertyPrefix() + "-erase-test-dir"; + String prop = System.getProperty(propName); + if (prop != null && prop.length() > 0) { + doErase = Boolean.getBoolean(prop); + } + if (doErase) { + File tmpdirF = new File(tmpdir); + if (tmpdirF.exists()) { + eraseFiles(tmpdirF); + tmpdirF.delete(); + } + } + } + + /** + * Sort a list + */ + public > List sort(List data) { + List dup = new ArrayList(); + dup.addAll(data); + Collections.sort(dup); + return dup; + } + + /** + * Return map sorted by key + */ + public , V> LinkedHashMap sort(Map data) { + LinkedHashMap dup = new LinkedHashMap(); + List keys = new ArrayList(); + keys.addAll(data.keySet()); + Collections.sort(keys); + for (K k: keys) { + dup.put(k, data.get(k)); + } + return dup; + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestCompositeLexers.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestCompositeLexers.java new file mode 100644 index 000000000..d1d353875 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestCompositeLexers.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.CompositeLexersDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestCompositeLexers extends BaseRuntimeTest { + public TestCompositeLexers(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(CompositeLexersDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestCompositeParsers.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestCompositeParsers.java new file mode 100644 index 000000000..dd5b0015a --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestCompositeParsers.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.CompositeParsersDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestCompositeParsers extends BaseRuntimeTest { + public TestCompositeParsers(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(CompositeParsersDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestFullContextParsing.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestFullContextParsing.java new file mode 100644 index 000000000..60efc0718 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestFullContextParsing.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.FullContextParsingDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestFullContextParsing extends BaseRuntimeTest { + public TestFullContextParsing(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(FullContextParsingDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLeftRecursion.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLeftRecursion.java new file mode 100644 index 000000000..cb200ef38 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLeftRecursion.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.LeftRecursionDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestLeftRecursion extends BaseRuntimeTest { + public TestLeftRecursion(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(LeftRecursionDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLexerErrors.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLexerErrors.java new file mode 100644 index 000000000..cd7a5c596 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLexerErrors.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.LexerErrorsDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestLexerErrors extends BaseRuntimeTest { + public TestLexerErrors(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(LexerErrorsDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLexerExec.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLexerExec.java new file mode 100644 index 000000000..03595f564 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestLexerExec.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.LexerExecDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestLexerExec extends BaseRuntimeTest { + public TestLexerExec(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(LexerExecDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestListeners.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestListeners.java new file mode 100644 index 000000000..52260158d --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestListeners.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.ListenersDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestListeners extends BaseRuntimeTest { + public TestListeners(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(ListenersDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParseTrees.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParseTrees.java new file mode 100644 index 000000000..656e14d71 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParseTrees.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.ParseTreesDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestParseTrees extends BaseRuntimeTest { + public TestParseTrees(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(ParseTreesDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParserErrors.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParserErrors.java new file mode 100644 index 000000000..ac3ab88ef --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParserErrors.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.ParserErrorsDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestParserErrors extends BaseRuntimeTest { + public TestParserErrors(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(ParserErrorsDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParserExec.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParserExec.java new file mode 100644 index 000000000..01e3f321c --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestParserExec.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.ParserExecDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestParserExec extends BaseRuntimeTest { + public TestParserExec(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(ParserExecDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestPerformance.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestPerformance.java new file mode 100644 index 000000000..7459d77d8 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestPerformance.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.PerformanceDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestPerformance extends BaseRuntimeTest { + public TestPerformance(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(PerformanceDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSemPredEvalLexer.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSemPredEvalLexer.java new file mode 100644 index 000000000..ec7f14efc --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSemPredEvalLexer.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.SemPredEvalLexerDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestSemPredEvalLexer extends BaseRuntimeTest { + public TestSemPredEvalLexer(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(SemPredEvalLexerDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSemPredEvalParser.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSemPredEvalParser.java new file mode 100644 index 000000000..1441444c5 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSemPredEvalParser.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.SemPredEvalParserDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestSemPredEvalParser extends BaseRuntimeTest { + public TestSemPredEvalParser(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(SemPredEvalParserDescriptors.class, "PHP"); + } +} diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSets.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSets.java new file mode 100644 index 000000000..996045361 --- /dev/null +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/php/TestSets.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.txt file in the project root. + */ + +package org.antlr.v4.test.runtime.php; + +import org.antlr.v4.test.runtime.BaseRuntimeTest; +import org.antlr.v4.test.runtime.RuntimeTestDescriptor; +import org.antlr.v4.test.runtime.descriptors.SetsDescriptors; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class TestSets extends BaseRuntimeTest { + public TestSets(RuntimeTestDescriptor descriptor) { + super(descriptor,new BasePHPTest()); + } + + @Parameterized.Parameters(name="{0}") + public static RuntimeTestDescriptor[] getAllTestDescriptors() { + return BaseRuntimeTest.getRuntimeTestDescriptors(SetsDescriptors.class, "PHP"); + } +} diff --git a/runtime/PHP b/runtime/PHP new file mode 160000 index 000000000..9e1b759d0 --- /dev/null +++ b/runtime/PHP @@ -0,0 +1 @@ +Subproject commit 9e1b759d02220eedf477771169bdfb6a186a2984 diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/PHP/PHP.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/PHP/PHP.stg new file mode 100644 index 000000000..5376d3566 --- /dev/null +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/PHP/PHP.stg @@ -0,0 +1,1231 @@ +/* + * [The "BSD license"] + * Copyright (c) 2012-2016 Terence Parr + * Copyright (c) 2012-2016 Sam Harwell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +phpTypeInitMap ::= [ + "int":"0", + "long":"0", + "float":"0.0", + "double":"0.0", + "boolean":"false", + default:"null" +] + +// args must be , + +ParserFile(file, parser, namedActions, contextSuperClass) ::= << + + +>> + +ListenerFile(file, header, namedActions) ::= << + + +namespace ; + +

+use Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeListener; + +/** + * This interface defines a complete listener for a parse tree produced by + * {@see }. + */ +interface Listener extends ParseTreeListener { + + * Enter a parse tree produced by the `` + * labeled alternative in {@see ::()\}. + + * Enter a parse tree produced by {@see ::()\}. + + * @param $context The parse tree. + */ +public function enter(Context\\Context $context) : void; +/** + + * Exit a parse tree produced by the `` labeled alternative + * in {@see ::()\}. + + * Exit a parse tree produced by {@see ::()\}. + + * @param $context The parse tree. + */ +public function exit(Context\\Context $context) : void;}; separator="\n"> +} +>> + +BaseListenerFile(file, header, namedActions) ::= << + + +namespace ; + +
+ +use Antlr\\Antlr4\\Runtime\\ParserRuleContext; +use Antlr\\Antlr4\\Runtime\\Tree\\ErrorNode; +use Antlr\\Antlr4\\Runtime\\Tree\\TerminalNode; + +/** + * This class provides an empty implementation of {@see Listener}, + * which can be extended to create a listener which only needs to handle a subset + * of the available methods. + */ +class BaseListener implements Listener +{ + (Context\\Context $context) : void {\} + +/** + * {@inheritdoc\} + * + * The default implementation does nothing. + */ +public function exit(Context\\Context $context) : void {\}}; separator="\n"> + + /** + * {@inheritdoc\} + * + * The default implementation does nothing. + */ + public function enterEveryRule(ParserRuleContext $context) : void {} + + /** + * {@inheritdoc\} + * + * The default implementation does nothing. + */ + public function exitEveryRule(ParserRuleContext $context) : void {} + + /** + * {@inheritdoc\} + * + * The default implementation does nothing. + */ + public function visitTerminal(TerminalNode $node) : void {} + + /** + * {@inheritdoc\} + * + * The default implementation does nothing. + */ + public function visitErrorNode(ErrorNode $node) : void {} +} +>> + +VisitorFile(file, header, namedActions) ::= << + + +namespace ; + +
+use Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeVisitor; + +/** + * This interface defines a complete generic visitor for a parse tree produced + by {@see }. + */ +interface Visitor extends ParseTreeVisitor +{ + + * Visit a parse tree produced by the `` labeled alternative + * in {@see ::()\}. + + * Visit a parse tree produced by {@see ::()\}. + + * @param Context $context The parse tree. + * + * @return mixed The visitor result. + */ +public function visit(Context\\Context $context);}; separator="\n\n"> +} +>> + +BaseVisitorFile(file, header, namedActions) ::= << + + +namespace ; + +
+use Antlr\\Antlr4\\Runtime\\Tree\\AbstractParseTreeVisitor; + +/** + * This class provides an empty implementation of {@see Visitor}, + * which can be extended to create a visitor which only needs to handle a subset + * of the available methods. + */ +class BaseVisitor extends AbstractParseTreeVisitor implements Visitor +{ + (Context\\Context $context) +{ + return $this->visitChildren($context); +\}}; separator="\n\n"> +} +>> + +fileHeader(grammarFileName, ANTLRVersion) ::= << +\ by ANTLR +>> +Parser(parser, funcs, atn, sempredFuncs, superClass) ::= << + +>> + +Parser_(parser, funcs, atn, sempredFuncs, ctor, superClass) ::= << +namespace { + + use Antlr\\Antlr4\\Runtime\\Atn\\ATN; + use Antlr\\Antlr4\\Runtime\\Atn\\ATNDeserializer; + use Antlr\\Antlr4\\Runtime\\Atn\\ParserATNSimulator; + use Antlr\\Antlr4\\Runtime\\Dfa\\DFA; + use Antlr\\Antlr4\\Runtime\\Error\\Exceptions\\FailedPredicateException; + use Antlr\\Antlr4\\Runtime\\Error\\Exceptions\\NoViableAltException; + use Antlr\\Antlr4\\Runtime\\PredictionContexts\\PredictionContextCache; + use Antlr\\Antlr4\\Runtime\\Error\\Exceptions\\RecognitionException; + use Antlr\\Antlr4\\Runtime\\RuleContext; + use Antlr\\Antlr4\\Runtime\\Token; + use Antlr\\Antlr4\\Runtime\\TokenStream; + use Antlr\\Antlr4\\Runtime\\Vocabulary; + use Antlr\\Antlr4\\Runtime\\VocabularyImpl; + use Antlr\\Antlr4\\Runtime\\RuntimeMetaData; + use Antlr\\Antlr4\\Runtime\\Parser; + + + final class extends + { + + public const = }; separator=", ", wrap, anchor>; + + + public const = }; separator=", ", wrap, anchor>; + + /** + * @var array\ + */ + public const RULE_NAMES = [ + '}; separator=", ", wrap, anchor> + ]; + + + + + protected static $atn; + protected static $decisionToDFA; + protected static $sharedContextCache; + + + + + + + + + private static function initialize() : void + { + if (self::$atn !== null) { + return; + } + + RuntimeMetaData::checkVersion('', RuntimeMetaData::VERSION); + + $atn = (new ATNDeserializer())->deserialize(self::SERIALIZED_ATN); + + $decisionToDFA = []; + for ($i = 0, $count = $atn->getNumberOfDecisions(); $i \< $count; $i++) { + $decisionToDFA[] = new DFA($atn->getDecisionState($i), $i); + } + + self::$atn = $atn; + self::$decisionToDFA = $decisionToDFA; + self::$sharedContextCache = new PredictionContextCache(); + } + + public function getGrammarFileName() : string + { + return ""; + } + + public function getRuleNames() : array + { + return self::RULE_NAMES; + } + + public function getSerializedATN() : string + { + return self::SERIALIZED_ATN; + } + + public function getATN() : ATN + { + return self::$atn; + } + + public function getVocabulary() : Vocabulary + { + static $vocabulary; + + return $vocabulary = $vocabulary ?? new VocabularyImpl(self::LITERAL_NAMES, self::SYMBOLIC_NAMES); + } + + + + + + + public function sempred(?RuleContext $localContext, int $ruleIndex, int $predicateIndex) : bool + { + switch ($ruleIndex) { + : + return $this->sempred($localContext, $predicateIndex);}; separator="\n\n"> + + default: + return true; + } + } + + + + } +} + +namespace \\Context { + use Antlr\\Antlr4\\Runtime\\ParserRuleContext; + use Antlr\\Antlr4\\Runtime\\Token; + use Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeVisitor; + use Antlr\\Antlr4\\Runtime\\Tree\\TerminalNode; + use Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeListener; + use \\; + use \\Visitor; + use \\Listener; + + + }; separator="\n\n"> + }; separator="\n\n">}> +} +>> + +vocabulary(literalNames, symbolicNames) ::= << +/** + * @var array\ + */ +private const LITERAL_NAMES = [ + }; null="null", separator=", ", wrap, anchor> +]; + +/** + * @var array\ + */ +private const SYMBOLIC_NAMES = [ + }; null="null", separator=", ", wrap, anchor> +]; +>> + +dumpActions(recog, argFuncs, actionFuncs, sempredFuncs) ::= << + + +public function action(?RuleContext $localContext, int $ruleIndex, int $actionIndex) : void +{ + switch ($ruleIndex) { + : + $this->action($localContext, $actionIndex); + + break;}; separator="\n\n"> + } +} + + + + + +public function sempred(?RuleContext $localContext, int $ruleIndex, int $predicateIndex) : bool +{ + switch ($ruleIndex) { + : + return $this->sempred($localContext, $predicateIndex);}; separator="\n\n"> + } + + return true; +} + + +>> + +parser_ctor(p) ::= << +public function __construct(TokenStream $input) +{ + parent::__construct($input); + + self::initialize(); + + $this->interp = new ParserATNSimulator($this, self::$atn, self::$decisionToDFA, self::$sharedContextCache); +} +>> + +/** + * This generates a private method since the actionIndex is generated, making + * an overriding implementation impossible to maintain. + */ +RuleActionFunction(r, actions) ::= << +private function action(? $localContext, int $actionIndex) : void +{ + switch ($actionIndex) { + : + + + break;}; separator="\n\n"> + } +} +>> + +/** + * This generates a private method since the predicateIndex is generated, making + * an overriding implementation impossible to maintain. + */ +RuleSempredFunction(r, actions) ::= << +private function sempred(?Context\\ $localContext, int $predicateIndex) : bool +{ + switch ($predicateIndex) { + : + return ;}; separator="\n\n"> + } + + return true; +} +>> + +RuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,exceptions,postamble) ::= << +/** + * @throws RecognitionException + */ + }>public function () : Context\\ +{ + $localContext = new Context\\($this->ctx, $this->getState()}>); + + $this->enterRule($localContext, , ::RULE_); + + + + try { + + + + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + + $this->exitRule(); + } + + return $localContext; +} +>> + +LeftRecursiveRuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble) ::= << +/** + * @throws RecognitionException + */ + }>public function () : Context\\ +{ + return $this->recursive(0}>); +} + +/** + * @throws RecognitionException + */ +private function recursive(int $precedence}>) : Context\\ +{ + $parentContext = $this->ctx; + $parentState = $this->getState(); + $localContext = new Context\\($this->ctx, $parentState}>); + $previousContext = $localContext; + $startState = ; + $this->enterRecursionRule($localContext, , ::RULE_, $precedence); + + + + try { + + + + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + + $this->unrollRecursionContexts($parentContext); + } + + return $localContext; +} +>> + +CodeBlockForOuterMostAlt(currentOuterMostAltCodeBlock, locals, preamble, ops) ::= << +$localContext = new Context\\Context($localContext); +$this->enterOuterAlt($localContext, ); + +>> + +CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= << + + + +>> + +LL1AltBlock(choice, preamble, alts, error) ::= << +$this->setState(); +$this->errorHandler->sync($this); + = $this->input->LT(1); + + +switch ($this->input->LA(1)) { + + + break;}; separator="\n\n"> + +default: + +} +>> + +LL1OptionalBlock(choice, alts, error) ::= << +$this->setState(); +$this->errorHandler->sync($this); + +switch ($this->input->LA(1)) { + + + break;}; separator="\n\n"> + +default: + break; +} +>> + +LL1OptionalBlockSingleAlt(choice, expr, alts, preamble, error, followExpr) ::= << +$this->setState(); +$this->errorHandler->sync($this); + + +if () { + +} +>> + +LL1StarBlockSingleAlt(choice, loopExpr, alts, preamble, iteration) ::= << +$this->setState(); +$this->errorHandler->sync($this); + + +while () { + + $this->setState(); + $this->errorHandler->sync($this); + +} +>> + +LL1PlusBlockSingleAlt(choice, loopExpr, alts, preamble, iteration) ::= << +$this->setState(); +$this->errorHandler->sync($this); + + +do { + + $this->setState(); + $this->errorHandler->sync($this); + +} while (); +>> + +// LL(*) stuff + +AltBlock(choice, preamble, alts, error) ::= << +$this->setState(); +$this->errorHandler->sync($this); + = $this->input->LT(1); + + +switch ($this->getInterpreter()->adaptivePredict($this->input, , $this->ctx)) { + : + +break;}; separator="\n\n"> +} +>> + +OptionalBlock(choice, alts, error) ::= << +$this->setState(); +$this->errorHandler->sync($this); + +switch ($this->getInterpreter()->adaptivePredict($this->input, , $this->ctx)) { ++1: + + break;}; separator="\n\n"> +} +>> + +StarBlock(choice, alts, sync, iteration) ::= << +$this->setState(); +$this->errorHandler->sync($this); + +$alt = $this->getInterpreter()->adaptivePredict($this->input, , $this->ctx); + +while ($alt !== && $alt !== ATN::INVALID_ALT_NUMBER) { + if ($alt === 1+1) { + + + } + + $this->setState(); + $this->errorHandler->sync($this); + + $alt = $this->getInterpreter()->adaptivePredict($this->input, , $this->ctx); +} +>> + +PlusBlock(choice, alts, error) ::= << +$this->setState(); +$this->errorHandler->sync($this); + +$alt = 1+1; + +do { + switch ($alt) { + +1: + + + break;}; separator="\n\n"> + default: + + } + + $this->setState(); + $this->errorHandler->sync($this); + + $alt = $this->getInterpreter()->adaptivePredict($this->input, , $this->ctx); +} while ($alt !== && $alt !== ATN::INVALID_ALT_NUMBER); +>> + +Sync(s) ::= "sync();" + +ThrowNoViableAlt(t) ::= "throw new NoViableAltException($this);" + +TestSetInline(s) ::= << +}; separator=" || "> +>> + +// Java language spec 15.19 - shift operators mask operands rather than overflow to 0... need range test +testShiftInRange(shiftAmount) ::= << +(() & ~0x3f) === 0 +>> + +// produces smaller bytecode only when bits.ttypes contains more than two items +bitsetBitfieldComparison(s, bits) ::= <% +(})> && ((1 \<\< ) & ()}; separator=" | ">)) !== 0) +%> + +isZero ::= [ +"0":true, +default:false +] + +offsetShiftVar(shiftAmount, offset) ::= <% +($ - )$ +%> +offsetShiftConst(shiftAmount, offset) ::= <% +(self:: - )self:: +%> + +// produces more efficient bytecode when bits.ttypes contains at most two items +bitsetInlineComparison(s, bits) ::= <% + === self::}; separator=" || "> +%> + +cases(ttypes) ::= << +:::}; separator="\n"> +>> + +InvokeRule(r, argExprsChunks) ::= << +$this->setState(); + = }>$this->recursive(,); +>> + +MatchToken(m) ::= << +$this->setState(); + = }>$this->match(::); +>> + +MatchSet(m, expr, capture) ::= "" + +MatchNotSet(m, expr, capture) ::= "" + +CommonSetStuff(m, expr, capture, invert) ::= << +$this->setState(); + + = }>$this->input->LT(1); + + +if ($ \<= 0 || !()) { + = }>$this->errorHandler->recoverInline($this); +} else { + if ($this->input->LA(1) === Token::EOF) { + $this->matchedEOF = true; + } + + $this->errorHandler->reportMatch($this); + $this->consume(); +} +>> + +Wildcard(w) ::= << +$this->setState(); + = }>$this->matchWildcard(); +>> + +// ACTION STUFF + +Action(a, foo, chunks) ::= "" + +ArgAction(a, chunks) ::= "" + +SemPred(p, chunks, failChunks) ::= << +$this->setState(); + +if (!()) { + throw new FailedPredicateException($this, , , ); +} +>> + +ExceptionClause(e, catchArg, catchAction) ::= << +catch () { + +} +>> + +// lexer actions are not associated with model objects + +LexerSkipCommand() ::= "$this->skip();" +LexerMoreCommand() ::= "$this->more();" +LexerPopModeCommand() ::= "$this->popMode();" + +LexerTypeCommand(arg, grammar) ::= "$this->type = ;" +LexerChannelCommand(arg, grammar) ::= "$this->channel = ;" +LexerModeCommand(arg, grammar) ::= "$this->mode = ;" +LexerPushModeCommand(arg, grammar) ::= "$this->pushMode();" + +ActionText(t) ::= "" +ActionTemplate(t) ::= "" +ArgRef(a) ::= "$localContext->" +LocalRef(a) ::= "$localContext->" +RetValueRef(a) ::= "$localContext->" +QRetValueRef(a) ::= "->->" +/** How to translate $tokenLabel */ +TokenRef(t) ::= "->" +LabelRef(t) ::= "->" +ListLabelRef(t) ::= "->" +SetAttr(s,rhsChunks) ::= "-> = ;" + +TokenLabelType() ::= "" +InputSymbolType() ::= "" + +TokenPropertyRef_text(t) ::= "(-> !== null ? ->->getText() : null)" +TokenPropertyRef_type(t) ::= "(-> !== null ? ->->getType() : 0)" +TokenPropertyRef_line(t) ::= "(-> !== null ? ->->getLine() : 0)" +TokenPropertyRef_pos(t) ::= "(-> !== null ? ->->getCharPositionInLine() : 0)" +TokenPropertyRef_channel(t) ::= "(-> !== null ? ->->getChannel() : 0)" +TokenPropertyRef_index(t) ::= "(-> !== null ? ->->getTokenIndex() : 0)" +TokenPropertyRef_int(t) ::= "(-> !== null ? (int) ->->getText() : 0)" + +RulePropertyRef_start(r) ::= "(-> !== null ? (->->start) : null)" +RulePropertyRef_stop(r) ::= "(-> !== null ? (->->stop) : null)" +RulePropertyRef_text(r) ::= "(-> !== null ? $this->input->getTextByTokens(->->start, ->->stop) : null)" +RulePropertyRef_ctx(r) ::= "->" +RulePropertyRef_parser(r)::= "\$this" + +ThisRulePropertyRef_start(r) ::= "$localContext->start" +ThisRulePropertyRef_stop(r) ::= "$localContext->stop" +ThisRulePropertyRef_text(r) ::= "$this->input->getTextByTokens($localContext->start, $this->input->LT(-1))" +ThisRulePropertyRef_ctx(r) ::= "$localContext" +ThisRulePropertyRef_parser(r)::= "$this" + +NonLocalAttrRef(s) ::= "\$this->getInvokingContext()->" +SetNonLocalAttr(s, rhsChunks) ::= "\$this->getInvokingContext()-> = ;" + +AddToLabelList(a) ::= "->[] = ;" + +TokenDecl(t) ::= " $" +TokenTypeDecl(t) ::= "" +TokenListDecl(t) ::= "array $ = []" +RuleContextDecl(r) ::= " $" +RuleContextListDecl(rdecl) ::= "array $ = []" +AttributeDecl(d) ::= " $ = " + +PropertiesDecl(struct) ::= << + + |null $ + */ +public $;}; separator="\n\n"> + + + + + + |null $ + */ +public $;}; separator="\n\n"> + + + + + + |null $ + */ +public $;}; separator="\n\n"> + + + + + + \>|null $ + */ +public $;}; separator="\n\n"> + + + + + + |null $ + */ +public $ = ;}; separator="\n\n"> + + +>> + +ContextTokenGetterDecl(t) ::= << +public function () : ?TerminalNode +{ + return $this->getToken(::, 0); +} +>> + +ContextTokenListGetterDecl(t) ::= << +>> + +ContextTokenListIndexedGetterDecl(t) ::= << +/** + * @return array\|TerminalNode|null + */ +public function (?int $index = null) +{ + if ($index === null) { + return $this->getTokens(::); + } + + return $this->getToken(::, $index); +} +>> + +ContextRuleGetterDecl(r) ::= << +public function () : ? +{ + return $this->getTypedRuleContext(::class, 0); +} +>> + +ContextRuleListGetterDecl(r) ::= << +>> + +ContextRuleListIndexedGetterDecl(r) ::= << +/** + * @return array\<\>||null + */ +public function (?int $index = null) +{ + if ($index === null) { + return $this->getTypedRuleContexts(::class); + } + + return $this->getTypedRuleContext(::class, $index); +} +>> + +LexerRuleContext() ::= "RuleContext" + +/** + * The rule context name is the rule followed by a suffix; e.g., r becomes rContext. + */ +RuleContextNameSuffix() ::= "Context" + +ImplicitTokenLabel(tokenName) ::= "" +ImplicitRuleLabel(ruleName) ::= "" +ImplicitSetLabel(id) ::= "_tset" +ListLabelName(label) ::= "

." +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << public override IToken NextToken() { diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Chrome.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Chrome.test.stg index e02457a90..070409c21 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Chrome.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Chrome.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "" Append(a,b) ::= " + " +AppendStr(a,b) ::= <%%> + Concat(a,b) ::= "" DeclareLocal(s,v) ::= "var = ;" @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <%this. = ;%> InitBooleanMember(n,v) ::= <%this. = ;%> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "" + +VarRef(n) ::= "" + GetMember(n) ::= <%this.%> SetMember(n,v) ::= <%this. = ;%> @@ -92,6 +100,8 @@ this.Property = function() { } >> +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << PositionAdjustingLexer.prototype.resetAcceptPosition = function(index, line, column) { diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Cpp.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Cpp.test.stg index c2b1a7f84..bd3f0dd79 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Cpp.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Cpp.test.stg @@ -9,6 +9,7 @@ Assert(s) ::= "" Cast(t,v) ::= "dynamic_cast\< *>()" // Should actually use a more specific name. We may have to use other casts as well. Append(a,b) ::= " + ->toString()" Concat(a,b) ::= "" +AppendStr(a,b) ::= " + " DeclareLocal(s,v) ::= " = " @@ -17,6 +18,9 @@ AssignLocal(s,v) ::= " = ;" InitIntMember(n,v) ::= "int = ;" InitBooleanMember(n,v) ::= "bool = ;" +InitIntVar(n,v) ::= <%%> +IntArg(n) ::= "int " +VarRef(n) ::= "" GetMember(n) ::= "" SetMember(n,v) ::= " = ;" @@ -68,6 +72,8 @@ bool Property() { ParserPropertyCall(p, call) ::= "" +PositionAdjustingLexerDef() ::= "" + PositionAdjustingLexer() ::= << protected: class PositionAdjustingLexerATNSimulator : public antlr4::atn::LexerATNSimulator { diff --git a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Explorer.test.stg b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Explorer.test.stg index 6cfe9ba27..a3d4cb026 100644 --- a/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Explorer.test.stg +++ b/runtime-testsuite/resources/org/antlr/v4/test/runtime/templates/Explorer.test.stg @@ -14,6 +14,8 @@ Cast(t,v) ::= "" Append(a,b) ::= " + " +AppendStr(a,b) ::= <%%> + Concat(a,b) ::= "" DeclareLocal(s,v) ::= "var = ;" @@ -26,6 +28,12 @@ InitIntMember(n,v) ::= <%this. = ;%> InitBooleanMember(n,v) ::= <%this. = ;%> +InitIntVar(n,v) ::= <%%> + +IntArg(n) ::= "" + +VarRef(n) ::= "" + GetMember(n) ::= <%this.%> SetMember(n,v) ::= <%this. = ;%> @@ -98,6 +106,8 @@ this.Property = function() { ParserPropertyCall(p, call) ::= "