]> gitweb.ps.run Git - toc/blob - src/toc.h
comments
[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 std::ostream & operator<< (std::ostream & out, const Variable & v)\r
97 {\r
98   out << v.type << " ";\r
99 \r
100   std::stringstream sstr;\r
101   std::string s = v.name;\r
102   \r
103   // lookup variable and change name to reflect containing namespace\r
104   auto var = findVariable(v.name, namespaces, globalCtx);\r
105   if (var.has_value())\r
106     s = vectorStr(std::get<1>(*var), "_", true) + s;\r
107 \r
108   // nest modifiers, inverted because C defines them\r
109   // the opposite direction\r
110   for (auto m = v.type.modifiers.rbegin(); m != v.type.modifiers.rend(); m++)\r
111   {\r
112     if (m->type == TypeModifierType::Pointer)\r
113     {\r
114       sstr.str(std::string());\r
115       sstr << "*(" << s << ")";\r
116       s = sstr.str();\r
117     }\r
118     else\r
119     {\r
120       sstr.str(std::string());\r
121       sstr << "(" << s << ")[";\r
122       if (m->_staticArray)\r
123         sstr << m->_arraySize;\r
124       sstr << "]";\r
125       s = sstr.str();\r
126     }\r
127   }\r
128   out << s;\r
129 \r
130   return out;\r
131 }\r
132 std::ostream & operator<< (std::ostream & out, const Body & b)\r
133 {\r
134   b.ctx->parent = globalCtx;\r
135   globalCtx = b.ctx;\r
136 \r
137   indent(out);\r
138   out << "{\n";\r
139   indentation += 2;\r
140 \r
141   for (auto v : b.ctx->variables)\r
142   {\r
143     indent(out);\r
144     out << v << ";\n";\r
145   }\r
146 \r
147   out << "\n";\r
148   \r
149   for (auto s : b.statements)\r
150   {\r
151     indent(out);\r
152     out << s << "\n";\r
153   }\r
154 \r
155   indent(out, -2);\r
156   out << "}\n";\r
157 \r
158   globalCtx = b.ctx->parent;\r
159 \r
160   return out;\r
161 }\r
162 std::ostream & operator<< (std::ostream & out, const Expr & e)\r
163 {\r
164   switch (e.type)\r
165   {\r
166   case ExprType::Func:\r
167   {\r
168     // print function call\r
169     auto f = findFunction(e._func.functionName, e._func.namespacePrefixes, globalCtx);\r
170 \r
171     if (std::get<0>(*f).defined)\r
172       out << vectorStr(std::get<1>(*f), "_", true);\r
173 \r
174     out << e._func.functionName;\r
175     if (!e._func.genericInstantiation.empty())\r
176       out << genericAppendix(e._func.genericInstantiation);\r
177     out <<"(" << vectorStr(e._func.arguments, ", ") << ")"; break;\r
178   }\r
179   case ExprType::Method:\r
180   {\r
181     // get TypeInfo on the Expression that the method is called on\r
182     // then print method call\r
183     TypeInfo ti = typeExpr(globalCtx, *e._method.expr);\r
184     out <<\r
185       vectorStr(ti.type.namespacePrefixes, "_", true) <<\r
186       ti.type.name << genericAppendix(ti.type.genericInstantiation) << "_" << e._method.methodName;\r
187     if (!e._method.genericInstantiation.empty())\r
188       out << genericAppendix(e._method.genericInstantiation);\r
189     out << "(";\r
190     if (e._method.expr->type == ExprType::Identifier)\r
191       out << "&";\r
192     out << *e._method.expr << (e._method.arguments.empty() ? "" : ", ") <<\r
193     vectorStr(e._method.arguments, ", ") << ")"; break;\r
194   }\r
195   case ExprType::Lit:\r
196     /**/ if (e._lit.type == LitType::Int) out << e._lit._int;\r
197     else if (e._lit.type == LitType::Decimal) out << e._lit._decimal;\r
198     else if (e._lit.type == LitType::String) out << e._lit._string;\r
199     else if (e._lit.type == LitType::Bool) out << e._lit._bool;\r
200     break;\r
201   case ExprType::Paren:\r
202     out << "(" << *e._paren.expr << ")"; break;\r
203   case ExprType::Dot:\r
204     out << *e._dot.expr << (e._dot.isPointer ? "->" : ".") << e._dot.identifier; break;\r
205   case ExprType::PrefixOp:\r
206     out << PrefixOperatorTypeStrings[(int)e._prefixOp.type] << *e._prefixOp.expr; break;\r
207   case ExprType::PostfixOp:\r
208     out << *e._postfixOp.expr << PostfixOperatorTypeStrings[(int)e._postfixOp.type]; break;\r
209   case ExprType::BinaryOp:\r
210     out << *e._binaryOp.lexpr <<\r
211     " " << BinaryOperatorTypeStrings[(int)e._binaryOp.type] << " " <<\r
212     *e._binaryOp.rexpr; break;\r
213   case ExprType::TernaryOp:\r
214     out << *e._ternaryOp.lexpr <<\r
215       " ? " << *e._ternaryOp.rexprTrue <<\r
216       " : " << *e._ternaryOp.rexprFalse; break;\r
217   case ExprType::Bracket:\r
218     out << *e._brackets.lexpr << "[" << *e._brackets.rexpr << "]"; break;\r
219   case ExprType::Identifier:\r
220     // try variable lookup\r
221     auto v = findVariable(e._identifier.identifier, e._identifier.namespacePrefixes, globalCtx);\r
222     if (v.has_value())\r
223       out << vectorStr(std::get<1>(*v), "_", true);\r
224     else\r
225       out << vectorStr(e._identifier.namespacePrefixes, "_", true);\r
226 \r
227     out << e._identifier.identifier; break;\r
228   }\r
229 \r
230   return out;\r
231 }\r
232 std::ostream & operator<< (std::ostream & out, const Stmt & s)\r
233 {\r
234   switch (s.type)\r
235   {\r
236   case StmtType::If:\r
237     out << "if (" << s._if.condition << ")\n" << s._if.body; break;\r
238   case StmtType::Switch:\r
239     out << "switch (" << s._switch.ident << ")\n{\n";\r
240     for (auto c : s._switch.cases)\r
241     {\r
242       indent(out, 2);\r
243       out << "case " << *c.expr << ": " << c.body << "break;";\r
244     }\r
245     indent(out, -2);\r
246     out << "}\n";\r
247     break;\r
248   case StmtType::For:\r
249     out << "for (" <<\r
250       s._for.init << "; " <<\r
251       *s._for.condition << "; " <<\r
252       *s._for.action <<\r
253       ")\n" << s._for.body; break;\r
254   case StmtType::While:\r
255     out << "while (" << s._while.condition << ")\n" << s._while.body; break;\r
256   case StmtType::Assign:\r
257     out << s._assign.lexpr << " = " << s._assign.rexpr << ";"; break;\r
258   case StmtType::Return:\r
259     out << "return " << s._return.expr << ";"; break;\r
260   case StmtType::Expr:\r
261     out << s._expr << ";"; break;\r
262   }\r
263 \r
264   return out;\r
265 }\r
266 \r
267 \r
268 void tocFunction (std::ostream & out, const Function & f, bool stub)\r
269 {\r
270   // for a function that is not defined, only the stub can be printed\r
271   if (!f.defined && !stub) return;\r
272 \r
273   // regular function\r
274   if (f.genericTypeNames.empty())\r
275   {\r
276     out << f.returnType << " " << namespacePrefix() << f.name << " (" << vectorStr(f.parameters, ", ") << ")";\r
277 \r
278     if (stub)\r
279     {\r
280       out << ";\n";\r
281     }\r
282     else\r
283     {\r
284       out << "\n" << f.body;\r
285     }\r
286   }\r
287   // generic function\r
288   else\r
289   {\r
290     // print one instance per instantiation\r
291     for (auto instantiation : f.genericInstantiations)\r
292     {\r
293       // set global type mapping\r
294       for (int i = 0; i < f.genericTypeNames.size(); i++)\r
295       {\r
296         currentInstantiation[f.genericTypeNames[i]] = instantiation[i];\r
297       }\r
298 \r
299       out << f.returnType << " " << namespacePrefix() << f.name << genericAppendix(instantiation) << " (" << vectorStr(f.parameters, ", ") << ")";\r
300 \r
301       if (stub)\r
302       {\r
303         out << ";\n";\r
304       }\r
305       else\r
306       {\r
307         out << "\n" << f.body;\r
308       }\r
309 \r
310       currentInstantiation.clear();\r
311     }\r
312   }\r
313 }\r
314 void tocStruct (std::ostream & out, const Struct & s, bool stub)\r
315 {\r
316   // regular struct\r
317   if (s.genericTypeNames.empty())\r
318   {\r
319     out << "struct " << namespacePrefix() << s.name;\r
320     if (stub)\r
321     {\r
322       out << ";\n";\r
323       for (auto m : s.methods)\r
324       {\r
325         Function f = m;\r
326 \r
327         // add implicit this parameter\r
328         f.parameters.insert(f.parameters.begin(),\r
329         {"this",\r
330           {\r
331             namespaces,\r
332             s.name,\r
333             {\r
334               {TypeModifierType::Pointer, false, -1}\r
335             }\r
336           }\r
337         });\r
338         out << f.returnType << " " <<\r
339           namespacePrefix() << s.name << "_" << f.name <<\r
340           " (" << vectorStr(f.parameters, ", ") << ");\n";\r
341       }\r
342       return;\r
343     }\r
344     out << "\n{\n";\r
345     indentation += 2;\r
346 \r
347     for (auto m : s.members)\r
348     {\r
349       indent(out);\r
350       out << m << ";\n";\r
351     }\r
352 \r
353     indent(out, -2);\r
354     out << "};\n";\r
355     \r
356     for (auto m : s.methods)\r
357     {\r
358       Function f = m;\r
359       \r
360       // add implicit this parameter\r
361       f.parameters.insert(f.parameters.begin(),\r
362         {"this",\r
363           {\r
364             namespaces,\r
365             s.name,\r
366             {\r
367               {TypeModifierType::Pointer, false, -1}\r
368             }\r
369           }\r
370         });\r
371       out << f.returnType << " " <<\r
372       namespacePrefix() << s.name << "_" << f.name <<\r
373       " (" << vectorStr(f.parameters, ", ") << ")\n" << f.body;\r
374     }\r
375   }\r
376   // generic struct\r
377   else\r
378   {\r
379     for (auto instantiation : s.genericInstantiations)\r
380     {\r
381       for (int i = 0; i < s.genericTypeNames.size(); i++)\r
382       {\r
383         currentInstantiation[s.genericTypeNames[i]] = instantiation[i];\r
384       }\r
385 \r
386       out << "struct " << namespacePrefix() << s.name << genericAppendix(instantiation);\r
387       if (stub)\r
388       {\r
389         out << ";\n";\r
390         for (auto m : s.methods)\r
391         {\r
392           Function f = m;\r
393 \r
394         // add implicit this parameter\r
395           f.parameters.insert(f.parameters.begin(),\r
396           {"this",\r
397             {\r
398               namespaces,\r
399               s.name + genericAppendix(instantiation),\r
400               {\r
401                 {TypeModifierType::Pointer, false, -1}\r
402               }\r
403             }\r
404           });\r
405           out << f.returnType << " " <<\r
406             namespacePrefix() << s.name << genericAppendix(instantiation) << "_" << f.name <<\r
407             " (" << vectorStr(f.parameters, ", ") << ");\n";\r
408         }\r
409         return;\r
410       }\r
411       out << "\n{\n";\r
412       indentation += 2;\r
413 \r
414       for (auto m : s.members)\r
415       {\r
416         indent(out);\r
417         out << m << ";\n";\r
418       }\r
419 \r
420       indent(out, -2);\r
421       out << "};\n";\r
422       \r
423       for (auto m : s.methods)\r
424       {\r
425         Function f = m;\r
426         \r
427         // add implicit this parameter\r
428         f.parameters.insert(f.parameters.begin(),\r
429           {"this",\r
430             {\r
431               namespaces,\r
432               s.name + genericAppendix(instantiation),\r
433               {\r
434                 {TypeModifierType::Pointer, false, -1}\r
435               }\r
436             }\r
437           });\r
438         out << f.returnType << " " <<\r
439         namespacePrefix() << s.name << genericAppendix(instantiation) << "_" << f.name <<\r
440         " (" << vectorStr(f.parameters, ", ") << ")\n" << f.body;\r
441       }\r
442 \r
443       currentInstantiation.clear();\r
444     }\r
445   }\r
446 }\r
447 void tocProgram (std::ostream & out, const Program & p)\r
448 {\r
449   globalCtx = p.ctx;\r
450 \r
451   for (auto n : p.ctx->namespaces)\r
452   {\r
453     tocNamespace(out, n, true);\r
454   }\r
455   out << "\n\n";\r
456   for (auto s : p.ctx->structs)\r
457   {\r
458     tocStruct(out, s, true);\r
459   }\r
460   out << "\n\n";\r
461   for (auto f : p.ctx->functions)\r
462   {\r
463     tocFunction(out, f, true);\r
464   }\r
465   out << "\n\n";\r
466 \r
467   for (auto v : p.ctx->variables)\r
468   {\r
469     out << v << ";\n";\r
470   }\r
471   out << "\n\n";\r
472   for (auto n : p.ctx->namespaces)\r
473   {\r
474     tocNamespace(out, n, false);\r
475   }\r
476   out << "\n\n";\r
477   for (auto s : p.ctx->structs)\r
478   {\r
479     tocStruct(out, s, false);\r
480   }\r
481   out << "\n\n";\r
482   for (auto f : p.ctx->functions)\r
483   {\r
484     tocFunction(out, f, false);\r
485   }\r
486   out << "\n\n";\r
487 }\r
488 \r
489 \r
490 void tocNamespace  (std::ostream & out, const Namespace & n, bool stub)\r
491 {\r
492   n.ctx->parent = globalCtx;\r
493   globalCtx = n.ctx;\r
494 \r
495   namespaces.push_back(n.name);\r
496   if (!stub)\r
497   {\r
498     for (auto v : n.ctx->variables)\r
499     {\r
500       out << v << ";\n";\r
501     }\r
502     out << "\n\n";\r
503   }\r
504   for (auto n : n.ctx->namespaces)\r
505   {\r
506     tocNamespace(out, n, stub);\r
507     out << "\n\n";\r
508   }\r
509   for (auto s : n.ctx->structs)\r
510   {\r
511     tocStruct(out, s, stub);\r
512     out << "\n\n";\r
513   }\r
514   for (auto f : n.ctx->functions)\r
515   {\r
516     tocFunction(out, f, stub);\r
517     out << "\n\n";\r
518   }\r
519   namespaces.pop_back();\r
520 \r
521   globalCtx = n.ctx->parent;\r
522 }