1 #include <msp/stringcodec/utf8.h>
2 #include <msp/strings/format.h>
11 const DumpTree::Colors DumpTree::no_colors =
12 { "", "", "", "", "", "", "" };
14 const DumpTree::Colors DumpTree::default_colors =
17 "\033[38;5;250m", // tree
18 "\033[38;5;244m", // location
19 "\033[38;5;146m", // label
20 "\033[38;5;194m", // type
21 "\033[38;5;230m", // name
22 "\033[38;5;210m" // error
25 DumpTree::DumpTree(bool use_colors):
26 colors(use_colors ? default_colors : no_colors)
29 string DumpTree::apply(Stage &stage)
31 formatted = format("Stage: %s\n", Stage::get_stage_name(stage.type));
33 append(format("Version: %d.%02d", stage.required_features.glsl_version.major, stage.required_features.glsl_version.minor));
35 for(const auto &kvp: stage.types)
36 append(format("Type: %s %s%s%s", get_label(*kvp.second), colors.type_color, kvp.first, colors.default_color));
38 for(const auto &kvp: stage.interface_blocks)
39 append(format("Interface block: %s %s", get_label(*kvp.second), format_name(kvp.first)));
41 for(const auto &kvp: stage.functions)
42 append(format("Function: %s %s", get_label(*kvp.second), format_name(kvp.first)));
45 stage.content.visit(*this);
49 void DumpTree::append(const string &line)
51 formatted += colors.tree_color;
52 StringCodec::Utf8::Encoder enc;
53 for(auto i=tree.begin(); i!=tree.end(); )
55 enc.encode_char(*i++, formatted);
56 enc.encode_char((i==tree.end() ? REACH : EMPTY), formatted);
58 formatted += colors.default_color;
63 void DumpTree::append(const Node &node, const string &line)
66 if(node.source==BUILTIN_SOURCE)
68 else if(node.source==INTERNAL_SOURCE)
69 location = "internal";
70 else if(node.source==GENERATED_SOURCE)
71 location = "generated";
73 location = format("%s:%s", node.source, node.line);
74 append(format("%s<%s>%s %s", colors.location_color, location, colors.default_color, line));
77 void DumpTree::append_subtree(const vector<Branch> &branches)
80 for(auto i=branches.begin(); i!=branches.end(); )
82 auto j = increment(i, branches);
90 j->node->visit(*this);
95 j->node->visit(*this);
100 void DumpTree::append_subtree(Node &node)
108 void DumpTree::begin_sub()
111 tree.back() = (tree.back()==BRANCH_LAST ? EMPTY : STRAIGHT);
112 tree.push_back(BRANCH);
115 void DumpTree::last_branch()
117 tree.back() = BRANCH_LAST;
120 void DumpTree::end_sub()
123 if(!tree.empty() && tree.back()==STRAIGHT)
124 tree.back() = BRANCH;
127 std::string DumpTree::get_label(const Node &node)
129 unsigned &label = node_labels[&node];
131 label = node_labels.size();
132 return format("%s%%%d%s", colors.label_color, label, colors.default_color);
135 string DumpTree::format_type(TypeDeclaration *type)
137 return type ? format_type(type->name) : format("%s?%s", colors.error_color, colors.default_color);
140 string DumpTree::format_type(const string &type)
142 return format("%s%s%s", colors.type_color, type, colors.default_color);
145 string DumpTree::format_name(const string &name)
147 return format("%s%s%s", colors.name_color, name, colors.default_color);
151 typename T::const_iterator DumpTree::increment(typename T::const_iterator &iter, const T &container)
154 if(iter==container.end())
159 void DumpTree::visit(Block &block)
161 append(block, format("Block %s", (block.use_braces ? "{}" : "(inline)")));
164 for(const auto &kvp: block.variables)
165 append(format("Variable: %s %s %s", get_label(*kvp.second), format_type(kvp.second->type), format_name(kvp.first)));
167 for(auto i=block.body.cbegin(); i!=block.body.cend(); )
169 auto j = increment(i, block.body);
176 void DumpTree::visit(Literal &literal)
178 append(literal, format("Literal: %s -> %s", literal.token, format_type(literal.type)));
181 void DumpTree::visit(VariableReference &var)
185 text += format("%s ", get_label(*var.declaration));
186 text += format("%s -> %s", format_name(var.name), format_type(var.type));
190 void DumpTree::visit(MemberAccess &memacc)
192 string text = "Member access:";
193 if(memacc.declaration)
194 text += format(" %s", get_label(*memacc.declaration));
195 text += format(" .%s (%d) -> %s", format_name(memacc.member), memacc.index, format_type(memacc.type));
196 append(memacc, text);
197 append_subtree(*memacc.left);
200 void DumpTree::visit(Swizzle &swizzle)
202 static const char components[4] = { 'x', 'y', 'z', 'w' };
203 string text = "Swizzle: .";
204 for(unsigned i=0; i<swizzle.count; ++i)
205 text += components[swizzle.components[i]];
206 text += format(" -> %s", format_type(swizzle.type));
207 append(swizzle, text);
208 append_subtree(*swizzle.left);
211 void DumpTree::visit(UnaryExpression &unary)
213 string text = format("Unary: %s, %sfix -> %s", unary.oper->token, (unary.oper->type==Operator::PREFIX ? "pre" : "post"), format_type(unary.type));
215 append_subtree(*unary.expression);
218 void DumpTree::visit(BinaryExpression &binary)
220 append(binary, format("Binary: %s%s -> %s", binary.oper->token, binary.oper->token2, format_type(binary.type)));
222 binary.left->visit(*this);
224 binary.right->visit(*this);
228 void DumpTree::visit(Assignment &assign)
230 append(assign, format("Assignment: %s%s -> %s", assign.oper->token, (assign.self_referencing ? " (self-referencing)" : ""), format_type(assign.type)));
232 if(assign.target.declaration)
234 string text = format("Target: %s", get_label(*assign.target.declaration));
236 static const char swizzle[4] = { 'x', 'y', 'z', 'w' };
237 for(unsigned i=0; i<assign.target.chain_len; ++i)
239 unsigned component = assign.target.chain[i];
240 switch(static_cast<Assignment::Target::ChainType>(component&0xC0))
242 case Assignment::Target::MEMBER:
243 text += format(" .%d", component&0x3F);
245 case Assignment::Target::SWIZZLE:
247 for(unsigned j=0; j<4; ++j)
251 case Assignment::Target::ARRAY:
252 text += format(" [%d]", component&0x3F);
258 assign.left->visit(*this);
260 assign.right->visit(*this);
264 void DumpTree::visit(TernaryExpression &ternary)
266 append(ternary, format("Ternary: %s%s -> %s", ternary.oper->token, ternary.oper->token2, format_type(ternary.type)));
268 ternary.condition->visit(*this);
269 ternary.true_expr->visit(*this);
271 ternary.false_expr->visit(*this);
275 void DumpTree::visit(FunctionCall &call)
277 string head = "Function call: ";
279 head += format("%s ", get_label(*call.declaration));
280 head += format_name(call.name);
282 head += " (constructor)";
283 head += format(" -> %s", format_type(call.type));
287 for(auto i=call.arguments.cbegin(); i!=call.arguments.cend(); )
289 auto j = increment(i, call.arguments);
295 void DumpTree::visit(ExpressionStatement &expr)
297 append(expr, "expr;");
298 append_subtree(*expr.expression);
301 void DumpTree::visit(Import &import)
303 append(import, format("import %s", import.module));
306 void DumpTree::visit(Precision &prec)
308 append(prec, format("precision %s %s", prec.precision, prec.type));
311 void DumpTree::visit(Layout &layout)
313 append(layout, "Layout");
315 for(auto i=layout.qualifiers.cbegin(); i!=layout.qualifiers.cend(); )
317 auto j = increment(i, layout.qualifiers);
318 string qualifier = j->name;
320 qualifier += format("=%d", j->value);
326 void DumpTree::visit(InterfaceLayout &layout)
328 append(layout, format("Layout: %s", layout.interface));
329 append_subtree(layout.layout);
332 void DumpTree::visit(BasicTypeDeclaration &type)
334 append(type, format("%s typedef %s", get_label(type), format_type(type.name)));
336 vector<Branch> branches;
338 branches.emplace_back(format("%s: %s %s", (type.kind==BasicTypeDeclaration::ALIAS ? "Alias of" : "Base"), get_label(*type.base_type), format_type(type.base_type->name)));
339 if(type.kind==BasicTypeDeclaration::VECTOR)
340 branches.emplace_back(format("Vector: %d", type.size));
341 else if(type.kind==BasicTypeDeclaration::MATRIX)
342 branches.emplace_back(format("Matrix: %dx%d", type.size&0xFFFF, type.size>>16));
343 if(type.extended_alignment)
344 branches.emplace_back("Extended alignment");
345 append_subtree(branches);
348 void DumpTree::visit(ImageTypeDeclaration &type)
350 static const char *const dims[] = { "1D", "2D", "3D", "Cube" };
352 append(type, format("%s typedef %s", get_label(type), format_type(type.name)));
354 vector<Branch> branches;
355 branches.emplace_back(format("Dimensions: %s%s", dims[type.dimensions-1], (type.array ? " array" : "")));
357 branches.emplace_back(format("Element type: %s %s", get_label(*type.base_type), format_type(type.base_type->name)));
359 branches.emplace_back("Shadow");
360 append_subtree(branches);
363 void DumpTree::visit(StructDeclaration &strct)
365 append(strct, format("%s struct %s", get_label(strct), strct.name));
366 vector<Branch> branches;
367 if(!strct.block_name.empty())
368 branches.emplace_back(format("Interface block: %s", format_name(strct.block_name)));
369 if(strct.extended_alignment)
370 branches.emplace_back("Extended alignment");
371 branches.emplace_back(&strct.members);
372 append_subtree(branches);
375 void DumpTree::visit(VariableDeclaration &var)
377 string decl = format("%s ", get_label(var));
380 if(!var.interpolation.empty())
381 decl += format("%s ", var.interpolation);
382 if(!var.sampling.empty())
383 decl += format("%s ", var.sampling);
384 if(!var.interface.empty())
385 decl += format("%s ", var.interface);
386 if(!var.precision.empty())
387 decl += format("%s ", var.precision);
388 decl += format("%s %s", format_type(var.type), format_name(var.name));
389 if(var.source==BUILTIN_SOURCE)
390 decl += " (builtin)";
391 else if(var.linked_declaration)
395 vector<Branch> branches;
396 if(var.type_declaration)
397 branches.emplace_back(format("Type: %s %s", get_label(*var.type_declaration), format_type(var.type_declaration->name)));
398 if(var.block_declaration)
399 branches.emplace_back(format("Interface block: %s", format_name(var.block_declaration->block_name)));
401 branches.emplace_back(var.layout.get());
405 branches.emplace_back("Array []", var.array_size.get());
407 branches.emplace_back("Array []");
409 if(var.init_expression)
410 branches.emplace_back(var.init_expression.get());
411 append_subtree(branches);
414 void DumpTree::visit(FunctionDeclaration &func)
416 string text = format("%s %s %s%s", get_label(func), format_type(func.return_type), format_name(func.name), (func.signature.empty() ? "(?)" : func.signature));
417 if(func.source==BUILTIN_SOURCE)
418 text += " (builtin)";
419 else if(!func.definition)
420 text += " (undefined)";
424 if(func.return_type_declaration)
425 append(format("Return type: %s %s", get_label(*func.return_type_declaration), format_type(func.return_type_declaration)));
426 for(const RefPtr<VariableDeclaration> &p: func.parameters)
429 if(func.definition==&func)
430 func.body.visit(*this);
431 else if(func.definition)
432 append(format("Definition: %s", get_label(*func.definition)));
436 void DumpTree::visit(Conditional &cond)
438 append(cond, "if()");
440 vector<Branch> branches;
441 branches.emplace_back(cond.condition.get());
442 branches.emplace_back("then", &cond.body);
443 if(!cond.else_body.body.empty())
444 branches.emplace_back("else", &cond.else_body);
445 append_subtree(branches);
448 void DumpTree::visit(Iteration &iter)
450 append(iter, "for()");
452 vector<Branch> branches;
453 if(iter.init_statement)
454 branches.emplace_back("Initialization", iter.init_statement.get());
456 branches.emplace_back("Condition", iter.condition.get());
457 if(iter.loop_expression)
458 branches.emplace_back("Loop", iter.loop_expression.get());
459 branches.emplace_back(&iter.body);
460 append_subtree(branches);
463 void DumpTree::visit(Passthrough &pass)
465 append(pass, (pass.subscript ? "passthrough[]" : "passthrough"));
467 append_subtree(*pass.subscript);
470 void DumpTree::visit(Return &ret)
472 append(ret, (ret.expression ? "return" : "return;"));
474 append_subtree(*ret.expression);
477 void DumpTree::visit(Jump &jump)
479 append(jump, format("%s;", jump.keyword));