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(unittest) { 144 import dshould : be, equal, not, should; 145 import unit_threaded; 146 147 class Test { 148 149 @Tags("ArrayPredictionContext") 150 @("Empty") 151 unittest { 152 import antlr.v4.runtime.atn.EmptyPredictionContext; 153 auto spc = new EmptyPredictionContext; 154 auto apc = new ArrayPredictionContext(spc); 155 ArrayPredictionContext apcp; 156 apc.toString.should.equal("[]"); 157 apc.size.should.equal(1); 158 apc.isEmpty.should.equal(true); 159 static if (size_t.sizeof == 4) 160 apc.toHash.should.equal(786443632U); 161 else 162 apc.toHash.should.equal(6723470047294944096UL); 163 apc.getParent(0).should.be(null); 164 apc.getReturnState(0).should.equal(PredictionContext.EMPTY_RETURN_STATE); 165 auto apc1 = new ArrayPredictionContext(spc); 166 apcp = apc; 167 apc.should.equal(apcp); 168 class A {} 169 auto apc2 = new A; 170 apc.should.not.equal(apc2); 171 apc.should.equal(apc1); 172 } 173 174 @Tags("ArrayPredictionContext") 175 @("Flat") 176 unittest { 177 import antlr.v4.runtime.atn.EmptyPredictionContext; 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 @Tags("ArrayPredictionContext") 201 @("Deep") 202 unittest { 203 import antlr.v4.runtime.atn.EmptyPredictionContext; 204 auto spc = new EmptyPredictionContext; 205 auto apc = new ArrayPredictionContext(spc); 206 auto apc1 = new ArrayPredictionContext(spc); 207 apc.returnStates = 12 ~ apc.returnStates; 208 apc.toString.should.equal("[12, null, $]"); 209 apc.size.should.equal(2); 210 apc.isEmpty.should.equal(false); 211 apc.getParent(0).should.be(null); 212 apc.getReturnState(0).should.equal(12); 213 apc.parents[0] = apc1; 214 auto apc2 = new ArrayPredictionContext(apc.parents, apc.returnStates); 215 apc2.toString.should.equal("[12, [], $]"); 216 apc.toString.should.equal("[12, [], $]"); 217 apc.should.not.equal(apc2); 218 apc2.parents = apc1 ~ apc2.parents; 219 apc2.returnStates = 13 ~ apc2.returnStates; 220 apc2.toString.should.equal("[13, [], 12, [], $]"); 221 } 222 } 223 }