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