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 /**
51  * TODO add class description
52  */
53 class ProfilingATNSimulator : ParserATNSimulator
54 {
55 
56     protected DecisionInfo[] decisions;
57 
58     protected int currentDecision;
59 
60     protected int numDecisions;
61 
62     protected int _sllStopIndex;
63 
64     protected int _llStopIndex;
65 
66     protected DFAState currentState;
67 
68     /**
69      *  we can determine whether or not a decision / input pair is context-sensitive.
70      *  If LL gives a different result than SLL's predicted alternative, we have a
71      *  context sensitivity for sure. The converse is not necessarily true, however.
72      *  It's possible that after conflict resolution chooses minimum alternatives,
73      *  SLL could get the same answer as LL. Regardless of whether or not the result indicates
74      *  an ambiguity, it is not treated as a context sensitivity because LL prediction
75      *  was not required in order to produce a correct prediction for this decision and input sequence.
76      *  It may in fact still be a context sensitivity but we don't know by looking at the
77      *  minimum alternatives for the current input.
78      */
79     public int conflictingAltResolvedBySLL;
80 
81     public this(Parser parser)
82     {
83 	super(parser,
84               parser.getInterpreter().atn,
85               parser.getInterpreter().decisionToDFA,
86               parser.getInterpreter().sharedContextCache);
87         numDecisions = to!int(atn.decisionToState.length);
88         decisions = new DecisionInfo[numDecisions];
89         for (int i=0; i<numDecisions; i++) {
90             decisions[i] = new DecisionInfo(i);
91         }
92     }
93 
94     /**
95      * @uml
96      * @override
97      */
98     public override int adaptivePredict(TokenStream input, int decision, ParserRuleContext outerContext)
99     {
100 	try {
101             this._sllStopIndex = -1;
102             this._llStopIndex = -1;
103             this.currentDecision = decision;
104             auto start = MonoTime.currTime; // expensive but useful info
105             int alt = super.adaptivePredict(input, decision, outerContext);
106             auto stop = MonoTime.currTime;
107             decisions[decision].timeInPrediction += ticksToNSecs(stop.ticks - start.ticks);
108             decisions[decision].invocations++;
109 
110             int SLL_k = _sllStopIndex - _startIndex + 1;
111             decisions[decision].SLL_TotalLook += SLL_k;
112             decisions[decision].SLL_MinLook = decisions[decision].SLL_MinLook==0 ? SLL_k : min(decisions[decision].SLL_MinLook, SLL_k);
113             if ( SLL_k > decisions[decision].SLL_MaxLook ) {
114                 decisions[decision].SLL_MaxLook = SLL_k;
115                 decisions[decision].SLL_MaxLookEvent =
116                     new LookaheadEventInfo(decision, null, alt, input, _startIndex, _sllStopIndex, false);
117             }
118 
119             if (_llStopIndex >= 0) {
120                 int LL_k = _llStopIndex - _startIndex + 1;
121                 decisions[decision].LL_TotalLook += LL_k;
122                 decisions[decision].LL_MinLook = decisions[decision].LL_MinLook==0 ? LL_k : min(decisions[decision].LL_MinLook, LL_k);
123                 if ( LL_k > decisions[decision].LL_MaxLook ) {
124                     decisions[decision].LL_MaxLook = LL_k;
125                     decisions[decision].LL_MaxLookEvent =
126                         new LookaheadEventInfo(decision, null, alt, input, _startIndex, _llStopIndex, true);
127                 }
128             }
129 
130             return alt;
131         }
132         finally {
133             this.currentDecision = -1;
134         }
135 
136     }
137 
138     /**
139      * @uml
140      * @override
141      */
142     public override DFAState getExistingTargetState(DFAState previousD, int t)
143     {
144 	// this method is called after each time the input position advances
145         // during SLL prediction
146         _sllStopIndex = _input.index();
147 
148         DFAState existingTargetState = super.getExistingTargetState(previousD, t);
149         if (existingTargetState !is null) {
150             decisions[currentDecision].SLL_DFATransitions++; // count only if we transition over a DFA state
151             if ( existingTargetState==ERROR ) {
152                 decisions[currentDecision].errors
153                     ~= new ErrorInfo(currentDecision, previousD.configs, _input, _startIndex, _sllStopIndex, false);
154             }
155         }
156 
157         currentState = existingTargetState;
158         return existingTargetState;
159 
160     }
161 
162     /**
163      * @uml
164      * @override
165      */
166     protected override DFAState computeTargetState(DFA dfa, DFAState previousD, int t)
167     {
168 	DFAState state = super.computeTargetState(dfa, previousD, t);
169         currentState = state;
170         return state;
171     }
172 
173     /**
174      * @uml
175      * @override
176      */
177     protected override ATNConfigSet computeReachSet(ATNConfigSet closure, int t, bool fullCtx)
178     {
179 	if (fullCtx) {
180             // this method is called after each time the input position advances
181             // during full context prediction
182             _llStopIndex = _input.index();
183         }
184 
185         ATNConfigSet reachConfigs = super.computeReachSet(closure, t, fullCtx);
186         if (fullCtx) {
187             decisions[currentDecision].LL_ATNTransitions++; // count computation even if error
188             if (reachConfigs !is null) {
189             }
190             else { // no reach on current lookahead symbol. ERROR.
191                 // TODO: does not handle delayed errors per getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule()
192                 decisions[currentDecision].errors
193                     ~= new ErrorInfo(currentDecision, closure, _input, _startIndex, _llStopIndex, true);
194             }
195         }
196         else {
197             decisions[currentDecision].SLL_ATNTransitions++;
198             if (reachConfigs !is null) {
199             }
200             else { // no reach on current lookahead symbol. ERROR.
201                 decisions[currentDecision].errors
202                     ~= new ErrorInfo(currentDecision, closure, _input, _startIndex, _sllStopIndex, false);
203             }
204         }
205         return reachConfigs;
206 
207     }
208 
209     /**
210      * @uml
211      * @override
212      */
213     protected override bool evalSemanticContext(SemanticContext pred, ParserRuleContext parserCallStack,
214         int alt, bool fullCtx)
215     {
216 	bool result = super.evalSemanticContext(pred, parserCallStack, alt, fullCtx);
217         if (pred.classinfo != SemanticContext.PrecedencePredicate.classinfo) {
218             bool fullContext = _llStopIndex >= 0;
219             int stopIndex = fullContext ? _llStopIndex : _sllStopIndex;
220             decisions[currentDecision].predicateEvals
221                 ~= new PredicateEvalInfo(currentDecision, _input, _startIndex, stopIndex, pred, result, alt, fullCtx);
222         }
223         return result;
224     }
225 
226     public DecisionInfo[] getDecisionInfo()
227     {
228         return decisions;
229     }
230 
231 }