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