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 std.typecons : tuple; 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 }