5 #include <functional>
\r
7 // struct with callback functions for all relevant types
\r
8 // tree can be walked selectively by providing only
\r
11 std::function<void(const Type &, const std::shared_ptr<Context> ctx)> onType = [](auto, auto){};
\r
12 std::function<void(const Expr &, const std::shared_ptr<Context> ctx)> onExpr = [](auto, auto){};
\r
13 std::function<void(const Stmt &, const std::shared_ptr<Context> ctx)> onStmt = [](auto, auto){};
\r
14 std::function<void(const Body &, const std::shared_ptr<Context> ctx)> onBody = [](auto, auto){};
\r
15 std::function<void(const Function &, const std::shared_ptr<Context> ctx)> onFunction = [](auto, auto){};
\r
16 std::function<void(const Variable &, const std::shared_ptr<Context> ctx)> onVariable = [](auto, auto){};
\r
17 std::function<void(const StructMember<Function> &, const std::shared_ptr<Context> ctx)> onStructMethod = [](auto, auto){};
\r
18 std::function<void(const StructMember<Variable> &, const std::shared_ptr<Context> ctx)> onStructMember = [](auto, auto){};
\r
19 std::function<void(const Struct &, const std::shared_ptr<Context> ctx)> onStruct = [](auto, auto){};
\r
20 std::function<void(const Namespace &, const std::shared_ptr<Context> ctx)> onNamespace = [](auto, auto){};
\r
21 std::function<void(const Program &, const std::shared_ptr<Context> ctx)> onProgram = [](auto, auto){};
\r
24 #define VISIT(XS) for (auto x : XS) visit(x);
\r
26 // simply walk IR by recursively calling functions for all children
\r
30 std::shared_ptr<Context> ctx;
\r
36 void visit(const Type & x)
\r
40 void visit(const Expr & x)
\r
46 case ExprType::Func:
\r
47 VISIT(x._func.arguments)
\r
49 case ExprType::Method:
\r
50 visit(*x._method.expr);
\r
51 VISIT(x._method.arguments);
\r
55 case ExprType::Paren:
\r
56 visit(*x._paren.expr);
\r
59 visit(*x._dot.expr);
\r
61 case ExprType::PrefixOp:
\r
62 visit(*x._prefixOp.expr);
\r
64 case ExprType::PostfixOp:
\r
65 visit(*x._postfixOp.expr);
\r
67 case ExprType::BinaryOp:
\r
68 visit(*x._binaryOp.lexpr);
\r
69 visit(*x._binaryOp.rexpr);
\r
71 case ExprType::TernaryOp:
\r
72 visit(*x._ternaryOp.lexpr);
\r
73 visit(*x._ternaryOp.rexprTrue);
\r
74 visit(*x._ternaryOp.rexprFalse);
\r
76 case ExprType::Bracket:
\r
77 visit(*x._brackets.lexpr);
\r
78 visit(*x._brackets.rexpr);
\r
80 case ExprType::Identifier:
\r
84 void visit(const Stmt & x)
\r
90 case StmtType::Assign:
\r
91 visit(x._assign.lexpr);
\r
92 visit(x._assign.rexpr);
\r
94 case StmtType::Expr:
\r
98 visit(x._for.init->lexpr);
\r
99 visit(x._for.init->rexpr);
\r
100 visit(*x._for.condition);
\r
101 visit(*x._for.action);
\r
102 visit(x._for.body);
\r
105 visit(x._if.condition);
\r
107 for (auto e : x._if.elses)
\r
114 case StmtType::Return:
\r
115 visit(x._return.expr);
\r
117 case StmtType::Switch:
\r
118 visit(*x._switch.ident);
\r
119 for (auto c : x._switch.cases)
\r
125 case StmtType::While:
\r
126 visit(x._while.condition);
\r
127 visit(x._while.body);
\r
131 void visit(const Body & x)
\r
137 VISIT(x.ctx->variables)
\r
138 VISIT(x.statements)
\r
142 void visit(const Namespace & x)
\r
144 v.onNamespace(x, ctx);
\r
148 VISIT(x.ctx->namespaces)
\r
149 VISIT(x.ctx->variables)
\r
150 VISIT(x.ctx->structs)
\r
151 VISIT(x.ctx->functions)
\r
155 void visit(const Variable & x)
\r
157 v.onVariable(x, ctx);
\r
160 void visit(const Function & x)
\r
162 v.onFunction(x, ctx);
\r
165 for (auto v : x.parameters)
\r
170 void visit(const StructMember<Function> & x)
\r
172 v.onStructMethod(x, ctx);
\r
176 void visit(const StructMember<Variable> & x)
\r
178 v.onStructMember(x, ctx);
\r
182 void visit(const Struct & x)
\r
184 v.onStruct(x, ctx);
\r
189 void visit(const Program & x)
\r
191 v.onProgram(x, ctx);
\r
195 VISIT(x.ctx->namespaces)
\r
196 VISIT(x.ctx->variables)
\r
197 VISIT(x.ctx->structs)
\r
198 VISIT(x.ctx->functions)
\r