From df616907580db2710eecc5b462d1ca6cad134a14 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Tue, 10 Dec 2013 20:15:32 -0600 Subject: [PATCH] Clean up the caching of ATN instances with bypass alternatives --- .../Java/src/org/antlr/v4/runtime/Parser.java | 50 ++++++++++++------- .../tree/pattern/ParseTreePatternMatcher.java | 3 -- .../v4/tool/templates/codegen/Java/Java.stg | 5 -- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/runtime/Java/src/org/antlr/v4/runtime/Parser.java b/runtime/Java/src/org/antlr/v4/runtime/Parser.java index 246a81da0..b89b57712 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/Parser.java +++ b/runtime/Java/src/org/antlr/v4/runtime/Parser.java @@ -51,6 +51,8 @@ import org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher; import java.util.ArrayList; import java.util.Collections; 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. */ public abstract class Parser extends Recognizer { @@ -98,6 +100,15 @@ public abstract class Parser extends Recognizer { } } + /** + * This field maps from the serialized ATN string to the deserialized {@link ATN} with + * bypass alternatives. + * + * @see ATNDeserializationOptions#isGenerateRuleBypassTransitions() + */ + private static final Map bypassAltsAtnCache = + new WeakHashMap(); + /** * The error handling strategy for the parser. The default value is a new * instance of {@link DefaultErrorStrategy}. @@ -435,26 +446,30 @@ public abstract class Parser extends Recognizer { _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 - * setters/getters. createATNWithBypassAlts() does the creation. + /** + * The ATN with bypass alternatives is expensive to create so we create it + * lazily. + * + * @throws UnsupportedOperationException if the current parser does not + * implement the {@link #getSerializedATN()} method. */ - public void setATNWithBypassAlts(ATN atn) { } - public ATN getATNWithBypassAlts() { return null; } + @NotNull + 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 - * part of the typical API--use compileParseTreePattern(). - */ - public void createATNWithBypassAlts() { - if ( getATNWithBypassAlts()==null ) { - synchronized (Parser.class) { // create just one pattern matcher - if ( getATNWithBypassAlts()==null ) { // double-check - String sATN = getSerializedATN(); - ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions(); - deserializationOptions.setGenerateRuleBypassTransitions(true); - setATNWithBypassAlts( new ATNDeserializer(deserializationOptions).deserialize(sATN.toCharArray()) ); - } + synchronized (bypassAltsAtnCache) { + ATN result = bypassAltsAtnCache.get(serializedAtn); + if (result == null) { + ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions(); + deserializationOptions.setGenerateRuleBypassTransitions(true); + result = new ATNDeserializer(deserializationOptions).deserialize(serializedAtn.toCharArray()); + bypassAltsAtnCache.put(serializedAtn, result); } + + return result; } } @@ -483,7 +498,6 @@ public abstract class Parser extends Recognizer { public ParseTreePattern compileParseTreePattern(String pattern, int patternRuleIndex, Lexer lexer) { - createATNWithBypassAlts(); ParseTreePatternMatcher m = new ParseTreePatternMatcher(lexer, this); return m.compile(pattern, patternRuleIndex); } diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/pattern/ParseTreePatternMatcher.java b/runtime/Java/src/org/antlr/v4/runtime/tree/pattern/ParseTreePatternMatcher.java index 486d64e87..40be37526 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/tree/pattern/ParseTreePatternMatcher.java +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/pattern/ParseTreePatternMatcher.java @@ -132,9 +132,6 @@ public class ParseTreePatternMatcher { public ParseTreePatternMatcher(Lexer lexer, Parser parser) { this.lexer = lexer; this.parser = parser; - if ( parser!=null ) { - parser.createATNWithBypassAlts(); - } } public void setDelimiters(String start, String stop, String escapeLeft) { diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg index 6fda84498..e69ededb2 100644 --- a/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg @@ -247,10 +247,6 @@ public class extends { @Override public ATN getATN() { return _ATN; } - @Override - public ATN getATNWithBypassAlts() { return _ATNWithBypassAlts; } - @Override - public void setATNWithBypassAlts(ATN atn) { _ATNWithBypassAlts = atn; } @Override public Map\ getTokenTypeMap() { return tokenNameToType; } @@ -935,7 +931,6 @@ public static final String _serializedATN = public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); -public static ATN _ATNWithBypassAlts; static { _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; for (int i = 0; i \< _ATN.getNumberOfDecisions(); i++) {