2010-12-26 MORITA Hajime <morrita@google.com>
[WebKit.git] / ANGLE / src / compiler / parseConst.cpp
1 //
2 // Copyright (c) 2002-2010 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/ParseHelper.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:
15     TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t)
16         : error(false),
17           index(0),
18           unionArray(cUnion),
19           type(t),
20           constructorType(constructType),
21           singleConstantParam(singleConstParam),
22           infoSink(sink),
23           symbolTable(symTable),
24           size(0),
25           isMatrix(false),
26           matrixSize(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     int index;
42     ConstantUnion *unionArray;
43     TType type;
44     TOperator constructorType;
45     bool singleConstantParam;
46     TInfoSink& infoSink;
47     TSymbolTable& symbolTable;
48     int size; // size of the constructor ( 4 for vec4)
49     bool isMatrix;
50     int matrixSize; // dimension of the matrix (nominal size and not the instance size)
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
62 void TConstTraverser::visitSymbol(TIntermSymbol* node)
63 {
64     infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
65     return;
66
67 }
68
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, buf.c_str(), node->getLine());
78         error = true;
79         return false;  
80     }
81
82    infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine());
83     
84     return false;
85 }
86
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, buf.c_str(), node->getLine());
93     error = true;
94     return false;  
95 }
96
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, buf.c_str(), node->getLine());
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             isMatrix = true;
122             matrixSize = node->getType().getNominalSize();
123         }
124     }       
125
126     for (TIntermSequence::iterator p = node->getSequence().begin(); 
127                                    p != node->getSequence().end(); p++) {
128
129         if (node->getOp() == EOpComma)
130             index = 0;           
131
132         (*p)->traverse(this);
133     }   
134     if (flag) 
135     {
136         singleConstantParam = false;   
137         constructorType = EOpNull;
138         size = 0;
139         isMatrix = false;
140         matrixSize = 0;
141     }
142     return false;
143 }
144
145 bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node)
146 {
147     infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine());
148     error = true;
149     return false;
150 }
151
152 void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
153 {
154     ConstantUnion* leftUnionArray = unionArray;
155     int instanceSize = type.getObjectSize();
156
157     if (index >= instanceSize)
158         return;
159
160     if (!singleConstantParam) {
161         int size = node->getType().getObjectSize();
162     
163         ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
164         for (int i=0; i < size; i++) {
165             if (index >= instanceSize)
166                 return;
167             leftUnionArray[index] = rightUnionArray[i];
168
169             (index)++;
170         }
171     } else {
172         int totalSize = index + size;
173         ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
174         if (!isMatrix) {
175             int count = 0;
176             for (int i = index; i < totalSize; i++) {
177                 if (i >= instanceSize)
178                     return;
179
180                 leftUnionArray[i] = rightUnionArray[count];
181
182                 (index)++;
183                 
184                 if (node->getType().getObjectSize() > 1)
185                     count++;
186             }
187         } else {  // for matrix constructors
188             int count = 0;
189             int element = index;
190             for (int i = index; i < totalSize; i++) {
191                 if (i >= instanceSize)
192                     return;
193                 if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 )
194                     leftUnionArray[i] = rightUnionArray[count];
195                 else 
196                     leftUnionArray[i].setFConst(0.0f);
197
198                 (index)++;
199
200                 if (node->getType().getObjectSize() > 1)
201                     count++;                
202             }
203         }
204     }
205 }
206
207 bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node)
208 {
209     infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine());
210     error = true;
211     return false;
212 }
213
214 bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node)
215 {
216     infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine());
217     error = true;
218     return false;
219 }
220
221 //
222 // This function is the one to call externally to start the traversal.
223 // Individual functions can be initialized to 0 to skip processing of that
224 // type of node.  It's children will still be processed.
225 //
226 bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam)
227 {
228     if (root == 0)
229         return false;
230
231     TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t);
232
233     root->traverse(&it);
234     if (it.error)
235         return true;
236     else
237         return false;
238 }