1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity very low)
4 module dil.ast.ASTSerializer;
5 
6 import dil.ast.Visitor,
7        dil.ast.Node,
8        dil.ast.Declarations,
9        dil.ast.Expressions,
10        dil.ast.Statements,
11        dil.ast.Types,
12        dil.ast.Parameters;
13 import dil.lexer.IdTable;
14 import dil.semantic.Module;
15 import dil.Enums,
16        dil.Diagnostics,
17        dil.String;
18 import common;
19 
20 /// Serializes a complete parse tree.
21 class ASTSerializer : Visitor2
22 {
23   static immutable HEADER = "DIL1.0AST\x1A\x04\n"; /// Appears at the start.
24   ubyte[] data; /// The binary text.
25   Token* firstToken; /// The first token in the token array.
26 
27   /// An enumeration of types that may appear in the data.
28   enum TID : ubyte
29   {
30     Array = 'A',
31     Null,
32     Char,
33     Bool,
34     Uint,
35     TOK,
36     Protection,
37     LinkageType,
38     StorageClass,
39     NodeKind,
40     Node,
41     Declaration,
42     Statement,
43     Expression,
44     TypeNode,
45     Parameter,
46     TemplateParam,
47     Nodes,
48     Declarations,
49     Statements,
50     Expressions,
51     Types,
52     Parameters,
53     TemplateParams,
54     EnumMemberDecls,
55     BaseClassTypes,
56     CatchStmts,
57     Token,
58     Tokens,
59     TokenArrays,
60   }
61 
62   this()
63   {
64   }
65 
66   /// Starts serialization.
67   ubyte[] serialize(Module mod)
68   {
69     data ~= HEADER;
70     firstToken = mod.firstToken;
71     visitN(mod.root);
72     return data;
73   }
74 
75   /// Returns the index number of a token.
76   /// If token is null, size_t.max is returned.
77   size_t indexOf(Token* token)
78   {
79     return token ? token - firstToken : size_t.max;
80   }
81 
82   /// Writes 1 byte.
83   void write1B(ubyte x)
84   {
85     data ~= x;
86   }
87 
88   /// Writes T.sizeof bytes.
89   void writeXB(T)(T x)
90   {
91     data ~= (cast(ubyte*)&x)[0..T.sizeof];
92   }
93 
94   /// Writes 2 bytes.
95   alias write2B = writeXB!(ushort);
96 
97   /// Writes 4 bytes.
98   alias write4B = writeXB!(uint);
99 
100   /// Writes size_t.sizeof bytes.
101   alias writeSB = writeXB!(size_t);
102 
103 
104   /// Writes the kind of a Node.
105   void write(NodeKind k)
106   {
107     static assert(NodeKind.max <= ubyte.max);
108     write1B(TID.NodeKind);
109     write1B(cast(ubyte)k);
110   }
111 
112   /// Writes the protection attribute.
113   void write(Protection prot)
114   {
115     static assert(Protection.max <= ubyte.max);
116     write1B(TID.Protection);
117     write1B(cast(ubyte)prot);
118   }
119 
120   /// Writes the StorageClass attribute.
121   void write(StorageClass stcs)
122   {
123     static assert(StorageClass.max <= uint.max);
124     write1B(TID.StorageClass);
125     write4B(cast(uint)stcs);
126   }
127 
128   /// Writes the LinkageType attribute.
129   void write(LinkageType lnkg)
130   {
131     static assert(LinkageType.max <= ubyte.max);
132     write1B(TID.LinkageType);
133     write1B(cast(ubyte)lnkg);
134   }
135 
136   /// Writes a node.
137   void write(Node n, TID tid)
138   {
139     if (n is null) {
140       write1B(TID.Null);
141       write1B(tid);
142     }
143     else
144       visitN(n);
145   }
146 
147   void write(Node n)
148   {
149     write(n, TID.Node);
150   }
151 
152   void write(Declaration n)
153   {
154     write(n, TID.Declaration);
155   }
156 
157   void write(Statement n)
158   {
159     write(n, TID.Statement);
160   }
161 
162   void write(Expression n)
163   {
164     write(n, TID.Expression);
165   }
166 
167   void write(TypeNode n)
168   {
169     write(n, TID.TypeNode);
170   }
171 
172   void write(Parameter n)
173   {
174     write(n, TID.Parameter);
175   }
176 
177   void write(TemplateParam n)
178   {
179     write(n, TID.TemplateParam);
180   }
181 
182   /// Writes the mangled array type and then visits each node.
183   void write(Node[] nodes, TID tid)
184   {
185     write1B(TID.Array);
186     write1B(tid);
187     writeSB(nodes.length);
188     foreach (n; nodes)
189       write(n, tid);
190   }
191 
192   void write(Node[] nodes)
193   {
194     write(nodes, TID.Nodes);
195   }
196 
197   void write(Declaration[] nodes)
198   {
199     write(cast(Node[])nodes, TID.Declarations);
200   }
201 
202   void write(Statement[] nodes)
203   {
204     write(cast(Node[])nodes, TID.Statements);
205   }
206 
207   void write(Expression[] nodes)
208   {
209     write(cast(Node[])nodes, TID.Expressions);
210   }
211 
212   void write(TypeNode[] nodes)
213   {
214     write(cast(Node[])nodes, TID.Types);
215   }
216 
217   void write(Parameter[] nodes)
218   {
219     write(cast(Node[])nodes, TID.Parameters);
220   }
221 
222   void write(TemplateParam[] nodes)
223   {
224     write(cast(Node[])nodes, TID.TemplateParams);
225   }
226 
227   void write(EnumMemberDecl[] nodes)
228   {
229     write(cast(Node[])nodes, TID.EnumMemberDecls);
230   }
231 
232   void write(BaseClassType[] nodes)
233   {
234     write(cast(Node[])nodes, TID.BaseClassTypes);
235   }
236 
237   void write(CatchStmt[] nodes)
238   {
239     write(cast(Node[])nodes, TID.CatchStmts);
240   }
241 
242   /// Writes a char.
243   void write(char c)
244   {
245     write1B(TID.Char);
246     write1B(c);
247   }
248 
249   /// Writes a boolean.
250   void write(bool b)
251   {
252     write1B(TID.Bool);
253     write1B(b);
254   }
255 
256   /// Writes a uint.
257   void write(uint u)
258   {
259     write1B(TID.Uint);
260     write4B(u);
261   }
262 
263   /// Writes a TOK.
264   void write(TOK tok)
265   {
266     assert(TOK.max <= ushort.max);
267     write1B(TID.TOK);
268     write2B(cast(ushort)tok);
269   }
270 
271   /// Writes a Token.
272   void write(Token* t)
273   {
274     write1B(TID.Token);
275     writeSB(indexOf(t));
276   }
277 
278   /// Writes an array of Tokens.
279   void write(Token*[] tokens)
280   {
281     write1B(TID.Tokens);
282     writeSB(tokens.length);
283     foreach (t; tokens)
284       writeSB(indexOf(t));
285   }
286 
287   /// Writes an array of arrays of Tokens.
288   void write(Token*[][] tokenLists)
289   {
290     write1B(TID.TokenArrays);
291     writeSB(tokenLists.length);
292     foreach (tokens; tokenLists)
293       write(tokens);
294   }
295 
296   // Visitor methods:
297 
298   /// Generates a visit method for a specific Node.
299   mixin template visitX(N)
300   {
301     override void visit(N n)
302     {
303       alias Members = Array2Tuple!(N.CTTI_Members);
304       assert(n);
305       write1B(TID.Node);
306       write(n.kind);
307       write(n.begin);
308       write(n.end);
309       static if (is(N : Declaration))
310       { // Write the attributes of Declarations.
311         write(n.stcs);
312         write(n.prot);
313       }
314       assert(Members.length < ubyte.max);
315       write1B(Members.length);
316       foreach (m; Members)
317         write(mixin("n."~m));
318     }
319   }
320 
321   /// Generates a list of mixin declarations for all Node classes.
322   /// E.g.:
323   /// ---
324   /// mixin visitX!(CompoundDecl);
325   /// mixin visitX!(CompoundStmt);
326   /// mixin visitX!(CondExpr);
327   /// ---
328   static char[] mixinVisitMethods()
329   {
330     char[] code;
331     foreach (name; NodeClassNames)
332       code ~= "mixin visitX!(" ~ name ~ ");\n";
333     return code;
334   }
335 
336   mixin(mixinVisitMethods());
337 }
338 
339 
340 
341 /// Deserializes a binary AST file.
342 class ASTDeserializer : Visitor
343 {
344   Token*[] tokens; /// The list of Tokens.
345   const(ubyte)* p; /// Current byte.
346   const(ubyte)* end; /// One past the last byte.
347   Diagnostics diag; /// For error messages.
348 
349   /// Constructs an object.
350   this(Token*[] tokens, Diagnostics diag)
351   {
352     this.tokens = tokens;
353     this.diag = diag;
354   }
355 
356   alias TID = ASTSerializer.TID;
357 
358   /// Reads T.sizeof bytes.
359   bool readXB(T)(out T x)
360   {
361     if (p + T.sizeof > end)
362       return false;
363     x = *cast(const T*)p;
364     p += T.sizeof;
365     return true;
366   }
367 
368   /// Reads 1 byte.
369   alias read1B = readXB!(ubyte);
370 
371   /// Reads 2 bytes.
372   alias read2B = readXB!(ushort);
373 
374   /// Reads 4 bytes.
375   alias read4B = readXB!(uint);
376 
377   /// Reads size_t.sizeof bytes.
378   alias readSB = readXB!(size_t);
379 
380   /// Creates an error message.
381   bool error(cstring msg, ...)
382   {
383     // TODO:
384     return false;
385   }
386 
387   /// Reads a byte and checks if it equals tid.
388   bool check(TID tid)
389   {
390     ubyte x;
391     return read1B(x) && x == tid || error("expected ‘TID.{}’", tid);
392   }
393 
394   /// Reads a type id.
395   bool read(out TID tid)
396   {
397     return read1B(tid);
398   }
399 
400   /// Reads the kind of a Node.
401   bool read(out NodeKind k)
402   {
403     return check(TID.NodeKind) && read1B(*cast(ubyte*)&k) &&
404            k <= NodeKind.max || error("NodeKind value out of range");
405   }
406 
407   /// Reads the protection attribute.
408   bool read(out Protection prot)
409   {
410     return check(TID.Protection) && read1B(*cast(ubyte*)&prot) &&
411            prot <= Protection.max || error("Protection value out of range");
412   }
413 
414   /// Reads the StorageClass attribute.
415   bool read(out StorageClass stcs)
416   {
417     return check(TID.StorageClass) && read4B(*cast(uint*)&stcs);
418   }
419 
420   /// Reads the LinkageType attribute.
421   bool read(out LinkageType lnkg)
422   {
423     return check(TID.LinkageType) && read1B(*cast(ubyte*)&lnkg);
424   }
425 
426   /// Reads the mangled array type and then each node.
427   bool read(ref Node[] nodes, TID tid)
428   {
429     size_t len;
430     if (!check(TID.Array) || !check(tid) || !readSB(len))
431       return false;
432     nodes = new Node[len];
433     foreach (ref n; nodes)
434       if (!read(n))
435         return false;
436     return true;
437   }
438 
439   bool read(out Node[] nodes)
440   {
441     return read(nodes, TID.Nodes);
442   }
443 
444   bool read(out Declaration[] nodes)
445   {
446     return read(*cast(Node[]*)&nodes, TID.Declarations);
447   }
448 
449   bool read(out Statement[] nodes)
450   {
451     return read(*cast(Node[]*)&nodes, TID.Statements);
452   }
453 
454   bool read(out Expression[] nodes)
455   {
456     return read(*cast(Node[]*)&nodes, TID.Expressions);
457   }
458 
459   bool read(out TypeNode[] nodes)
460   {
461     return read(*cast(Node[]*)&nodes, TID.Types);
462   }
463 
464   bool read(out Parameter[] nodes)
465   {
466     return read(*cast(Node[]*)&nodes, TID.Parameters);
467   }
468 
469   bool read(out TemplateParam[] nodes)
470   {
471     return read(*cast(Node[]*)&nodes, TID.TemplateParams);
472   }
473 
474   bool read(out EnumMemberDecl[] nodes)
475   {
476     return read(*cast(Node[]*)&nodes, TID.EnumMemberDecls);
477   }
478 
479   bool read(out BaseClassType[] nodes)
480   {
481     return read(*cast(Node[]*)&nodes, TID.BaseClassTypes);
482   }
483 
484   bool read(out CatchStmt[] nodes)
485   {
486     return read(*cast(Node[]*)&nodes, TID.CatchStmts);
487   }
488 
489   /// Reads a char.
490   bool read(out char c)
491   {
492     return check(TID.Char) && read1B(*cast(ubyte*)&c);
493   }
494 
495   /// Reads a boolean.
496   bool read(out bool b)
497   {
498     ubyte u;
499     auto a = check(TID.Bool) && read1B(u) && u <= 1;
500     if (a)
501       b = !!u;
502     return a;
503   }
504 
505   /// Reads a uint.
506   bool read(out uint u)
507   {
508     return check(TID.Uint) && read4B(u);
509   }
510 
511   /// Reads a TOK.
512   bool read(out TOK tok)
513   {
514     return check(TID.TOK) && read2B(tok) && tok <= TOK.max;
515   }
516 
517   /// Reads a Token.
518   bool read(out Token* t)
519   {
520     size_t index;
521     bool b = check(TID.Token) && readSB(index);
522     if (b)
523       t = index == size_t.max ? null : tokens[index];
524     return b;
525   }
526 
527   /// Reads an array of Tokens.
528   bool read(out Token*[] tokens)
529   {
530     size_t len;
531     if (!check(TID.Tokens) || !readSB(len))
532       return false;
533     tokens = new Token*[len];
534     foreach (ref t; tokens)
535       if (!read(t))
536         return false;
537     return true;
538   }
539 
540   /// Reads an array of arrays of Tokens.
541   bool read(out Token*[][] tokenLists)
542   {
543     size_t len;
544     if (!check(TID.TokenArrays) || !readSB(len))
545       return false;
546     tokenLists = new Token*[][len];
547     foreach (ref tokens; tokenLists)
548       if (!read(tokens))
549         return false;
550     return true;
551   }
552 
553   bool read(ref Node n)
554   {
555     TID tid;
556     NodeKind kind;
557     Token* begin, end;
558     if (!read(tid) && tid == TID.Node ||
559         !read(kind) ||
560         !read(begin) ||
561         !read(end))
562       return false; // Error
563     n = dispatch(n, kind);
564     if (n is null)
565       return false; // Error
566     n.setTokens(begin, end);
567     return true;
568   }
569 
570   bool read(out CompoundDecl n)
571   {
572     return read(*cast(Node*)&n);
573   }
574 
575   bool read(out CompoundStmt n)
576   {
577     return read(*cast(Node*)&n);
578   }
579 
580   bool read(out Declaration n)
581   {
582     return read(*cast(Node*)&n);
583   }
584 
585   bool read(out Statement n)
586   {
587     return read(*cast(Node*)&n);
588   }
589 
590   bool read(out Expression n)
591   {
592     return read(*cast(Node*)&n);
593   }
594 
595   bool read(out TypeNode n)
596   {
597     return read(*cast(Node*)&n);
598   }
599 
600   bool read(out TemplateParameters n)
601   {
602     return read(*cast(Node*)&n);
603   }
604 
605   bool read(out Parameters n)
606   {
607     return read(*cast(Node*)&n);
608   }
609 
610   bool read(out Parameter n)
611   {
612     return read(*cast(Node*)&n);
613   }
614 
615   bool read(out FuncBodyStmt n)
616   {
617     return read(*cast(Node*)&n);
618   }
619 
620   bool read(out TemplateArguments n)
621   {
622     return read(*cast(Node*)&n);
623   }
624 
625   bool read(out FinallyStmt n)
626   {
627     return read(*cast(Node*)&n);
628   }
629 
630   Module deserialize(const ubyte[] data)
631   {
632     p = data.ptr;
633     end = data.ptr + data.length;
634     Node rootDecl;
635     read(rootDecl);
636     return null;
637   }
638 
639   mixin template visitX(N)
640   {
641     override returnType!(N) visit(N n)
642     {
643       mixin(generateReaders(N.CTTI_TypeStrs));
644       static if (is(N : Declaration))
645       {
646         StorageClass stcs;
647         Protection prot;
648         if (!read(stcs) || !read(prot))
649           return null;
650         n.setStorageClass(stcs);
651         n.setProtection(prot);
652       }
653       return mixin(generateCtorCall(N.CTTI_Members.length));
654     }
655   }
656 
657   /// Generates e.g.:
658   /// ---
659   /// Token* _0;
660   /// if (!read(_0)) return null;
661   /// Token*[] _1;
662   /// if (!read(_1)) return null;
663   /// ---
664   static char[] generateReaders(string[] types)
665   {
666     char[] code;
667     foreach (i, t; types)
668     {
669       const arg = "_" ~ itoa(i);
670       code ~= t ~ " " ~ arg ~ ";\n" ~
671         "if (!read(" ~ arg ~ ")) return null;\n";
672     }
673     return code;
674   }
675 
676   /// Generates e.g.: _0, _1, _2
677   static char[] generateCtorCall(size_t num)
678   {
679     char[] code = "new N( ".dup;
680     for (size_t i; i < num; i++)
681       code ~= "_" ~ itoa(i) ~ ",";
682     code[$-1] = ')';
683     return code;
684   }
685 
686   /// Generates e.g.: mixin visitX!(CompoundDecl);
687   static char[] generateMixins()
688   {
689     char[] code;
690     foreach (name; NodeClassNames)
691       code ~= "mixin visitX!(" ~ name ~ ");\n";
692     return code;
693   }
694 
695   mixin(generateMixins());
696 }