Clean up the caching of ATN instances with bypass alternatives

This commit is contained in:
Sam Harwell 2013-12-10 20:15:32 -06:00
parent 2618aa335a
commit df61690758
3 changed files with 32 additions and 26 deletions

View File

@ -51,6 +51,8 @@ import org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
/** This is all the parsing support code essentially; most of it is error recovery stuff. */ /** This is all the parsing support code essentially; most of it is error recovery stuff. */
public abstract class Parser extends Recognizer<Token, ParserATNSimulator> { public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
@ -98,6 +100,15 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
} }
} }
/**
* This field maps from the serialized ATN string to the deserialized {@link ATN} with
* bypass alternatives.
*
* @see ATNDeserializationOptions#isGenerateRuleBypassTransitions()
*/
private static final Map<String, ATN> bypassAltsAtnCache =
new WeakHashMap<String, ATN>();
/** /**
* The error handling strategy for the parser. The default value is a new * The error handling strategy for the parser. The default value is a new
* instance of {@link DefaultErrorStrategy}. * instance of {@link DefaultErrorStrategy}.
@ -435,26 +446,30 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
_input.getTokenSource().setTokenFactory(factory); _input.getTokenSource().setTokenFactory(factory);
} }
/** The ATN with bypass alternatives is expensive to create so we create it lazily. /**
* The actual generated parsers override this method. These are just * The ATN with bypass alternatives is expensive to create so we create it
* setters/getters. createATNWithBypassAlts() does the creation. * lazily.
*
* @throws UnsupportedOperationException if the current parser does not
* implement the {@link #getSerializedATN()} method.
*/ */
public void setATNWithBypassAlts(ATN atn) { } @NotNull
public ATN getATNWithBypassAlts() { return null; } public ATN getATNWithBypassAlts() {
String serializedAtn = getSerializedATN();
if (serializedAtn == null) {
throw new UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives.");
}
/** Create and cache the ATN with bypass alternatives. This is not synchronized (bypassAltsAtnCache) {
* part of the typical API--use compileParseTreePattern(). ATN result = bypassAltsAtnCache.get(serializedAtn);
*/ if (result == null) {
public void createATNWithBypassAlts() { ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions();
if ( getATNWithBypassAlts()==null ) { deserializationOptions.setGenerateRuleBypassTransitions(true);
synchronized (Parser.class) { // create just one pattern matcher result = new ATNDeserializer(deserializationOptions).deserialize(serializedAtn.toCharArray());
if ( getATNWithBypassAlts()==null ) { // double-check bypassAltsAtnCache.put(serializedAtn, result);
String sATN = getSerializedATN();
ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions();
deserializationOptions.setGenerateRuleBypassTransitions(true);
setATNWithBypassAlts( new ATNDeserializer(deserializationOptions).deserialize(sATN.toCharArray()) );
}
} }
return result;
} }
} }
@ -483,7 +498,6 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
public ParseTreePattern compileParseTreePattern(String pattern, int patternRuleIndex, public ParseTreePattern compileParseTreePattern(String pattern, int patternRuleIndex,
Lexer lexer) Lexer lexer)
{ {
createATNWithBypassAlts();
ParseTreePatternMatcher m = new ParseTreePatternMatcher(lexer, this); ParseTreePatternMatcher m = new ParseTreePatternMatcher(lexer, this);
return m.compile(pattern, patternRuleIndex); return m.compile(pattern, patternRuleIndex);
} }

View File

@ -132,9 +132,6 @@ public class ParseTreePatternMatcher {
public ParseTreePatternMatcher(Lexer lexer, Parser parser) { public ParseTreePatternMatcher(Lexer lexer, Parser parser) {
this.lexer = lexer; this.lexer = lexer;
this.parser = parser; this.parser = parser;
if ( parser!=null ) {
parser.createATNWithBypassAlts();
}
} }
public void setDelimiters(String start, String stop, String escapeLeft) { public void setDelimiters(String start, String stop, String escapeLeft) {

View File

@ -247,10 +247,6 @@ public class <parser.name> extends <superClass> {
@Override @Override
public ATN getATN() { return _ATN; } public ATN getATN() { return _ATN; }
@Override
public ATN getATNWithBypassAlts() { return _ATNWithBypassAlts; }
@Override
public void setATNWithBypassAlts(ATN atn) { _ATNWithBypassAlts = atn; }
@Override @Override
public Map\<String, Integer> getTokenTypeMap() { return tokenNameToType; } public Map\<String, Integer> getTokenTypeMap() { return tokenNameToType; }
@ -935,7 +931,6 @@ public static final String _serializedATN =
<endif> <endif>
public static final ATN _ATN = public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray()); new ATNDeserializer().deserialize(_serializedATN.toCharArray());
public static ATN _ATNWithBypassAlts;
static { static {
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i \< _ATN.getNumberOfDecisions(); i++) { for (int i = 0; i \< _ATN.getNumberOfDecisions(); i++) {