--- /dev/null
+#pragma once\r
+\r
+#include "repr.h"\r
+\r
+#include <functional>\r
+\r
+struct Visitor {\r
+ std::function<void(const Type &, const std::vector<std::string> & namespaces)> onType = [](auto, auto){};\r
+ std::function<void(const Expr &, const std::vector<std::string> & namespaces)> onExpr = [](auto, auto){};\r
+ std::function<void(const Stmt &, const std::vector<std::string> & namespaces)> onStmt = [](auto, auto){};\r
+ std::function<void(const Body &, const std::vector<std::string> & namespaces)> onBody = [](auto, auto){};\r
+ std::function<void(const Function &, const std::vector<std::string> & namespaces)> onFunction = [](auto, auto){};\r
+ std::function<void(const Variable &, const std::vector<std::string> & namespaces)> onVariable = [](auto, auto){};\r
+ std::function<void(const StructMember<Function> &, const std::vector<std::string> & namespaces)> onStructMethod = [](auto, auto){};\r
+ std::function<void(const StructMember<Variable> &, const std::vector<std::string> & namespaces)> onStructMember = [](auto, auto){};\r
+ std::function<void(const Struct &, const std::vector<std::string> & namespaces)> onStruct = [](auto, auto){};\r
+ std::function<void(const Namespace &, const std::vector<std::string> & namespaces)> onNamespace = [](auto, auto){};\r
+ std::function<void(const Program &, const std::vector<std::string> & namespaces)> onProgram = [](auto, auto){};\r
+};\r
+\r
+#define VISIT(XS) for (auto x : XS) visit(x);\r
+\r
+struct Visit {\r
+private:\r
+ Visitor v;\r
+ std::vector<std::string> namespaces;\r
+public:\r
+ Visit(Visitor v)\r
+ {\r
+ this->v = v;\r
+ }\r
+ void visit(const Type & x)\r
+ {\r
+ v.onType(x, namespaces);\r
+ }\r
+ void visit(const Expr & x)\r
+ {\r
+ v.onExpr(x, namespaces);\r
+\r
+ switch (x.type)\r
+ {\r
+ case ExprType::Func:\r
+ VISIT(x._func.arguments)\r
+ break;\r
+ case ExprType::Method:\r
+ visit(*x._method.expr);\r
+ VISIT(x._method.arguments);\r
+ break;\r
+ case ExprType::Lit:\r
+ break;\r
+ case ExprType::Paren:\r
+ visit(*x._paren.expr);\r
+ break;\r
+ case ExprType::Dot:\r
+ visit(*x._dot.expr);\r
+ break;\r
+ case ExprType::PrefixOp:\r
+ visit(*x._prefixOp.expr);\r
+ break;\r
+ case ExprType::PostfixOp:\r
+ visit(*x._postfixOp.expr);\r
+ break;\r
+ case ExprType::BinaryOp:\r
+ visit(*x._binaryOp.lexpr);\r
+ visit(*x._binaryOp.rexpr);\r
+ break;\r
+ case ExprType::TernaryOp:\r
+ visit(*x._ternaryOp.lexpr);\r
+ visit(*x._ternaryOp.rexprTrue);\r
+ visit(*x._ternaryOp.rexprFalse);\r
+ break;\r
+ case ExprType::Bracket:\r
+ visit(*x._brackets.lexpr);\r
+ visit(*x._brackets.rexpr);\r
+ break;\r
+ case ExprType::Identifier:\r
+ break;\r
+ }\r
+ }\r
+ void visit(const Stmt & x)\r
+ {\r
+ v.onStmt(x, namespaces);\r
+\r
+ switch (x.type)\r
+ {\r
+ case StmtType::Assign:\r
+ visit(x._assign.lexpr);\r
+ visit(x._assign.rexpr);\r
+ break;\r
+ case StmtType::Expr:\r
+ visit(x._expr);\r
+ break;\r
+ case StmtType::For:\r
+ visit(x._for.init->lexpr);\r
+ visit(x._for.init->rexpr);\r
+ visit(*x._for.condition);\r
+ visit(*x._for.action);\r
+ visit(x._for.body);\r
+ break;\r
+ case StmtType::If:\r
+ visit(x._if.condition);\r
+ visit(x._if.body);\r
+ for (auto e : x._if.elses)\r
+ {\r
+ if (e._if)\r
+ visit(*e.expr);\r
+ visit(e.body);\r
+ }\r
+ break;\r
+ case StmtType::Return:\r
+ visit(x._return.expr);\r
+ break;\r
+ case StmtType::Switch:\r
+ visit(*x._switch.ident);\r
+ for (auto c : x._switch.cases)\r
+ {\r
+ visit(*c.expr);\r
+ visit(c.body);\r
+ }\r
+ break;\r
+ case StmtType::While:\r
+ visit(x._while.condition);\r
+ visit(x._while.body);\r
+ break;\r
+ }\r
+ }\r
+ void visit(const Body & x)\r
+ {\r
+ v.onBody(x, namespaces);\r
+\r
+ VISIT(x.ctx->variables)\r
+ VISIT(x.statements)\r
+ }\r
+ void visit(const Namespace & x)\r
+ {\r
+ v.onNamespace(x, namespaces);\r
+\r
+ namespaces.push_back(x.name);\r
+\r
+ VISIT(x.namespaces)\r
+ VISIT(x.ctx->variables)\r
+ VISIT(x.structs)\r
+ VISIT(x.functions)\r
+\r
+ namespaces.pop_back();\r
+ }\r
+ void visit(const Variable & x)\r
+ {\r
+ v.onVariable(x, namespaces);\r
+ visit(x.type);\r
+ }\r
+ void visit(const Function & x)\r
+ {\r
+ v.onFunction(x, namespaces);\r
+\r
+ if (x.defined) {\r
+ visit(x.body);\r
+ for (auto v : x.parameters)\r
+ visit(v.type);\r
+ }\r
+ }\r
+ void visit(const StructMember<Function> & x)\r
+ {\r
+ v.onStructMethod(x, namespaces);\r
+\r
+ visit(x.t);\r
+ }\r
+ void visit(const StructMember<Variable> & x)\r
+ {\r
+ v.onStructMember(x, namespaces);\r
+\r
+ visit(x.t);\r
+ }\r
+ void visit(const Struct & x)\r
+ {\r
+ v.onStruct(x, namespaces);\r
+\r
+ VISIT(x.members)\r
+ VISIT(x.methods)\r
+ }\r
+ void visit(const Program & x)\r
+ {\r
+ v.onProgram(x, namespaces);\r
+\r
+ VISIT(x.namespaces)\r
+ VISIT(x.ctx->variables)\r
+ VISIT(x.structs)\r
+ VISIT(x.functions)\r
+ }\r
+};\r
+\r
+#undef VISIT\r
+\r