1 // 2 // Copyright (c) 2002-2010 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/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, TSymbolTable& symTable, TType& t) 16 : error(false), 17 index(0), 18 unionArray(cUnion), 19 type(t), 20 constructorType(constructType), 21 singleConstantParam(singleConstParam), 22 infoSink(sink), 23 symbolTable(symTable), 24 size(0), 25 isMatrix(false), 26 matrixSize(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 TSymbolTable& symbolTable; 48 size_t size; // size of the constructor ( 4 for vec4) 49 bool isMatrix; 50 size_t matrixSize; // dimension of the matrix (nominal size and not the instance size) 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 isMatrix = true; 122 matrixSize = node->getType().getNominalSize(); 123 } 124 } 125 126 for (TIntermSequence::iterator p = node->getSequence().begin(); 127 p != node->getSequence().end(); p++) { 128 129 if (node->getOp() == EOpComma) 130 index = 0; 131 132 (*p)->traverse(this); 133 } 134 if (flag) 135 { 136 singleConstantParam = false; 137 constructorType = EOpNull; 138 size = 0; 139 isMatrix = false; 140 matrixSize = 0; 141 } 142 return false; 143 } 144 145 bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) 146 { 147 infoSink.info.message(EPrefixInternalError, node->getLine(), "Selection Node found in constant constructor"); 148 error = true; 149 return false; 150 } 151 152 void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) 153 { 154 if (!node->getUnionArrayPointer()) 155 { 156 // The constant was not initialized, this should already have been logged 157 assert(infoSink.info.size() != 0); 158 return; 159 } 160 161 ConstantUnion* leftUnionArray = unionArray; 162 size_t instanceSize = type.getObjectSize(); 163 164 if (index >= instanceSize) 165 return; 166 167 if (!singleConstantParam) { 168 size_t size = node->getType().getObjectSize(); 169 170 ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); 171 for (size_t i = 0; i < size; i++) { 172 if (index >= instanceSize) 173 return; 174 leftUnionArray[index] = rightUnionArray[i]; 175 176 (index)++; 177 } 178 } else { 179 size_t totalSize = index + size; 180 ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); 181 if (!isMatrix) { 182 size_t count = 0; 183 for (size_t i = index; i < totalSize; i++) { 184 if (i >= instanceSize) 185 return; 186 187 leftUnionArray[i] = rightUnionArray[count]; 188 189 (index)++; 190 191 if (node->getType().getObjectSize() > 1) 192 count++; 193 } 194 } else { // for matrix constructors 195 size_t count = 0; 196 size_t element = index; 197 for (size_t i = index; i < totalSize; i++) { 198 if (i >= instanceSize) 199 return; 200 if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 ) 201 leftUnionArray[i] = rightUnionArray[count]; 202 else 203 leftUnionArray[i].setFConst(0.0f); 204 205 (index)++; 206 207 if (node->getType().getObjectSize() > 1) 208 count++; 209 } 210 } 211 } 212 } 213 214 bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) 215 { 216 infoSink.info.message(EPrefixInternalError, node->getLine(), "Loop Node found in constant constructor"); 217 error = true; 218 return false; 219 } 220 221 bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) 222 { 223 infoSink.info.message(EPrefixInternalError, node->getLine(), "Branch Node found in constant constructor"); 224 error = true; 225 return false; 226 } 227 228 // 229 // This function is the one to call externally to start the traversal. 230 // Individual functions can be initialized to 0 to skip processing of that 231 // type of node. It's children will still be processed. 232 // 233 bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam) 234 { 235 if (root == 0) 236 return false; 237 238 TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t); 239 240 root->traverse(&it); 241 if (it.error) 242 return true; 243 else 244 return false; 245 } 246