diff --git a/runtime/Java/src/org/antlr/v4/runtime/Recognizer.java b/runtime/Java/src/org/antlr/v4/runtime/Recognizer.java index b9af65ee0..24256a085 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/Recognizer.java +++ b/runtime/Java/src/org/antlr/v4/runtime/Recognizer.java @@ -38,6 +38,7 @@ import org.antlr.v4.runtime.misc.Nullable; import org.antlr.v4.runtime.misc.Utils; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -46,8 +47,8 @@ import java.util.concurrent.CopyOnWriteArrayList; public abstract class Recognizer { public static final int EOF=-1; - private static final Map> tokenTypeMapCache = - new WeakHashMap>(); + private static final Map> tokenTypeMapCache = + new WeakHashMap>(); private static final Map> ruleIndexMapCache = new WeakHashMap>(); @@ -91,18 +92,26 @@ public abstract class Recognizer { */ @NotNull public Map getTokenTypeMap() { - String[] tokenNames = getTokenNames(); - if (tokenNames == null) { - throw new UnsupportedOperationException("The current recognizer does not provide a list of token names."); - } - + Vocabulary vocabulary = getVocabulary(); synchronized (tokenTypeMapCache) { - Map result = tokenTypeMapCache.get(tokenNames); + Map result = tokenTypeMapCache.get(vocabulary); if (result == null) { - result = Utils.toMap(tokenNames); + result = new HashMap(); + for (int i = 0; i < getATN().maxTokenType; i++) { + String literalName = vocabulary.getLiteralName(i); + if (literalName != null) { + result.put(literalName, i); + } + + String symbolicName = vocabulary.getSymbolicName(i); + if (symbolicName != null) { + result.put(symbolicName, i); + } + } + result.put("EOF", Token.EOF); result = Collections.unmodifiableMap(result); - tokenTypeMapCache.put(tokenNames, result); + tokenTypeMapCache.put(vocabulary, result); } return result; diff --git a/tool/test/org/antlr/v4/test/TestXPath.java b/tool/test/org/antlr/v4/test/TestXPath.java index f36864807..f3cc5b5a3 100644 --- a/tool/test/org/antlr/v4/test/TestXPath.java +++ b/tool/test/org/antlr/v4/test/TestXPath.java @@ -42,6 +42,7 @@ public class TestXPath extends BaseTest { "DIV : '/' ;\n" + "ADD : '+' ;\n" + "SUB : '-' ;\n" + + "RETURN : 'return' ;\n" + "ID : [a-zA-Z]+ ; // match identifiers\n" + "INT : [0-9]+ ; // match integers\n" + "NEWLINE:'\\r'? '\\n' -> skip; // return newlines to parser (is end-statement signal)\n" + @@ -67,7 +68,8 @@ public class TestXPath extends BaseTest { "//ID", // any ID in tree "//expr/primary/ID",// any ID child of a primary under any expr "//body//ID", // any ID under a body - "//'return'", // any 'return' literal in tree + "//'return'", // any 'return' literal in tree, matched by literal name + "//RETURN", // any 'return' literal in tree, matched by symbolic name "//primary/*", // all kids of any primary "//func/*/stat", // all stat nodes grandkids of any func node "/prog/func/'def'", // all def literal kids of func kid of prog @@ -90,6 +92,7 @@ public class TestXPath extends BaseTest { "[y, x]", "[x, y, x]", "[return]", + "[return]", "[3, 4, y, 1, 2, x]", "[stat, stat, stat, stat]", "[def, def]",