// // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // #include "compiler/translator/ParseContext.h" // // Use this class to carry along data from node to node in // the traversal // class TConstTraverser : public TIntermTraverser { public: TConstTraverser(ConstantUnion *cUnion, bool singleConstParam, TOperator constructType, TInfoSink &sink, TType &t) : error(false), mIndex(0), mUnionArray(cUnion), mType(t), mConstructorType(constructType), mSingleConstantParam(singleConstParam), mInfoSink(sink), mSize(0), mIsDiagonalMatrixInit(false), mMatrixCols(0), mMatrixRows(0) { } bool error; protected: void visitSymbol(TIntermSymbol *); void visitConstantUnion(TIntermConstantUnion *); bool visitBinary(Visit visit, TIntermBinary *); bool visitUnary(Visit visit, TIntermUnary *); bool visitSelection(Visit visit, TIntermSelection *); bool visitAggregate(Visit visit, TIntermAggregate *); bool visitLoop(Visit visit, TIntermLoop *); bool visitBranch(Visit visit, TIntermBranch *); size_t mIndex; ConstantUnion *mUnionArray; TType mType; TOperator mConstructorType; bool mSingleConstantParam; TInfoSink &mInfoSink; size_t mSize; // size of the constructor ( 4 for vec4) bool mIsDiagonalMatrixInit; int mMatrixCols; // columns of the matrix int mMatrixRows; // rows of the matrix }; // // The rest of the file are the traversal functions. The last one // is the one that starts the traversal. // // Return true from interior nodes to have the external traversal // continue on to children. If you process children yourself, // return false. // void TConstTraverser::visitSymbol(TIntermSymbol *node) { mInfoSink.info.message(EPrefixInternalError, node->getLine(), "Symbol Node found in constant constructor"); return; } bool TConstTraverser::visitBinary(Visit visit, TIntermBinary *node) { TQualifier qualifier = node->getType().getQualifier(); if (qualifier != EvqConst) { TString buf; buf.append("'constructor' : assigning non-constant to "); buf.append(mType.getCompleteString()); mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); error = true; return false; } mInfoSink.info.message(EPrefixInternalError, node->getLine(), "Binary Node found in constant constructor"); return false; } bool TConstTraverser::visitUnary(Visit visit, TIntermUnary *node) { TString buf; buf.append("'constructor' : assigning non-constant to "); buf.append(mType.getCompleteString()); mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); error = true; return false; } bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate *node) { if (!node->isConstructor() && node->getOp() != EOpComma) { TString buf; buf.append("'constructor' : assigning non-constant to "); buf.append(mType.getCompleteString()); mInfoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); error = true; return false; } if (node->getSequence()->size() == 0) { error = true; return false; } bool flag = node->getSequence()->size() == 1 && (*node->getSequence())[0]->getAsTyped()->getAsConstantUnion(); if (flag) { mSingleConstantParam = true; mConstructorType = node->getOp(); mSize = node->getType().getObjectSize(); if (node->getType().isMatrix()) { mIsDiagonalMatrixInit = true; mMatrixCols = node->getType().getCols(); mMatrixRows = node->getType().getRows(); } } for (TIntermSequence::iterator p = node->getSequence()->begin(); p != node->getSequence()->end(); p++) { if (node->getOp() == EOpComma) mIndex = 0; (*p)->traverse(this); } if (flag) { mSingleConstantParam = false; mConstructorType = EOpNull; mSize = 0; mIsDiagonalMatrixInit = false; mMatrixCols = 0; mMatrixRows = 0; } return false; } bool TConstTraverser::visitSelection(Visit visit, TIntermSelection *node) { mInfoSink.info.message(EPrefixInternalError, node->getLine(), "Selection Node found in constant constructor"); error = true; return false; } void TConstTraverser::visitConstantUnion(TIntermConstantUnion *node) { if (!node->getUnionArrayPointer()) { // The constant was not initialized, this should already have been logged ASSERT(mInfoSink.info.size() != 0); return; } ConstantUnion *leftUnionArray = mUnionArray; size_t instanceSize = mType.getObjectSize(); TBasicType basicType = mType.getBasicType(); if (mIndex >= instanceSize) return; if (!mSingleConstantParam) { size_t objectSize = node->getType().getObjectSize(); ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); for (size_t i=0; i < objectSize; i++) { if (mIndex >= instanceSize) return; leftUnionArray[mIndex].cast(basicType, rightUnionArray[i]); mIndex++; } } else { size_t totalSize = mIndex + mSize; ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); if (!mIsDiagonalMatrixInit) { int count = 0; for (size_t i = mIndex; i < totalSize; i++) { if (i >= instanceSize) return; leftUnionArray[i].cast(basicType, rightUnionArray[count]); mIndex++; if (node->getType().getObjectSize() > 1) count++; } } else { // for matrix diagonal constructors from a single scalar for (int i = 0, col = 0; col < mMatrixCols; col++) { for (int row = 0; row < mMatrixRows; row++, i++) { if (col == row) { leftUnionArray[i].cast(basicType, rightUnionArray[0]); } else { leftUnionArray[i].setFConst(0.0f); } mIndex++; } } } } } bool TConstTraverser::visitLoop(Visit visit, TIntermLoop *node) { mInfoSink.info.message(EPrefixInternalError, node->getLine(), "Loop Node found in constant constructor"); error = true; return false; } bool TConstTraverser::visitBranch(Visit visit, TIntermBranch *node) { mInfoSink.info.message(EPrefixInternalError, node->getLine(), "Branch Node found in constant constructor"); error = true; return false; } // // This function is the one to call externally to start the traversal. // Individual functions can be initialized to 0 to skip processing of that // type of node. It's children will still be processed. // bool TIntermediate::parseConstTree( const TSourceLoc &line, TIntermNode *root, ConstantUnion *unionArray, TOperator constructorType, TType t, bool singleConstantParam) { if (root == 0) return false; TConstTraverser it(unionArray, singleConstantParam, constructorType, mInfoSink, t); root->traverse(&it); if (it.error) return true; else return false; }