1 /*
2  * Copyright (c) 2012-2019 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.ArrayPredictionContext;
8 
9 import antlr.v4.runtime.atn.PredictionContext;
10 import antlr.v4.runtime.atn.SingletonPredictionContext;
11 import std.array;
12 import std.container.array;
13 import std.conv;
14 import std.stdio;
15 
16 /**
17  * Array of prediction contexts
18  */
19 class ArrayPredictionContext : PredictionContext
20 {
21 
22     /**
23      * Parent can be null only if full ctx mode and we make an array
24      * from {@link #EMPTY} and non-empty. We merge {@link #EMPTY} by using null parent and
25      * returnState == {@link #EMPTY_RETURN_STATE}.
26      */
27     public PredictionContext[] parents;
28 
29     /**
30      * Sorted for merge, no duplicates; if present,
31      * {@link #EMPTY_RETURN_STATE} is always last.
32      * @uml
33      * @final
34      */
35     public int[] returnStates;
36 
37     public this(SingletonPredictionContext a)
38     {
39         PredictionContext[] parents;
40         parents ~= a.parent;
41         int[] returnStates;
42         returnStates ~= a.returnState;
43         this(parents, returnStates);
44     }
45 
46     public this(PredictionContext[] parents, int[] returnStates)
47     {
48         super(calculateHashCode(parents, returnStates)); // caching the hash code
49         assert(parents && parents.length > 0);
50         assert(returnStates && returnStates.length > 0);
51         debug {
52             import std.stdio;
53             writefln("CREATE ARRAY: %s, %s", parents, returnStates);
54         }
55         this.parents = parents;
56         this.returnStates = returnStates;
57     }
58 
59     /**
60      * @uml
61      * @override
62      */
63     public override bool isEmpty()
64     {
65         // since EMPTY_RETURN_STATE can only appear in the last position, we
66         // don't need to verify that size==1
67         return returnStates[0] == EMPTY_RETURN_STATE;
68     }
69 
70     /**
71      * @uml
72      * @override
73      */
74     public override size_t size()
75     {
76         return returnStates.length;
77     }
78 
79     /**
80      * @uml
81      * @override
82      */
83     public override PredictionContext getParent(int index)
84     {
85         return parents[index];
86     }
87 
88     /**
89      * @uml
90      * @override
91      */
92     public override int getReturnState(int index)
93     {
94         return returnStates[index];
95     }
96 
97     /**
98      * @uml
99      * @override
100      */
101     public override bool opEquals(Object o)
102     {
103         if (!cast(ArrayPredictionContext)o) {
104             return false;
105         }
106 
107         if (this.toHash != o.toHash) {
108             return false; // can't be same if hash is different
109         }
110         auto aObject = cast(ArrayPredictionContext)o;
111         import std.algorithm.comparison : equal;
112         return equal(parents, aObject.parents) &&
113             equal(returnStates, aObject.returnStates);
114     }
115 
116     /**
117      * @uml
118      * @override
119      */
120     public override string toString()
121     {
122         if (isEmpty)
123             return "[]";
124         string[] buf;
125         foreach (i, el; returnStates) {
126             if (el == EMPTY_RETURN_STATE) {
127                 buf ~= "$";
128                 continue;
129             }
130             buf ~= to!string(el);
131             if (parents[i]) {
132                 buf ~= " " ~ parents[i].toString;
133             }
134             else {
135                 buf ~= "null";
136             }
137         }
138         return "[" ~ join(buf, ", ") ~ "]";
139     }
140 
141 }
142 
143 version (AntlrUnittest)
144 {
145     import dshould;
146 
147     @("Empty")
148     unittest
149     {
150         import antlr.v4.runtime.atn.EmptyPredictionContext;
151 
152         auto spc = new EmptyPredictionContext;
153         auto apc = new ArrayPredictionContext(spc);
154         ArrayPredictionContext apcp;
155         apc.toString.should.equal("[]");
156         apc.size.should.equal(1);
157         apc.isEmpty.should.equal(true);
158         static if (size_t.sizeof == 4)
159             apc.toHash.should.equal(786443632U);
160         else
161             apc.toHash.should.equal(6723470047294944096UL);
162         apc.getParent(0).should.be(null);
163         apc.getReturnState(0).should.equal(PredictionContext.EMPTY_RETURN_STATE);
164         auto apc1 = new ArrayPredictionContext(spc);
165         apcp = apc;
166         apc.should.equal(apcp);
167         class A {}
168         auto apc2 = new A;
169         apc.should.not.equal(apc2);
170         apc.should.equal(apc1);
171     }
172 
173     @("Flat")
174     unittest
175     {
176         import antlr.v4.runtime.atn.EmptyPredictionContext;
177 
178         auto spc = new EmptyPredictionContext;
179         auto apc = new ArrayPredictionContext(spc);
180         apc.returnStates = 12 ~ apc.returnStates;
181         apc.toString.should.equal("[12, null, $]");
182         apc.size.should.equal(2);
183         apc.isEmpty.should.equal(false);
184         apc.getParent(0).should.be(null);
185         static if (size_t.sizeof == 4)
186             apc.toHash.should.equal(786443632U);
187         else
188             apc.toHash.should.equal(6723470047294944096UL);
189         static if (size_t.sizeof == 4)
190             apc.calculateHashCode(apc.getParent(0), apc.getReturnState(0))
191                 .should.equal(182986417U);
192         else
193             apc.calculateHashCode(apc.getParent(0), apc.getReturnState(0))
194                 .should.equal(4292457832056041856UL);
195         apc.getReturnState(0).should.equal(12);
196         auto apc1 = new ArrayPredictionContext(spc);
197         apc.should.not.equal(apc1);
198     }
199 
200     @("Deep")
201     unittest
202     {
203         import antlr.v4.runtime.atn.EmptyPredictionContext;
204 
205         auto spc = new EmptyPredictionContext;
206         auto apc = new ArrayPredictionContext(spc);
207         auto apc1 = new ArrayPredictionContext(spc);
208         apc.returnStates = 12 ~ apc.returnStates;
209         apc.toString.should.equal("[12, null, $]");
210         apc.size.should.equal(2);
211         apc.isEmpty.should.equal(false);
212         apc.getParent(0).should.be(null);
213         apc.getReturnState(0).should.equal(12);
214         apc.parents[0] = apc1;
215         auto apc2 = new ArrayPredictionContext(apc.parents, apc.returnStates);
216         apc2.toString.should.equal("[12,  [], $]");
217         apc.toString.should.equal("[12,  [], $]");
218         apc.should.not.equal(apc2);
219         apc2.parents = apc1 ~ apc2.parents;
220         apc2.returnStates = 13 ~ apc2.returnStates;
221         apc2.toString.should.equal("[13,  [], 12,  [], $]");
222     }
223 }