Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix .interp file parsing test for the Java runtime. #3520

Merged
merged 1 commit into from
Jan 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ protected ATN createATN(Grammar g, boolean useSerializer) {

return atn;
}

protected void semanticProcess(Grammar g) {
if ( g.ast!=null && !g.ast.hasErrors ) {
// System.out.println(g.ast.toStringTree());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,54 @@
package org.antlr.v4.test.runtime.java;

import org.antlr.v4.Tool;
import org.antlr.v4.runtime.Vocabulary;
import org.antlr.v4.runtime.VocabularyImpl;
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.runtime.misc.InterpreterDataReader;
import org.antlr.v4.runtime.misc.Utils;
import org.antlr.v4.tool.Grammar;
import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class TestInterpreterDataReader {

/** This file represents a simple sanity checks on the parsing of the .interp file
* available to the Java runtime for interpreting rather than compiling and executing parsers.
*/
public class TestInterpreterDataReader extends BaseJavaTest {
@Test
public void testParseFile() throws NoSuchFieldException, IllegalAccessException {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
// pay attention to the path where the InterpDataReaderTest.interp is stored.
final URL stuff = loader.getResource("org/antlr/v4/test/runtime/InterpDataReaderTest.interp");
Assert.assertNotNull(stuff);
public void testParseFile() throws IOException, NoSuchFieldException, IllegalAccessException, org.antlr.runtime.RecognitionException {
Grammar g = new Grammar(
"grammar Calc;\n" +
"s : expr EOF\n" +
" ;\n" +
"expr\n" +
" : INT # number\n" +
" | expr (MUL | DIV) expr # multiply\n" +
" | expr (ADD | SUB) expr # add\n" +
" ;\n" +
"\n" +
"INT : [0-9]+;\n" +
"MUL : '*';\n" +
"DIV : '/';\n" +
"ADD : '+';\n" +
"SUB : '-';\n" +
"WS : [ \\t]+ -> channel(HIDDEN);");
String interpString = Tool.generateInterpreterData(g);
Path interpFile = Files.createTempFile(null, null);
Files.write(interpFile, interpString.getBytes(StandardCharsets.UTF_8));

InterpreterDataReader.InterpreterData interpreterData = InterpreterDataReader.parseFile(stuff.getPath());
InterpreterDataReader.InterpreterData interpreterData = InterpreterDataReader.parseFile(interpFile.toString());
Field atnField = interpreterData.getClass().getDeclaredField("atn");
Field vocabularyField = interpreterData.getClass().getDeclaredField("vocabulary");
Field ruleNamesField = interpreterData.getClass().getDeclaredField("ruleNames");
Expand All @@ -36,30 +63,21 @@ public void testParseFile() throws NoSuchFieldException, IllegalAccessException

ATN atn = (ATN) atnField.get(interpreterData);
Vocabulary vocabulary = (Vocabulary) vocabularyField.get(interpreterData);
List<String> ruleNames = castList(ruleNamesField.get(interpreterData), String.class);
String[] literalNames = ((VocabularyImpl) vocabulary).getLiteralNames();
String[] symbolicNames = ((VocabularyImpl) vocabulary).getSymbolicNames();
List<String> ruleNames = castList(ruleNamesField.get(interpreterData), String.class);
List<String> channels = castList(channelsField.get(interpreterData), String.class);
List<String> modes = castList(modesField.get(interpreterData), String.class);

char[] atnChars = ATNSerializer.getSerializedAsChars(atn);
Assert.assertTrue(atnChars.length > 0);
Assert.assertNotNull(vocabulary);
Assert.assertEquals(11, ruleNames.size());
Assert.assertEquals(2, channels.size());
Assert.assertEquals(1, modes.size());
}
Assert.assertEquals(6, vocabulary.getMaxTokenType());
Assert.assertArrayEquals(new String[]{"s","expr"}, ruleNames.toArray());
Assert.assertArrayEquals(new String[]{"", "", "'*'", "'/'", "'+'", "'-'", ""}, literalNames);
Assert.assertArrayEquals(new String[]{"", "INT", "MUL", "DIV", "ADD", "SUB", "WS"}, symbolicNames);
Assert.assertNull(channels);
Assert.assertNull(modes);

@Test
public void testParseFileError() {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
final URL stuff = loader.getResource("org/antlr/v4/test/runtime/InterpDataReaderTest2.interp");
Assert.assertNotNull(stuff);

try {
InterpreterDataReader.InterpreterData interpreterData = InterpreterDataReader.parseFile(stuff.getPath());
} catch (Exception e) {
Assert.assertEquals(e.getClass(), RuntimeException.class);
Assert.assertEquals(e.getMessage(), "Unexpected data entry");
}
char[] atnChars = ATNSerializer.getSerializedAsChars(atn);
Assert.assertEquals(ATNDeserializer.SERIALIZED_VERSION, atnChars[0]);
}

private <T> List<T> castList(Object obj, Class<T> clazz) {
Expand Down
14 changes: 14 additions & 0 deletions runtime/Java/src/org/antlr/v4/runtime/VocabularyImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,18 @@ public String getDisplayName(int tokenType) {

return Integer.toString(tokenType);
}

// Because this is an actual implementation object, we can provide access methods for vocabulary symbols

public String[] getLiteralNames() {
return literalNames;
}

public String[] getSymbolicNames() {
return symbolicNames;
}

public String[] getDisplayNames() {
return displayNames;
}
}
25 changes: 11 additions & 14 deletions tool/src/org/antlr/v4/Tool.java
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,15 @@ public void processNonCombinedGrammar(Grammar g, boolean gencode) {

if ( generate_ATN_dot ) generateATNs(g);

if (gencode && g.tool.getNumErrors()==0 ) generateInterpreterData(g);
if (gencode && g.tool.getNumErrors()==0 ) {
String interpFile = generateInterpreterData(g);
try (Writer fw = getOutputFileWriter(g, g.name + ".interp")) {
fw.write(interpFile);
}
catch (IOException ioe) {
errMgr.toolError(ErrorType.CANNOT_WRITE_FILE, ioe);
}
}

// PERFORM GRAMMAR ANALYSIS ON ATN: BUILD DECISION DFAs
AnalysisPipeline anal = new AnalysisPipeline(g);
Expand Down Expand Up @@ -690,7 +698,7 @@ public void generateATNs(Grammar g) {
}
}

private void generateInterpreterData(Grammar g) {
public static String generateInterpreterData(Grammar g) {
StringBuilder content = new StringBuilder();

content.append("token literal names:\n");
Expand Down Expand Up @@ -738,18 +746,7 @@ private void generateInterpreterData(Grammar g) {
content.append("atn:\n");
content.append(serializedATN.toString());

try {
Writer fw = getOutputFileWriter(g, g.name + ".interp");
try {
fw.write(content.toString());
}
finally {
fw.close();
}
}
catch (IOException ioe) {
errMgr.toolError(ErrorType.CANNOT_WRITE_FILE, ioe);
}
return content.toString();
}

/** This method is used by all code generators to create new output
Expand Down