1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
import lombok.SneakyThrows; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.atn.ATN; import org.antlr.v4.runtime.atn.LexerATNSimulator; import org.antlr.v4.runtime.atn.ParserATNSimulator; import org.antlr.v4.runtime.atn.PredictionContextCache; import org.antlr.v4.runtime.dfa.DFA;
import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer;
import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull;
public class RefreshableParserInitializer<L extends Lexer,P extends Parser> implements BiConsumer<L , P > { private final AtomicReference<ParserAndLexerATNCaches<L,P>> caches = new AtomicReference<>();
public RefreshableParserInitializer() { Type superClass = this.getClass().getGenericSuperclass(); lexer = (Class<?>)((ParameterizedType)superClass).getActualTypeArguments()[0]; parser = (Class<?>)((ParameterizedType)superClass).getActualTypeArguments()[1]; refresh(); }
public void refresh() { caches.set(buildATNCache()); }
private final Class<?> lexer; private final Class<?> parser;
@SneakyThrows({SecurityException.class, NoSuchFieldException.class,IllegalAccessException.class}) private static ATN getATNField(Class<?> clazz) { Field field = clazz.getDeclaredField("_ATN"); field.setAccessible(true); return (ATN)field.get(null); }
private ParserAndLexerATNCaches<L,P> buildATNCache(){ ATN lexerATN =getATNField(lexer); ATN parserATN = getATNField(parser); return new ParserAndLexerATNCaches(new AntlrATNCacheFields(lexerATN),new AntlrATNCacheFields(parserATN)); }
@Override public void accept(L l, P p) { ParserAndLexerATNCaches<L,P> cache =caches.get(); cache.lexer.configureLexer(l); cache.parser.configureParser(p); }
private static final class ParserAndLexerATNCaches<L extends Lexer,P extends Parser> { public ParserAndLexerATNCaches(AntlrATNCacheFields lexer, AntlrATNCacheFields parser) { this.lexer = lexer; this.parser = parser; }
public final AntlrATNCacheFields lexer; public final AntlrATNCacheFields parser; } public static final class AntlrATNCacheFields { private final ATN atn; private final PredictionContextCache predictionContextCache; private final DFA[] decisionToDFA;
public AntlrATNCacheFields(ATN atn) { this.atn = requireNonNull(atn, "atn is null"); this.predictionContextCache = new PredictionContextCache(); this.decisionToDFA = createDecisionToDFA(atn); }
@SuppressWarnings("ObjectEquality") public void configureLexer(Lexer lexer) { requireNonNull(lexer, "lexer is null"); checkArgument(atn == lexer.getATN(), "Lexer ATN mismatch: expected %s, found %s", atn, lexer.getATN()); lexer.setInterpreter(new LexerATNSimulator(lexer, atn, decisionToDFA, predictionContextCache)); }
@SuppressWarnings("ObjectEquality") public void configureParser(Parser parser) { requireNonNull(parser, "parser is null"); checkArgument(atn == parser.getATN(), "Parser ATN mismatch: expected %s, found %s", atn, parser.getATN()); parser.setInterpreter(new ParserATNSimulator(parser, atn, decisionToDFA, predictionContextCache)); }
private static DFA[] createDecisionToDFA(ATN atn) { DFA[] decisionToDFA = new DFA[atn.getNumberOfDecisions()]; for (int i = 0; i < decisionToDFA.length; i++) { decisionToDFA[i] = new DFA(atn.getDecisionState(i), i); } return decisionToDFA; } } }
|