1 // 2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include "compiler/translator/ParseContext.h" 8 9 // 10 // Use this class to carry along data from node to node in 11 // the traversal 12 // 13 class TConstTraverser : public TIntermTraverser { 14 public: 15 TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TType& t) 16 : error(false), 17 index(0), 18 unionArray(cUnion), 19 type(t), 20 constructorType(constructType), 21 singleConstantParam(singleConstParam), 22 infoSink(sink), 23 size(0), 24 isDiagonalMatrixInit(false), 25 matrixCols(0), 26 matrixRows(0) { 27 } 28 29 bool error; 30 31 protected: 32 void visitSymbol(TIntermSymbol*); 33 void visitConstantUnion(TIntermConstantUnion*); 34 bool visitBinary(Visit visit, TIntermBinary*); 35 bool visitUnary(Visit visit, TIntermUnary*); 36 bool visitSelection(Visit visit, TIntermSelection*); 37 bool visitAggregate(Visit visit, TIntermAggregate*); 38 bool visitLoop(Visit visit, TIntermLoop*); 39 bool visitBranch(Visit visit, TIntermBranch*); 40 41 size_t index; 42 ConstantUnion *unionArray; 43 TType type; 44 TOperator constructorType; 45 bool singleConstantParam; 46 TInfoSink& infoSink; 47 size_t size; // size of the constructor ( 4 for vec4) 48 bool isDiagonalMatrixInit; 49 int matrixCols; // columns of the matrix 50 int matrixRows; // rows of the matrix 51 }; 52 53 // 54 // The rest of the file are the traversal functions. The last one 55 // is the one that starts the traversal. 56 // 57 // Return true from interior nodes to have the external traversal 58 // continue on to children. If you process children yourself, 59 // return false. 60 // 61 62 void TConstTraverser::visitSymbol(TIntermSymbol* node) 63 { 64 infoSink.info.message(EPrefixInternalError, node->getLine(), "Symbol Node found in constant constructor"); 65 return; 66 67 } 68 69 bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node) 70 { 71 TQualifier qualifier = node->getType().getQualifier(); 72 73 if (qualifier != EvqConst) { 74 TString buf; 75 buf.append("'constructor' : assigning non-constant to "); 76 buf.append(type.getCompleteString()); 77 infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); 78 error = true; 79 return false; 80 } 81 82 infoSink.info.message(EPrefixInternalError, node->getLine(), "Binary Node found in constant constructor"); 83 84 return false; 85 } 86 87 bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) 88 { 89 TString buf; 90 buf.append("'constructor' : assigning non-constant to "); 91 buf.append(type.getCompleteString()); 92 infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); 93 error = true; 94 return false; 95 } 96 97 bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node) 98 { 99 if (!node->isConstructor() && node->getOp() != EOpComma) { 100 TString buf; 101 buf.append("'constructor' : assigning non-constant to "); 102 buf.append(type.getCompleteString()); 103 infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); 104 error = true; 105 return false; 106 } 107 108 if (node->getSequence().size() == 0) { 109 error = true; 110 return false; 111 } 112 113 bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); 114 if (flag) 115 { 116 singleConstantParam = true; 117 constructorType = node->getOp(); 118 size = node->getType().getObjectSize(); 119 120 if (node->getType().isMatrix()) { 121 isDiagonalMatrixInit = true; 122 matrixCols = node->getType().getCols(); 123 matrixRows = node->getType().getRows(); 124 } 125 } 126 127 for (TIntermSequence::iterator p = node->getSequence().begin(); 128 p != node->getSequence().end(); p++) { 129 130 if (node->getOp() == EOpComma) 131 index = 0; 132 133 (*p)->traverse(this); 134 } 135 if (flag) 136 { 137 singleConstantParam = false; 138 constructorType = EOpNull; 139 size = 0; 140 isDiagonalMatrixInit = false; 141 matrixCols = 0; 142 matrixRows = 0; 143 } 144 return false; 145 } 146 147 bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) 148 { 149 infoSink.info.message(EPrefixInternalError, node->getLine(), "Selection Node found in constant constructor"); 150 error = true; 151 return false; 152 } 153 154 void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) 155 { 156 if (!node->getUnionArrayPointer()) 157 { 158 // The constant was not initialized, this should already have been logged 159 assert(infoSink.info.size() != 0); 160 return; 161 } 162 163 ConstantUnion* leftUnionArray = unionArray; 164 size_t instanceSize = type.getObjectSize(); 165 166 if (index >= instanceSize) 167 return; 168 169 if (!singleConstantParam) { 170 size_t objectSize = node->getType().getObjectSize(); 171 172 ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); 173 for (size_t i=0; i < objectSize; i++) { 174 if (index >= instanceSize) 175 return; 176 leftUnionArray[index] = rightUnionArray[i]; 177 178 (index)++; 179 } 180 } else { 181 size_t totalSize = index + size; 182 ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); 183 if (!isDiagonalMatrixInit) { 184 int count = 0; 185 for (size_t i = index; i < totalSize; i++) { 186 if (i >= instanceSize) 187 return; 188 189 leftUnionArray[i] = rightUnionArray[count]; 190 191 (index)++; 192 193 if (node->getType().getObjectSize() > 1) 194 count++; 195 } 196 } 197 else 198 { 199 // for matrix diagonal constructors from a single scalar 200 for (int i = 0, col = 0; col < matrixCols; col++) 201 { 202 for (int row = 0; row < matrixRows; row++, i++) 203 { 204 if (col == row) 205 { 206 leftUnionArray[i] = rightUnionArray[0]; 207 } 208 else 209 { 210 leftUnionArray[i].setFConst(0.0f); 211 } 212 213 (index)++; 214 } 215 } 216 } 217 } 218 } 219 220 bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) 221 { 222 infoSink.info.message(EPrefixInternalError, node->getLine(), "Loop Node found in constant constructor"); 223 error = true; 224 return false; 225 } 226 227 bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) 228 { 229 infoSink.info.message(EPrefixInternalError, node->getLine(), "Branch Node found in constant constructor"); 230 error = true; 231 return false; 232 } 233 234 // 235 // This function is the one to call externally to start the traversal. 236 // Individual functions can be initialized to 0 to skip processing of that 237 // type of node. It's children will still be processed. 238 // 239 bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam) 240 { 241 if (root == 0) 242 return false; 243 244 TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, t); 245 246 root->traverse(&it); 247 if (it.error) 248 return true; 249 else 250 return false; 251 } 252