]> gitweb.ps.run Git - toc/blob - src/toc.h
fix function and method return types
[toc] / src / toc.h
1 #pragma once\r
2 \r
3 #include <iostream>\r
4 #include <sstream>\r
5 \r
6 #include "repr.h"\r
7 #include "generic.h"\r
8 #include "typeInfo.h"\r
9 \r
10 // print a generic vector with specified separator, optionally printing the separator at the end aswell\r
11 template<typename T>\r
12 std::string vectorStr (const std::vector<T> & v, const std::string & separator, bool end = false)\r
13 {\r
14   std::stringstream sstr;\r
15 \r
16   bool putSeparator = false;\r
17   for (auto t : v)\r
18   {\r
19     if (putSeparator) sstr << separator;\r
20     else putSeparator = true;\r
21     sstr << t;\r
22   }\r
23   if (end && !v.empty())\r
24     sstr << separator;\r
25 \r
26   return sstr.str();\r
27 }\r
28 \r
29 std::ostream & operator<< (std::ostream & out, const Type & t);\r
30 std::ostream & operator<< (std::ostream & out, const Variable & v);\r
31 std::ostream & operator<< (std::ostream & out, const Body & b);\r
32 std::ostream & operator<< (std::ostream & out, const Expr & e);\r
33 std::ostream & operator<< (std::ostream & out, const Stmt & s);\r
34 \r
35 void tocFunction (std::ostream & out, const Function & f, bool stub);\r
36 void tocStruct   (std::ostream & out, const Struct & s, bool stub);\r
37 void tocProgram  (std::ostream & out, const Program & p);\r
38 void tocNamespace  (std::ostream & out, const Namespace & n, bool stub);\r
39 \r
40 static const int TAB_WIDTH = 2;\r
41 static int indentation = 0;\r
42 static void indent(std::ostream & out, int change = 0)\r
43 {\r
44   indentation += change;\r
45   out << std::string(indentation, ' ');\r
46 }\r
47 \r
48 static std::vector<std::string> namespaces;\r
49 static std::string namespacePrefix() {\r
50   std::stringstream sstr;\r
51   for (auto n : namespaces)\r
52   {\r
53     sstr << n << "_";\r
54   }\r
55   return sstr.str();\r
56 }\r
57 \r
58 // mapping from generic typenames (which are just names)\r
59 // to actual instantiated types\r
60 static std::map<std::string, Type> currentInstantiation;\r
61 \r
62 // set current context so that lookups can be made correctly\r
63 static std::shared_ptr<Context> globalCtx;\r
64 \r
65 \r
66 std::ostream & operator<< (std::ostream & out, const Type & t)\r
67 {\r
68   // if the typename equals one of the current generic instantiations\r
69   // print instantiated type instead\r
70   for (auto kv : currentInstantiation)\r
71   {\r
72     if (t.name == kv.first)\r
73     {\r
74       out << kv.second;\r
75       return out;\r
76     }\r
77   }\r
78   TypeInfo ti = typeType(globalCtx, t);\r
79   if (ti.isStruct)\r
80     out << "struct ";\r
81   // try finding type in current context\r
82   auto s = findStruct(t.name, t.namespacePrefixes, globalCtx);\r
83   // print prefix for either found type or the specified \r
84   // prefix if type is not found (shouldn't happen)\r
85   if (s.has_value())\r
86     out << vectorStr(std::get<1>(*s), "_", true) << t.name; \r
87   else\r
88     out << vectorStr(t.namespacePrefixes, "_", true) << t.name;\r
89 \r
90   // print generic appendix\r
91   if (!t.genericInstantiation.empty())\r
92     out << genericAppendix(t.genericInstantiation);\r
93 \r
94   return out;\r
95 }\r
96 \r
97 std::string generateModifiers (std::string s, std::vector<TypeModifier> modifiers)\r
98 {\r
99   std::stringstream sstr;\r
100 \r
101   // apply modifiers, inverted because C defines them\r
102   // the opposite direction\r
103   for (auto m = modifiers.rbegin(); m != modifiers.rend(); m++)\r
104   {\r
105     if (m->type == TypeModifierType::Pointer)\r
106     {\r
107       sstr.str(std::string());\r
108       sstr << "*(" << s << ")";\r
109       s = sstr.str();\r
110     }\r
111     else\r
112     {\r
113       sstr.str(std::string());\r
114       sstr << "(" << s << ")[";\r
115       if (m->_staticArray)\r
116         sstr << m->_arraySize;\r
117       sstr << "]";\r
118       s = sstr.str();\r
119     }\r
120   }\r
121 \r
122   return s;\r
123 }\r
124 \r
125 std::ostream & operator<< (std::ostream & out, const Variable & v)\r
126 {\r
127   out << v.type << " ";\r
128 \r
129   std::string s = v.name;\r
130   \r
131   // lookup variable and change name to reflect containing namespace\r
132   auto var = findVariable(v.name, namespaces, globalCtx);\r
133   if (var.has_value())\r
134     s = vectorStr(std::get<1>(*var), "_", true) + s;\r
135 \r
136   // apply modifiers in C fashion\r
137   out << generateModifiers(s, v.type.modifiers);\r
138 \r
139   return out;\r
140 }\r
141 std::ostream & operator<< (std::ostream & out, const Body & b)\r
142 {\r
143   b.ctx->parent = globalCtx;\r
144   globalCtx = b.ctx;\r
145 \r
146   indent(out);\r
147   out << "{\n";\r
148   indentation += 2;\r
149 \r
150   for (auto v : b.ctx->variables)\r
151   {\r
152     indent(out);\r
153     out << v << ";\n";\r
154   }\r
155 \r
156   out << "\n";\r
157   \r
158   for (auto s : b.statements)\r
159   {\r
160     indent(out);\r
161     out << s << "\n";\r
162   }\r
163 \r
164   indent(out, -2);\r
165   out << "}\n";\r
166 \r
167   globalCtx = b.ctx->parent;\r
168 \r
169   return out;\r
170 }\r
171 std::ostream & operator<< (std::ostream & out, const Expr & e)\r
172 {\r
173   switch (e.type)\r
174   {\r
175   case ExprType::Func:\r
176   {\r
177     // print function call\r
178     auto f = findFunction(e._func.functionName, e._func.namespacePrefixes, globalCtx);\r
179 \r
180     if (std::get<0>(*f).defined)\r
181       out << vectorStr(std::get<1>(*f), "_", true);\r
182 \r
183     out << e._func.functionName;\r
184     if (!e._func.genericInstantiation.empty())\r
185       out << genericAppendix(e._func.genericInstantiation);\r
186     out <<"(" << vectorStr(e._func.arguments, ", ") << ")"; break;\r
187   }\r
188   case ExprType::Method:\r
189   {\r
190     // get TypeInfo on the Expression that the method is called on\r
191     // then print method call\r
192     TypeInfo ti = typeExpr(globalCtx, *e._method.expr);\r
193     out <<\r
194       vectorStr(ti.type.namespacePrefixes, "_", true) <<\r
195       ti.type.name << genericAppendix(ti.type.genericInstantiation) << "_" << e._method.methodName;\r
196     if (!e._method.genericInstantiation.empty())\r
197       out << genericAppendix(e._method.genericInstantiation);\r
198     out << "(";\r
199     if (e._method.expr->type == ExprType::Identifier)\r
200       out << "&";\r
201     out << *e._method.expr << (e._method.arguments.empty() ? "" : ", ") <<\r
202     vectorStr(e._method.arguments, ", ") << ")"; break;\r
203   }\r
204   case ExprType::Lit:\r
205     /**/ if (e._lit.type == LitType::Int) out << e._lit._int;\r
206     else if (e._lit.type == LitType::Decimal) out << e._lit._decimal;\r
207     else if (e._lit.type == LitType::String) out << e._lit._string;\r
208     else if (e._lit.type == LitType::Bool) out << e._lit._bool;\r
209     break;\r
210   case ExprType::Paren:\r
211     out << "(" << *e._paren.expr << ")"; break;\r
212   case ExprType::Dot:\r
213     out << *e._dot.expr << (e._dot.isPointer ? "->" : ".") << e._dot.identifier; break;\r
214   case ExprType::PrefixOp:\r
215     out << PrefixOperatorTypeStrings[(int)e._prefixOp.type] << *e._prefixOp.expr; break;\r
216   case ExprType::PostfixOp:\r
217     out << *e._postfixOp.expr << PostfixOperatorTypeStrings[(int)e._postfixOp.type]; break;\r
218   case ExprType::BinaryOp:\r
219     out << *e._binaryOp.lexpr <<\r
220     " " << BinaryOperatorTypeStrings[(int)e._binaryOp.type] << " " <<\r
221     *e._binaryOp.rexpr; break;\r
222   case ExprType::TernaryOp:\r
223     out << *e._ternaryOp.lexpr <<\r
224       " ? " << *e._ternaryOp.rexprTrue <<\r
225       " : " << *e._ternaryOp.rexprFalse; break;\r
226   case ExprType::Bracket:\r
227     out << *e._brackets.lexpr << "[" << *e._brackets.rexpr << "]"; break;\r
228   case ExprType::Identifier:\r
229     // try variable lookup\r
230     auto v = findVariable(e._identifier.identifier, e._identifier.namespacePrefixes, globalCtx);\r
231     if (v.has_value())\r
232       out << vectorStr(std::get<1>(*v), "_", true);\r
233     else\r
234       out << vectorStr(e._identifier.namespacePrefixes, "_", true);\r
235 \r
236     out << e._identifier.identifier; break;\r
237   }\r
238 \r
239   return out;\r
240 }\r
241 std::ostream & operator<< (std::ostream & out, const Stmt & s)\r
242 {\r
243   switch (s.type)\r
244   {\r
245   case StmtType::If:\r
246     out << "if (" << s._if.condition << ")\n" << s._if.body; break;\r
247   case StmtType::Switch:\r
248     out << "switch (" << s._switch.ident << ")\n{\n";\r
249     for (auto c : s._switch.cases)\r
250     {\r
251       indent(out, 2);\r
252       out << "case " << *c.expr << ": " << c.body << "break;";\r
253     }\r
254     indent(out, -2);\r
255     out << "}\n";\r
256     break;\r
257   case StmtType::For:\r
258     out << "for (" <<\r
259       s._for.init << "; " <<\r
260       *s._for.condition << "; " <<\r
261       *s._for.action <<\r
262       ")\n" << s._for.body; break;\r
263   case StmtType::While:\r
264     out << "while (" << s._while.condition << ")\n" << s._while.body; break;\r
265   case StmtType::Assign:\r
266     out << s._assign.lexpr << " = " << s._assign.rexpr << ";"; break;\r
267   case StmtType::Return:\r
268     out << "return " << s._return.expr << ";"; break;\r
269   case StmtType::Expr:\r
270     out << s._expr << ";"; break;\r
271   }\r
272 \r
273   return out;\r
274 }\r
275 \r
276 \r
277 void tocFunction (std::ostream & out, const Function & f, bool stub)\r
278 {\r
279   // for a function that is not defined, only the stub can be printed\r
280   if (!f.defined && !stub) return;\r
281 \r
282   // regular function\r
283   if (f.genericTypeNames.empty())\r
284   {\r
285     out << f.returnType << " " << generateModifiers(namespacePrefix() + f.name, f.returnType.modifiers) << " (" << vectorStr(f.parameters, ", ") << ")";\r
286 \r
287     if (stub)\r
288     {\r
289       out << ";\n";\r
290     }\r
291     else\r
292     {\r
293       out << "\n" << f.body;\r
294     }\r
295   }\r
296   // generic function\r
297   else\r
298   {\r
299     // print one instance per instantiation\r
300     for (auto instantiation : f.genericInstantiations)\r
301     {\r
302       // set global type mapping\r
303       for (int i = 0; i < f.genericTypeNames.size(); i++)\r
304       {\r
305         currentInstantiation[f.genericTypeNames[i]] = instantiation[i];\r
306       }\r
307 \r
308       out << f.returnType << " " << generateModifiers(namespacePrefix() + f.name, f.returnType.modifiers) << genericAppendix(instantiation) << " (" << vectorStr(f.parameters, ", ") << ")";\r
309 \r
310       if (stub)\r
311       {\r
312         out << ";\n";\r
313       }\r
314       else\r
315       {\r
316         out << "\n" << f.body;\r
317       }\r
318 \r
319       currentInstantiation.clear();\r
320     }\r
321   }\r
322 }\r
323 void tocStruct (std::ostream & out, const Struct & s, bool stub)\r
324 {\r
325   // regular struct\r
326   if (s.genericTypeNames.empty())\r
327   {\r
328     out << "struct " << namespacePrefix() << s.name;\r
329     if (stub)\r
330     {\r
331       out << ";\n";\r
332       for (auto m : s.methods)\r
333       {\r
334         Function f = m;\r
335 \r
336         // add implicit this parameter\r
337         f.parameters.insert(f.parameters.begin(),\r
338         {"this",\r
339           {\r
340             namespaces,\r
341             s.name,\r
342             {\r
343               {TypeModifierType::Pointer, false, -1}\r
344             }\r
345           }\r
346         });\r
347         out << f.returnType << " " <<\r
348           generateModifiers(namespacePrefix() + s.name + "_" + f.name, f.returnType.modifiers) <<\r
349           " (" << vectorStr(f.parameters, ", ") << ");\n";\r
350       }\r
351       return;\r
352     }\r
353     out << "\n{\n";\r
354     indentation += 2;\r
355 \r
356     for (auto m : s.members)\r
357     {\r
358       indent(out);\r
359       out << m << ";\n";\r
360     }\r
361 \r
362     indent(out, -2);\r
363     out << "};\n";\r
364     \r
365     for (auto m : s.methods)\r
366     {\r
367       Function f = m;\r
368       \r
369       // add implicit this parameter\r
370       f.parameters.insert(f.parameters.begin(),\r
371         {"this",\r
372           {\r
373             namespaces,\r
374             s.name,\r
375             {\r
376               {TypeModifierType::Pointer, false, -1}\r
377             }\r
378           }\r
379         });\r
380       out << f.returnType << " " <<\r
381         generateModifiers(namespacePrefix() + s.name + "_" + f.name, f.returnType.modifiers) <<\r
382         " (" << vectorStr(f.parameters, ", ") << ")\n" << f.body;\r
383     }\r
384   }\r
385   // generic struct\r
386   else\r
387   {\r
388     for (auto instantiation : s.genericInstantiations)\r
389     {\r
390       for (int i = 0; i < s.genericTypeNames.size(); i++)\r
391       {\r
392         currentInstantiation[s.genericTypeNames[i]] = instantiation[i];\r
393       }\r
394 \r
395       out << "struct " << namespacePrefix() << s.name << genericAppendix(instantiation);\r
396       if (stub)\r
397       {\r
398         out << ";\n";\r
399         for (auto m : s.methods)\r
400         {\r
401           Function f = m;\r
402 \r
403         // add implicit this parameter\r
404           f.parameters.insert(f.parameters.begin(),\r
405           {"this",\r
406             {\r
407               namespaces,\r
408               s.name + genericAppendix(instantiation),\r
409               {\r
410                 {TypeModifierType::Pointer, false, -1}\r
411               }\r
412             }\r
413           });\r
414           out << f.returnType << " " <<\r
415             generateModifiers(namespacePrefix() + s.name + genericAppendix(instantiation) + "_" + f.name, f.returnType.modifiers) <<\r
416             " (" << vectorStr(f.parameters, ", ") << ");\n";\r
417         }\r
418         return;\r
419       }\r
420       out << "\n{\n";\r
421       indentation += 2;\r
422 \r
423       for (auto m : s.members)\r
424       {\r
425         indent(out);\r
426         out << m << ";\n";\r
427       }\r
428 \r
429       indent(out, -2);\r
430       out << "};\n";\r
431       \r
432       for (auto m : s.methods)\r
433       {\r
434         Function f = m;\r
435         \r
436         // add implicit this parameter\r
437         f.parameters.insert(f.parameters.begin(),\r
438           {"this",\r
439             {\r
440               namespaces,\r
441               s.name + genericAppendix(instantiation),\r
442               {\r
443                 {TypeModifierType::Pointer, false, -1}\r
444               }\r
445             }\r
446           });\r
447         out << f.returnType << " " <<\r
448           generateModifiers(namespacePrefix() + s.name + genericAppendix(instantiation) + "_" + f.name, f.returnType.modifiers) <<\r
449           " (" << vectorStr(f.parameters, ", ") << ")\n" << f.body;\r
450       }\r
451 \r
452       currentInstantiation.clear();\r
453     }\r
454   }\r
455 }\r
456 void tocProgram (std::ostream & out, const Program & p)\r
457 {\r
458   globalCtx = p.ctx;\r
459 \r
460   for (auto n : p.ctx->namespaces)\r
461   {\r
462     tocNamespace(out, n, true);\r
463   }\r
464   out << "\n\n";\r
465   for (auto s : p.ctx->structs)\r
466   {\r
467     tocStruct(out, s, true);\r
468   }\r
469   out << "\n\n";\r
470   for (auto f : p.ctx->functions)\r
471   {\r
472     tocFunction(out, f, true);\r
473   }\r
474   out << "\n\n";\r
475 \r
476   for (auto v : p.ctx->variables)\r
477   {\r
478     out << v << ";\n";\r
479   }\r
480   out << "\n\n";\r
481   for (auto n : p.ctx->namespaces)\r
482   {\r
483     tocNamespace(out, n, false);\r
484   }\r
485   out << "\n\n";\r
486   for (auto s : p.ctx->structs)\r
487   {\r
488     tocStruct(out, s, false);\r
489   }\r
490   out << "\n\n";\r
491   for (auto f : p.ctx->functions)\r
492   {\r
493     tocFunction(out, f, false);\r
494   }\r
495   out << "\n\n";\r
496 }\r
497 \r
498 \r
499 void tocNamespace  (std::ostream & out, const Namespace & n, bool stub)\r
500 {\r
501   n.ctx->parent = globalCtx;\r
502   globalCtx = n.ctx;\r
503 \r
504   namespaces.push_back(n.name);\r
505   if (!stub)\r
506   {\r
507     for (auto v : n.ctx->variables)\r
508     {\r
509       out << v << ";\n";\r
510     }\r
511     out << "\n\n";\r
512   }\r
513   for (auto n : n.ctx->namespaces)\r
514   {\r
515     tocNamespace(out, n, stub);\r
516     out << "\n\n";\r
517   }\r
518   for (auto s : n.ctx->structs)\r
519   {\r
520     tocStruct(out, s, stub);\r
521     out << "\n\n";\r
522   }\r
523   for (auto f : n.ctx->functions)\r
524   {\r
525     tocFunction(out, f, stub);\r
526     out << "\n\n";\r
527   }\r
528   namespaces.pop_back();\r
529 \r
530   globalCtx = n.ctx->parent;\r
531 }