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 (var) -> %s", format_name(var.name), format_type(var.type));
190 void DumpTree::visit(InterfaceBlockReference &iface)
193 if(iface.declaration)
194 text += format("%s ", get_label(*iface.declaration));
195 text += format("%s (iface) -> %s", format_name(iface.name), format_type(iface.type));
199 void DumpTree::visit(MemberAccess &memacc)
201 string text = "Member access:";
202 if(memacc.declaration)
203 text += format(" %s", get_label(*memacc.declaration));
204 text += format(" .%s (%d) -> %s", format_name(memacc.member), memacc.index, format_type(memacc.type));
205 append(memacc, text);
206 append_subtree(*memacc.left);
209 void DumpTree::visit(Swizzle &swizzle)
211 static const char components[4] = { 'x', 'y', 'z', 'w' };
212 string text = "Swizzle: .";
213 for(unsigned i=0; i<swizzle.count; ++i)
214 text += components[swizzle.components[i]];
215 text += format(" -> %s", format_type(swizzle.type));
216 append(swizzle, text);
217 append_subtree(*swizzle.left);
220 void DumpTree::visit(UnaryExpression &unary)
222 string text = format("Unary: %s, %sfix -> %s", unary.oper->token, (unary.oper->type==Operator::PREFIX ? "pre" : "post"), format_type(unary.type));
224 append_subtree(*unary.expression);
227 void DumpTree::visit(BinaryExpression &binary)
229 append(binary, format("Binary: %s%s -> %s", binary.oper->token, binary.oper->token2, format_type(binary.type)));
231 binary.left->visit(*this);
233 binary.right->visit(*this);
237 void DumpTree::visit(Assignment &assign)
239 append(assign, format("Assignment: %s%s -> %s", assign.oper->token, (assign.self_referencing ? " (self-referencing)" : ""), format_type(assign.type)));
241 if(assign.target.declaration)
243 string text = format("Target: %s", get_label(*assign.target.declaration));
245 static const char swizzle[4] = { 'x', 'y', 'z', 'w' };
246 for(unsigned i=0; i<assign.target.chain_len; ++i)
248 unsigned component = assign.target.chain[i];
249 switch(static_cast<Assignment::Target::ChainType>(component&0xC0))
251 case Assignment::Target::MEMBER:
252 text += format(" .%d", component&0x3F);
254 case Assignment::Target::SWIZZLE:
256 for(unsigned j=0; j<4; ++j)
260 case Assignment::Target::ARRAY:
261 text += format(" [%d]", component&0x3F);
267 assign.left->visit(*this);
269 assign.right->visit(*this);
273 void DumpTree::visit(TernaryExpression &ternary)
275 append(ternary, format("Ternary: %s%s -> %s", ternary.oper->token, ternary.oper->token2, format_type(ternary.type)));
277 ternary.condition->visit(*this);
278 ternary.true_expr->visit(*this);
280 ternary.false_expr->visit(*this);
284 void DumpTree::visit(FunctionCall &call)
286 string head = "Function call: ";
288 head += format("%s ", get_label(*call.declaration));
289 head += format_name(call.name);
291 head += " (constructor)";
292 head += format(" -> %s", format_type(call.type));
296 for(auto i=call.arguments.cbegin(); i!=call.arguments.cend(); )
298 auto j = increment(i, call.arguments);
304 void DumpTree::visit(ExpressionStatement &expr)
306 append(expr, "expr;");
307 append_subtree(*expr.expression);
310 void DumpTree::visit(Import &import)
312 append(import, format("import %s", import.module));
315 void DumpTree::visit(Precision &prec)
317 append(prec, format("precision %s %s", prec.precision, prec.type));
320 void DumpTree::visit(Layout &layout)
322 append(layout, "Layout");
324 for(auto i=layout.qualifiers.cbegin(); i!=layout.qualifiers.cend(); )
326 auto j = increment(i, layout.qualifiers);
327 string qualifier = j->name;
329 qualifier += format("=%d", j->value);
335 void DumpTree::visit(InterfaceLayout &layout)
337 append(layout, format("Layout: %s", layout.interface));
338 append_subtree(layout.layout);
341 void DumpTree::visit(BasicTypeDeclaration &type)
343 append(type, format("%s typedef %s", get_label(type), format_type(type.name)));
345 vector<Branch> branches;
347 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)));
348 if(type.kind==BasicTypeDeclaration::VECTOR)
349 branches.emplace_back(format("Vector: %d", type.size));
350 else if(type.kind==BasicTypeDeclaration::MATRIX)
351 branches.emplace_back(format("Matrix: %dx%d", type.size&0xFFFF, type.size>>16));
352 if(type.extended_alignment)
353 branches.emplace_back("Extended alignment");
354 append_subtree(branches);
357 void DumpTree::visit(ImageTypeDeclaration &type)
359 static const char *const dims[] = { "1D", "2D", "3D", "Cube" };
361 append(type, format("%s typedef %s", get_label(type), format_type(type.name)));
363 vector<Branch> branches;
364 branches.emplace_back(format("Dimensions: %s%s", dims[type.dimensions-1], (type.array ? " array" : "")));
366 branches.emplace_back(format("Element type: %s %s", get_label(*type.base_type), format_type(type.base_type->name)));
368 branches.emplace_back("Shadow");
369 append_subtree(branches);
372 void DumpTree::visit(StructDeclaration &strct)
374 append(strct, format("%s struct %s", get_label(strct), strct.name));
375 vector<Branch> branches;
376 if(strct.extended_alignment)
377 branches.emplace_back("Extended alignment");
378 branches.emplace_back(&strct.members);
379 append_subtree(branches);
382 void DumpTree::visit(VariableDeclaration &var)
384 string decl = format("%s ", get_label(var));
387 if(!var.interpolation.empty())
388 decl += format("%s ", var.interpolation);
389 if(!var.sampling.empty())
390 decl += format("%s ", var.sampling);
391 if(!var.interface.empty())
392 decl += format("%s ", var.interface);
393 if(!var.precision.empty())
394 decl += format("%s ", var.precision);
395 decl += format("%s %s", format_type(var.type), format_name(var.name));
396 if(var.source==BUILTIN_SOURCE)
397 decl += " (builtin)";
398 else if(var.linked_declaration)
402 vector<Branch> branches;
403 if(var.type_declaration)
404 branches.emplace_back(format("Type: %s %s", get_label(*var.type_declaration), format_type(var.type_declaration->name)));
406 branches.emplace_back(var.layout.get());
410 branches.emplace_back("Array []", var.array_size.get());
412 branches.emplace_back("Array []");
414 if(var.init_expression)
415 branches.emplace_back(var.init_expression.get());
416 append_subtree(branches);
419 void DumpTree::visit(InterfaceBlock &iface)
421 string head = format("%s %s %s", get_label(iface), iface.interface, format_name(iface.block_name));
422 if(!iface.instance_name.empty())
423 head += format(" %s", format_name(iface.instance_name));
426 if(iface.source==BUILTIN_SOURCE)
427 head += " (builtin)";
428 else if(iface.linked_block)
432 vector<Branch> branches;
433 if(iface.type_declaration)
434 branches.emplace_back(format("Type: %s %s", get_label(*iface.type_declaration), format_type(iface.type_declaration->name)));
436 branches.emplace_back(iface.layout.get());
438 branches.emplace_back(iface.members.get());
439 append_subtree(branches);
442 void DumpTree::visit(FunctionDeclaration &func)
444 string text = format("%s %s %s%s", get_label(func), format_type(func.return_type), format_name(func.name), (func.signature.empty() ? "(?)" : func.signature));
445 if(func.source==BUILTIN_SOURCE)
446 text += " (builtin)";
447 else if(!func.definition)
448 text += " (undefined)";
452 if(func.return_type_declaration)
453 append(format("Return type: %s %s", get_label(*func.return_type_declaration), format_type(func.return_type_declaration)));
454 for(const RefPtr<VariableDeclaration> &p: func.parameters)
457 if(func.definition==&func)
458 func.body.visit(*this);
459 else if(func.definition)
460 append(format("Definition: %s", get_label(*func.definition)));
464 void DumpTree::visit(Conditional &cond)
466 append(cond, "if()");
468 vector<Branch> branches;
469 branches.emplace_back(cond.condition.get());
470 branches.emplace_back("then", &cond.body);
471 if(!cond.else_body.body.empty())
472 branches.emplace_back("else", &cond.else_body);
473 append_subtree(branches);
476 void DumpTree::visit(Iteration &iter)
478 append(iter, "for()");
480 vector<Branch> branches;
481 if(iter.init_statement)
482 branches.emplace_back("Initialization", iter.init_statement.get());
484 branches.emplace_back("Condition", iter.condition.get());
485 if(iter.loop_expression)
486 branches.emplace_back("Loop", iter.loop_expression.get());
487 branches.emplace_back(&iter.body);
488 append_subtree(branches);
491 void DumpTree::visit(Passthrough &pass)
493 append(pass, (pass.subscript ? "passthrough[]" : "passthrough"));
495 append_subtree(*pass.subscript);
498 void DumpTree::visit(Return &ret)
500 append(ret, (ret.expression ? "return" : "return;"));
502 append_subtree(*ret.expression);
505 void DumpTree::visit(Jump &jump)
507 append(jump, format("%s;", jump.keyword));