\r
template<typename T>\r
using opt = std::optional<T>;\r
+template<typename ... Ts>\r
+using tup = std::tuple<Ts ...>;\r
\r
+// find an item in a vector by predicate\r
template<typename T>\r
opt<T> find(const std::vector<T> & ts, std::function<bool(T)> f)\r
{\r
return nullopt;\r
}\r
\r
+// same as above but return pointer into raw array held by vector\r
template<typename T>\r
opt<T *> findPtr(const std::vector<T> & ts, std::function<bool(T)> f)\r
{\r
return nullopt;\r
}\r
\r
-bool checkNamespace(std::shared_ptr<Context> ctx, const std::vector<std::string> & namespacePrefix)\r
+opt<tup<\r
+ std::shared_ptr<Context>,\r
+ std::vector<std::string>>>\r
+getContext(std::shared_ptr<Context> ctx, const std::vector<std::string> & namespacePrefix)\r
{\r
- \r
- bool prefixMatches = true;\r
+ // try finding a continuos series of namespaces in a given context\r
+ auto result = ctx;\r
\r
- auto nIt = ctx;\r
- for (int i = namespacePrefix.size() - 1; i >= 0; i--)\r
+ for (auto name : namespacePrefix)\r
+ {\r
+ auto newResult = find<Namespace>(result->namespaces, [&](Namespace n) { return n.name == name; });\r
+ if (newResult.has_value())\r
+ {\r
+ result = newResult->ctx;\r
+ }\r
+ else\r
{\r
- const std::string & prefix = namespacePrefix[i];\r
- if (nIt == nullptr || ! nIt->name.has_value() || nIt->name.value() != prefix)\r
- {\r
- prefixMatches = false;\r
- break;\r
- }\r
- nIt = nIt->parent;\r
+ return nullopt;\r
}\r
+ }\r
\r
- return prefixMatches;\r
-}\r
+ // if the found context is the end of a series of namespaces, also return\r
+ // a vector of namespace names\r
+ std::vector<std::string> namespaces;\r
+ for (auto it = result; it != nullptr; it = it->parent)\r
+ {\r
+ if (it->name.has_value())\r
+ {\r
+ namespaces.insert(namespaces.begin(), it->name.value());\r
+ }\r
+ else if (it->parent != nullptr)\r
+ {\r
+ namespaces.clear();\r
+ break;\r
+ }\r
+ }\r
\r
+ return std::make_tuple(result, namespaces);\r
+}\r
\r
+// all of the following functions work the same way,\r
+// walking up the context hierarchy until the global context.\r
+// return the first found instance that matches provided criteria\r
+// theres also a variant to get a pointer instead for functions and\r
+// structs used for generic instantiation\r
\r
-opt<Function> findFunction(\r
+opt<tup<Function, std::vector<std::string>>> findFunction(\r
const std::string & name,\r
const std::vector<std::string> & namespacePrefix,\r
std::shared_ptr<Context> ctx)\r
{\r
for (auto it = ctx; it != nullptr; it = it->parent)\r
{\r
- auto f = find<Function>(it->functions, [&](Function f) { return f.name == name; });\r
- if (f.has_value() && checkNamespace(it, namespacePrefix))\r
- return f;\r
+ auto n = getContext(it, namespacePrefix);\r
+ if (n.has_value())\r
+ {\r
+ auto x = find<Function>(std::get<0>(*n)->functions, [&](Function _) { return _.name == name; });\r
+ if (x.has_value())\r
+ return std::make_tuple(x.value(), std::get<1>(*n));\r
+ }\r
}\r
return nullopt;\r
}\r
\r
-opt<Function *> findFunctionPtr(\r
+opt<tup<Function *, std::vector<std::string>>> findFunctionPtr(\r
const std::string & name,\r
const std::vector<std::string> & namespacePrefix,\r
std::shared_ptr<Context> ctx)\r
{\r
for (auto it = ctx; it != nullptr; it = it->parent)\r
{\r
- auto f = findPtr<Function>(it->functions, [&](Function f) { return f.name == name; });\r
- if (f.has_value() && checkNamespace(it, namespacePrefix))\r
- return f;\r
+ auto n = getContext(it, namespacePrefix);\r
+ if (n.has_value())\r
+ {\r
+ auto x = findPtr<Function>(std::get<0>(*n)->functions, [&](Function _) { return _.name == name; });\r
+ if (x.has_value())\r
+ return std::make_tuple(x.value(), std::get<1>(*n));\r
+ }\r
}\r
return nullopt;\r
}\r
\r
\r
\r
-opt<Struct> findStruct(\r
+opt<tup<Struct, std::vector<std::string>>> findStruct(\r
const std::string & name,\r
const std::vector<std::string> & namespacePrefix,\r
std::shared_ptr<Context> ctx)\r
{\r
for (auto it = ctx; it != nullptr; it = it->parent)\r
{\r
- auto s = find<Struct>(it->structs, [&](Struct s) { return s.name == name; });\r
- if (s.has_value() && checkNamespace(it, namespacePrefix))\r
- return s;\r
+ auto n = getContext(it, namespacePrefix);\r
+ if (n.has_value())\r
+ {\r
+ auto x = find<Struct>(std::get<0>(*n)->structs, [&](Struct _) { return _.name == name; });\r
+ if (x.has_value())\r
+ return std::make_tuple(x.value(), std::get<1>(*n));\r
+ }\r
}\r
return nullopt;\r
}\r
\r
-opt<Struct *> findStructPtr(\r
+opt<tup<Struct *, std::vector<std::string>>> findStructPtr(\r
const std::string & name,\r
const std::vector<std::string> & namespacePrefix,\r
std::shared_ptr<Context> ctx)\r
{\r
for (auto it = ctx; it != nullptr; it = it->parent)\r
{\r
- auto s = findPtr<Struct>(it->structs, [&](Struct s) { return s.name == name; });\r
- if (s.has_value() && checkNamespace(it, namespacePrefix))\r
- return s;\r
+ auto n = getContext(it, namespacePrefix);\r
+ if (n.has_value())\r
+ {\r
+ auto x = findPtr<Struct>(std::get<0>(*n)->structs, [&](Struct _) { return _.name == name; });\r
+ if (x.has_value())\r
+ return std::make_tuple(x.value(), std::get<1>(*n));\r
+ }\r
}\r
return nullopt;\r
}\r
\r
\r
\r
-opt<Variable> findVariable(\r
+opt<tup<Variable, std::vector<std::string>>> findVariable(\r
const std::string & name,\r
const std::vector<std::string> & namespacePrefix,\r
std::shared_ptr<Context> ctx)\r
{\r
for (auto it = ctx; it != nullptr; it = it->parent)\r
{\r
- auto v = find<Variable>(it->variables, [&](Variable v) { return v.name == name; });\r
- if (v.has_value() && checkNamespace(it, namespacePrefix))\r
- return v;\r
+ auto n = getContext(it, namespacePrefix);\r
+ if (n.has_value())\r
+ {\r
+ auto x = find<Variable>(std::get<0>(*n)->variables, [&](Variable _) { return _.name == name; });\r
+ if (x.has_value())\r
+ return std::make_tuple(x.value(), std::get<1>(*n));\r
+ }\r
}\r
return nullopt;\r
}\r
\r
\r
\r
+// find struct members and pointer variants\r
+\r
opt<StructMember<Function>> findStructMethod(\r
const std::string & name,\r
const Struct & s)\r