Create a base GLSL front-end from the 3Dlabs glslang front-end from 20-Sep-2005.
[platform/upstream/glslang.git] / glslang / MachineIndependent / parseConst.cpp
1 //
2 //Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 //All rights reserved.
4 //
5 //Redistribution and use in source and binary forms, with or without
6 //modification, are permitted provided that the following conditions
7 //are met:
8 //
9 //    Redistributions of source code must retain the above copyright
10 //    notice, this list of conditions and the following disclaimer.
11 //
12 //    Redistributions in binary form must reproduce the above
13 //    copyright notice, this list of conditions and the following
14 //    disclaimer in the documentation and/or other materials provided
15 //    with the distribution.
16 //
17 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
18 //    contributors may be used to endorse or promote products derived
19 //    from this software without specific prior written permission.
20 //
21 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 //POSSIBILITY OF SUCH DAMAGE.
33 //
34
35 #include "ParseHelper.h"
36
37 //
38 // Use this class to carry along data from node to node in 
39 // the traversal
40 //
41 class TConstTraverser : public TIntermTraverser {
42 public:
43     TConstTraverser(constUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t) : unionArray(cUnion), type(t),
44         constructorType(constructType), singleConstantParam(singleConstParam), infoSink(sink), symbolTable(symTable), error(false), isMatrix(false), matrixSize(0) {  index = 0; tOp = EOpNull;}
45     int index ;
46     constUnion *unionArray;
47     TOperator tOp;
48     TType type;
49     TOperator constructorType;
50     bool singleConstantParam;
51     TInfoSink& infoSink;
52     TSymbolTable& symbolTable;
53     bool error;
54     int size; // size of the constructor ( 4 for vec4)
55     bool isMatrix;
56     int matrixSize; // dimension of the matrix (nominal size and not the instance size)
57 };
58
59 //
60 // The rest of the file are the traversal functions.  The last one
61 // is the one that starts the traversal.
62 //
63 // Return true from interior nodes to have the external traversal
64 // continue on to children.  If you process children yourself,
65 // return false.
66 //
67
68 void ParseSymbol(TIntermSymbol* node, TIntermTraverser* it)
69 {
70     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
71     oit->infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
72     return;
73
74 }
75
76 bool ParseBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it)
77 {
78     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
79     
80     TQualifier qualifier = node->getType().getQualifier();
81     
82     if (qualifier != EvqConst) {
83         char buf[200];
84         sprintf(buf, "'constructor' : assigning non-constant to %s", oit->type.getCompleteString().c_str());
85         oit->infoSink.info.message(EPrefixError, buf, node->getLine());
86         oit->error = true;
87         return false;  
88     }
89
90    oit->infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine());
91     
92     return false;
93 }
94
95 bool ParseUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it)
96 {
97     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
98
99     char buf[200];
100     sprintf(buf, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str());
101     oit->infoSink.info.message(EPrefixError, buf, node->getLine());
102     oit->error = true;
103     return false;  
104 }
105
106 bool ParseAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it)
107 {
108     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
109
110     if (!node->isConstructor() && node->getOp() != EOpComma) {
111         char buf[200];
112         sprintf(buf, "'constructor' : assigning non-constant to '%s'", oit->type.getCompleteString().c_str());
113         oit->infoSink.info.message(EPrefixError, buf, node->getLine());
114         oit->error = true;
115         return false;  
116     }
117
118     if (node->getSequence().size() == 0) {
119         oit->error = true;
120         return false;
121     }
122
123     bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
124     if (flag) 
125     {
126         oit->singleConstantParam = true; 
127         oit->constructorType = node->getOp();
128         oit->size = node->getType().getObjectSize();
129
130         if (node->getType().isMatrix()) {
131             oit->isMatrix = true;
132             oit->matrixSize = node->getType().getNominalSize();
133         }
134     }       
135
136     for (TIntermSequence::iterator p = node->getSequence().begin(); 
137                                    p != node->getSequence().end(); p++) {
138
139         if (node->getOp() == EOpComma)
140             oit->index = 0;           
141
142         (*p)->traverse(oit);
143     }   
144     if (flag) 
145     {
146         oit->singleConstantParam = false;   
147         oit->constructorType = EOpNull;
148         oit->size = 0;
149         oit->isMatrix = false;
150         oit->matrixSize = 0;
151     }
152     return false;
153 }
154
155 bool ParseSelection(bool /* preVisit */, TIntermSelection* node, TIntermTraverser* it)
156 {
157     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
158     oit->infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine());
159     oit->error = true;
160     return false;
161 }
162
163 void ParseConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
164 {
165     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
166     constUnion* leftUnionArray = oit->unionArray;
167     int instanceSize = oit->type.getObjectSize();
168
169     if (oit->index >= instanceSize)
170         return;
171
172     if (!oit->singleConstantParam) {
173         int size = node->getType().getObjectSize();
174     
175         constUnion *rightUnionArray = node->getUnionArrayPointer();
176         for (int i=0; i < size; i++) {
177             if (oit->index >= instanceSize)
178                 return;
179             leftUnionArray[oit->index] = rightUnionArray[i];
180
181             (oit->index)++;
182         }
183     } else {
184         int size, totalSize, matrixSize;
185         bool isMatrix = false;
186         size = oit->size;
187         matrixSize = oit->matrixSize;
188         isMatrix = oit->isMatrix;
189         totalSize = oit->index + size ;
190         constUnion *rightUnionArray = node->getUnionArrayPointer();
191         if (!isMatrix) {
192             int count = 0;
193             for (int i = oit->index; i < totalSize; i++) {
194                 if (i >= instanceSize)
195                     return;
196
197                 leftUnionArray[i] = rightUnionArray[count];
198
199                 (oit->index)++;
200                 
201                 if (node->getType().getObjectSize() > 1)
202                     count++;
203             }
204         } else {  // for matrix constructors
205             int count = 0;
206             int index = oit->index;
207             for (int i = index; i < totalSize; i++) {
208                 if (i >= instanceSize)
209                     return;
210                 if (index - i == 0 || (i - index) % (matrixSize + 1) == 0 )
211                     leftUnionArray[i] = rightUnionArray[count];
212                 else 
213                     leftUnionArray[i].setFConst(0.0f);
214
215                 (oit->index)++;
216
217                 if (node->getType().getObjectSize() > 1)
218                     count++;                
219             }
220         }
221     }
222 }
223
224 bool ParseLoop(bool /* preVisit */, TIntermLoop* node, TIntermTraverser* it)
225 {
226     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
227     oit->infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine());
228     oit->error = true;
229     return false;
230 }
231
232 bool ParseBranch(bool /* previsit*/, TIntermBranch* node, TIntermTraverser* it)
233 {
234     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
235     oit->infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine());
236     oit->error = true;
237     return false;
238 }
239
240 //
241 // This function is the one to call externally to start the traversal.
242 // Individual functions can be initialized to 0 to skip processing of that
243 // type of node.  It's children will still be processed.
244 //
245 bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, constUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam)
246 {
247     if (root == 0)
248         return false;
249
250     TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t);
251     
252     it.visitAggregate = ParseAggregate;
253     it.visitBinary = ParseBinary;
254     it.visitConstantUnion = ParseConstantUnion;
255     it.visitSelection = ParseSelection;
256     it.visitSymbol = ParseSymbol;
257     it.visitUnary = ParseUnary;
258     it.visitLoop = ParseLoop;
259     it.visitBranch = ParseBranch;
260
261     root->traverse(&it);
262     if (it.error)
263         return true;
264     else
265         return false;
266 }