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