1 /*
2  * [The "BSD license"]
3  *  Copyright (c) 2013 Terence Parr
4  *  Copyright (c) 2013 Sam Harwell
5  *  Copyright (c) 2017 Egbert Voigt
6  *  All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *  3. The name of the author may not be used to endorse or promote products
18  *     derived from this software without specific prior written permission.
19  *
20  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 module antlr.v4.runtime.atn.ProfilingATNSimulator;
33 
34 import std.conv;
35 import std.datetime;
36 import std.algorithm;
37 import antlr.v4.runtime.atn.ATNConfigSet;
38 import antlr.v4.runtime.atn.ParserATNSimulator;
39 import antlr.v4.runtime.atn.DecisionInfo;
40 import antlr.v4.runtime.atn.ErrorInfo;
41 import antlr.v4.runtime.atn.PredicateEvalInfo;
42 import antlr.v4.runtime.atn.LookaheadEventInfo;
43 import antlr.v4.runtime.dfa.DFAState;
44 import antlr.v4.runtime.dfa.DFA;
45 import antlr.v4.runtime.Parser;
46 import antlr.v4.runtime.atn.SemanticContext;
47 import antlr.v4.runtime.TokenStream;
48 import antlr.v4.runtime.ParserRuleContext;
49 
50 // Class ProfilingATNSimulator
51 /**
52  * TODO add class description
53  */
54 class ProfilingATNSimulator : ParserATNSimulator
55 {
56 
57     protected DecisionInfo[] decisions;
58 
59     protected int currentDecision;
60 
61     protected int numDecisions;
62 
63     protected int _sllStopIndex;
64 
65     protected int _llStopIndex;
66 
67     protected DFAState currentState;
68 
69     /**
70      *  we can determine whether or not a decision / input pair is context-sensitive.
71      *  If LL gives a different result than SLL's predicted alternative, we have a
72      *  context sensitivity for sure. The converse is not necessarily true, however.
73      *  It's possible that after conflict resolution chooses minimum alternatives,
74      *  SLL could get the same answer as LL. Regardless of whether or not the result indicates
75      *  an ambiguity, it is not treated as a context sensitivity because LL prediction
76      *  was not required in order to produce a correct prediction for this decision and input sequence.
77      *  It may in fact still be a context sensitivity but we don't know by looking at the
78      *  minimum alternatives for the current input.
79      */
80     public int conflictingAltResolvedBySLL;
81 
82     public this(Parser parser)
83     {
84 	super(parser,
85               parser.getInterpreter().atn,
86               parser.getInterpreter().decisionToDFA,
87               parser.getInterpreter().sharedContextCache);
88         numDecisions = to!int(atn.decisionToState.length);
89         decisions = new DecisionInfo[numDecisions];
90         for (int i=0; i<numDecisions; i++) {
91             decisions[i] = new DecisionInfo(i);
92         }
93     }
94 
95     /**
96      * @uml
97      * @override
98      */
99     public override int adaptivePredict(TokenStream input, int decision, ParserRuleContext outerContext)
100     {
101 	try {
102             this._sllStopIndex = -1;
103             this._llStopIndex = -1;
104             this.currentDecision = decision;
105             auto start = MonoTime.currTime; // expensive but useful info
106             int alt = super.adaptivePredict(input, decision, outerContext);
107             auto stop = MonoTime.currTime;
108             decisions[decision].timeInPrediction += ticksToNSecs(stop.ticks - start.ticks);
109             decisions[decision].invocations++;
110 
111             int SLL_k = _sllStopIndex - _startIndex + 1;
112             decisions[decision].SLL_TotalLook += SLL_k;
113             decisions[decision].SLL_MinLook = decisions[decision].SLL_MinLook==0 ? SLL_k : min(decisions[decision].SLL_MinLook, SLL_k);
114             if ( SLL_k > decisions[decision].SLL_MaxLook ) {
115                 decisions[decision].SLL_MaxLook = SLL_k;
116                 decisions[decision].SLL_MaxLookEvent =
117                     new LookaheadEventInfo(decision, null, alt, input, _startIndex, _sllStopIndex, false);
118             }
119 
120             if (_llStopIndex >= 0) {
121                 int LL_k = _llStopIndex - _startIndex + 1;
122                 decisions[decision].LL_TotalLook += LL_k;
123                 decisions[decision].LL_MinLook = decisions[decision].LL_MinLook==0 ? LL_k : min(decisions[decision].LL_MinLook, LL_k);
124                 if ( LL_k > decisions[decision].LL_MaxLook ) {
125                     decisions[decision].LL_MaxLook = LL_k;
126                     decisions[decision].LL_MaxLookEvent =
127                         new LookaheadEventInfo(decision, null, alt, input, _startIndex, _llStopIndex, true);
128                 }
129             }
130 
131             return alt;
132         }
133         finally {
134             this.currentDecision = -1;
135         }
136 
137     }
138 
139     /**
140      * @uml
141      * @override
142      */
143     public override DFAState getExistingTargetState(DFAState previousD, int t)
144     {
145 	// this method is called after each time the input position advances
146         // during SLL prediction
147         _sllStopIndex = _input.index();
148 
149         DFAState existingTargetState = super.getExistingTargetState(previousD, t);
150         if (existingTargetState !is null) {
151             decisions[currentDecision].SLL_DFATransitions++; // count only if we transition over a DFA state
152             if ( existingTargetState==ERROR ) {
153                 decisions[currentDecision].errors
154                     ~= new ErrorInfo(currentDecision, previousD.configs, _input, _startIndex, _sllStopIndex, false);
155             }
156         }
157 
158         currentState = existingTargetState;
159         return existingTargetState;
160 
161     }
162 
163     /**
164      * @uml
165      * @override
166      */
167     protected override DFAState computeTargetState(DFA dfa, DFAState previousD, int t)
168     {
169 	DFAState state = super.computeTargetState(dfa, previousD, t);
170         currentState = state;
171         return state;
172     }
173 
174     /**
175      * @uml
176      * @override
177      */
178     protected override ATNConfigSet computeReachSet(ATNConfigSet closure, int t, bool fullCtx)
179     {
180 	if (fullCtx) {
181             // this method is called after each time the input position advances
182             // during full context prediction
183             _llStopIndex = _input.index();
184         }
185 
186         ATNConfigSet reachConfigs = super.computeReachSet(closure, t, fullCtx);
187         if (fullCtx) {
188             decisions[currentDecision].LL_ATNTransitions++; // count computation even if error
189             if (reachConfigs !is null) {
190             }
191             else { // no reach on current lookahead symbol. ERROR.
192                 // TODO: does not handle delayed errors per getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule()
193                 decisions[currentDecision].errors
194                     ~= new ErrorInfo(currentDecision, closure, _input, _startIndex, _llStopIndex, true);
195             }
196         }
197         else {
198             decisions[currentDecision].SLL_ATNTransitions++;
199             if (reachConfigs !is null) {
200             }
201             else { // no reach on current lookahead symbol. ERROR.
202                 decisions[currentDecision].errors
203                     ~= new ErrorInfo(currentDecision, closure, _input, _startIndex, _sllStopIndex, false);
204             }
205         }
206         return reachConfigs;
207 
208     }
209 
210     /**
211      * @uml
212      * @override
213      */
214     protected override bool evalSemanticContext(SemanticContext pred, ParserRuleContext parserCallStack,
215         int alt, bool fullCtx)
216     {
217 	bool result = super.evalSemanticContext(pred, parserCallStack, alt, fullCtx);
218         if (pred.classinfo != SemanticContext.PrecedencePredicate.classinfo) {
219             bool fullContext = _llStopIndex >= 0;
220             int stopIndex = fullContext ? _llStopIndex : _sllStopIndex;
221             decisions[currentDecision].predicateEvals
222                 ~= new PredicateEvalInfo(currentDecision, _input, _startIndex, stopIndex, pred, result, alt, fullCtx);
223         }
224         return result;
225     }
226 
227     public DecisionInfo[] getDecisionInfo()
228     {
229         return decisions;
230     }
231 
232 }