From: Mikko Rasa Date: Sat, 20 Feb 2021 22:47:44 +0000 (+0200) Subject: Add a visitor to dump the AST for debugging purposes X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=d2f75fa9ccf8252ff8a750071b26e77047a346cb;p=libs%2Fgl.git Add a visitor to dump the AST for debugging purposes --- diff --git a/source/glsl/debug.cpp b/source/glsl/debug.cpp new file mode 100644 index 00000000..80346dd0 --- /dev/null +++ b/source/glsl/debug.cpp @@ -0,0 +1,315 @@ +#include +#include +#include "debug.h" + +using namespace std; + +namespace Msp { +namespace GL { +namespace SL { + +const std::string &DumpTree::apply(Stage &stage) +{ + formatted = format("Stage %s\n", Stage::get_stage_name(stage.type)); + tree.push_back(BRANCH); + for(map::const_iterator i=stage.in_variables.begin(); i!=stage.in_variables.end(); ++i) + append(format("Input: %%%d %s %s", get_label(*i->second), i->second->type, i->first)); + for(map::const_iterator i=stage.out_variables.begin(); i!=stage.out_variables.end(); ++i) + append(format("Output: %%%d %s %s", get_label(*i->second), i->second->type, i->first)); + last_branch(); + visit(stage.content); + return formatted; +} + +void DumpTree::append(const string &line) +{ + StringCodec::Utf8::Encoder enc; + for(vector::const_iterator i=tree.begin(); i!=tree.end(); ) + { + enc.encode_char(*i++, formatted); + enc.encode_char((i==tree.end() ? REACH : EMPTY), formatted); + } + formatted += line; + formatted += '\n'; +} + +void DumpTree::begin_sub() +{ + tree.back() = (tree.back()==BRANCH_LAST ? EMPTY : STRAIGHT); + tree.push_back(BRANCH); +} + +void DumpTree::last_branch() +{ + tree.back() = BRANCH_LAST; +} + +void DumpTree::end_sub() +{ + tree.pop_back(); + if(tree.back()==STRAIGHT) + tree.back() = BRANCH; +} + +void DumpTree::annotated_branch(const string &annotation, Node &node) +{ + append(annotation); + begin_sub(); + last_branch(); + node.visit(*this); + end_sub(); +} + +unsigned DumpTree::get_label(const Node &node) +{ + unsigned &label = node_labels[&node]; + if(!label) + label = node_labels.size(); + return label; +} + +template +typename T::const_iterator DumpTree::increment(typename T::const_iterator &iter, const T &container) +{ + typename T::const_iterator ret = iter++; + if(iter==container.end()) + last_branch(); + return ret; +} + +void DumpTree::visit(Block &block) +{ + append(format("Block %s", (block.use_braces ? "{}" : "(inline)"))); + begin_sub(); + + for(std::map::const_iterator i=block.types.begin(); i!=block.types.end(); ++i) + append(format("Type %%%d %s", get_label(*i->second), i->first)); + + for(std::map::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i) + append(format("Variable %%%d %s %s", get_label(*i->second), i->second->type, i->first)); + + bool labeled_body = (!block.types.empty() || !block.variables.empty()); + if(labeled_body) + { + last_branch(); + append("Body"); + begin_sub(); + } + for(NodeList::const_iterator i=block.body.begin(); i!=block.body.end(); ) + { + NodeList::const_iterator j = increment(i, block.body); + (*j)->visit(*this); + } + if(labeled_body) + end_sub(); + + end_sub(); +} + +void DumpTree::visit(Literal &literal) +{ + append(format("Literal: %s", literal.token)); +} + +void DumpTree::visit(ParenthesizedExpression &parexpr) +{ + annotated_branch("(expr)", *parexpr.expression); +} + +void DumpTree::visit(VariableReference &var) +{ + string text; + if(var.declaration) + text += format("%%%d ", get_label(*var.declaration)); + text += var.name; + append(text); +} + +void DumpTree::visit(MemberAccess &memacc) +{ + annotated_branch(format("Member access: .%s", memacc.member), *memacc.left); +} + +void DumpTree::visit(UnaryExpression &unary) +{ + annotated_branch(format("Unary: %s, %sfix", unary.oper, (unary.prefix ? "pre" : "suff")), *unary.expression); +} + +void DumpTree::visit(BinaryExpression &binary) +{ + append(format("Binary: %s%s", binary.oper, binary.after)); + begin_sub(); + binary.left->visit(*this); + last_branch(); + binary.right->visit(*this); + end_sub(); +} + +void DumpTree::visit(Assignment &assign) +{ + append(format("Assignment%s", (assign.self_referencing ? " (self-referencing)" : ""))); + begin_sub(); + assign.left->visit(*this); + last_branch(); + assign.right->visit(*this); + end_sub(); +} + +void DumpTree::visit(FunctionCall &call) +{ + string head = format("Function call: %s", call.name); + if(call.declaration) + head += format(", declaration %%%d", get_label(*call.declaration)); + if(call.constructor) + head += ", constructor"; + append(head); + + begin_sub(); + for(NodeArray::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ) + { + NodeArray::const_iterator j = increment(i, call.arguments); + (*j)->visit(*this); + } + end_sub(); +} + +void DumpTree::visit(ExpressionStatement &expr) +{ + annotated_branch("expr;", *expr.expression); +} + +void DumpTree::visit(Import &import) +{ + append(format("import %s", import.module)); +} + +void DumpTree::visit(Precision &prec) +{ + append(format("precision %s %s", prec.precision, prec.type)); +} + +void DumpTree::visit(Layout &layout) +{ + append("Layout"); + begin_sub(); + for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ) + { + vector::const_iterator j = increment(i, layout.qualifiers); + string qualifier = j->identifier; + if(!j->value.empty()) + qualifier += format("=%s", j->value); + append(qualifier); + } + end_sub(); +} + +void DumpTree::visit(InterfaceLayout &layout) +{ + annotated_branch(format("Layout: %s", layout.interface), layout.layout); +} + +void DumpTree::visit(StructDeclaration &strct) +{ + annotated_branch(format("%%%d struct %s", get_label(strct), strct.name), strct.members); +} + +void DumpTree::visit(VariableDeclaration &var) +{ + string decl = format("%%%d ", get_label(var)); + if(var.constant) + decl += "const "; + if(!var.interpolation.empty()) + decl += format("%s ", var.interpolation); + if(!var.sampling.empty()) + decl += format("%s ", var.sampling); + if(!var.interface.empty()) + decl += format("%s ", var.interface); + if(!var.precision.empty()) + decl += format("%s ", var.precision); + decl += format("%s %s", var.type, var.name); + append(decl); + + begin_sub(); + if(!var.array && !var.init_expression) + last_branch(); + if(var.layout) + var.layout->visit(*this); + + if(!var.init_expression) + last_branch(); + if(var.array) + annotated_branch("Array []", *var.array_size); + + last_branch(); + if(var.init_expression) + var.init_expression->visit(*this); + end_sub(); +} + +void DumpTree::visit(InterfaceBlock &block) +{ + annotated_branch(format("%s %s", block.interface, block.name), block.members); +} + +void DumpTree::visit(FunctionDeclaration &func) +{ + append(format("%%%d %s %s()", get_label(func), func.return_type, func.name)); + begin_sub(); + for(NodeArray::const_iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + (*i)->visit(*this); + if(func.definition) + append(format("Definition %%%d", get_label(*func.definition))); + last_branch(); + func.body.visit(*this); + end_sub(); +} + +void DumpTree::visit(Conditional &cond) +{ + append("if()"); + begin_sub(); + cond.condition->visit(*this); + if(cond.else_body.body.empty()) + last_branch(); + cond.body.visit(*this); + if(!cond.else_body.body.empty()) + { + last_branch(); + cond.else_body.visit(*this); + } + end_sub(); +} + +void DumpTree::visit(Iteration &iter) +{ + append("for()"); + begin_sub(); + + if(iter.init_statement) + annotated_branch("Initialization", *iter.init_statement); + if(iter.condition) + annotated_branch("Condition", *iter.condition); + if(iter.loop_expression) + annotated_branch("Loop", *iter.loop_expression); + last_branch(); + annotated_branch("Body", iter.body); + + end_sub(); +} + +void DumpTree::visit(Return &ret) +{ + if(ret.expression) + annotated_branch("return", *ret.expression); + else + append("return;"); +} + +void DumpTree::visit(Jump &jump) +{ + append(format("%s;", jump.keyword)); +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/debug.h b/source/glsl/debug.h new file mode 100644 index 00000000..9806d545 --- /dev/null +++ b/source/glsl/debug.h @@ -0,0 +1,70 @@ +#ifndef MSP_GL_SL_DEBUG_H_ +#define MSP_GL_SL_DEBUG_H_ + +#include "syntax.h" +#include "visitor.h" + +namespace Msp { +namespace GL { +namespace SL { + +class DumpTree: private TraversingVisitor +{ +private: + enum TreeChars + { + EMPTY = 0x20, + STRAIGHT = 0x2502, // │ + BRANCH = 0x251C, // ├ + BRANCH_LAST = 0x2514, // └ + REACH = 0x2574 // ╴ + }; + + std::map node_labels; + std::string formatted; + std::vector tree; + +public: + const std::string &apply(Stage &); + +private: + void append(const std::string &); + void begin_sub(); + void last_branch(); + void end_sub(); + void annotated_branch(const std::string &, Node &); + unsigned get_label(const Node &); + + template + typename T::const_iterator increment(typename T::const_iterator &, const T &); + + virtual void visit(Block &); + virtual void visit(Literal &); + virtual void visit(ParenthesizedExpression &); + virtual void visit(VariableReference &); + virtual void visit(MemberAccess &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); + virtual void visit(Assignment &); + virtual void visit(FunctionCall &); + virtual void visit(ExpressionStatement &); + virtual void visit(Import &); + virtual void visit(Precision &); + virtual void visit(Layout &); + virtual void visit(InterfaceLayout &); + virtual void visit(StructDeclaration &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); + virtual void visit(FunctionDeclaration &); + virtual void visit(Conditional &); + virtual void visit(Iteration &); + virtual void visit(Return &); + virtual void visit(Jump &); + using TraversingVisitor::visit; +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif