1 module bamboo.astgen;
2 import std.conv;
3 import pegged.peg;
4 import bamboo.parser;
5 import bamboo.types;
6 import bamboo.util;
7 
8 Module parseString(string source)
9 {
10     auto node = DClass(source);
11     auto completed = transform(node);
12     return completed;
13 }
14 
15 /// Given a path, parses a DC file.
16 /// Returns: a `Module`, representing the parsed file.
17 Module parseModule(string file)
18 {
19     import std.file : readText;
20 
21     return parseString(readText(file));
22 }
23 
24 /// Destructively mutates `file`, appending members from `other`.
25 void combineWith(Module file, Module other)
26 {
27     ushort typeId = file.lastTypeId;
28     ushort fieldId = file.lastFieldId;
29 
30     foreach (i, type; other.typesById)
31     {
32         type.id = ++typeId;
33         if (auto cls = cast(ClassDeclaration) type)
34         {
35             foreach (field; cls.fields)
36             {
37                 field.id = ++fieldId;
38             }
39             file.classes ~= cls;
40         }
41         else if (auto strct = cast(StructDeclaration) type)
42         {
43             foreach (field; strct.parameters)
44             {
45                 field.id = ++fieldId;
46             }
47             file.structs ~= strct;
48         }
49         else if (auto def = cast(AliasDeclaration) type)
50         {
51             file.aliases ~= def;
52         }
53         else if (auto keyword = cast(KeywordDeclaration) type)
54         {
55             file.keywords ~= keyword;
56         }
57     }
58     foreach (imprt; other.importDeclarations)
59     {
60         file.importDeclarations ~= imprt;
61     }
62 
63     foreach (keyword; other.keywords)
64     {
65         file.keywords ~= keyword;
66     }
67 
68     file.lastTypeId = typeId;
69     file.lastFieldId = fieldId;
70 }
71 
72 private:
73 
74 class SyntaxResolver : Visitor
75 {
76     enum Type[string] builtins = genbuiltins;
77     TypeDeclaration[string] aliases;
78 
79     Module _module;
80 
81     override void visit(Module file)
82     {
83         _module = file;
84         foreach (decl; file.aliases)
85         {
86             decl.visit(this);
87         }
88         foreach (type; file.typesById)
89         {
90             type.visit(this);
91         }
92     }
93 
94     TypeDeclaration resolve(string type)
95     {
96         if (auto ret = type in builtins)
97         {
98             return new BuiltinType(-1, type, *ret);
99         }
100         if (auto ret = type in aliases)
101         {
102             return *ret;
103         }
104         return _module.findType(type);
105     }
106 
107     Parameter createParameter(TypeDeclaration type, string name)
108     {
109         import std.conv : to;
110 
111         switch (type.type) with (Type)
112         {
113         case int8:
114         case int16:
115         case int32:
116         case int64:
117         case uint8:
118         case uint16:
119         case uint32:
120         case uint64:
121         case char_:
122         case float32:
123         case float64:
124             return new NumericParameter(name, type.type.to!string, 1, double.nan, null, null);
125         case string_:
126         case blob:
127             return new SizedParameter(name, type.type.to!string, new SizeConstraint(0, 0), "");
128         default:
129             break;
130         }
131         return null;
132     }
133 
134     override void visit(ImportDeclaration node)
135     {
136     }
137 
138     override void visit(KeywordList node)
139     {
140     }
141 
142     override void visit(KeywordDeclaration node)
143     {
144     }
145 
146     override void visit(BuiltinType node)
147     {
148     }
149 
150     override void visit(StructDeclaration node)
151     {
152         foreach (field; node.parameters)
153         {
154             field.visit(this);
155         }
156     }
157 
158     override void visit(ClassDeclaration node)
159     {
160         node.resolve(_module);
161         foreach (field; node.fields)
162         {
163             if (auto molecular = cast(MolecularField) field)
164             {
165                 FieldDeclaration[] refs;
166                 foreach (reference; molecular.referenceNames)
167                 {
168                     refs ~= node.getField(reference);
169                 }
170                 molecular.references = refs;
171             }
172             field.visit(this);
173         }
174         if (node.hasConstructor)
175         {
176             node.constructor.visit(this);
177         }
178     }
179 
180     override void visit(AliasDeclaration node)
181     {
182         node.aliasedType = resolve(node.aliasedTypeName);
183         aliases[node.symbol] = node.aliasedType;
184     }
185 
186     override void visit(MolecularField node)
187     {
188 
189     }
190 
191     override void visit(AtomicField node)
192     {
193         Parameter[] parameters;
194 
195         foreach (parameter; node.parameters)
196         {
197             parameter.visit(this);
198             if (auto structPara = cast(StructParameter) parameter)
199             {
200                 if (auto type = cast(BuiltinType) structPara.type)
201                 {
202                     auto newPara = createParameter(structPara.type, structPara.symbol);
203                     if (newPara !is null)
204                     {
205                         parameters ~= newPara;
206                         continue;
207                     }
208                 }
209             }
210             parameters ~= parameter;
211         }
212 
213         node.parameters = parameters;
214     }
215 
216     override void visit(ParameterField node)
217     {
218         node.parameter.visit(this);
219     }
220 
221     override void visit(NumericParameter node)
222     {
223     }
224 
225     override void visit(NumericRange node)
226     {
227     }
228 
229     override void visit(NumericTransform node)
230     {
231     }
232 
233     override void visit(NumericConstant node)
234     {
235     }
236 
237     override void visit(SizedParameter node)
238     {
239     }
240 
241     override void visit(SizeConstraint node)
242     {
243     }
244 
245     override void visit(StructParameter node)
246     {
247         node.type = resolve(node.typeName);
248     }
249 
250     override void visit(ArrayParameter node)
251     {
252         node.elementType = resolve(node.type);
253     }
254 
255     override void visit(ArrayRange node)
256     {
257     }
258 
259 }
260 
261 Module transform(ParseTree node)
262 {
263     assert(node.name == "DClass");
264 
265     return transformModule(node.children[0]);
266 }
267 
268 //dfmt off
269 enum SyntaxType
270 {
271     Module              = "DClass.Module",
272     DCFile              = "DClass.DCFile",
273     ParseDirective      = "DClass.ParseDirective",
274     ImportDecl          = "DClass.ImportDecl",
275     ImportList          = "DClass.ImportList",
276     TypeDecl            = "DClass.TypeDecl",
277     AliasType           = "DClass.AliasType",
278     KeywordType         = "DClass.KeywordType",
279     KeywordList         = "DClass.KeywordList",
280     StructType          = "DClass.StructType",
281     ClassType           = "DClass.ClassType",
282     FieldDecl           = "DClass.FieldDecl",
283     MolecularField      = "DClass.MolecularField",
284     AtomicField         = "DClass.AtomicField",
285     ParameterField      = "DClass.ParameterField",
286     Parameter           = "DClass.Parameter",
287     ParameterList       = "DClass.ParameterList",
288     CharParameter       = "DClass.CharParameter",
289     IntParameter        = "DClass.IntParameter",
290     IntConstant         = "DClass.IntConstant",
291     IntTransform        = "DClass.IntTransform",
292     IntRange            = "DClass.IntRange",
293     FloatParameter      = "DClass.FloatParameter",
294     FloatConstant       = "DClass.FloatConstant",
295     FloatTransform      = "DClass.FloatTransform",
296     FloatRange          = "DClass.FloatRange",
297     SizedParameter      = "DClass.SizedParameter",
298     SizeConstraint      = "DClass.SizeConstraint",
299     StructParameter     = "DClass.StructParameter",
300     ArrayParameter      = "DClass.ArrayParameter",
301     ArrayRange          = "DClass.ArrayRange",
302     Identifier          = "DClass.Identifier",
303     QualifiedIdentifier = "DClass.QualifiedIdentifier",
304     dataType            = "DClass.dataType",
305 }
306 
307 enum LiteralType
308 {
309     charLiteral     = "DClass.charLiteral",
310     intLiteral      = "DClass.intLiteral",
311     floatLiteral    = "DClass.floatLiteral",
312     stringLiteral   = "DClass.stringLiteral",
313 }
314 //dfmt on
315 
316 ParseTree child(ParseTree node, int index)
317 {
318     if (node.children.length <= index)
319     {
320         return ParseTree("", false, [], "", 0, 0, []);
321     }
322     return node.children[index];
323 }
324 
325 Module transformModule(ParseTree node)
326 {
327     assert(node.name == SyntaxType.Module);
328 
329     auto file = transformFile(node.children[0]);
330 
331     SyntaxResolver resolver = new SyntaxResolver();
332     resolver.visit(file);
333 
334     return file;
335 }
336 
337 Module transformFile(ParseTree node)
338 {
339     assert(node.name == SyntaxType.DCFile);
340 
341     ushort id;
342     ushort fieldId;
343     int skip;
344     string name;
345 
346     ImportDeclaration[] imports;
347 
348     ClassDeclaration[] classes;
349     StructDeclaration[] structs;
350     KeywordDeclaration[] keywords;
351     AliasDeclaration[] aliases;
352 
353     // Check if this module has a name.
354     if (node.children[0].name == SyntaxType.ParseDirective)
355     {
356         ParseTree child = node.children[0];
357         string directive = transformIdentifier(child.children[0]);
358         string value = child.children[1].matches[0];
359 
360         if (directive == "module")
361         {
362             skip = 1;
363             name = value;
364         }
365     }
366 
367     foreach (child; node.children[skip .. $])
368     {
369         switch (cast(SyntaxType) child.name) with (SyntaxType)
370         {
371         case ParseDirective:
372             {
373                 string directive = transformIdentifier(child.children[0]);
374                 string value = child.children[1].matches[0];
375 
376                 if(directive == "typeid")
377                 {
378                     id = value.to!ushort;
379                 }
380             }
381             break;
382         case ImportDecl:
383             imports ~= transformImport(child);
384             break;
385         case TypeDecl:
386             child = child.children[0];
387             switch (cast(SyntaxType) child.name) with (SyntaxType)
388             {
389             case KeywordType:
390                 keywords ~= transformKeywordType(child, id);
391                 break;
392             case StructType:
393                 structs ~= transformStructType(child, id, fieldId);
394                 break;
395             case ClassType:
396                 classes ~= transformClassType(child, id, fieldId);
397                 break;
398             case AliasType:
399                 aliases ~= transformAliasType(child, id);
400                 break;
401             default:
402                 assert(0);
403             }
404             break;
405         default:
406             assert(0, "Expected ImportDecl or TypeDecl. Got " ~ child.name);
407         }
408         id++;
409     }
410 
411     return new Module(name, imports, aliases, classes, structs, keywords, id, fieldId);
412 }
413 
414 string transformIdentifier(SyntaxType type = SyntaxType.Identifier)(ParseTree node)
415 {
416     assert(node.name == type, node.name ~ " != " ~ type);
417     return node.matches[0];
418 }
419 
420 ImportDeclaration transformImport(ParseTree node)
421 {
422     assert(node.name == SyntaxType.ImportDecl);
423     string module_ = transformIdentifier!(SyntaxType.QualifiedIdentifier)(node.children[0]);
424 
425     string[] symbols = transformImportList(node.children[1]);
426 
427     return new ImportDeclaration(module_, symbols);
428 }
429 
430 string[] transformImportList(ParseTree node)
431 {
432     assert(node.name == SyntaxType.ImportList);
433     // Expand symbol list from, e.g., LoginManager/AI/UD
434     // to LoginManager, LoginManagerAI, LoginManagerUD
435     string firstSymbol = transformIdentifier(node.children[0]);
436     string[] symbols;
437 
438     symbols ~= firstSymbol;
439     foreach (child; node.children[1 .. $])
440     {
441         symbols ~= firstSymbol ~ transformIdentifier(child);
442     }
443 
444     return symbols;
445 }
446 
447 AliasDeclaration transformAliasType(ParseTree node, ref ushort id)
448 {
449     assert(node.name == SyntaxType.AliasType);
450     string symbol = transformIdentifier(node.children[1]);
451     string type = transformIdentifier!(SyntaxType.dataType)(node.children[0]);
452 
453     return new AliasDeclaration(id, symbol, type);
454 }
455 
456 KeywordDeclaration transformKeywordType(ParseTree node, ref ushort id)
457 {
458     assert(node.name == SyntaxType.KeywordType);
459     string symbol = transformIdentifier(node.children[0]);
460     return new KeywordDeclaration(id, symbol);
461 }
462 
463 KeywordList transformKeywordList(ParseTree node)
464 {
465     assert(node.name == SyntaxType.KeywordList);
466 
467     string[] symbols;
468 
469     foreach (child; node.children)
470     {
471         symbols ~= transformIdentifier(child);
472     }
473 
474     return new KeywordList(symbols);
475 }
476 
477 StructDeclaration transformStructType(ParseTree node, ref ushort id, ref ushort fieldId)
478 {
479     assert(node.name == SyntaxType.StructType);
480 
481     string symbol = transformIdentifier(node.children[0]);
482 
483     ParameterField[] members;
484 
485     foreach (child; node.children[1 .. $])
486     {
487         members ~= new ParameterField(fieldId++, transformParameter(child), new KeywordList([]));
488     }
489 
490     return new StructDeclaration(id, symbol, members);
491 }
492 
493 ClassDeclaration transformClassType(ParseTree node, ref ushort id, ref ushort fieldId)
494 {
495     assert(node.name == SyntaxType.ClassType);
496 
497     string symbol = transformIdentifier(node.children[0]);
498     string superclass;
499     int cur = 1;
500 
501     if (node.children[cur].name == SyntaxType.Identifier)
502     {
503         superclass = transformIdentifier(node.children[cur++]);
504     }
505 
506     FieldDeclaration[] members;
507     FieldDeclaration cotr;
508 
509     foreach (child; node.children[cur .. $])
510     {
511         auto field = transformFieldDecl(child, fieldId++);
512         if (is(field == AtomicField))
513         {
514             cotr = field;
515         }
516         else
517         {
518             members ~= field;
519         }
520     }
521 
522     return new ClassDeclaration(id, symbol, superclass, cotr, members);
523 }
524 
525 FieldDeclaration transformFieldDecl(ParseTree node, ushort id)
526 {
527     assert(node.name == SyntaxType.FieldDecl);
528 
529     ParseTree child = node.children[0];
530 
531     switch (cast(SyntaxType) child.name) with (SyntaxType)
532     {
533     case AtomicField:
534         return transformAtomicField(child, id);
535     case MolecularField:
536         return transformMolecularField(child, id);
537     case ParameterField:
538         return transformParameterField(child, id);
539     default:
540         assert(0);
541     }
542 }
543 
544 MolecularField transformMolecularField(ParseTree node, ref ushort id)
545 {
546     assert(node.name == SyntaxType.MolecularField);
547 
548     string symbol = transformIdentifier(node.children[0]);
549     string[] references;
550 
551     foreach (child; node.children[1].children)
552     {
553         references ~= transformIdentifier(child);
554     }
555 
556     return new MolecularField(id, symbol, references);
557 }
558 
559 AtomicField transformAtomicField(ParseTree node, ref ushort id)
560 {
561     assert(node.name == SyntaxType.AtomicField);
562 
563     string symbol = transformIdentifier(node.children[0]);
564 
565     Parameter[] parameters;
566     KeywordList keywords = new KeywordList([]);
567 
568     int cur = 1;
569 
570     if (node.child(cur).name == SyntaxType.ParameterList)
571     {
572         parameters = transformParameterList(node.children[cur++]);
573     }
574     if (node.child(cur).name == SyntaxType.KeywordList)
575     {
576         keywords = transformKeywordList(node.child(cur));
577     }
578 
579     return new AtomicField(id, symbol, parameters, keywords);
580 }
581 
582 Parameter[] transformParameterList(ParseTree node)
583 {
584     assert(node.name == SyntaxType.ParameterList);
585 
586     Parameter[] parameters;
587 
588     foreach (child; node.children)
589     {
590         parameters ~= transformParameter(child);
591     }
592 
593     return parameters;
594 }
595 
596 ParameterField transformParameterField(ParseTree node, ref ushort id)
597 {
598     assert(node.name == SyntaxType.ParameterField);
599 
600     Parameter parameter = transformParameter(node.children[0]);
601     KeywordList keywords = new KeywordList([]);
602 
603     if (node.children.length == 2)
604     {
605         keywords = transformKeywordList(node.children[1]);
606     }
607 
608     return new ParameterField(id, parameter, keywords);
609 }
610 
611 Parameter transformParameter(ParseTree node)
612 {
613     assert(node.name == SyntaxType.Parameter);
614 
615     ParseTree child = node.children[0];
616 
617     switch (child.name) with (SyntaxType)
618     {
619     case CharParameter:
620         return transformCharParameter(child);
621     case IntParameter:
622     case FloatParameter:
623         return transformNumericParameter(child);
624     case SizedParameter:
625         return transformSizedParameter(child);
626     case ArrayParameter:
627         return transformArrayParameter(child);
628     case StructParameter:
629         return transformStructParameter(child);
630     default:
631         assert(0);
632     }
633 }
634 
635 //dfmt off
636 T readLiteral(T)(ParseTree node)
637     if(is(T == char)
638     || is(T == string)
639     || is(T == int)
640     || is(T == double)
641     )
642 {
643     import std.conv : to;
644 
645     static if (is(T == char))
646     {
647         assert(node.name == LiteralType.charLiteral);
648         return node.children[0].matches[0][0];
649     }
650     else static if (is(T == string))
651     {
652         assert(node.name == LiteralType.stringLiteral);
653         return node.children[0].matches[0];
654     }
655     else static if (is(T == int))
656     {
657         assert(node.name == LiteralType.intLiteral);
658         return node.matches[0].to!int();
659     }
660     else static if (is(T == double))
661     {
662         //assert(node.name == LiteralType.floatLiteral);
663         return node.matches[0].to!double();
664     }
665     else
666     {
667         static assert(0, "?");
668     }
669 }
670 //dfmt on
671 
672 NumericParameter transformCharParameter(ParseTree node)
673 {
674     assert(node.name == SyntaxType.CharParameter);
675 
676     string symbol;
677     char defaultVal;
678     int valIndex;
679 
680     if (node.children.length == 0)
681     {
682         return new NumericParameter(symbol, "char", 1, double.nan, null, null);
683     }
684 
685     if (node.child(valIndex).name == SyntaxType.Identifier)
686     {
687         symbol = transformIdentifier(node.children[valIndex++]);
688     }
689 
690     if (node.child(valIndex).name == LiteralType.charLiteral)
691     {
692         defaultVal = readLiteral!char(node.children[valIndex]);
693     }
694 
695     return new NumericParameter(symbol, "char", 1, double.nan, null,
696             new NumericConstant(cast(double) defaultVal, null));
697 }
698 
699 NumericParameter transformNumericParameter(ParseTree node)
700 {
701     //assert(node.name == SyntaxType.IntParameter);
702 
703     immutable string type = node.children[0].matches[0];
704     int cur = 1;
705 
706     NumericRange range;
707     NumericTransform transform;
708     string symbol;
709     NumericConstant defaultValue;
710 
711     // dfmt off
712     if (node.child(cur).name == SyntaxType.IntRange
713      || node.child(cur).name == SyntaxType.FloatRange)
714     {
715         range = transformNumericRange(node.children[cur++]);
716     }
717     if (node.child(cur).name == SyntaxType.IntTransform
718      || node.child(cur).name == SyntaxType.FloatTransform)
719     {
720         transform = transformNumericTransform(node.children[cur++]);
721     }
722     if (node.child(cur).name == SyntaxType.Identifier)
723     {
724         symbol = transformIdentifier(node.children[cur++]);
725     }
726     if (node.child(cur).name == SyntaxType.IntConstant
727      || node.child(cur).name == SyntaxType.FloatConstant)
728     {
729         defaultValue = transformNumericConstant(node.children[cur++]);
730     }
731     // dfmt on
732 
733     auto parameter = new NumericParameter(symbol, type, 1, double.nan, range, defaultValue);
734     if (transform !is null)
735     {
736         if (transform.operator == Operator.modulo)
737         {
738             parameter.modulus = transform.value;
739         }
740         else if (transform.operator == Operator.divide)
741         {
742             parameter.divisor = cast(uint) transform.value;
743         }
744         else if (transform.operator == Operator.multiply)
745         {
746             //parameter.divisor = (1 / transform.value);
747         }
748     }
749     return parameter;
750 }
751 
752 NumericConstant transformNumericConstant(ParseTree node)
753 {
754     //assert(node.name == SyntaxType.IntConstant);
755 
756     immutable double value = readLiteral!double(node.children[0]);
757     NumericTransform transform;
758 
759     if (node.children.length > 1)
760     {
761         transform = transformNumericTransform(node.children[1]);
762     }
763 
764     return new NumericConstant(value, transform);
765 }
766 
767 NumericTransform transformNumericTransform(ParseTree node)
768 {
769     //assert(node.name == SyntaxType.IntTransform);
770 
771     Operator op = cast(Operator) node.children[0].matches[0];
772     immutable double value = readLiteral!double(node.children[1]);
773     NumericTransform next;
774 
775     if (node.children.length > 2)
776     {
777         next = transformNumericTransform(node.children[2]);
778     }
779 
780     return new NumericTransform(op, value, next);
781 }
782 
783 NumericRange transformNumericRange(ParseTree node)
784 {
785     // assert(node.name == SyntaxType.IntRange);
786 
787     int lower;
788     int upper = readLiteral!int(node.children[0]);
789 
790     if (node.children.length == 2)
791     {
792         lower = upper;
793         upper = readLiteral!int(node.children[1]);
794     }
795 
796     return new NumericRange(lower, upper);
797 }
798 
799 void swap(T)(T* left, T* right)
800 {
801     const auto tmp = left;
802     left = right;
803     right = tmp;
804 }
805 
806 SizedParameter transformSizedParameter(ParseTree node)
807 {
808     assert(node.name == SyntaxType.SizedParameter);
809 
810     string type = node.children[0].matches[0];
811     SizeConstraint size;
812     string symbol;
813     string defaultVal;
814 
815     int cur = 1;
816 
817     if (node.child(cur).name == SyntaxType.SizeConstraint)
818     {
819         size = transformSizeConstraint(node.children[cur++]);
820     }
821     if (node.child(cur).name == SyntaxType.Identifier)
822     {
823         symbol = transformIdentifier(node.children[cur++]);
824     }
825     if (node.child(cur).name == LiteralType.stringLiteral)
826     {
827         defaultVal = readLiteral!string(node.child(cur));
828     }
829 
830     return new SizedParameter(symbol, type, size, defaultVal);
831 }
832 
833 SizeConstraint transformSizeConstraint(ParseTree node)
834 {
835     assert(node.name == SyntaxType.SizeConstraint);
836 
837     int upper = readLiteral!int(node.children[0]);
838     immutable int lower = upper;
839 
840     if (node.children.length == 2)
841     {
842         upper = readLiteral!int(node.children[1]);
843     }
844 
845     return new SizeConstraint(lower, upper);
846 }
847 
848 StructParameter transformStructParameter(ParseTree node)
849 {
850     assert(node.name == SyntaxType.StructParameter);
851 
852     string type = transformIdentifier(node.children[0]);
853     string symbol;
854 
855     if (node.children.length > 1)
856     {
857         symbol = transformIdentifier(node.children[1]);
858     }
859 
860     return new StructParameter(symbol, type);
861 }
862 
863 ArrayParameter transformArrayParameter(ParseTree node)
864 {
865     assert(node.name == SyntaxType.ArrayParameter);
866 
867     string type = node.children[0].matches[0];
868     string symbol;
869     ArrayRange size;
870 
871     int cur = 1;
872     if (node.child(cur).name == SyntaxType.Identifier)
873     {
874         symbol = transformIdentifier(node.children[cur++]);
875     }
876 
877     size = transformArrayRange(node.child(cur));
878 
879     return new ArrayParameter(symbol, type, size);
880 }
881 
882 ArrayRange transformArrayRange(ParseTree node)
883 {
884     assert(node.name == SyntaxType.ArrayRange);
885 
886     if (node.children.length == 0)
887     {
888         return new ArrayRange(0, 0);
889     }
890 
891     int minLength;
892     int maxLength;
893 
894     if (node.children.length == 1)
895     {
896         maxLength = readLiteral!int(node.children[0]);
897         minLength = maxLength;
898     }
899     else if (node.children.length == 2)
900     {
901         minLength = readLiteral!int(node.children[0]);
902         maxLength = readLiteral!int(node.children[1]);
903     }
904 
905     return new ArrayRange(minLength, maxLength);
906 }