]> gitweb.ps.run Git - toc/blob - src/generic.h
comments
[toc] / src / generic.h
1 #pragma once\r
2 \r
3 #include "repr.h"\r
4 #include "typeInfo.h"\r
5 #include "visit.h"\r
6 \r
7 // add a generic instantiation if its not in the vector already\r
8 void addGenericInstantiation(\r
9   std::vector<std::vector<Type>> & insts,\r
10   const std::vector<Type> & newInst)\r
11 {\r
12   if (insts.empty())\r
13   {\r
14     insts.push_back(newInst);\r
15     return;\r
16   }\r
17   for (auto inst : insts)\r
18   {\r
19     for (int i = 0; i < inst.size(); i++)\r
20     {\r
21       if (inst[i] != newInst[i])\r
22       {\r
23         insts.push_back(newInst);\r
24         return;\r
25       }\r
26     }\r
27   }\r
28 }\r
29 \r
30 Program instantiateGenerics(const Program & p)\r
31 {\r
32   Program result = p;\r
33 \r
34   // Find generic instantiations\r
35 \r
36   // visit expressions (only function calls are considered) and types,\r
37   // find the function/struct by pointer and add an instantiation\r
38   Visitor findGenericInstantiations;\r
39   findGenericInstantiations.onExpr =\r
40   [&](const Expr & e, const std::shared_ptr<Context> ctx)\r
41   {\r
42     if (e.type == ExprType::Func && !e._func.genericInstantiation.empty())\r
43     {\r
44       auto f = findFunctionPtr(e._func.functionName, e._func.namespacePrefixes, ctx);\r
45       if (f.has_value())\r
46       {\r
47         if (std::get<0>(*f)->genericTypeNames.empty())\r
48           throw "Trying to instantiate non-generic function";\r
49         if (e._func.genericInstantiation.size() != std::get<0>(*f)->genericTypeNames.size())\r
50           throw "Trying to instantiate function with wrong number of types";\r
51         addGenericInstantiation(std::get<0>(*f)->genericInstantiations, e._func.genericInstantiation);\r
52       }\r
53     }\r
54   };\r
55   findGenericInstantiations.onType =\r
56   [&](const Type & t, const std::shared_ptr<Context> ctx)\r
57   {\r
58     if (!t.genericInstantiation.empty())\r
59     {\r
60       auto s = findStructPtr(t.name, t.namespacePrefixes, ctx);\r
61       if (s.has_value())\r
62       {\r
63         if (std::get<0>(*s)->genericTypeNames.empty())\r
64           throw "Trying to instantiate non-generic struct";\r
65         if (t.genericInstantiation.size() != std::get<0>(*s)->genericTypeNames.size())\r
66           throw "Trying to instantiate struct with wrong number of types";\r
67         addGenericInstantiation(std::get<0>(*s)->genericInstantiations, t.genericInstantiation);\r
68       }\r
69     }\r
70   };\r
71   Visit v(findGenericInstantiations);\r
72   v.visit(result);\r
73 \r
74   return result;\r
75 }\r
76 \r
77 // generate the appendix for C struct/function names\r
78 // including array/pointer indicators because\r
79 // there might be distinct instantiations\r
80 // for int and int* for example\r
81 std::string genericAppendix(const std::vector<Type> & ts)\r
82 {\r
83   std::stringstream sstr;\r
84   for (auto t : ts)\r
85   {\r
86     sstr << "_";\r
87     sstr << t.name;\r
88     for (auto m : t.modifiers)\r
89     {\r
90       if (m.type == TypeModifierType::Array)\r
91       {\r
92         sstr << "_arr";\r
93         if (m._staticArray)\r
94           sstr << m._arraySize;\r
95       }\r
96       else if (m.type == TypeModifierType::Pointer)\r
97       {\r
98         sstr << "_ptr";\r
99       }\r
100     }\r
101     if (!t.genericInstantiation.empty())\r
102     {\r
103       sstr << genericAppendix(t.genericInstantiation);\r
104     }\r
105   }\r
106   return sstr.str();\r
107 }