Merge pull request #2931 from ericvergnaud/javascript-es6-migration

Javascript es6 migration
This commit is contained in:
Terence Parr 2020-10-10 16:25:22 -07:00 committed by GitHub
commit 9e64dfc6e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 353 additions and 680 deletions

View File

@ -203,6 +203,9 @@ matrix:
jdk: openjdk8
env: TARGET=javascript
stage: main-test
before_install:
- nvm install 14 # otherwise it runs by default on node 8
- f="./.travis/before-install-linux-javascript.sh"; ! [ -x "$f" ] || "$f"
- os: linux
dist: trusty
jdk: openjdk8
@ -215,7 +218,7 @@ before_install:
script:
- |
cd runtime-testsuite;
travis_wait 40 ../.travis/run-tests-$TARGET.sh;
rc=$?;
cat target/surefire-reports/*.dumpstream || true;
travis_wait 40 ../.travis/run-tests-$TARGET.sh
rc=$?
cat target/surefire-reports/*.dumpstream || true
exit $rc

View File

@ -2,7 +2,6 @@
set -euo pipefail
sudo apt-get update -qq
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -qq nodejs
node --version
# use v14 and check
echo node version: $(node --version)

View File

@ -2,4 +2,8 @@
set -euo pipefail
mvn -q -Dparallel=methods -DthreadCount=4 -Dtest=javascript.* test
cd ../runtime/JavaScript
npm install
npm link
cd ../../runtime-testsuite
mvn -q -Dparallel=methods -DthreadCount=1 -Dtest=javascript.* test

View File

@ -16,7 +16,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-php-php="C:\tools\php\php.exe" -Dantlr-dart-dart="C:\tools\dart-sdk\bin\dart.exe" -Dantlr-dart-pub="C:\tools\dart-sdk\bin\pub.bat" -Dantlr-dart-dart2native="C:\tools\dart-sdk\bin\dart2native.bat" -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\php\php.exe" -Dantlr-dart-dart="C:\tools\dart-sdk\bin\dart.exe" -Dantlr-dart-pub="C:\tools\dart-sdk\bin\pub.bat" -Dantlr-dart-dart2native="C:\tools\dart-sdk\bin\dart2native.bat" -Dantlr-python2-python="C:\Python27\python.exe" -Dantlr-python3-python="C:\Python35\python.exe" --batch-mode
artifacts:
- path: 'runtime\**\*.nupkg'
name: NuGet

View File

@ -11,11 +11,18 @@ In practice, this target has been extensively tested against:
* Chrome 39.0.2171
* Explorer 11.0.3
The tests were conducted using Selenium. No issue was found, so you should find that the runtime works pretty much against any recent JavaScript engine.
The above tests were conducted using Selenium. No issue was found, so you should find that the runtime works pretty much against any recent JavaScript engine.
## Is NodeJS supported?
The runtime has also been extensively tested against Node.js 10 LTS. No issue was found.
The runtime has also been extensively tested against Node.js 14 LTS. No issue was found.
NodeJS together with a packaging tool is now the preferred development path, developers are encouraged to follow it.
## What about modules?
Starting with version 8.1, Antlr4 JavaScript runtime follows esm semantics (see https://tc39.es/ecma262/#sec-modules for details)
Generated lexers, parsers, listeners and visitors also follow this new standard.
If you have used previous versions of the runtime, you will need to migrate and make your parser a module.
## How to create a JavaScript lexer or parser?
@ -80,18 +87,18 @@ Let's suppose that your grammar is named, as above, "MyGrammar". Let's suppose t
Now a fully functioning script might look like the following:
```javascript
var antlr4 = require('antlr4');
var MyGrammarLexer = require('./MyGrammarLexer').MyGrammarLexer;
var MyGrammarParser = require('./MyGrammarParser').MyGrammarParser;
var MyGrammarListener = require('./MyGrammarListener').MyGrammarListener;
import antlr4 from 'antlr4';
import MyGrammarLexer from './MyGrammarLexer.js');
import MyGrammarParser from './MyGrammarParser.js';
import MyGrammarListener from './MyGrammarListener.js';
var input = "your text to parse here"
var chars = new antlr4.InputStream(input);
var lexer = new MyGrammarLexer(chars);
var tokens = new antlr4.CommonTokenStream(lexer);
var parser = new MyGrammarParser(tokens);
const input = "your text to parse here"
const chars = new antlr4.InputStream(input);
const lexer = new MyGrammarLexer(chars);
const tokens = new antlr4.CommonTokenStream(lexer);
const parser = new MyGrammarParser(tokens);
parser.buildParseTrees = true;
var tree = parser.MyStartRule();
const tree = parser.MyStartRule();
```
This program will work. But it won't be useful unless you do one of the following:
@ -105,19 +112,19 @@ This program will work. But it won't be useful unless you do one of the followin
## How do I create and run a visitor?
```javascript
// test.js
var antlr4 = require('antlr4');
var MyGrammarLexer = require('./QueryLexer').QueryLexer;
var MyGrammarParser = require('./QueryParser').QueryParser;
var MyGrammarListener = require('./QueryListener').QueryListener;
import antlr4 from 'antlr4';
import MyGrammarLexer from './QueryLexer.js';
import MyGrammarParser from './QueryParser.js';
import MyGrammarListener from './QueryListener.js';
var input = "field = 123 AND items in (1,2,3)"
var chars = new antlr4.InputStream(input);
var lexer = new MyGrammarLexer(chars);
var tokens = new antlr4.CommonTokenStream(lexer);
var parser = new MyGrammarParser(tokens);
const input = "field = 123 AND items in (1,2,3)"
const chars = new antlr4.InputStream(input);
const lexer = new MyGrammarLexer(chars);
const tokens = new antlr4.CommonTokenStream(lexer);
const parser = new MyGrammarParser(tokens);
parser.buildParseTrees = true;
var tree = parser.query();
const tree = parser.query();
class Visitor {
visitChildren(ctx) {
@ -145,40 +152,37 @@ tree.accept(new Visitor());
Let's suppose your MyGrammar grammar comprises 2 rules: "key" and "value". The antlr4 tool will have generated the following listener:
```javascript
MyGrammarListener = function(ParseTreeListener) {
// some code here
}
// some code here
MyGrammarListener.prototype.enterKey = function(ctx) {};
MyGrammarListener.prototype.exitKey = function(ctx) {};
MyGrammarListener.prototype.enterValue = function(ctx) {};
MyGrammarListener.prototype.exitValue = function(ctx) {};
class MyGrammarListener extends ParseTreeListener {
constructor() {
super();
}
enterKey(ctx) {}
exitKey(ctx) {}
enterValue(ctx) {}
exitValue(ctx) {}
}
```
In order to provide custom behavior, you might want to create the following class:
```javascript
var KeyPrinter = function() {
MyGrammarListener.call(this); // inherit default listener
return this;
};
class KeyPrinter extends MyGrammarListener {
// continue inheriting default listener
KeyPrinter.prototype = Object.create(MyGrammarListener.prototype);
KeyPrinter.prototype.constructor = KeyPrinter;
// override default listener behavior
KeyPrinter.prototype.exitKey = function(ctx) {
console.log("Oh, a key!");
};
// override default listener behavior
exitKey(ctx) {
console.log("Oh, a key!");
}
}
```
In order to execute this listener, you would simply add the following lines to the above code:
```javascript
...
tree = parser.StartRule() // only repeated here for reference
var printer = new KeyPrinter();
...
tree = parser.StartRule() // only repeated here for reference
const printer = new KeyPrinter();
antlr4.tree.ParseTreeWalker.DEFAULT.walk(printer, tree);
```

View File

@ -74,7 +74,7 @@ LANotEquals(i, v) ::= <%this._input.LA(<i>)!=<v>%>
TokenStartColumnEquals(i) ::= <%this._tokenStartColumn===<i>%>
ImportListener(X) ::= <<var <X>Listener = require('./<X>Listener').<X>Listener;>>
ImportListener(X) ::= ""
GetExpectedTokenNames() ::= "this.getExpectedTokens().toString(this.literalNames)"

View File

@ -76,11 +76,7 @@ LANotEquals(i, v) ::= <%this._input.LA(<i>)!=<v>%>
TokenStartColumnEquals(i) ::= <%this._tokenStartColumn===<i>%>
ImportListener(X) ::= <<
@parser::header {
var <X>Listener = require('./<X>Listener').<X>Listener;
}
>>
ImportListener(X) ::= ""
GetExpectedTokenNames() ::= "this.getExpectedTokens().toString(this.literalNames)"

View File

@ -74,11 +74,7 @@ LANotEquals(i, v) ::= <%this._input.LA(<i>)!=<v>%>
TokenStartColumnEquals(i) ::= <%this._tokenStartColumn===<i>%>
ImportListener(X) ::= <<
@parser::header {
var <X>Listener = require('./<X>Listener').<X>Listener;
}
>>
ImportListener(X) ::= ""
GetExpectedTokenNames() ::= "this.getExpectedTokens().toString(this.literalNames)"

View File

@ -74,11 +74,7 @@ LANotEquals(i, v) ::= <%this._input.LA(<i>)!=<v>%>
TokenStartColumnEquals(i) ::= <%this._tokenStartColumn===<i>%>
ImportListener(X) ::= <<
@parser::header {
var <X>Listener = require('./<X>Listener').<X>Listener;
}
>>
ImportListener(X) ::= ""
GetExpectedTokenNames() ::= "this.getExpectedTokens().toString(this.literalNames)"

View File

@ -46,13 +46,14 @@ import static org.junit.Assume.assumeFalse;
public abstract class BaseRuntimeTest {
public final static String[] Targets = {
"Cpp",
"Java",
"Go",
"CSharp",
"Python2", "Python3",
"PHP",
"Dart",
"Go",
"Java",
"Node",
"Dart"
"PHP",
"Python2", "Python3",
"Swift"
};
static {
@ -95,10 +96,17 @@ public abstract class BaseRuntimeTest {
public void setUp() throws Exception {
// From http://junit.sourceforge.net/javadoc/org/junit/Assume.html
// "The default JUnit runner treats tests with failing assumptions as ignored"
assumeFalse(descriptor.ignore(descriptor.getTarget()));
assumeFalse(checkIgnored());
delegate.testSetUp();
}
public boolean checkIgnored() {
boolean ignored = !TestContext.isSupportedTarget(descriptor.getTarget()) || descriptor.ignore(descriptor.getTarget());
if(ignored)
System.out.println("Ignore " + descriptor);
return ignored;
}
@Rule
public final TestRule testWatcher = new TestWatcher() {
@Override
@ -112,7 +120,7 @@ public abstract class BaseRuntimeTest {
public void testOne() throws Exception {
// System.out.println(delegate.getTmpDir());
if ( descriptor.ignore(descriptor.getTarget()) ) {
System.out.printf("Ignore "+descriptor);
System.out.println("Ignore " + descriptor);
return;
}
@ -273,6 +281,8 @@ public abstract class BaseRuntimeTest {
// ---- support ----
public static RuntimeTestDescriptor[] getRuntimeTestDescriptors(Class<?> clazz, String targetName) {
if(!TestContext.isSupportedTarget(targetName))
return new RuntimeTestDescriptor[0];
Class<?>[] nestedClasses = clazz.getClasses();
List<RuntimeTestDescriptor> descriptors = new ArrayList<RuntimeTestDescriptor>();
for (Class<?> nestedClass : nestedClasses) {
@ -280,8 +290,10 @@ public abstract class BaseRuntimeTest {
if ( RuntimeTestDescriptor.class.isAssignableFrom(nestedClass) && !Modifier.isAbstract(modifiers) ) {
try {
RuntimeTestDescriptor d = (RuntimeTestDescriptor) nestedClass.newInstance();
d.setTarget(targetName);
descriptors.add(d);
if(!d.ignore(targetName)) {
d.setTarget(targetName);
descriptors.add(d);
}
} catch (Exception e) {
e.printStackTrace(System.err);
}

View File

@ -0,0 +1,19 @@
package org.antlr.v4.test.runtime;
public abstract class TestContext {
public static boolean isTravisCI() {
return "true".equals(String.valueOf(System.getenv("TRAVIS")).toLowerCase());
}
public static boolean isAppVeyorCI() {
return "true".equals(String.valueOf(System.getenv("APPVEYOR")).toLowerCase());
}
public static boolean isSupportedTarget(String target) {
if(isAppVeyorCI())
return !target.matches("Swift|Node");
else
return true;
}
}

View File

@ -34,6 +34,7 @@ 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.test.runtime.TestContext;
import org.antlr.v4.tool.ANTLRMessage;
import org.antlr.v4.tool.DOTGenerator;
import org.antlr.v4.tool.Grammar;
@ -45,6 +46,7 @@ import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupString;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@ -55,6 +57,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import static org.antlr.v4.test.runtime.BaseRuntimeTest.antlrOnString;
import static org.antlr.v4.test.runtime.BaseRuntimeTest.writeFile;
@ -128,16 +131,6 @@ public class BaseNodeTest implements RuntimeTestSupport {
return antlrToolErrors.toString();
}
protected org.antlr.v4.Tool newTool(String[] args) {
Tool tool = new Tool(args);
return tool;
}
protected Tool newTool() {
org.antlr.v4.Tool tool = new Tool(new String[] { "-o", tmpdir });
return tool;
}
protected ATN createATN(Grammar g, boolean useSerializer) {
if (g.atn == null) {
semanticProcess(g);
@ -179,57 +172,6 @@ public class BaseNodeTest implements RuntimeTestSupport {
}
}
IntegerList getTypesFromString(Grammar g, String expecting) {
IntegerList expectingTokenTypes = new IntegerList();
if (expecting != null && !expecting.trim().isEmpty()) {
for (String tname : expecting.replace(" ", "").split(",")) {
int ttype = g.getTokenType(tname);
expectingTokenTypes.add(ttype);
}
}
return expectingTokenTypes;
}
public IntegerList getTokenTypesViaATN(String input,
LexerATNSimulator lexerATN) {
ANTLRInputStream in = new ANTLRInputStream(input);
IntegerList tokenTypes = new IntegerList();
int ttype;
do {
ttype = lexerATN.match(in, Lexer.DEFAULT_MODE);
tokenTypes.add(ttype);
} while (ttype != Token.EOF);
return tokenTypes;
}
public List<String> getTokenTypes(LexerGrammar lg, ATN atn, CharStream input) {
LexerATNSimulator interp = new LexerATNSimulator(atn,
new DFA[] { new DFA(
atn.modeToStartState.get(Lexer.DEFAULT_MODE)) }, null);
List<String> tokenTypes = new ArrayList<String>();
int ttype;
boolean hitEOF = false;
do {
if (hitEOF) {
tokenTypes.add("EOF");
break;
}
int t = input.LA(1);
ttype = interp.match(input, Lexer.DEFAULT_MODE);
if (ttype == Token.EOF) {
tokenTypes.add("EOF");
}
else {
tokenTypes.add(lg.typeToTokenList.get(ttype));
}
if (t == IntStream.EOF) {
hitEOF = true;
}
} while (ttype != Token.EOF);
return tokenTypes;
}
protected String execLexer(String grammarFileName, String grammarStr,
String lexerName, String input) {
return execLexer(grammarFileName, grammarStr, lexerName, input, false);
@ -243,8 +185,9 @@ public class BaseNodeTest implements RuntimeTestSupport {
assertTrue(success);
writeFile(tmpdir, "input", input);
writeLexerTestFile(lexerName, showDFA);
writeFile(tmpdir, "package.json", "{\"type\": \"module\"}");
String output = execModule("Test.js");
if ( output.length()==0 ) {
if ( output!=null && output.length()==0 ) {
output = null;
}
return output;
@ -262,6 +205,7 @@ public class BaseNodeTest implements RuntimeTestSupport {
writeFile(tmpdir, "input", input);
rawBuildRecognizerTestFile(parserName, lexerName, listenerName,
visitorName, startRuleName, showDiagnosticErrors);
writeFile(tmpdir, "package.json", "{\"type\": \"module\"}");
return execRecognizer();
}
@ -323,17 +267,21 @@ public class BaseNodeTest implements RuntimeTestSupport {
}
public String execModule(String fileName) {
String nodejsPath = locateNodeJS();
String runtimePath = locateRuntime();
String modulePath = new File(new File(tmpdir), fileName)
.getAbsolutePath();
String inputPath = new File(new File(tmpdir), "input")
.getAbsolutePath();
try {
String npmPath = locateNpm();
if(!TestContext.isTravisCI()) {
installRuntime(npmPath);
registerRuntime(npmPath);
}
String modulePath = new File(new File(tmpdir), fileName)
.getAbsolutePath();
linkRuntime(npmPath);
String nodejsPath = locateNodeJS();
String inputPath = new File(new File(tmpdir), "input")
.getAbsolutePath();
ProcessBuilder builder = new ProcessBuilder(nodejsPath, modulePath,
inputPath);
builder.environment().put("NODE_PATH",
runtimePath + File.pathSeparator + tmpdir);
builder.environment().put("NODE_PATH", tmpdir);
builder.directory(new File(tmpdir));
Process process = builder.start();
StreamVacuum stdoutVacuum = new StreamVacuum(
@ -342,7 +290,10 @@ public class BaseNodeTest implements RuntimeTestSupport {
process.getErrorStream());
stdoutVacuum.start();
stderrVacuum.start();
// TODO switch to jdk 8
process.waitFor();
// if(!process.waitFor(1L, TimeUnit.MINUTES))
// process.destroyForcibly();
stdoutVacuum.join();
stderrVacuum.join();
String output = stdoutVacuum.toString();
@ -353,22 +304,59 @@ public class BaseNodeTest implements RuntimeTestSupport {
this.stderrDuringParse = stderrVacuum.toString();
}
return output;
}
catch (Exception e) {
} catch (Exception e) {
System.err.println("can't exec recognizer");
e.printStackTrace(System.err);
System.err.println();
return null;
}
return null;
}
private String locateTool(String tool) {
String[] roots = { "/usr/bin/", "/usr/local/bin/" };
for (String root : roots) {
if (new File(root + tool).exists()) {
return root + tool;
}
}
return null;
private void installRuntime(String npmPath) throws IOException, InterruptedException {
String runtimePath = locateRuntime();
ProcessBuilder builder = new ProcessBuilder(npmPath, "install");
builder.directory(new File(runtimePath));
builder.redirectError(new File(tmpdir, "error.txt"));
builder.redirectOutput(new File(tmpdir, "output.txt"));
Process process = builder.start();
// TODO switch to jdk 8
process.waitFor();
// if(!process.waitFor(30L, TimeUnit.SECONDS))
// process.destroyForcibly();
int error = process.exitValue();
if(error!=0)
throw new IOException("'npm install' failed");
}
private void registerRuntime(String npmPath) throws IOException, InterruptedException {
String runtimePath = locateRuntime();
ProcessBuilder builder = new ProcessBuilder(npmPath, "link");
builder.directory(new File(runtimePath));
builder.redirectError(new File(tmpdir, "error.txt"));
builder.redirectOutput(new File(tmpdir, "output.txt"));
Process process = builder.start();
// TODO switch to jdk 8
process.waitFor();
// if(!process.waitFor(30L, TimeUnit.SECONDS))
// process.destroyForcibly();
int error = process.exitValue();
if(error!=0)
throw new IOException("'npm link' failed");
}
private void linkRuntime(String npmPath) throws IOException, InterruptedException {
ProcessBuilder builder = new ProcessBuilder(npmPath, "link", "antlr4");
builder.directory(new File(tmpdir));
builder.redirectError(new File(tmpdir, "error.txt"));
builder.redirectOutput(new File(tmpdir, "output.txt"));
Process process = builder.start();
// TODO switch to jdk 8
process.waitFor();
// if(!process.waitFor(30L, TimeUnit.SECONDS))
// process.destroyForcibly();
int error = process.exitValue();
if(error!=0)
throw new IOException("'npm link antlr4' failed");
}
private boolean canExecute(String tool) {
@ -378,21 +366,29 @@ public class BaseNodeTest implements RuntimeTestSupport {
Process process = builder.start();
StreamVacuum vacuum = new StreamVacuum(process.getInputStream());
vacuum.start();
// TODO switch to jdk 8
process.waitFor();
// if(!process.waitFor(30L, TimeUnit.SECONDS))
// process.destroyForcibly();
vacuum.join();
return process.exitValue() == 0;
} catch (Exception e) {
return false;
}
catch (Exception e) {
;
}
private String locateNpm() {
// typically /usr/local/bin/npm
String prop = System.getProperty("antlr-javascript-npm");
if ( prop!=null && prop.length()!=0 ) {
return prop;
}
return false;
return "npm"; // everywhere
}
private String locateNodeJS() {
// typically /usr/local/bin/node
String propName = "antlr-javascript-nodejs";
String prop = System.getProperty(propName);
String prop = System.getProperty("antlr-javascript-nodejs");
if ( prop!=null && prop.length()!=0 ) {
return prop;
}
@ -404,7 +400,7 @@ public class BaseNodeTest implements RuntimeTestSupport {
private String locateRuntime() {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
final URL runtimeSrc = loader.getResource("JavaScript/src");
final URL runtimeSrc = loader.getResource("JavaScript");
if ( runtimeSrc==null ) {
throw new RuntimeException("Cannot find JavaScript runtime");
}
@ -418,213 +414,16 @@ public class BaseNodeTest implements RuntimeTestSupport {
return System.getProperty("os.name").toLowerCase().contains("windows");
}
// void ambig(List<Message> msgs, int[] expectedAmbigAlts, String
// expectedAmbigInput)
// throws Exception
// {
// ambig(msgs, 0, expectedAmbigAlts, expectedAmbigInput);
// }
// void ambig(List<Message> msgs, int i, int[] expectedAmbigAlts, String
// expectedAmbigInput)
// throws Exception
// {
// List<Message> amsgs = getMessagesOfType(msgs, AmbiguityMessage.class);
// AmbiguityMessage a = (AmbiguityMessage)amsgs.get(i);
// if ( a==null ) assertNull(expectedAmbigAlts);
// else {
// assertEquals(a.conflictingAlts.toString(),
// Arrays.toString(expectedAmbigAlts));
// }
// assertEquals(expectedAmbigInput, a.input);
// }
// void unreachable(List<Message> msgs, int[] expectedUnreachableAlts)
// throws Exception
// {
// unreachable(msgs, 0, expectedUnreachableAlts);
// }
// void unreachable(List<Message> msgs, int i, int[]
// expectedUnreachableAlts)
// throws Exception
// {
// List<Message> amsgs = getMessagesOfType(msgs,
// UnreachableAltsMessage.class);
// UnreachableAltsMessage u = (UnreachableAltsMessage)amsgs.get(i);
// if ( u==null ) assertNull(expectedUnreachableAlts);
// else {
// assertEquals(u.conflictingAlts.toString(),
// Arrays.toString(expectedUnreachableAlts));
// }
// }
List<ANTLRMessage> getMessagesOfType(List<ANTLRMessage> msgs,
Class<? extends ANTLRMessage> c) {
List<ANTLRMessage> filtered = new ArrayList<ANTLRMessage>();
for (ANTLRMessage m : msgs) {
if (m.getClass() == c)
filtered.add(m);
}
return filtered;
}
void checkRuleATN(Grammar g, String ruleName, String expecting) {
ParserATNFactory f = new ParserATNFactory(g);
ATN atn = f.createATN();
DOTGenerator dot = new DOTGenerator(g);
System.out
.println(dot.getDOT(atn.ruleToStartState[g.getRule(ruleName).index]));
Rule r = g.getRule(ruleName);
ATNState startState = atn.ruleToStartState[r.index];
ATNPrinter serializer = new ATNPrinter(g, startState);
String result = serializer.asString();
// System.out.print(result);
assertEquals(expecting, result);
}
public void testActions(String templates, String actionName, String action,
String expected) throws org.antlr.runtime.RecognitionException {
int lp = templates.indexOf('(');
String name = templates.substring(0, lp);
STGroup group = new STGroupString(templates);
ST st = group.getInstanceOf(name);
st.add(actionName, action);
String grammar = st.render();
ErrorQueue equeue = new ErrorQueue();
Grammar g = new Grammar(grammar, equeue);
if (g.ast != null && !g.ast.hasErrors) {
SemanticPipeline sem = new SemanticPipeline(g);
sem.process();
ATNFactory factory = new ParserATNFactory(g);
if (g.isLexer())
factory = new LexerATNFactory((LexerGrammar) g);
g.atn = factory.createATN();
CodeGenerator gen = new CodeGenerator(g);
ST outputFileST = gen.generateParser();
String output = outputFileST.render();
// System.out.println(output);
String b = "#" + actionName + "#";
int start = output.indexOf(b);
String e = "#end-" + actionName + "#";
int end = output.indexOf(e);
String snippet = output.substring(start + b.length(), end);
assertEquals(expected, snippet);
}
if (equeue.size() > 0) {
System.err.println(equeue.toString());
}
}
protected void checkGrammarSemanticsError(ErrorQueue equeue,
GrammarSemanticsMessage expectedMessage) throws Exception {
ANTLRMessage foundMsg = null;
for (int i = 0; i < equeue.errors.size(); i++) {
ANTLRMessage m = equeue.errors.get(i);
if (m.getErrorType() == expectedMessage.getErrorType()) {
foundMsg = m;
}
}
assertNotNull("no error; " + expectedMessage.getErrorType()
+ " expected", foundMsg);
assertTrue("error is not a GrammarSemanticsMessage",
foundMsg instanceof GrammarSemanticsMessage);
assertEquals(Arrays.toString(expectedMessage.getArgs()),
Arrays.toString(foundMsg.getArgs()));
if (equeue.size() != 1) {
System.err.println(equeue);
}
}
protected void checkGrammarSemanticsWarning(ErrorQueue equeue,
GrammarSemanticsMessage expectedMessage) throws Exception {
ANTLRMessage foundMsg = null;
for (int i = 0; i < equeue.warnings.size(); i++) {
ANTLRMessage m = equeue.warnings.get(i);
if (m.getErrorType() == expectedMessage.getErrorType()) {
foundMsg = m;
}
}
assertNotNull("no error; " + expectedMessage.getErrorType()
+ " expected", foundMsg);
assertTrue("error is not a GrammarSemanticsMessage",
foundMsg instanceof GrammarSemanticsMessage);
assertEquals(Arrays.toString(expectedMessage.getArgs()),
Arrays.toString(foundMsg.getArgs()));
if (equeue.size() != 1) {
System.err.println(equeue);
}
}
protected void checkError(ErrorQueue equeue, ANTLRMessage expectedMessage)
throws Exception {
// System.out.println("errors="+equeue);
ANTLRMessage foundMsg = null;
for (int i = 0; i < equeue.errors.size(); i++) {
ANTLRMessage m = equeue.errors.get(i);
if (m.getErrorType() == expectedMessage.getErrorType()) {
foundMsg = m;
}
}
assertTrue("no error; " + expectedMessage.getErrorType() + " expected",
!equeue.errors.isEmpty());
assertTrue("too many errors; " + equeue.errors,
equeue.errors.size() <= 1);
assertNotNull(
"couldn't find expected error: "
+ expectedMessage.getErrorType(), foundMsg);
/*
* assertTrue("error is not a GrammarSemanticsMessage", foundMsg
* instanceof GrammarSemanticsMessage);
*/
assertArrayEquals(expectedMessage.getArgs(), foundMsg.getArgs());
}
public static class FilteringTokenStream extends CommonTokenStream {
public FilteringTokenStream(TokenSource src) {
super(src);
}
Set<Integer> hide = new HashSet<Integer>();
@Override
protected boolean sync(int i) {
if (!super.sync(i)) {
return false;
}
Token t = get(i);
if (hide.contains(t.getType())) {
((WritableToken) t).setChannel(Token.HIDDEN_CHANNEL);
}
return true;
}
public void setTokenTypeChannel(int ttype, int channel) {
hide.add(ttype);
}
}
protected void mkdir(String dir) {
File f = new File(dir);
f.mkdirs();
}
protected void writeParserTestFile(String parserName, String lexerName,
String listenerName, String visitorName,
String parserStartRuleName, boolean debug) {
ST outputFileST = new ST(
"var antlr4 = require('antlr4');\n"
+ "var <lexerName> = require('./<lexerName>');\n"
+ "var <parserName> = require('./<parserName>');\n"
+ "var <listenerName> = require('./<listenerName>').<listenerName>;\n"
+ "var <visitorName> = require('./<visitorName>').<visitorName>;\n"
"import antlr4 from 'antlr4';\n"
+ "import <lexerName> from './<lexerName>.js';\n"
+ "import <parserName> from './<parserName>.js';\n"
+ "import <listenerName> from './<listenerName>.js';\n"
+ "import <visitorName> from './<visitorName>.js';\n"
+ "\n"
+ "class TreeShapeListener extends antlr4.tree.ParseTreeListener {\n" +
" enterEveryRule(ctx) {\n" +
@ -640,11 +439,11 @@ public class BaseNodeTest implements RuntimeTestSupport {
+ "\n"
+ "function main(argv) {\n"
+ " var input = new antlr4.FileStream(argv[2], true);\n"
+ " var lexer = new <lexerName>.<lexerName>(input);\n"
+ " var lexer = new <lexerName>(input);\n"
+ " var stream = new antlr4.CommonTokenStream(lexer);\n"
+ "<createParser>"
+ " parser.buildParseTrees = true;\n"
+ " printer = function() {\n"
+ " const printer = function() {\n"
+ " this.println = function(s) { console.log(s); }\n"
+ " this.print = function(s) { process.stdout.write(s); }\n"
+ " return this;\n"
@ -654,10 +453,10 @@ public class BaseNodeTest implements RuntimeTestSupport {
+ " antlr4.tree.ParseTreeWalker.DEFAULT.walk(new TreeShapeListener(), tree);\n"
+ "}\n" + "\n" + "main(process.argv);\n" + "\n");
ST createParserST = new ST(
" var parser = new <parserName>.<parserName>(stream);\n");
" var parser = new <parserName>(stream);\n");
if (debug) {
createParserST = new ST(
" var parser = new <parserName>.<parserName>(stream);\n"
" var parser = new <parserName>(stream);\n"
+ " parser.addErrorListener(new antlr4.error.DiagnosticErrorListener());\n");
}
outputFileST.add("createParser", createParserST);
@ -671,12 +470,12 @@ public class BaseNodeTest implements RuntimeTestSupport {
protected void writeLexerTestFile(String lexerName, boolean showDFA) {
ST outputFileST = new ST(
"var antlr4 = require('antlr4');\n"
+ "var <lexerName> = require('./<lexerName>');\n"
"import antlr4 from 'antlr4';\n"
+ "import <lexerName> from './<lexerName>.js';\n"
+ "\n"
+ "function main(argv) {\n"
+ " var input = new antlr4.FileStream(argv[2], true);\n"
+ " var lexer = new <lexerName>.<lexerName>(input);\n"
+ " var lexer = new <lexerName>(input);\n"
+ " var stream = new antlr4.CommonTokenStream(lexer);\n"
+ " stream.fill();\n"
+ " for(var i=0; i\\<stream.tokens.length; i++) {\n"
@ -689,28 +488,6 @@ public class BaseNodeTest implements RuntimeTestSupport {
writeFile(tmpdir, "Test.js", outputFileST.render());
}
public void writeRecognizer(String parserName, String lexerName,
String listenerName, String visitorName,
String parserStartRuleName, boolean debug) {
if (parserName == null) {
writeLexerTestFile(lexerName, debug);
}
else {
writeParserTestFile(parserName, lexerName, listenerName,
visitorName, parserStartRuleName, debug);
}
}
protected void eraseFiles(final String filesEndingWith) {
File tmpdirF = new File(tmpdir);
String[] files = tmpdirF.list();
for (int i = 0; files != null && i < files.length; i++) {
if (files[i].endsWith(filesEndingWith)) {
new File(tmpdir + "/" + files[i]).delete();
}
}
}
protected void eraseFiles(File dir) {
String[] files = dir.list();
for (int i = 0; files != null && i < files.length; i++) {
@ -734,153 +511,10 @@ public class BaseNodeTest implements RuntimeTestSupport {
}
}
public String getFirstLineOfException() {
if (this.stderrDuringParse == null) {
return null;
}
String[] lines = this.stderrDuringParse.split("\n");
String prefix = "Exception in thread \"main\" ";
return lines[0].substring(prefix.length(), lines[0].length());
}
/**
* When looking at a result set that consists of a Map/HashTable we cannot
* rely on the output order, as the hashing algorithm or other aspects of
* the implementation may be different on differnt JDKs or platforms. Hence
* we take the Map, convert the keys to a List, sort them and Stringify the
* Map, which is a bit of a hack, but guarantees that we get the same order
* on all systems. We assume that the keys are strings.
*
* @param m
* The Map that contains keys we wish to return in sorted order
* @return A string that represents all the keys in sorted order.
*/
public <K, V> String sortMapToString(Map<K, V> m) {
// Pass in crap, and get nothing back
//
if (m == null) {
return null;
}
System.out.println("Map toString looks like: " + m.toString());
// Sort the keys in the Map
//
TreeMap<K, V> nset = new TreeMap<K, V>(m);
System.out.println("Tree map looks like: " + nset.toString());
return nset.toString();
}
public List<String> realElements(List<String> elements) {
return elements.subList(Token.MIN_USER_TOKEN_TYPE, elements.size());
}
public void assertNotNullOrEmpty(String message, String text) {
assertNotNull(message, text);
assertFalse(message, text.isEmpty());
}
public void assertNotNullOrEmpty(String text) {
assertNotNull(text);
assertFalse(text.isEmpty());
}
public static class IntTokenStream implements TokenStream {
IntegerList types;
int p = 0;
public IntTokenStream(IntegerList types) {
this.types = types;
}
@Override
public void consume() {
p++;
}
@Override
public int LA(int i) {
return LT(i).getType();
}
@Override
public int mark() {
return index();
}
@Override
public int index() {
return p;
}
@Override
public void release(int marker) {
seek(marker);
}
@Override
public void seek(int index) {
p = index;
}
@Override
public int size() {
return types.size();
}
@Override
public String getSourceName() {
return null;
}
@Override
public Token LT(int i) {
CommonToken t;
int rawIndex = p + i - 1;
if (rawIndex >= types.size())
t = new CommonToken(Token.EOF);
else
t = new CommonToken(types.get(rawIndex));
t.setTokenIndex(rawIndex);
return t;
}
@Override
public Token get(int i) {
return new org.antlr.v4.runtime.CommonToken(types.get(i));
}
@Override
public TokenSource getTokenSource() {
return null;
}
@Override
public String getText() {
throw new UnsupportedOperationException("can't give strings");
}
@Override
public String getText(Interval interval) {
throw new UnsupportedOperationException("can't give strings");
}
@Override
public String getText(RuleContext ctx) {
throw new UnsupportedOperationException("can't give strings");
}
@Override
public String getText(Token start, Token stop) {
throw new UnsupportedOperationException("can't give strings");
}
}
/** Sort a list */
public <T extends Comparable<? super T>> List<T> sort(List<T> data) {
List<T> dup = new ArrayList<T>();
dup.addAll(data);
List<T> dup = new ArrayList<T>(data);
Collections.sort(dup);
return dup;
}
@ -889,8 +523,7 @@ public class BaseNodeTest implements RuntimeTestSupport {
public <K extends Comparable<? super K>, V> LinkedHashMap<K, V> sort(
Map<K, V> data) {
LinkedHashMap<K, V> dup = new LinkedHashMap<K, V>();
List<K> keys = new ArrayList<K>();
keys.addAll(data.keySet());
List<K> keys = new ArrayList<K>(data.keySet());
Collections.sort(keys);
for (K k : keys) {
dup.put(k, data.get(k));

View File

@ -2468,7 +2468,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -2489,12 +2490,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -2509,17 +2512,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -2636,7 +2642,8 @@
"inherits": {
"version": "2.0.4",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -2648,6 +2655,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -2662,6 +2670,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -2669,12 +2678,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -2693,6 +2704,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -2782,7 +2794,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -2794,6 +2807,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -2879,7 +2893,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -2915,6 +2930,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -2934,6 +2950,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -2977,12 +2994,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},

View File

@ -27,6 +27,6 @@
"build": "webpack"
},
"engines": {
"node": ">=10"
"node": ">=14"
}
}

View File

@ -7,6 +7,7 @@ const RuleContext = require('./RuleContext');
const {Hash, Map, equalArrays} = require('./Utils');
class PredictionContext {
constructor(cachedHashCode) {
this.cachedHashCode = cachedHashCode;
}
@ -83,6 +84,7 @@ function calculateHashString(parent, returnState) {
* can be used for both lexers and parsers.
*/
class PredictionContextCache {
constructor() {
this.cache = new Map();
}
@ -115,6 +117,7 @@ class PredictionContextCache {
class SingletonPredictionContext extends PredictionContext {
constructor(parent, returnState) {
let hashCode = 0;
const hash = new Hash();
@ -182,6 +185,7 @@ class SingletonPredictionContext extends PredictionContext {
}
class EmptyPredictionContext extends SingletonPredictionContext {
constructor() {
super(null, PredictionContext.EMPTY_RETURN_STATE);
}
@ -211,6 +215,7 @@ class EmptyPredictionContext extends SingletonPredictionContext {
PredictionContext.EMPTY = new EmptyPredictionContext();
class ArrayPredictionContext extends PredictionContext {
constructor(parents, returnStates) {
/**
* Parent can be null only if full ctx mode and we make an array

View File

@ -5,7 +5,6 @@
const {RuleNode} = require('./tree/Tree');
const {INVALID_INTERVAL} = require('./tree/Tree');
const INVALID_ALT_NUMBER = require('./atn/ATN').INVALID_ALT_NUMBER || 0; // TODO: solve cyclic dependency to avoid || 0
const Trees = require('./tree/Trees');
class RuleContext extends RuleNode {
@ -98,7 +97,10 @@ class RuleContext extends RuleNode {
* option contextSuperClass.
* to set it.
*/
getAltNumber() { return INVALID_ALT_NUMBER; }
getAltNumber() {
// use constant value of ATN.INVALID_ALT_NUMBER to avoid circular dependency
return 0;
}
/**
* Set the outer alternative number for this context node. Default

View File

@ -8,8 +8,8 @@ const {IntervalSet} = require('./../IntervalSet');
const {Token} = require('./../Token');
class ATN {
constructor(grammarType , maxTokenType) {
constructor(grammarType , maxTokenType) {
/**
* Used for runtime deserialization of ATNs from strings
* The type of the ATN.

View File

@ -18,7 +18,7 @@ const PredictionMode = require('./PredictionMode');
const RuleContext = require('./../RuleContext');
const ParserRuleContext = require('./../ParserRuleContext');
const {SemanticContext} = require('./SemanticContext');
const PredictionContext = require('./../PredictionContext');
const {PredictionContext} = require('./../PredictionContext');
const {Interval} = require('./../IntervalSet');
const {Transition, SetTransition, NotSetTransition, RuleTransition, ActionTransition} = require('./Transition');
const {NoViableAltException} = require('./../error/Errors');

View File

@ -6,7 +6,6 @@
const Utils = require('./../Utils');
const {Token} = require('./../Token');
const {ErrorNode, TerminalNode, RuleNode} = require('./Tree');
const ATN = require('./../atn/ATN');
/** A set of utility routines useful for all kinds of ANTLR trees. */
const Trees = {
@ -50,7 +49,8 @@ const Trees = {
if (t instanceof RuleNode) {
const context = t.getRuleContext()
const altNumber = context.getAltNumber();
if ( altNumber != (ATN.INVALID_ALT_NUMBER || 0) ) { // TODO: solve cyclic dependency to avoid || 0
// use const value of ATN.INVALID_ALT_NUMBER to avoid circular dependency
if ( altNumber != 0 ) {
return ruleNames[t.ruleIndex]+":"+altNumber;
}
return ruleNames[t.ruleIndex];

View File

@ -48,12 +48,12 @@ javascriptTypeInitMap ::= [
ParserFile(file, parser, namedActions, contextSuperClass) ::= <<
<fileHeader(file.grammarFileName, file.ANTLRVersion)>
var antlr4 = require('antlr4/index');
import antlr4 from 'antlr4';
<if(file.genListener)>
var <file.grammarName>Listener = require('./<file.grammarName>Listener').<file.grammarName>Listener;
import <file.grammarName>Listener from './<file.grammarName>Listener.js';
<endif>
<if(file.genVisitor)>
var <file.grammarName>Visitor = require('./<file.grammarName>Visitor').<file.grammarName>Visitor;
import <file.grammarName>Visitor from './<file.grammarName>Visitor.js';
<endif>
<namedActions.header>
@ -62,54 +62,43 @@ var <file.grammarName>Visitor = require('./<file.grammarName>Visitor').<file.gra
ListenerFile(file, header, namedActions) ::= <<
<fileHeader(file.grammarFileName, file.ANTLRVersion)>
var antlr4 = require('antlr4/index');
import antlr4 from 'antlr4';
// This class defines a complete listener for a parse tree produced by <file.parserName>.
function <file.grammarName>Listener() {
return this;
}
<file.grammarName>Listener.prototype = Object.create(antlr4.tree.ParseTreeListener.prototype);
<file.grammarName>Listener.prototype.constructor = <file.grammarName>Listener;
export default class <file.grammarName>Listener extends antlr4.tree.ParseTreeListener {
<file.listenerNames:{lname |
// Enter a parse tree produced by <file.parserName>#<lname>.
<file.grammarName>Listener.prototype.enter<lname; format="cap"> = function(ctx) {
\};
// Enter a parse tree produced by <file.parserName>#<lname>.
enter<lname; format="cap">(ctx) {
\}
// Exit a parse tree produced by <file.parserName>#<lname>.
<file.grammarName>Listener.prototype.exit<lname; format="cap"> = function(ctx) {
\};
// Exit a parse tree produced by <file.parserName>#<lname>.
exit<lname; format="cap">(ctx) {
\}
}; separator="\n">
exports.<file.grammarName>Listener = <file.grammarName>Listener;
}
>>
VisitorFile(file, header, namedActions) ::= <<
<fileHeader(file.grammarFileName, file.ANTLRVersion)>
var antlr4 = require('antlr4/index');
import antlr4 from 'antlr4';
// This class defines a complete generic visitor for a parse tree produced by <file.parserName>.
function <file.grammarName>Visitor() {
antlr4.tree.ParseTreeVisitor.call(this);
return this;
}
<file.grammarName>Visitor.prototype = Object.create(antlr4.tree.ParseTreeVisitor.prototype);
<file.grammarName>Visitor.prototype.constructor = <file.grammarName>Visitor;
export default class <file.grammarName>Visitor extends antlr4.tree.ParseTreeVisitor {
<file.visitorNames:{lname |
// Visit a parse tree produced by <file.parserName>#<lname>.
<file.grammarName>Visitor.prototype.visit<lname; format="cap"> = function(ctx) {
return this.visitChildren(ctx);
\};
// Visit a parse tree produced by <file.parserName>#<lname>.
visit<lname; format="cap">(ctx) {
return this.visitChildren(ctx);
\}
}; separator="\n">
exports.<file.grammarName>Visitor = <file.grammarName>Visitor;
}
>>
@ -120,32 +109,30 @@ fileHeader(grammarFileName, ANTLRVersion) ::= <<
Parser(parser, funcs, atn, sempredFuncs, superClass) ::= <<
<if(superClass)>
var <superClass> = require('./<superClass>').<superClass>;
import <superClass> from './<superClass>.js';
<endif>
var grammarFileName = "<parser.grammarFileName; format="java-escape">";
<atn>
var atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);
const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);
var decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new antlr4.dfa.DFA(ds, index); });
const decisionsToDFA = atn.decisionToState.map( (ds, index) => new antlr4.dfa.DFA(ds, index) );
var sharedContextCache = new antlr4.PredictionContextCache();
const sharedContextCache = new antlr4.PredictionContextCache();
var literalNames = [ <parser.literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ];
export default class <parser.name> extends <superClass; null="antlr4.Parser"> {
var symbolicNames = [ <parser.symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ];
static grammarFileName = "<parser.grammarFileName; format="java-escape">";
static literalNames = [ <parser.literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ];
static symbolicNames = [ <parser.symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ];
static ruleNames = [ <parser.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ];
var ruleNames = [ <parser.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ];
class <parser.name> extends <superClass; null="antlr4.Parser"> {
constructor(input) {
super(input);
this._interp = new antlr4.atn.ParserATNSimulator(this, atn, decisionsToDFA, sharedContextCache);
this.ruleNames = ruleNames;
this.literalNames = literalNames;
this.symbolicNames = symbolicNames;
this.ruleNames = <parser.name>.ruleNames;
this.literalNames = <parser.name>.literalNames;
this.symbolicNames = <parser.name>.symbolicNames;
<namedActions.members>
}
@ -161,10 +148,13 @@ class <parser.name> extends <superClass; null="antlr4.Parser"> {
default:
throw "No predicate with index:" + ruleIndex;
}
};
}
<sempredFuncs.values; separator="\n">
<endif>
<funcs; separator="\n">
}
<parser.name>.EOF = antlr4.Token.EOF;
@ -174,12 +164,19 @@ class <parser.name> extends <superClass; null="antlr4.Parser"> {
<parser.rules:{r | <parser.name>.RULE_<r.name> = <r.index>;}; separator="\n", wrap, anchor>
<funcs; separator="\n">
<funcs:{f | <ruleContexts(f)>}; separator="\n">
module.exports.<parser.name> = <parser.name>;
<! Define fields of this parser to export the context classes !>
<parser.funcs:{f | <parser.name>.<f.ctxType> = <f.ctxType>; }; separator="\n">
>>
ruleContexts(currentRule) ::= <<
<currentRule.ruleCtx>
<currentRule.altLabelCtxs:{l | <currentRule.altLabelCtxs.(l)>}; separator="\n">
>>
dumpActions(recog, argFuncs, actionFuncs, sempredFuncs) ::= <<
<if(actionFuncs)>
<lexer.name>.prototype.action = function(localctx, ruleIndex, actionIndex) {
@ -244,16 +241,9 @@ RuleSempredFunction(r, actions) ::= <<
RuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble,exceptions) ::= <<
<ruleCtx>
<altLabelCtxs:{l | <altLabelCtxs.(l)>}; separator="\n">
<! Define fields of this parser to export the context classes !>
<parser.name>.<currentRule.ctxType> = <currentRule.ctxType>;
<parser.name>.prototype.<currentRule.name> = function(<currentRule.args:{a | <a.name>}; separator=", ">) {
var localctx = new <currentRule.ctxType>(this, this._ctx, this.state<currentRule.args:{a | , <a.name>}>);
<currentRule.name>(<currentRule.args:{a | <a.name>}; separator=", ">) {
let localctx = new <currentRule.ctxType>(this, this._ctx, this.state<currentRule.args:{a | , <a.name>}>);
this.enterRule(localctx, <currentRule.startState>, <parser.name>.RULE_<currentRule.name>);
<namedActions.init>
<locals; separator="\n">
@ -277,7 +267,7 @@ RuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,namedActions,fina
this.exitRule();
}
return localctx;
};
}
>>
@ -285,18 +275,15 @@ LeftRecursiveRuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,
namedActions,finallyAction,postamble) ::=
<<
<ruleCtx>
<altLabelCtxs:{l | <altLabelCtxs.(l)>}; separator="\n">
<parser.name>.prototype.<currentRule.name> = function(_p<if(currentRule.args)>, <args:{a | , <a>}><endif>) {
<currentRule.name>(_p<if(currentRule.args)>, <args:{a | , <a>}><endif>) {
if(_p===undefined) {
_p = 0;
}
var _parentctx = this._ctx;
var _parentState = this.state;
var localctx = new <currentRule.ctxType>(this, this._ctx, _parentState<args:{a | , <a.name>}>);
var _prevctx = localctx;
var _startState = <currentRule.startState>;
const _parentctx = this._ctx;
const _parentState = this.state;
let localctx = new <currentRule.ctxType>(this, this._ctx, _parentState<args:{a | , <a.name>}>);
let _prevctx = localctx;
const _startState = <currentRule.startState>;
this.enterRecursionRule(localctx, <currentRule.startState>, <parser.name>.RULE_<currentRule.name>, _p);
<namedActions.init>
<locals; separator="\n">
@ -317,7 +304,7 @@ LeftRecursiveRuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,
this.unrollRecursionContexts(_parentctx)
}
return localctx;
};
}
>>
@ -424,7 +411,7 @@ if(la_===<i><if(!choice.ast.greedy)>+1<endif>) {
StarBlock(choice, alts, sync, iteration) ::= <<
this.state = <choice.stateNumber>;
this._errHandler.sync(this);
var _alt = this._interp.adaptivePredict(this._input,<choice.decision>,this._ctx)
let _alt = this._interp.adaptivePredict(this._input,<choice.decision>,this._ctx)
while(_alt!=<choice.exitAlt> && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {
if(_alt===1<if(!choice.ast.greedy)>+1<endif>) {
<iteration>
@ -440,7 +427,7 @@ while(_alt!=<choice.exitAlt> && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {
PlusBlock(choice, alts, error) ::= <<
this.state = <choice.blockStartStateNumber>; <! alt block decision !>
this._errHandler.sync(this);
var _alt = 1<if(!choice.ast.greedy)>+1<endif>;
let _alt = 1<if(!choice.ast.greedy)>+1<endif>;
do {
switch (_alt) {
<alts:{alt|
@ -604,15 +591,16 @@ RuleContextDecl(r) ::= "this.<r.name> = null; // <r.ctxName>"
RuleContextListDecl(rdecl) ::= "this.<rdecl.name> = []; // of <rdecl.ctxName>s"
ContextTokenGetterDecl(t) ::= <<
<t.name> = function() {
<t.name>() {
return this.getToken(<parser.name>.<t.name>, 0);
};
>>
// should never be called
ContextTokenListGetterDecl(t) ::= <<
def <t.name>_list(self):
return self.getTokens(<parser.name>.<t.name>)
<t.name>_list() {
return this.getTokens(<parser.name>.<t.name>);
}
>>
ContextTokenListIndexedGetterDecl(t) ::= <<
@ -630,16 +618,16 @@ ContextTokenListIndexedGetterDecl(t) ::= <<
>>
ContextRuleGetterDecl(r) ::= <<
<r.name> = function() {
<r.name>() {
return this.getTypedRuleContext(<r.ctxName>,0);
};
>>
// should never be called
ContextRuleListGetterDecl(r) ::= <<
def <r.name>_list(self):
return self.getTypedRuleContexts(<parser.name>.<r.ctxName>)
<r.name>_list() {
return this.getTypedRuleContexts(<parser.name>.<r.ctxName>);
}
>>
ContextRuleListIndexedGetterDecl(r) ::= <<
@ -672,6 +660,7 @@ CaptureNextTokenType(d) ::= "<d.varName> = this._input.LA(1);"
StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) ::= <<
class <struct.name> extends <if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif> {
constructor(parser, parent, invokingState<struct.ctorAttrs:{a | , <a.name>}>) {
if(parent===undefined) {
parent = null;
@ -685,58 +674,59 @@ class <struct.name> extends <if(contextSuperClass)><contextSuperClass><else>antl
<attrs:{a | <a>}; separator="\n">
<struct.ctorAttrs:{a | this.<a.name> = <a.name> || null;}; separator="\n">
}
<getters:{g | <g>}; separator="\n\n">
<if(struct.provideCopyFrom)> <! don't need copy unless we have subclasses !>
copyFrom(ctx) {
super.copyFrom(ctx);
<struct.attrs:{a | this.<a.name> = ctx.<a.name>;}; separator="\n">
}
<endif>
<dispatchMethods; separator="\n">
<extensionMembers; separator="\n">
}
<getters:{g | <struct.name>.prototype.<g>}; separator="\n\n">
<if(struct.provideCopyFrom)> <! don't need copy unless we have subclasses !>
<struct.name>.prototype.copyFrom = function(ctx) {
<if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif>.prototype.copyFrom.call(this, ctx);
<struct.attrs:{a | this.<a.name> = ctx.<a.name>;}; separator="\n">
};
<endif>
<dispatchMethods; separator="\n">
<extensionMembers; separator="\n">
>>
AltLabelStructDecl(struct,attrs,getters,dispatchMethods) ::= <<
class <struct.name> extends <currentRule.name; format="cap">Context {
class <struct.name> extends <struct.parentRule; format="cap">Context {
constructor(parser, ctx) {
super(parser);
<attrs:{a | <a>;}; separator="\n">
<currentRule.name; format="cap">Context.prototype.copyFrom.call(this, ctx);
super.copyFrom(ctx);
}
}
<struct.name>.prototype = Object.create(<currentRule.name; format="cap">Context.prototype);
<struct.name>.prototype.constructor = <struct.name>;
<getters:{g | <g>}; separator="\n\n">
<dispatchMethods; separator="\n">
}
<! Define fields of this parser to export this struct/context class !>
<parser.name>.<struct.name> = <struct.name>;
<getters:{g | <struct.name>.prototype.<g>}; separator="\n\n">
<dispatchMethods; separator="\n">
>>
ListenerDispatchMethod(method) ::= <<
<struct.name>.prototype.<if(method.isEnter)>enter<else>exit<endif>Rule = function(listener) {
<if(method.isEnter)>enter<else>exit<endif>Rule(listener) {
if(listener instanceof <parser.grammarName>Listener ) {
listener.<if(method.isEnter)>enter<else>exit<endif><struct.derivedFromName; format="cap">(this);
}
};
}
>>
VisitorDispatchMethod(method) ::= <<
<struct.name>.prototype.accept = function(visitor) {
accept(visitor) {
if ( visitor instanceof <parser.grammarName>Visitor ) {
return visitor.visit<struct.derivedFromName; format="cap">(this);
} else {
return visitor.visitChildren(this);
}
};
}
>>
@ -787,7 +777,7 @@ _prevctx = localctx;
LexerFile(lexerFile, lexer, namedActions) ::= <<
<fileHeader(lexerFile.grammarFileName, lexerFile.ANTLRVersion)>
var antlr4 = require('antlr4/index');
import antlr4 from 'antlr4';
<namedActions.header>
@ -797,32 +787,28 @@ var antlr4 = require('antlr4/index');
Lexer(lexer, atn, actionFuncs, sempredFuncs, superClass) ::= <<
<if(superClass)>
var <superClass> = require('./<superClass>').<superClass>;
import <superClass> from './<superClass>.js';
<endif>
<atn>
var atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);
const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);
var decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new antlr4.dfa.DFA(ds, index); });
const decisionsToDFA = atn.decisionToState.map( (ds, index) => new antlr4.dfa.DFA(ds, index) );
export default class <lexer.name> extends <if(superClass)><superClass><else>antlr4.Lexer<endif> {
static grammarFileName = "<lexer.grammarFileName>";
static channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN"<if (lexer.channels)>, <lexer.channels:{c| "<c>"}; separator=", ", wrap, anchor><endif> ];
static modeNames = [ <lexer.modes:{m| "<m>"}; separator=", ", wrap, anchor> ];
static literalNames = [ <lexer.literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ];
static symbolicNames = [ <lexer.symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ];
static ruleNames = [ <lexer.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ];
class <lexer.name> extends <if(superClass)><superClass><else>antlr4.Lexer<endif> {
constructor(input) {
super(input)
this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache());
<namedActions.members>
this.channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN"<if (lexer.channels)>, <lexer.channels:{c| "<c>"}; separator=", ", wrap, anchor><endif> ];
this.modeNames = [ <lexer.modes:{m| "<m>"}; separator=", ", wrap, anchor> ];
this.literalNames = [ <lexer.literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ];
this.symbolicNames = [ <lexer.symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ];
this.ruleNames = [ <lexer.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ];
this.grammarFileName = "<lexer.grammarFileName>";
}
get atn() {
@ -844,14 +830,13 @@ class <lexer.name> extends <if(superClass)><superClass><else>antlr4.Lexer<endif>
<dumpActions(lexer, "", actionFuncs, sempredFuncs)>
module.exports.<lexer.name> = <lexer.name>;
>>
SerializedATN(model) ::= <<
<! only one segment, can be inlined !>
var serializedATN = ["<model.serialized; wrap={",<\n> "}>"].join("");
const serializedATN = ["<model.serialized; wrap={",<\n> "}>"].join("");
>>