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