| // |
| // Copyright (c) 2002-2010 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/ParseHelper.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, TSymbolTable& symTable, TType& t) |
| : error(false), |
| index(0), |
| unionArray(cUnion), |
| type(t), |
| constructorType(constructType), |
| singleConstantParam(singleConstParam), |
| infoSink(sink), |
| symbolTable(symTable), |
| size(0), |
| isMatrix(false), |
| matrixSize(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*); |
| |
| int index; |
| ConstantUnion *unionArray; |
| TType type; |
| TOperator constructorType; |
| bool singleConstantParam; |
| TInfoSink& infoSink; |
| TSymbolTable& symbolTable; |
| int size; // size of the constructor ( 4 for vec4) |
| bool isMatrix; |
| int matrixSize; // dimension of the matrix (nominal size and not the instance size) |
| }; |
| |
| // |
| // 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) |
| { |
| infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine()); |
| 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(type.getCompleteString()); |
| infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); |
| error = true; |
| return false; |
| } |
| |
| infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine()); |
| |
| return false; |
| } |
| |
| bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) |
| { |
| TString buf; |
| buf.append("'constructor' : assigning non-constant to "); |
| buf.append(type.getCompleteString()); |
| infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); |
| 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(type.getCompleteString()); |
| infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); |
| 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) |
| { |
| singleConstantParam = true; |
| constructorType = node->getOp(); |
| size = node->getType().getObjectSize(); |
| |
| if (node->getType().isMatrix()) { |
| isMatrix = true; |
| matrixSize = node->getType().getNominalSize(); |
| } |
| } |
| |
| for (TIntermSequence::iterator p = node->getSequence().begin(); |
| p != node->getSequence().end(); p++) { |
| |
| if (node->getOp() == EOpComma) |
| index = 0; |
| |
| (*p)->traverse(this); |
| } |
| if (flag) |
| { |
| singleConstantParam = false; |
| constructorType = EOpNull; |
| size = 0; |
| isMatrix = false; |
| matrixSize = 0; |
| } |
| return false; |
| } |
| |
| bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) |
| { |
| infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine()); |
| error = true; |
| return false; |
| } |
| |
| void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) |
| { |
| ConstantUnion* leftUnionArray = unionArray; |
| int instanceSize = type.getObjectSize(); |
| |
| if (index >= instanceSize) |
| return; |
| |
| if (!singleConstantParam) { |
| int size = node->getType().getObjectSize(); |
| |
| ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); |
| for (int i=0; i < size; i++) { |
| if (index >= instanceSize) |
| return; |
| leftUnionArray[index] = rightUnionArray[i]; |
| |
| (index)++; |
| } |
| } else { |
| int totalSize = index + size; |
| ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); |
| if (!isMatrix) { |
| int count = 0; |
| for (int i = index; i < totalSize; i++) { |
| if (i >= instanceSize) |
| return; |
| |
| leftUnionArray[i] = rightUnionArray[count]; |
| |
| (index)++; |
| |
| if (node->getType().getObjectSize() > 1) |
| count++; |
| } |
| } else { // for matrix constructors |
| int count = 0; |
| int element = index; |
| for (int i = index; i < totalSize; i++) { |
| if (i >= instanceSize) |
| return; |
| if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 ) |
| leftUnionArray[i] = rightUnionArray[count]; |
| else |
| leftUnionArray[i].setFConst(0.0f); |
| |
| (index)++; |
| |
| if (node->getType().getObjectSize() > 1) |
| count++; |
| } |
| } |
| } |
| } |
| |
| bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) |
| { |
| infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine()); |
| error = true; |
| return false; |
| } |
| |
| bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) |
| { |
| infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine()); |
| 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(TSourceLoc line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam) |
| { |
| if (root == 0) |
| return false; |
| |
| TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t); |
| |
| root->traverse(&it); |
| if (it.error) |
| return true; |
| else |
| return false; |
| } |