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