]> gitweb.ps.run Git - toc/blobdiff - src/visit.h
generic functions and structs
[toc] / src / visit.h
diff --git a/src/visit.h b/src/visit.h
new file mode 100644 (file)
index 0000000..0cfb9e6
--- /dev/null
@@ -0,0 +1,193 @@
+#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