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 }