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