1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity average)
4 module dil.translator.PyTreeEmitter;
5 
6 import dil.ast.Visitor,
7        dil.ast.Node,
8        dil.ast.Declarations,
9        dil.ast.Statements,
10        dil.ast.Expressions,
11        dil.ast.Parameters,
12        dil.ast.Types;
13 import dil.semantic.Module;
14 import dil.lexer.Funcs;
15 import dil.Time,
16        dil.String;
17 import common;
18 
19 /// Replaces \ with \\ and " with \".
20 cstring escapeDblQuotes(cstring text)
21 {
22   char[] result;
23   auto p = text.ptr;
24   auto end = p + text.length;
25   auto prev = p;
26   string esc;
27   for (; p < end; p++)
28     switch (*p)
29     {
30     case '"':  esc = `\"`;  goto case_common;
31     case '\\': esc = `\\`;  goto case_common;
32     case_common:
33       if (prev < p) // Copy previous piece.
34         result ~= slice(prev, p);
35       result ~= esc;
36       prev = p + 1;
37     default:
38     }
39   if (prev == text.ptr)
40     return text; // Nothing to escape.
41   if (prev < end) // Copy last piece.
42     result ~= slice(prev, p);
43   return result;
44 }
45 
46 /// Returns the number of characters if ws contains only ' ' chars,
47 /// otherwise returns ws in single quotes.
48 cstring quoteOrCountWhitespace(cstring ws)
49 {
50   foreach (c; ws)
51     if (c != ' ') return "'"~ws~"'";
52   return itoa(ws.length);
53 }
54 
55 /// Enumeration of flags that indicate what's contained in a string.
56 enum Flags
57 {
58   None = 0,      /// No special characters.
59   Backslash = 1, /// \
60   DblQuote = 2,  /// "
61   SglQuote = 4,  /// '
62   Newline = 8,   /// \n, \r, \u2028, \u2029
63   SglAndDbl = DblQuote | SglQuote, /// " and '
64 }
65 
66 /// Searches for backslashes, quotes and newlines in a string.
67 /// Returns: A set of flags.
68 Flags analyzeString(cstring str)
69 {
70   Flags flags;
71   foreach (c; str)
72     if (c == '\\') flags |= Flags.Backslash;
73     else if (c == '"') flags |= Flags.DblQuote;
74     else if (c == '\'') flags |= Flags.SglQuote;
75     else if (c == '\n' || c == '\r' || c == '\u2028' || c == '\u2029')
76       flags |= Flags.Newline;
77   return flags;
78 }
79 
80 char[] writeTokenList(Token* first_token, ref uint[Token*] indexMap)
81 {
82   char[] result = "token_list = (\n".dup;
83   char[] line;
84   class Tuple
85   {
86     uint_t count;
87     cstring str;
88     TOK kind;
89     alias pos = count;
90     this(uint_t count, cstring str, TOK kind)
91     {
92       this.count = count;
93       this.str = str;
94       this.kind = kind;
95     }
96     override int opCmp(Object o)
97     {
98       return count > (cast(Tuple)cast(void*)o).count;
99     }
100   }
101   // Gather all identifiers, comments, strings and numbers in this map.
102   Tuple[hash_t] map;
103   for (auto token = first_token; token.kind; token++)
104     if (token.kind.In(TOK.Identifier, TOK.Comment, TOK.String, TOK.Character,
105         TOK.Int32, TOK.Int64, TOK.UInt32, TOK.UInt64,
106         TOK.Float32, TOK.Float64, TOK.Float80,
107         TOK.IFloat32, TOK.IFloat64, TOK.IFloat80))
108     {
109       auto hash = hashOf(token.text);
110       auto p = hash in map;
111       if (p) p.count += 1;
112       else map[hash] = new Tuple(1, token.text, token.kind);
113     }
114   // Create a sorted list. We want the strings that appear the most
115   // in the source text to be at the beginning of the list.
116   // That way less space is taken up by index numbers in the emitted text.
117   // NB.: First tests showed, that this only saves about 3% of characters.
118   auto list = map.values.sort;
119   result ~= "(";
120   // Print the sorted string list.
121   foreach (i, item; list)
122   { // By analyzing the string we can determine the optimal
123     // way to represent strings in the Python source code.
124     auto str = item.str;
125     Flags flags = analyzeString(str);
126     string quote = `"`; // Default to double quotemarks.
127 
128     if (flags & Flags.Backslash ||
129         (flags & Flags.SglAndDbl) == Flags.SglAndDbl)
130     { // Use triple quotes for multiline strings.
131       quote = (flags & Flags.Newline) ? `"""` : `"`;
132       str = escapeDblQuotes(str);
133     }
134     else if (flags & Flags.Newline)
135       quote = (flags & Flags.DblQuote) ? "'''" : `"""`;
136     else if (flags & Flags.DblQuote)
137       quote = "'";
138     //else if (flags & Flags.SglQuote)
139     //  quote = `"`;
140 
141     line ~= quote;
142     line ~= str;
143     line ~= quote;
144     line ~= ',';
145 
146     if (line.length > 100)
147       (result ~= line ~ "\n"), line = null;
148     item.pos = i; /// Update position.
149   }
150   if (line.length)
151     result ~= line;
152   if (result[$-1] == '\n')
153     result.length--;
154   result ~= "),\n[\n";
155   line = null;
156 
157   // Print the list of all tokens, encoded with IDs and indices.
158   uint index;
159   for (auto token = first_token; token.kind; index++, token++)
160   {
161     indexMap[token] = index;
162     line ~= '(' ~ itoa(token.kind) ~ ',';
163     line ~= (token.ws) ? quoteOrCountWhitespace(token.wsChars) : `0`;
164     line ~= ',';
165     switch (token.kind)
166     {
167     case TOK.Identifier, TOK.Comment, TOK.String, TOK.Character,
168          TOK.Int32, TOK.Int64, TOK.UInt32, TOK.UInt64,
169          TOK.Float32, TOK.Float64, TOK.Float80,
170          TOK.IFloat32, TOK.IFloat64, TOK.IFloat80:
171       line ~= itoa(map[hashOf(token.text)].pos);
172       break;
173     case TOK.Shebang:
174       line ~= '"' ~ escapeDblQuotes(token.text) ~ '"';
175       break;
176     case TOK.HashLine:
177       // The text to be inserted into formatStr.
178       void printWS(cchar* start, cchar* end) {
179         line ~= '"' ~ start[0 .. end - start] ~ `",`;
180       }
181       auto num = token.hlval.lineNum;
182       line ~= `"#line"`;
183       if (num)
184       { // Print whitespace between #line and number.
185         printWS(token.start, num.start); // Prints "#line" as well.
186         line ~= '"' ~ num.text ~ '"'; // Print the number.
187         if (auto filespec = token.hlval.filespec)
188         { // Print whitespace between number and filespec.
189           printWS(num.end, filespec.start);
190           line ~= '"' ~ escapeDblQuotes(filespec.text) ~ '"';
191         }
192       }
193       break;
194     case TOK.Illegal:
195       line ~= '"' ~ escapeDblQuotes(token.text) ~ '"';
196       break;
197     default:
198       line = line[0..$-1];
199     }
200     line ~= "),";
201     if (line.length > 100)
202       (result ~= line ~ "\n"), line = null;
203   }
204   if (line.length)
205     result ~= line;
206   return result ~ "\n])\n";
207 }
208 
209 /// Emits a D parse tree as Python code.
210 class PyTreeEmitter : Visitor2
211 {
212   char[] text; /// Contains the code.
213   char[] line; /// Line buffer.
214   Module modul; /// The module to be processed.
215   uint[Token*] index; /// Map tokens to index numbers.
216 
217   /// Constructs a PyTreeEmitter object.
218   this(Module modul)
219   {
220     this.modul = modul;
221   }
222 
223   /// Entry method.
224   char[] emit()
225   {
226     string d_version = "1.0";
227     version(D2)
228       d_version = "2.0";
229     text = Format("# -*- coding: utf-8 -*-\n"
230                   "from __future__ import unicode_literals\n"
231                   "import dil.token\n"
232                   "from dil.module import Module\n"
233                   "from dil.nodes import *\n\n"
234                   "generated_by = 'dil'\n"
235                   "format_version = '1.0'\n"
236                   "d_version= '{}'\n"
237                   "date = '{}'\n\n",
238                   d_version, Time.now());
239 
240     text ~= writeTokenList(modul.firstToken, index);
241     text ~= "t = tokens = dil.token.create_tokens(token_list)\n\n";
242     text ~= "def p(beg,end):\n"
243             "  return (tokens[beg], tokens[beg+end])\n"
244             /+"def tl(*args):\n"
245             "  return [tokens[i] for i in args]\n"
246             "  #return map(tokens.__getitem__, args)\n"+/
247             "n = None\n\n"
248             /+"def N(id, *args):\n"+/
249             /+"  return NodeTable[id](*args)\n\n"+/;
250     text ~= `module = Module(tokens=tokens, fqn="` ~ modul.getFQN() ~
251             `",ext="` ~ modul.fileExtension() ~ `",root=`"\n";
252 
253     visitD(modul.root);
254     if (line.length)
255       text ~= line ~ "\n";
256     text ~= ")\n";
257     return text;
258   }
259 
260 
261   /// Returns the index number of a token as a string.
262   char[] indexOf(Token* token)
263   {
264     return "t["~itoa(index[token])~"]";
265   }
266 
267   void write(cstring str)
268   {
269     line ~= str;
270     if (line.length > 100)
271       (this.text ~= line ~ "\n"), line = null;
272   }
273 
274   /// Writes the list of nodes separated by commas.
275   void write(Node[] nodes)
276   {
277     write("(");
278     if (nodes.length)
279     {
280       visitN(nodes[0]);
281       foreach (n; nodes[1..$])
282         write(","), visitN(n);
283       if (nodes.length == 1)
284         write(","); // Trailing comma for single element tuples.
285     }
286     write(")");
287   }
288 
289   void writeNodes(T)(T nodes)
290   {
291     write(cast(Node[])nodes);
292   }
293 
294   void begin(Node n)
295   {
296     write("N"~itoa(n.kind)~"(");
297   }
298 
299   void end(Node n, bool writeComma = true)
300   {
301     assert(n !is null && n.begin !is null && n.end !is null);
302     auto i1 = index[n.begin], i2 = index[n.end];
303     assert(i1 <= i2,
304       Format("ops, Parser or AST buggy? {}@{},i1={},i2={}",
305         NodeClassNames[n.kind],
306         n.begin.getRealLocation(modul.filePath()).str(), i1, i2));
307     write((writeComma ? ",":"") ~ "p("~itoa(i1)~","~itoa(i2-i1)~"))");
308   }
309 
310 override
311 {
312   void visit(CompoundDecl d)
313   {
314     begin(d);
315     writeNodes(d.decls);
316     end(d);
317   }
318 
319   void visit(IllegalDecl)
320   { assert(0); }
321 
322   void visit(EmptyDecl d)
323   {
324     begin(d);
325     end(d, false);
326   }
327 
328   void visit(ModuleDecl d)
329   {
330     begin(d);
331     d.type ? write(indexOf(d.type)) : write("n");
332     write(",");
333     write(indexOf(d.name)~",");
334     write("(");
335     foreach (tok; d.packages)
336       write(indexOf(tok)~",");
337     write(")");
338     end(d);
339   }
340 
341   void visit(ImportDecl d)
342   {
343     begin(d);
344     write("(");
345     foreach (moduleFQN; d.moduleFQNs)
346     {
347       write("(");
348       foreach (tok; moduleFQN)
349         write(indexOf(tok)~",");
350       write("),");
351     }
352     write("),(");
353     foreach (tok; d.moduleAliases)
354       tok ? write(indexOf(tok)~",") : write("n,");
355     write("),(");
356     foreach (tok; d.bindNames)
357       write(indexOf(tok)~",");
358     write("),(");
359     foreach (tok; d.bindAliases)
360       tok ? write(indexOf(tok)~",") : write("n,");
361     write(")");
362     end(d);
363   }
364 
365   void visit(AliasThisDecl d)
366   {
367     begin(d);
368     write(indexOf(d.name));
369     end(d);
370   }
371 
372   void visit(AliasDecl d)
373   {
374     begin(d);
375     visitD(d.decl);
376     end(d);
377   }
378 
379   void visit(TypedefDecl d)
380   {
381     begin(d);
382     visitD(d.decl);
383     end(d);
384   }
385 
386   void visit(EnumDecl d)
387   {
388     begin(d);
389     write(indexOf(d.name));
390     write(",");
391     d.baseType ? visitT(d.baseType) : write("n");
392     write(",");
393     writeNodes(d.members);
394     end(d);
395   }
396 
397   void visit(EnumMemberDecl d)
398   {
399     begin(d);
400     d.type ? visitT(d.type) : write("n");
401     write(",");
402     write(indexOf(d.name));
403     write(",");
404     d.value ? visitE(d.value) : write("n");
405     end(d);
406   }
407 
408   void visit(ClassDecl d)
409   {
410     begin(d);
411     write(indexOf(d.name));
412     write(",");
413     writeNodes(d.bases);
414     write(",");
415     d.decls ? visitD(d.decls) : write("n");
416     end(d);
417   }
418 
419   void visit(InterfaceDecl d)
420   {
421     begin(d);
422     write(indexOf(d.name));
423     write(",");
424     writeNodes(d.bases);
425     write(",");
426     d.decls ? visitD(d.decls) : write("n");
427     end(d);
428   }
429 
430   void visit(StructDecl d)
431   {
432     begin(d);
433     write(indexOf(d.name));
434     write(",");
435     d.decls ? visitD(d.decls) : write("n");
436     end(d);
437   }
438 
439   void visit(UnionDecl d)
440   {
441     begin(d);
442     write(indexOf(d.name));
443     write(",");
444     d.decls ? visitD(d.decls) : write("n");
445     end(d);
446   }
447 
448   void visit(ConstructorDecl d)
449   {
450     begin(d);
451     visitN(d.params);
452     write(",");
453     visitS(d.funcBody);
454     end(d);
455   }
456 
457   void visit(StaticCtorDecl d)
458   {
459     begin(d);
460     visitS(d.funcBody);
461     end(d);
462   }
463 
464   void visit(DestructorDecl d)
465   {
466     begin(d);
467     visitS(d.funcBody);
468     end(d);
469   }
470 
471   void visit(StaticDtorDecl d)
472   {
473     begin(d);
474     visitS(d.funcBody);
475     end(d);
476   }
477 
478   void visit(FunctionDecl d)
479   {
480     begin(d);
481     d.returnType ? visitT(d.returnType) : write("n");
482     write(",");
483     write(indexOf(d.name));
484     write(",");
485     visitN(d.params);
486     write(",");
487     visitS(d.funcBody);
488     end(d);
489   }
490 
491   void visit(VariablesDecl d)
492   {
493     begin(d);
494     // Type
495     if (d.type !is null)
496       visitT(d.type);
497     else
498       write("-1");
499     // Variable names.
500     write(",(");
501     foreach (name; d.names)
502       write(indexOf(name) ~ ",");
503     write("),(");
504     foreach (init; d.inits) {
505       if (init) visitE(init);
506       else write("-1");
507       write(",");
508     }
509     write(")");
510     end(d);
511   }
512 
513   void visit(InvariantDecl d)
514   {
515     begin(d);
516     visitS(d.funcBody);
517     end(d);
518   }
519 
520   void visit(UnittestDecl d)
521   {
522     begin(d);
523     visitS(d.funcBody);
524     end(d);
525   }
526 
527   void visit(DebugDecl d)
528   {
529     begin(d);
530     d.spec ? write(indexOf(d.spec)) : write("n");
531     write(",");
532     d.cond ? write(indexOf(d.cond)) : write("n");
533     write(",");
534     d.decls ? visitD(d.decls) : write("n");
535     write(",");
536     d.elseDecls ? visitD(d.elseDecls) : write("n");
537     end(d);
538   }
539 
540   void visit(VersionDecl d)
541   {
542     begin(d);
543     d.spec ? write(indexOf(d.spec)) : write("n");
544     write(",");
545     d.cond ? write(indexOf(d.cond)) : write("n");
546     write(",");
547     d.decls ? visitD(d.decls) : write("n");
548     write(",");
549     d.elseDecls ? visitD(d.elseDecls) : write("n");
550     end(d);
551   }
552 
553   void visit(TemplateDecl d)
554   {
555     begin(d);
556     write(indexOf(d.name));
557     write(",");
558     visitN(d.tparams);
559     write(",");
560     d.constraint ? visitE(d.constraint) : write("n");
561     write(",");
562     visitD(d.decls);
563     end(d);
564   }
565 
566   void visit(NewDecl d)
567   {
568     begin(d);
569     visitN(d.params);
570     write(",");
571     visitS(d.funcBody);
572     end(d);
573   }
574 
575   void visit(DeleteDecl d)
576   {
577     begin(d);
578     visitN(d.params);
579     write(",");
580     visitS(d.funcBody);
581     end(d);
582   }
583 
584   // Attributes:
585 
586   void visit(ProtectionDecl d)
587   {
588     begin(d);
589     visitD(d.decls);
590     end(d);
591   }
592 
593   void visit(StorageClassDecl d)
594   {
595     begin(d);
596     visitD(d.decls);
597     end(d);
598   }
599 
600   void visit(LinkageDecl d)
601   {
602     begin(d);
603     visitD(d.decls);
604     end(d);
605   }
606 
607   void visit(AlignDecl d)
608   {
609     begin(d);
610     d.sizetok ? write(indexOf(d.sizetok)) : write("n");
611     write(",");
612     visitD(d.decls);
613     end(d);
614   }
615 
616   void visit(StaticAssertDecl d)
617   {
618     begin(d);
619     visitE(d.condition);
620     write(",");
621     d.message ? visitE(d.message) : write("n");
622     end(d);
623   }
624 
625   void visit(StaticIfDecl d)
626   {
627     begin(d);
628     visitE(d.condition);
629     write(",");
630     visitD(d.ifDecls);
631     write(",");
632     d.elseDecls ? visitD(d.elseDecls) : write("n");
633     end(d);
634   }
635 
636   void visit(MixinDecl d)
637   {
638     begin(d);
639     d.templateExpr ? visitE(d.templateExpr) : write("n");
640     write(",");
641     d.argument ? visitE(d.argument) : write("n");
642     write(",");
643     d.mixinIdent ? write(indexOf(d.mixinIdent)) : write("n");
644     end(d);
645   }
646 
647   void visit(PragmaDecl d)
648   {
649     begin(d);
650     write(indexOf(d.name));
651     write(",");
652     writeNodes(d.args);
653     write(",");
654     visitD(d.decls);
655     end(d);
656   }
657 
658 } // override
659 
660   /+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
661   |                                 Statements                                |
662    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+/
663 
664 override
665 {
666 
667   void visit(CompoundStmt s)
668   {
669     begin(s);
670     writeNodes(s.stmnts);
671     end(s);
672   }
673 
674   void visit(IllegalStmt)
675   { assert(0, "interpreting invalid AST"); }
676 
677   void visit(EmptyStmt s)
678   {
679     begin(s);
680     end(s, false);
681   }
682 
683   void visit(FuncBodyStmt s)
684   {
685     begin(s);
686     s.funcBody ? visitS(s.funcBody) : write("n");
687     write(",");
688     s.inBody ? visitS(s.inBody) : write("n");
689     write(",");
690     s.outBody ? visitS(s.outBody) : write("n");
691     write(",");
692     s.outIdent ? write(indexOf(s.outIdent)) : write("n");
693     end(s);
694   }
695 
696   void visit(ScopeStmt s)
697   {
698     begin(s);
699     visitS(s.stmnt);
700     end(s);
701   }
702 
703   void visit(LabeledStmt s)
704   {
705     begin(s);
706     write(indexOf(s.label));
707     write(",");
708     visitS(s.stmnt);
709     end(s);
710   }
711 
712   void visit(ExpressionStmt s)
713   {
714     begin(s);
715     visitE(s.expr);
716     end(s);
717   }
718 
719   void visit(DeclarationStmt s)
720   {
721     begin(s);
722     visitD(s.decl);
723     end(s);
724   }
725 
726   void visit(IfStmt s)
727   {
728     begin(s);
729     s.variable ? visitS(s.variable) : write("n");
730     write(",");
731     s.condition ? visitE(s.condition) : write("n");
732     write(",");
733     visitS(s.ifBody);
734     write(",");
735     s.elseBody ? visitS(s.elseBody) : write("n");
736     end(s);
737   }
738 
739   void visit(WhileStmt s)
740   {
741     begin(s);
742     visitE(s.condition);
743     write(",");
744     visitS(s.whileBody);
745     end(s);
746   }
747 
748   void visit(DoWhileStmt s)
749   {
750     begin(s);
751     visitS(s.doBody);
752     write(",");
753     visitE(s.condition);
754     end(s);
755   }
756 
757   void visit(ForStmt s)
758   {
759     begin(s);
760     s.init ? visitS(s.init) : write("n");
761     write(",");
762     s.condition ? visitE(s.condition) : write("n");
763     write(",");
764     s.increment ? visitE(s.increment) : write("n");
765     write(",");
766     s.forBody ? visitS(s.forBody) : write("n");
767     end(s);
768   }
769 
770   void visit(ForeachStmt s)
771   {
772     begin(s);
773     visitN(s.params);
774     write(",");
775     visitE(s.aggregate);
776     write(",");
777     visitS(s.forBody);
778     end(s);
779   }
780 
781   void visit(SwitchStmt s)
782   {
783     begin(s);
784     visitE(s.condition);
785     write(",");
786     visitS(s.switchBody);
787     end(s);
788   }
789 
790   void visit(CaseStmt s)
791   {
792     begin(s);
793     writeNodes(s.values);
794     write(",");
795     visitS(s.caseBody);
796     end(s);
797   }
798 
799   void visit(DefaultStmt s)
800   {
801     begin(s);
802     visitS(s.defaultBody);
803     end(s);
804   }
805 
806   void visit(ContinueStmt s)
807   {
808     begin(s);
809     s.label ? write(indexOf(s.label)) : write("n");
810     end(s);
811   }
812 
813   void visit(BreakStmt s)
814   {
815     begin(s);
816     s.label ? write(indexOf(s.label)) : write("n");
817     end(s);
818   }
819 
820   void visit(ReturnStmt s)
821   {
822     begin(s);
823     s.expr ? visitE(s.expr) : write("n");
824     end(s);
825   }
826 
827   void visit(GotoStmt s)
828   {
829     begin(s);
830     s.ident ? write(indexOf(s.ident)) : write("n");
831     write(",");
832     s.expr ? visitE(s.expr) : write("n");
833     end(s);
834   }
835 
836   void visit(WithStmt s)
837   {
838     begin(s);
839     visitE(s.expr);
840     write(",");
841     visitS(s.withBody);
842     end(s);
843   }
844 
845   void visit(SynchronizedStmt s)
846   {
847     begin(s);
848     s.expr ? visitE(s.expr) : write("n");
849     write(",");
850     visitS(s.syncBody);
851     end(s);
852   }
853 
854   void visit(TryStmt s)
855   {
856     begin(s);
857     visitS(s.tryBody);
858     write(",");
859     writeNodes(s.catchBodies);
860     write(",");
861     s.finallyBody ? visitS(s.finallyBody) : write("n");
862     end(s);
863   }
864 
865   void visit(CatchStmt s)
866   {
867     begin(s);
868     s.param ? visitN(s.param) : write("n");
869     write(",");
870     visitS(s.catchBody);
871     end(s);
872   }
873 
874   void visit(FinallyStmt s)
875   {
876     begin(s);
877     visitS(s.finallyBody);
878     end(s);
879   }
880 
881   void visit(ScopeGuardStmt s)
882   {
883     begin(s);
884     write(indexOf(s.condition));
885     write(",");
886     visitS(s.scopeBody);
887     end(s);
888   }
889 
890   void visit(ThrowStmt s)
891   {
892     begin(s);
893     visitE(s.expr);
894     end(s);
895   }
896 
897   void visit(VolatileStmt s)
898   {
899     begin(s);
900     s.volatileBody ? visitS(s.volatileBody) : write("n");
901     end(s);
902   }
903 
904   void visit(AsmBlockStmt s)
905   {
906     begin(s);
907     visitS(s.statements);
908     end(s);
909   }
910 
911   void visit(AsmStmt s)
912   {
913     begin(s);
914     s.opcode ? write(indexOf(s.opcode)) : write("n");
915     write(",");
916     writeNodes(s.operands);
917     end(s);
918   }
919 
920   void visit(AsmAlignStmt s)
921   {
922     begin(s);
923     write(indexOf(s.numtok));
924     end(s);
925   }
926 
927   void visit(IllegalAsmStmt)
928   { assert(0, "invalid AST"); }
929 
930   void visit(PragmaStmt s)
931   {
932     begin(s);
933     s.name ? write(indexOf(s.name)) : write("n");
934     write(",");
935     writeNodes(s.args);
936     write(",");
937     visitS(s.pragmaBody);
938     end(s);
939   }
940 
941   void visit(MixinStmt s)
942   {
943     begin(s);
944     visitE(s.templateExpr);
945     write(",");
946     s.mixinIdent ? write(indexOf(s.mixinIdent)) : write("n");
947     end(s);
948   }
949 
950   void visit(StaticIfStmt s)
951   {
952     begin(s);
953     visitE(s.condition);
954     write(",");
955     visitS(s.ifBody);
956     write(",");
957     s.elseBody ? visitS(s.elseBody) : write("n");
958     end(s);
959   }
960 
961   void visit(StaticAssertStmt s)
962   {
963     begin(s);
964     visitE(s.condition);
965     write(",");
966     s.message ? visitE(s.message) : write("n");
967     end(s);
968   }
969 
970   void visit(DebugStmt s)
971   {
972     begin(s);
973     visitS(s.mainBody);
974     write(",");
975     s.elseBody ? visitS(s.elseBody) : write("n");
976     end(s);
977   }
978 
979   void visit(VersionStmt s)
980   {
981     begin(s);
982     visitS(s.mainBody);
983     write(",");
984     s.elseBody ? visitS(s.elseBody) : write("n");
985     end(s);
986   }
987 
988 } // override
989 
990   /+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
991   |                                Expressions                                |
992    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+/
993 
994   enum binaryExpr = `
995     begin(e);
996     visitE(e.lhs);
997     write(",");
998     visitE(e.rhs);
999     write(",");
1000     write(indexOf(e.optok));
1001     end(e);`;
1002 
1003   enum unaryExpr = `
1004     begin(e);
1005     visitE(e.una);
1006     end(e);`;
1007 
1008 override
1009 {
1010   void visit(IllegalExpr)
1011   { assert(0, "interpreting invalid AST"); }
1012 
1013   void visit(CondExpr e)
1014   {
1015     begin(e);
1016     visitE(e.condition);
1017     write(",");
1018     visitE(e.lhs);
1019     write(",");
1020     visitE(e.rhs);
1021     write(",");
1022     write(indexOf(e.optok));
1023     write(",");
1024     write(indexOf(e.ctok));
1025     end(e);
1026   }
1027 
1028   void visit(CommaExpr e)
1029   {
1030     mixin(binaryExpr);
1031   }
1032 
1033   void visit(OrOrExpr e)
1034   {
1035     mixin(binaryExpr);
1036   }
1037 
1038   void visit(AndAndExpr e)
1039   {
1040     mixin(binaryExpr);
1041   }
1042 
1043   void visit(OrExpr e)
1044   {
1045     mixin(binaryExpr);
1046   }
1047 
1048   void visit(XorExpr e)
1049   {
1050     mixin(binaryExpr);
1051   }
1052 
1053   void visit(AndExpr e)
1054   {
1055     mixin(binaryExpr);
1056   }
1057 
1058   void visit(EqualExpr e)
1059   {
1060     mixin(binaryExpr);
1061   }
1062 
1063   void visit(IdentityExpr e)
1064   {
1065     mixin(binaryExpr);
1066   }
1067 
1068   void visit(RelExpr e)
1069   {
1070     mixin(binaryExpr);
1071   }
1072 
1073   void visit(InExpr e)
1074   {
1075     mixin(binaryExpr);
1076   }
1077 
1078   void visit(LShiftExpr e)
1079   {
1080     mixin(binaryExpr);
1081   }
1082 
1083   void visit(RShiftExpr e)
1084   {
1085     mixin(binaryExpr);
1086   }
1087 
1088   void visit(URShiftExpr e)
1089   {
1090     mixin(binaryExpr);
1091   }
1092 
1093   void visit(PlusExpr e)
1094   {
1095     mixin(binaryExpr);
1096   }
1097 
1098   void visit(MinusExpr e)
1099   {
1100     mixin(binaryExpr);
1101   }
1102 
1103   void visit(CatExpr e)
1104   {
1105     mixin(binaryExpr);
1106   }
1107 
1108   void visit(MulExpr e)
1109   {
1110     mixin(binaryExpr);
1111   }
1112 
1113   void visit(DivExpr e)
1114   {
1115     mixin(binaryExpr);
1116   }
1117 
1118   void visit(ModExpr e)
1119   {
1120     mixin(binaryExpr);
1121   }
1122 
1123   void visit(RangeExpr e)
1124   {
1125     mixin(binaryExpr);
1126   }
1127 
1128   void visit(AssignExpr e)
1129   {
1130     mixin(binaryExpr);
1131   }
1132 
1133   void visit(LShiftAssignExpr e)
1134   {
1135     mixin(binaryExpr);
1136   }
1137 
1138   void visit(RShiftAssignExpr e)
1139   {
1140     mixin(binaryExpr);
1141   }
1142 
1143   void visit(URShiftAssignExpr e)
1144   {
1145     mixin(binaryExpr);
1146   }
1147 
1148   void visit(OrAssignExpr e)
1149   {
1150     mixin(binaryExpr);
1151   }
1152 
1153   void visit(AndAssignExpr e)
1154   {
1155     mixin(binaryExpr);
1156   }
1157 
1158   void visit(PlusAssignExpr e)
1159   {
1160     mixin(binaryExpr);
1161   }
1162 
1163   void visit(MinusAssignExpr e)
1164   {
1165     mixin(binaryExpr);
1166   }
1167 
1168   void visit(DivAssignExpr e)
1169   {
1170     mixin(binaryExpr);
1171   }
1172 
1173   void visit(MulAssignExpr e)
1174   {
1175     mixin(binaryExpr);
1176   }
1177 
1178   void visit(ModAssignExpr e)
1179   {
1180     mixin(binaryExpr);
1181   }
1182 
1183   void visit(XorAssignExpr e)
1184   {
1185     mixin(binaryExpr);
1186   }
1187 
1188   void visit(CatAssignExpr e)
1189   {
1190     mixin(binaryExpr);
1191   }
1192 
1193   void visit(AddressExpr e)
1194   {
1195     mixin(unaryExpr);
1196   }
1197 
1198   void visit(PreIncrExpr e)
1199   {
1200     mixin(unaryExpr);
1201   }
1202 
1203   void visit(PreDecrExpr e)
1204   {
1205     mixin(unaryExpr);
1206   }
1207 
1208   void visit(PostIncrExpr e)
1209   {
1210     mixin(unaryExpr);
1211   }
1212 
1213   void visit(PostDecrExpr e)
1214   {
1215     mixin(unaryExpr);
1216   }
1217 
1218   void visit(DerefExpr e)
1219   {
1220     mixin(unaryExpr);
1221   }
1222 
1223   void visit(SignExpr e)
1224   {
1225     mixin(unaryExpr);
1226   }
1227 
1228   void visit(NotExpr e)
1229   {
1230     mixin(unaryExpr);
1231   }
1232 
1233   void visit(CompExpr e)
1234   {
1235     mixin(unaryExpr);
1236   }
1237 
1238   void visit(CallExpr e)
1239   {
1240     mixin(unaryExpr);
1241   }
1242 
1243   void visit(NewExpr e)
1244   {
1245     begin(e);
1246     writeNodes(e.newArgs);
1247     write(",");
1248     visitT(e.type);
1249     write(",");
1250     writeNodes(e.ctorArgs);
1251     end(e);
1252   }
1253 
1254   void visit(NewClassExpr e)
1255   {
1256     begin(e);
1257     writeNodes(e.newArgs);
1258     write(",");
1259     writeNodes(e.bases);
1260     write(",");
1261     writeNodes(e.ctorArgs);
1262     write(",");
1263     visitD(e.decls);
1264     end(e);
1265   }
1266 
1267   void visit(DeleteExpr e)
1268   {
1269     mixin(unaryExpr);
1270   }
1271 
1272   void visit(CastExpr e)
1273   {
1274     begin(e);
1275     version(D2)
1276     e.type ? visitT(e.type) : write("n");
1277     else
1278     visitT(e.type);
1279     write(",");
1280     visitE(e.una);
1281     end(e);
1282   }
1283 
1284   void visit(IndexExpr e)
1285   {
1286     begin(e);
1287     visitE(e.una);
1288     write(",");
1289     writeNodes(e.args);
1290     end(e);
1291   }
1292 
1293   void visit(SliceExpr e)
1294   {
1295     begin(e);
1296     visitE(e.una);
1297     write(",");
1298     e.range ? visitE(e.range) : write("n");
1299     end(e);
1300   }
1301 
1302   void visit(ModuleScopeExpr e)
1303   {
1304     begin(e);
1305     end(e, false);
1306   }
1307 
1308   void visit(IdentifierExpr e)
1309   {
1310     begin(e);
1311     write(indexOf(e.name));
1312     end(e);
1313   }
1314 
1315   void visit(TmplInstanceExpr e)
1316   {
1317     begin(e);
1318     write(indexOf(e.name));
1319     write(",");
1320     e.targs ? visitN(e.targs) : write("n");
1321     end(e);
1322   }
1323 
1324   void visit(SpecialTokenExpr e)
1325   {
1326     begin(e);
1327     write(indexOf(e.specialToken));
1328     end(e);
1329   }
1330 
1331   void visit(ThisExpr e)
1332   {
1333     begin(e);
1334     end(e, false);
1335   }
1336 
1337   void visit(SuperExpr e)
1338   {
1339     begin(e);
1340     end(e, false);
1341   }
1342 
1343   void visit(NullExpr e)
1344   {
1345     begin(e);
1346     end(e, false);
1347   }
1348 
1349   void visit(DollarExpr e)
1350   {
1351     begin(e);
1352     end(e, false);
1353   }
1354 
1355   void visit(BoolExpr e)
1356   {
1357     begin(e);
1358     end(e, false);
1359   }
1360 
1361   void visit(IntExpr e)
1362   {
1363     begin(e);
1364     end(e, false);
1365   }
1366 
1367   void visit(FloatExpr e)
1368   {
1369     begin(e);
1370     end(e, false);
1371   }
1372 
1373   void visit(ComplexExpr e)
1374   {
1375     begin(e);
1376     end(e, false);
1377   }
1378 
1379   void visit(CharExpr e)
1380   {
1381     begin(e);
1382     end(e, false);
1383   }
1384 
1385   void visit(StringExpr e)
1386   {
1387     begin(e);
1388     end(e, false);
1389   }
1390 
1391   void visit(ArrayLiteralExpr e)
1392   {
1393     begin(e);
1394     writeNodes(e.values);
1395     end(e);
1396   }
1397 
1398   void visit(AArrayLiteralExpr e)
1399   {
1400     begin(e);
1401     writeNodes(e.keys);
1402     write(",");
1403     writeNodes(e.values);
1404     end(e);
1405   }
1406 
1407   void visit(AssertExpr e)
1408   {
1409     begin(e);
1410     visitE(e.expr);
1411     write(",");
1412     e.msg ? visitE(e.msg) : write("n");
1413     end(e);
1414   }
1415 
1416   void visit(MixinExpr e)
1417   {
1418     begin(e);
1419     visitE(e.expr);
1420     end(e);
1421   }
1422 
1423   void visit(ImportExpr e)
1424   {
1425     begin(e);
1426     visitE(e.expr);
1427     end(e);
1428   }
1429 
1430   void visit(TypeofExpr e)
1431   {
1432     begin(e);
1433     visitT(e.type);
1434     end(e);
1435   }
1436 
1437   void visit(TypeDotIdExpr e)
1438   {
1439     begin(e);
1440     visitT(e.type);
1441     end(e);
1442   }
1443 
1444   void visit(TypeidExpr e)
1445   {
1446     begin(e);
1447     visitT(e.type);
1448     end(e);
1449   }
1450 
1451   void visit(IsExpr e)
1452   {
1453     begin(e);
1454     visitT(e.type);
1455     write(",");
1456     e.specType ? visitT(e.specType) : write("n");
1457     write(",");
1458     e.tparams ? visitN(e.tparams) : write("n");
1459     end(e);
1460   }
1461 
1462   void visit(ParenExpr e)
1463   {
1464     begin(e);
1465     visitE(e.next);
1466     end(e);
1467   }
1468 
1469   void visit(FuncLiteralExpr e)
1470   {
1471     begin(e);
1472     e.returnType ? visitT(e.returnType) : write("n");
1473     write(",");
1474     e.params ? visitN(e.params) : write("n");
1475     write(",");
1476     visitS(e.funcBody);
1477     end(e);
1478   }
1479 
1480   void visit(LambdaExpr e)
1481   {
1482     begin(e);
1483     visitN(e.params);
1484     write(",");
1485     visitE(e.expr);
1486     end(e);
1487   }
1488 
1489   void visit(TraitsExpr e) // D2.0
1490   {
1491     begin(e);
1492     write(indexOf(e.name)~",");
1493     visitN(e.targs);
1494     end(e);
1495   }
1496 
1497   void visit(VoidInitExpr e)
1498   {
1499     begin(e);
1500     end(e, false);
1501   }
1502 
1503   void visit(ArrayInitExpr e)
1504   {
1505     begin(e);
1506     write("(");
1507     foreach (k; e.keys)
1508       (k ? visitE(k) : write("n")), write(",");
1509     write("),");
1510     writeNodes(e.values);
1511     end(e);
1512   }
1513 
1514   void visit(StructInitExpr e)
1515   {
1516     begin(e);
1517     write("(");
1518     foreach (i; e.idents)
1519       (i ? write(indexOf(i)) : write("n")), write(",");
1520     write("),");
1521     writeNodes(e.values);
1522     end(e);
1523   }
1524 
1525   void visit(AsmTypeExpr e)
1526   {
1527     mixin(unaryExpr);
1528   }
1529 
1530   void visit(AsmOffsetExpr e)
1531   {
1532     mixin(unaryExpr);
1533   }
1534 
1535   void visit(AsmSegExpr e)
1536   {
1537     mixin(unaryExpr);
1538   }
1539 
1540   void visit(AsmPostBracketExpr e)
1541   {
1542     begin(e);
1543     visitE(e.una);
1544     write(",");
1545     visitE(e.index);
1546     end(e);
1547   }
1548 
1549   void visit(AsmBracketExpr e)
1550   {
1551     begin(e);
1552     visitE(e.expr);
1553     end(e);
1554   }
1555 
1556   void visit(AsmLocalSizeExpr e)
1557   {
1558     begin(e);
1559     end(e, false);
1560   }
1561 
1562   void visit(AsmRegisterExpr e)
1563   {
1564     begin(e);
1565     e.number ? visitE(e.number) : write("n");
1566     end(e);
1567   }
1568 } // override
1569 
1570   /+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1571   |                                   Types                                   |
1572    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+/
1573 
1574 override
1575 {
1576   void visit(IllegalType)
1577   { assert(0, "interpreting invalid AST"); }
1578 
1579   void visit(IntegralType t)
1580   {
1581     begin(t);
1582     write(indexOf(t.begin));
1583     end(t);
1584   }
1585 
1586   void visit(ModuleScopeType t)
1587   {
1588     begin(t);
1589     end(t, false);
1590   }
1591 
1592   void visit(IdentifierType t)
1593   {
1594     begin(t);
1595     t.next ? visitT(t.next) : write("n");
1596     write(",");
1597     write(indexOf(t.begin));
1598     end(t);
1599   }
1600 
1601   void visit(TypeofType t)
1602   {
1603     begin(t);
1604     t.expr ? visitE(t.expr) : write("n");
1605     end(t);
1606   }
1607 
1608   void visit(TmplInstanceType t)
1609   {
1610     begin(t);
1611     t.next ? visitT(t.next) : write("n");
1612     write(",");
1613     write(indexOf(t.begin));
1614     write(",");
1615     t.targs ? visitN(t.targs) : write("n");
1616     end(t);
1617   }
1618 
1619   void visit(PointerType t)
1620   {
1621     begin(t);
1622     visitT(t.next);
1623     end(t);
1624   }
1625 
1626   void visit(ArrayType t)
1627   {
1628     begin(t);
1629     visitT(t.next);
1630     write(",");
1631     t.assocType ? visitT(t.assocType) : write("n");
1632     write(",");
1633     t.index1 ? visitE(t.index1) : write("n");
1634     write(",");
1635     t.index2 ? visitE(t.index2) : write("n");
1636     end(t);
1637   }
1638 
1639   void visit(FunctionType t)
1640   {
1641     begin(t);
1642     visitT(t.returnType);
1643     write(",");
1644     visitN(t.params);
1645     end(t);
1646   }
1647 
1648   void visit(DelegateType t)
1649   {
1650     begin(t);
1651     visitT(t.returnType);
1652     write(",");
1653     visitN(t.params);
1654     end(t);
1655   }
1656 
1657   void visit(BaseClassType t)
1658   {
1659     begin(t);
1660     // TODO: emit t.prot?
1661     visitT(t.next);
1662     end(t);
1663   }
1664 
1665   void visit(ModifierType t) // D2.0
1666   {
1667     begin(t);
1668     write(indexOf(t.mod));
1669     t.next && visitT(t.next);
1670     end(t);
1671   }
1672 } // override
1673 
1674   /+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1675   |                                 Parameters                                |
1676    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+/
1677 
1678 override
1679 {
1680   void visit(Parameter p)
1681   {
1682     begin(p);
1683     p.type ? visitT(p.type) : write("n");
1684     write(",");
1685     p.defValue ? visitE(p.defValue) : write("n");
1686     end(p);
1687   }
1688 
1689   void visit(Parameters p)
1690   {
1691     begin(p);
1692     write(p.children);
1693     end(p);
1694   }
1695 
1696   void visit(TemplateAliasParam p)
1697   {
1698     begin(p);
1699     p.spec ? visitN(p.spec) : write("n");
1700     write(",");
1701     p.def ? visitN(p.def) : write("n");
1702     end(p);
1703   }
1704 
1705   void visit(TemplateTypeParam p)
1706   {
1707     begin(p);
1708     p.specType ? visitT(p.specType) : write("n");
1709     write(",");
1710     p.defType ? visitT(p.defType) : write("n");
1711     end(p);
1712   }
1713 
1714   void visit(TemplateThisParam p) // D2.0
1715   {
1716     begin(p);
1717     p.specType ? visitT(p.specType) : write("n");
1718     write(",");
1719     p.defType ? visitT(p.defType) : write("n");
1720     end(p);
1721   }
1722 
1723   void visit(TemplateValueParam p)
1724   {
1725     begin(p);
1726     p.valueType ? visitT(p.valueType) : write("n");
1727     write(",");
1728     p.specValue ? visitE(p.specValue) : write("n");
1729     write(",");
1730     p.defValue ? visitE(p.defValue) : write("n");
1731     end(p);
1732   }
1733 
1734   void visit(TemplateTupleParam p)
1735   {
1736     begin(p);
1737     end(p, false);
1738   }
1739 
1740   void visit(TemplateParameters p)
1741   {
1742     begin(p);
1743     write(p.children);
1744     end(p);
1745   }
1746 
1747   void visit(TemplateArguments p)
1748   {
1749     begin(p);
1750     write(p.children);
1751     end(p);
1752   }
1753 } // override
1754 }