1 /*
2 * Copyright (c) 2012-2020 The ANTLR Project. All rights reserved.
3 * Use of this file is governed by the BSD 3-clause license that
4 * can be found in the LICENSE.txt file in the project root.
5 */
6
7 module antlr.v4.runtime.atn.ProfilingATNSimulator;
8
9 import std.conv;
10 import std.datetime;
11 import std.algorithm;
12 import antlr.v4.runtime.atn.ATNConfigSet;
13 import antlr.v4.runtime.atn.ParserATNSimulator;
14 import antlr.v4.runtime.atn.DecisionInfo;
15 import antlr.v4.runtime.atn.ErrorInfo;
16 import antlr.v4.runtime.atn.PredicateEvalInfo;
17 import antlr.v4.runtime.atn.LookaheadEventInfo;
18 import antlr.v4.runtime.dfa.DFAState;
19 import antlr.v4.runtime.dfa.DFA;
20 import antlr.v4.runtime.Parser;
21 import antlr.v4.runtime.atn.SemanticContext;
22 import antlr.v4.runtime.TokenStream;
23 import antlr.v4.runtime.ParserRuleContext;
24
25 /**
26 * TODO add class description
27 */
28 class ProfilingATNSimulator : ParserATNSimulator
29 {
30
31 protected DecisionInfo[] decisions;
32
33 protected int currentDecision;
34
35 protected int numDecisions;
36
37 protected size_t _sllStopIndex;
38
39 protected size_t _llStopIndex;
40
41 protected DFAState currentState;
42
43 /**
44 * we can determine whether or not a decision / input pair is context-sensitive.
45 * If LL gives a different result than SLL's predicted alternative, we have a
46 * context sensitivity for sure. The converse is not necessarily true, however.
47 * It's possible that after conflict resolution chooses minimum alternatives,
48 * SLL could get the same answer as LL. Regardless of whether or not the result indicates
49 * an ambiguity, it is not treated as a context sensitivity because LL prediction
50 * was not required in order to produce a correct prediction for this decision and input sequence.
51 * It may in fact still be a context sensitivity but we don't know by looking at the
52 * minimum alternatives for the current input.
53 */
54 public int conflictingAltResolvedBySLL;
55
56 public this(Parser parser)
57 {
58 super(parser,
59 parser.getInterpreter().atn,
60 parser.getInterpreter().decisionToDFA,
61 parser.getInterpreter().sharedContextCache);
62 numDecisions = to!int(atn.decisionToState.length);
63 decisions = new DecisionInfo[numDecisions];
64 for (int i=0; i<numDecisions; i++) {
65 decisions[i] = new DecisionInfo(i);
66 }
67 }
68
69 /**
70 * @uml
71 * @override
72 */
73 public override int adaptivePredict(TokenStream input, int decision, ParserRuleContext outerContext)
74 {
75 try {
76 this._sllStopIndex = -1;
77 this._llStopIndex = -1;
78 this.currentDecision = decision;
79 auto start = MonoTime.currTime; // expensive but useful info
80 int alt = super.adaptivePredict(input, decision, outerContext);
81 auto stop = MonoTime.currTime;
82 decisions[decision].timeInPrediction += ticksToNSecs(stop.ticks - start.ticks);
83 decisions[decision].invocations++;
84
85 auto SLL_k = _sllStopIndex - _startIndex + 1;
86 decisions[decision].SLL_TotalLook += SLL_k;
87 decisions[decision].SLL_MinLook = decisions[decision].SLL_MinLook==0 ? SLL_k : min(decisions[decision].SLL_MinLook, SLL_k);
88 if ( SLL_k > decisions[decision].SLL_MaxLook ) {
89 decisions[decision].SLL_MaxLook = SLL_k;
90 decisions[decision].SLL_MaxLookEvent =
91 new LookaheadEventInfo(decision, null, alt, input, _startIndex, _sllStopIndex, false);
92 }
93
94 if (_llStopIndex >= 0) {
95 int LL_k = to!int(_llStopIndex - _startIndex) + 1;
96 decisions[decision].LL_TotalLook += LL_k;
97 decisions[decision].LL_MinLook = decisions[decision].LL_MinLook==0 ? LL_k : min(decisions[decision].LL_MinLook, LL_k);
98 if ( LL_k > decisions[decision].LL_MaxLook ) {
99 decisions[decision].LL_MaxLook = LL_k;
100 decisions[decision].LL_MaxLookEvent =
101 new LookaheadEventInfo(decision, null, alt, input, _startIndex, _llStopIndex, true);
102 }
103 }
104
105 return alt;
106 }
107 finally {
108 this.currentDecision = -1;
109 }
110
111 }
112
113 /**
114 * @uml
115 * @override
116 */
117 public override DFAState getExistingTargetState(DFAState previousD, int t)
118 {
119 // this method is called after each time the input position advances
120 // during SLL prediction
121 _sllStopIndex = _input.index;
122
123 DFAState existingTargetState = super.getExistingTargetState(previousD, t);
124 if (existingTargetState !is null) {
125 decisions[currentDecision].SLL_DFATransitions++; // count only if we transition over a DFA state
126 if ( existingTargetState==ERROR ) {
127 decisions[currentDecision].errors
128 ~= new ErrorInfo(currentDecision, previousD.configs, _input, _startIndex, _sllStopIndex, false);
129 }
130 }
131
132 currentState = existingTargetState;
133 return existingTargetState;
134
135 }
136
137 /**
138 * @uml
139 * @override
140 */
141 protected override DFAState computeTargetState(DFA dfa, DFAState previousD, int t)
142 {
143 DFAState state = super.computeTargetState(dfa, previousD, t);
144 currentState = state;
145 return state;
146 }
147
148 /**
149 * @uml
150 * @override
151 */
152 protected override ATNConfigSet computeReachSet(ATNConfigSet closure, int t, bool fullCtx)
153 {
154 if (fullCtx) {
155 // this method is called after each time the input position advances
156 // during full context prediction
157 _llStopIndex = _input.index();
158 }
159
160 ATNConfigSet reachConfigs = super.computeReachSet(closure, t, fullCtx);
161 if (fullCtx) {
162 decisions[currentDecision].LL_ATNTransitions++; // count computation even if error
163 if (reachConfigs !is null) {
164 }
165 else { // no reach on current lookahead symbol. ERROR.
166 // TODO: does not handle delayed errors per getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule()
167 decisions[currentDecision].errors
168 ~= new ErrorInfo(currentDecision, closure, _input, _startIndex, _llStopIndex, true);
169 }
170 }
171 else {
172 decisions[currentDecision].SLL_ATNTransitions++;
173 if (reachConfigs !is null) {
174 }
175 else { // no reach on current lookahead symbol. ERROR.
176 decisions[currentDecision].errors
177 ~= new ErrorInfo(currentDecision, closure, _input, _startIndex, _sllStopIndex, false);
178 }
179 }
180 return reachConfigs;
181
182 }
183
184 /**
185 * @uml
186 * @override
187 */
188 protected override bool evalSemanticContext(SemanticContext pred, ParserRuleContext parserCallStack,
189 int alt, bool fullCtx)
190 {
191 bool result = super.evalSemanticContext(pred, parserCallStack, alt, fullCtx);
192 if (pred.classinfo != SemanticContext.PrecedencePredicate.classinfo) {
193 bool fullContext = _llStopIndex >= 0;
194 auto stopIndex = fullContext ? _llStopIndex : _sllStopIndex;
195 decisions[currentDecision].predicateEvals
196 ~= new PredicateEvalInfo(currentDecision, _input, _startIndex, stopIndex, pred, result, alt, fullCtx);
197 }
198 return result;
199 }
200
201 public DecisionInfo[] getDecisionInfo()
202 {
203 return decisions;
204 }
205
206 }