]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/debug.cpp
Properly resolve arithmetic assignment operators
[libs/gl.git] / source / glsl / debug.cpp
1 #include <msp/stringcodec/utf8.h>
2 #include <msp/strings/format.h>
3 #include "debug.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9 namespace SL {
10
11 const std::string &DumpTree::apply(Stage &stage)
12 {
13         formatted = format("Stage: %s\n", Stage::get_stage_name(stage.type));
14         tree.push_back(BRANCH);
15         append(format("Version: %d.%02d", stage.required_features.glsl_version.major, stage.required_features.glsl_version.minor));
16
17         for(std::map<string, TypeDeclaration *>::const_iterator i=stage.types.begin(); i!=stage.types.end(); ++i)
18                 append(format("Type: %%%d %s", get_label(*i->second), i->first));
19
20         set<InterfaceBlock *> seen_interfaces;
21         for(std::map<string, InterfaceBlock *>::const_iterator i=stage.interface_blocks.begin(); i!=stage.interface_blocks.end(); ++i)
22                 if(seen_interfaces.insert(i->second).second)
23                 {
24                         string text = format("Interface block: %%%d %s %s", get_label(*i->second), i->second->interface, i->second->name);
25                         if(!i->second->instance_name.empty())
26                                 text += format(" %s", i->second->instance_name);
27                         append(text);
28                 }
29
30         for(std::map<string, FunctionDeclaration *>::const_iterator i=stage.functions.begin(); i!=stage.functions.end(); ++i)
31                 append(format("Function: %%%d %s", get_label(*i->second), i->first));
32
33         last_branch();
34         stage.content.visit(*this);
35         return formatted;
36 }
37
38 void DumpTree::append(const string &line)
39 {
40         StringCodec::Utf8::Encoder enc;
41         for(vector<TreeChars>::const_iterator i=tree.begin(); i!=tree.end(); )
42         {
43                 enc.encode_char(*i++, formatted);
44                 enc.encode_char((i==tree.end() ? REACH : EMPTY), formatted);
45         }
46         formatted += line;
47         formatted += '\n';
48 }
49
50 void DumpTree::begin_sub()
51 {
52         tree.back() = (tree.back()==BRANCH_LAST ? EMPTY : STRAIGHT);
53         tree.push_back(BRANCH);
54 }
55
56 void DumpTree::last_branch()
57 {
58         tree.back() = BRANCH_LAST;
59 }
60
61 void DumpTree::end_sub()
62 {
63         tree.pop_back();
64         if(tree.back()==STRAIGHT)
65                 tree.back() = BRANCH;
66 }
67
68 void DumpTree::annotated_branch(const string &annotation, Node &node)
69 {
70         append(annotation);
71         begin_sub();
72         last_branch();
73         node.visit(*this);
74         end_sub();
75 }
76
77 unsigned DumpTree::get_label(const Node &node)
78 {
79         unsigned &label = node_labels[&node];
80         if(!label)
81                 label = node_labels.size();
82         return label;
83 }
84
85 string DumpTree::format_type(TypeDeclaration *type)
86 {
87         return (type ? type->name : "?");
88 }
89
90 template<typename T>
91 typename T::const_iterator DumpTree::increment(typename T::const_iterator &iter, const T &container)
92 {
93         typename T::const_iterator ret = iter++;
94         if(iter==container.end())
95                 last_branch();
96         return ret;
97 }
98
99 void DumpTree::visit(Block &block)
100 {
101         append(format("Block %s", (block.use_braces ? "{}" : "(inline)")));
102         begin_sub();
103
104         for(std::map<string, VariableDeclaration *>::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
105                 append(format("Variable: %%%d %s %s", get_label(*i->second), i->second->type, i->first));
106
107         bool labeled_body = !block.variables.empty();
108         if(labeled_body)
109         {
110                 last_branch();
111                 append("Body");
112                 begin_sub();
113         }
114         for(NodeList<Statement>::const_iterator i=block.body.begin(); i!=block.body.end(); )
115         {
116                 NodeList<Statement>::const_iterator j = increment(i, block.body);
117                 (*j)->visit(*this);
118         }
119         if(labeled_body)
120                 end_sub();
121
122         end_sub();
123 }
124
125 void DumpTree::visit(Literal &literal)
126 {
127         append(format("Literal: %s -> %s", literal.token, format_type(literal.type)));
128 }
129
130 void DumpTree::visit(ParenthesizedExpression &parexpr)
131 {
132         annotated_branch(format("(expr) -> %s", format_type(parexpr.type)), *parexpr.expression);
133 }
134
135 void DumpTree::visit(VariableReference &var)
136 {
137         string text;
138         if(var.declaration)
139                 text += format("%%%d ", get_label(*var.declaration));
140         text += format("%s (var) -> %s", var.name, format_type(var.type));
141         append(text);
142 }
143
144 void DumpTree::visit(InterfaceBlockReference &iface)
145 {
146         string text;
147         if(iface.declaration)
148                 text += format("%%%d ", get_label(*iface.declaration));
149         text += format("%s (iface)", iface.name);
150         append(text);
151 }
152
153 void DumpTree::visit(MemberAccess &memacc)
154 {
155         string text = "Member access:";
156         if(memacc.declaration)
157                 text += format(" %%%d", get_label(*memacc.declaration));
158         text += format(" .%s -> %s", memacc.member, format_type(memacc.type));
159         annotated_branch(text, *memacc.left);
160 }
161
162 void DumpTree::visit(UnaryExpression &unary)
163 {
164         string text = format("Unary: %s, %sfix -> %s", unary.oper->token, (unary.oper->type==Operator::PREFIX ? "pre" : "post"), format_type(unary.type));
165         annotated_branch(text, *unary.expression);
166 }
167
168 void DumpTree::visit(BinaryExpression &binary)
169 {
170         append(format("Binary: %s -> %s", (binary.oper->token[0]=='[' ? "[]" : binary.oper->token), format_type(binary.type)));
171         begin_sub();
172         binary.left->visit(*this);
173         last_branch();
174         binary.right->visit(*this);
175         end_sub();
176 }
177
178 void DumpTree::visit(Assignment &assign)
179 {
180         append(format("Assignment: %s%s -> %s", assign.oper->token, (assign.self_referencing ? " (self-referencing)" : ""), format_type(assign.type)));
181         begin_sub();
182         if(assign.target_declaration)
183                 append(format("Target: %%%d %s %s", get_label(*assign.target_declaration), assign.target_declaration->type, assign.target_declaration->name));
184         assign.left->visit(*this);
185         last_branch();
186         assign.right->visit(*this);
187         end_sub();
188 }
189
190 void DumpTree::visit(FunctionCall &call)
191 {
192         string head = "Function call: ";
193         if(call.declaration)
194                 head += format("%%%d ", get_label(*call.declaration));
195         head += call.name;
196         if(call.constructor)
197                 head += " (constructor)";
198         head += format(" -> %s", format_type(call.type));
199         append(head);
200
201         begin_sub();
202         for(NodeArray<Expression>::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); )
203         {
204                 NodeArray<Expression>::const_iterator j = increment(i, call.arguments);
205                 (*j)->visit(*this);
206         }
207         end_sub();
208 }
209
210 void DumpTree::visit(ExpressionStatement &expr)
211 {
212         annotated_branch("expr;", *expr.expression);
213 }
214
215 void DumpTree::visit(Import &import)
216 {
217         append(format("import %s", import.module));
218 }
219
220 void DumpTree::visit(Precision &prec)
221 {
222         append(format("precision %s %s", prec.precision, prec.type));
223 }
224
225 void DumpTree::visit(Layout &layout)
226 {
227         append("Layout");
228         begin_sub();
229         for(vector<Layout::Qualifier>::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); )
230         {
231                 vector<Layout::Qualifier>::const_iterator j = increment(i, layout.qualifiers);
232                 string qualifier = j->name;
233                 if(j->has_value)
234                         qualifier += format("=%d", j->value);
235                 append(qualifier);
236         }
237         end_sub();
238 }
239
240 void DumpTree::visit(InterfaceLayout &layout)
241 {
242         annotated_branch(format("Layout: %s", layout.interface), layout.layout);
243 }
244
245 void DumpTree::visit(BasicTypeDeclaration &type)
246 {
247         append(format("%%%d typedef %s", get_label(type), type.name));
248         begin_sub();
249         if(type.kind!=BasicTypeDeclaration::VECTOR && type.kind!=BasicTypeDeclaration::MATRIX)
250                 last_branch();
251         if(type.base_type)
252                 append(format("%s: %%%d %s", (type.kind==BasicTypeDeclaration::ALIAS ? "Alias of" : "Base"), get_label(*type.base_type), type.base_type->name));
253
254         last_branch();
255         if(type.kind==BasicTypeDeclaration::VECTOR)
256                 append(format("Vector: %d", type.size));
257         else if(type.kind==BasicTypeDeclaration::MATRIX)
258                 append(format("Matrix: %dx%d", type.size&0xFFFF, type.size>>16));
259         end_sub();
260 }
261
262 void DumpTree::visit(ImageTypeDeclaration &type)
263 {
264         append(format("%%%d typedef %s", get_label(type), type.name));
265         begin_sub();
266
267         if(!type.shadow && !type.base_type)
268                 last_branch();
269         static const char *dims[] = { "1D", "2D", "3D", "Cube" };
270         append(format("Dimensions: %s%s", dims[type.dimensions-1], (type.array ? " array" : "")));
271
272         if(!type.shadow)
273                 last_branch();
274         if(type.base_type)
275                 append(format("Element type: %%%d %s", get_label(*type.base_type), type.base_type->name));
276
277         last_branch();
278         if(type.shadow)
279                 append("Shadow");
280
281         end_sub();
282 }
283
284 void DumpTree::visit(StructDeclaration &strct)
285 {
286         annotated_branch(format("%%%d struct %s", get_label(strct), strct.name), strct.members);
287 }
288
289 void DumpTree::visit(VariableDeclaration &var)
290 {
291         string decl = format("%%%d ", get_label(var));
292         if(var.constant)
293                 decl += "const ";
294         if(!var.interpolation.empty())
295                 decl += format("%s ", var.interpolation);
296         if(!var.sampling.empty())
297                 decl += format("%s ", var.sampling);
298         if(!var.interface.empty())
299                 decl += format("%s ", var.interface);
300         if(!var.precision.empty())
301                 decl += format("%s ", var.precision);
302         decl += format("%s %s", var.type, var.name);
303         if(var.source==BUILTIN_SOURCE)
304                 decl += " (builtin)";
305         else if(var.linked_declaration)
306                 decl += " (linked)";
307         append(decl);
308
309         begin_sub();
310         if(!var.layout && !var.array && !var.init_expression)
311                 last_branch();
312         if(var.type_declaration)
313                 append(format("Type: %%%d %s", get_label(*var.type_declaration), var.type_declaration->name));
314
315         if(!var.array && !var.init_expression)
316                 last_branch();
317         if(var.layout)
318                 var.layout->visit(*this);
319
320         if(!var.init_expression)
321                 last_branch();
322         if(var.array)
323         {
324                 if(var.array_size)
325                         annotated_branch("Array []", *var.array_size);
326                 else
327                         append("Array []");
328         }
329
330         last_branch();
331         if(var.init_expression)
332                 var.init_expression->visit(*this);
333         end_sub();
334 }
335
336 void DumpTree::visit(InterfaceBlock &block)
337 {
338         string head;
339         if(!block.instance_name.empty())
340                 head += format("%%%d ", get_label(block));
341         head += format("%s %s", block.interface, block.name);
342         if(!block.instance_name.empty())
343                 head += format(" %s", block.instance_name);
344         if(block.array)
345                 head += "[]";
346         if(block.source==BUILTIN_SOURCE)
347                 head += " (builtin)";
348         else if(block.linked_block)
349                 head += " (linked)";
350         annotated_branch(head, block.members);
351 }
352
353 void DumpTree::visit(FunctionDeclaration &func)
354 {
355         string text = format("%%%d %s %s", get_label(func), func.return_type, func.name);
356         if(func.source==BUILTIN_SOURCE)
357                 text += " (builtin)";
358         else if(!func.definition)
359                 text += " (undefined)";
360         append(text);
361         begin_sub();
362         for(NodeArray<VariableDeclaration>::const_iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
363                 (*i)->visit(*this);
364         last_branch();
365         if(func.definition==&func)
366                 func.body.visit(*this);
367         else if(func.definition)
368                 append(format("Definition: %%%d", get_label(*func.definition)));
369         end_sub();
370 }
371
372 void DumpTree::visit(Conditional &cond)
373 {
374         append("if()");
375         begin_sub();
376         cond.condition->visit(*this);
377         if(cond.else_body.body.empty())
378                 last_branch();
379         cond.body.visit(*this);
380         if(!cond.else_body.body.empty())
381         {
382                 last_branch();
383                 cond.else_body.visit(*this);
384         }
385         end_sub();
386 }
387
388 void DumpTree::visit(Iteration &iter)
389 {
390         append("for()");
391         begin_sub();
392
393         if(iter.init_statement)
394                 annotated_branch("Initialization", *iter.init_statement);
395         if(iter.condition)
396                 annotated_branch("Condition", *iter.condition);
397         if(iter.loop_expression)
398                 annotated_branch("Loop", *iter.loop_expression);
399         last_branch();
400         annotated_branch("Body", iter.body);
401
402         end_sub();
403 }
404
405 void DumpTree::visit(Passthrough &pass)
406 {
407         append("passthrough");
408         if(pass.subscript)
409         {
410                 begin_sub();
411                 last_branch();
412                 pass.subscript->visit(*this);
413                 end_sub();
414         }
415 }
416
417 void DumpTree::visit(Return &ret)
418 {
419         if(ret.expression)
420                 annotated_branch("return", *ret.expression);
421         else
422                 append("return;");
423 }
424
425 void DumpTree::visit(Jump &jump)
426 {
427         append(format("%s;", jump.keyword));
428 }
429
430 } // namespace SL
431 } // namespace GL
432 } // namespace Msp