1 module bamboo.types;
2 
3 import std.array;
4 import std.algorithm;
5 import std.conv;
6 import std.range;
7 
8 import boilerplate;
9 
10 import bamboo.hashgen;
11 import bamboo.util;
12 
13 private
14 {
15     enum string generateVisit = q{
16         override SyntaxKind syntaxKind() @property
17         {
18             return mixin("SyntaxKind." ~ (typeof(this).stringof));
19         }
20         override void visit(Visitor visitor)
21         {
22             visitor.visit(this);
23         }
24     };
25 
26     enum string generateSyntaxNode = q{
27         mixin(GenerateThis);
28         mixin(generateVisit);
29 
30         static if(is(typeof(symbol)))
31         {
32             override string toString()
33             {
34                 return typeid(this).name ~ " " ~ symbol;
35             }
36         }
37     };
38 }
39 
40 /// Represents the type of a SyntaxNode.
41 enum SyntaxKind
42 {
43     Module,
44     ImportDeclaration,
45     KeywordList,
46     BuiltinType,
47     KeywordDeclaration,
48     StructDeclaration,
49     ClassDeclaration,
50     AliasDeclaration,
51     MolecularField,
52     AtomicField,
53     ParameterField,
54     NumericParameter,
55     NumericRange,
56     NumericTransform,
57     NumericConstant,
58     SizedParameter,
59     SizeConstraint,
60     StructParameter,
61     ArrayParameter,
62     ArrayRange,
63 }
64 
65 //dfmt off
66 
67 /// Represents an operator in an $(D IntTransformation) or a $(D FloatTransformation).
68 enum Operator
69 {
70     modulo      = "%",
71     multiply    = "*",
72     add         = "+",
73     subtract    = "-",
74     divide      = "/",
75 }
76 //dfmt on
77 
78 // dfmt off
79 /// Represents the fundamental type of a node.
80 enum Type
81 {
82     int8, int16, int32, int64,
83     uint8, uint16, uint32, uint64,
84     char_,
85     float32, float64,
86 
87     string_,
88     varstring,
89     blob,
90     varblob,
91     array,
92     vararray,
93 
94     struct_,
95     method,
96     
97     invalid,
98 }
99 // dfmt on
100 
101 /// Represents an object which can act upon a $(D SyntaxNode).
102 abstract class Visitor
103 {
104     /// Visits the given $(D SyntaxNode).
105     void visitNode(SyntaxNode node)
106     {
107         final switch (node.syntaxKind)
108         {
109         case SyntaxKind.Module:
110             return visit(cast(Module) node);
111         case SyntaxKind.ImportDeclaration:
112             return visit(cast(ImportDeclaration) node);
113         case SyntaxKind.KeywordList:
114             return visit(cast(KeywordList) node);
115         case SyntaxKind.BuiltinType:
116             return visit(cast(BuiltinType) node);
117         case SyntaxKind.KeywordDeclaration:
118             return visit(cast(KeywordDeclaration) node);
119         case SyntaxKind.StructDeclaration:
120             return visit(cast(StructDeclaration) node);
121         case SyntaxKind.ClassDeclaration:
122             return visit(cast(ClassDeclaration) node);
123         case SyntaxKind.AliasDeclaration:
124             return visit(cast(AliasDeclaration) node);
125         case SyntaxKind.MolecularField:
126             return visit(cast(MolecularField) node);
127         case SyntaxKind.AtomicField:
128             return visit(cast(AtomicField) node);
129         case SyntaxKind.ParameterField:
130             return visit(cast(ParameterField) node);
131         case SyntaxKind.NumericParameter:
132             return visit(cast(NumericParameter) node);
133         case SyntaxKind.NumericRange:
134             return visit(cast(NumericRange) node);
135         case SyntaxKind.NumericTransform:
136             return visit(cast(NumericTransform) node);
137         case SyntaxKind.NumericConstant:
138             return visit(cast(NumericConstant) node);
139         case SyntaxKind.SizedParameter:
140             return visit(cast(SizedParameter) node);
141         case SyntaxKind.SizeConstraint:
142             return visit(cast(SizeConstraint) node);
143         case SyntaxKind.StructParameter:
144             return visit(cast(StructParameter) node);
145         case SyntaxKind.ArrayParameter:
146             return visit(cast(ArrayParameter) node);
147         case SyntaxKind.ArrayRange:
148             return visit(cast(ArrayRange) node);
149         }
150     }
151 
152     /// Visits the given $(D Module).
153     abstract void visit(Module file);
154 
155     /// Visits the given $(D ImportDeclaration).    
156     abstract void visit(ImportDeclaration node);
157 
158     /// Visits the given $(D KeywordList).    
159     abstract void visit(KeywordList node);
160 
161     /// Visits the given $(D BuiltinType).    
162     abstract void visit(BuiltinType node);
163 
164     /// Visits the given $(D KeywordDeclaration).    
165     abstract void visit(KeywordDeclaration node);
166 
167     /// Visits the given $(D StructDeclaration).    
168     abstract void visit(StructDeclaration node);
169 
170     /// Visits the given $(D ClassDeclaration).    
171     abstract void visit(ClassDeclaration node);
172 
173     /// Visits the given $(D AliasDeclaration).    
174     abstract void visit(AliasDeclaration node);
175 
176     /// Visits the given $(D MolecularField).    
177     abstract void visit(MolecularField node);
178 
179     /// Visits the given $(D AtomicField).    
180     abstract void visit(AtomicField node);
181 
182     /// Visits the given $(D ParameterField).    
183     abstract void visit(ParameterField node);
184 
185     /// Visits the given $(D IntParameter).    
186     abstract void visit(NumericParameter node);
187 
188     /// Visits the given $(D IntRange).    
189     abstract void visit(NumericRange node);
190 
191     /// Visits the given $(D IntTransform).    
192     abstract void visit(NumericTransform node);
193 
194     /// Visits the given $(D IntConstant).    
195     abstract void visit(NumericConstant node);
196 
197     /// Visits the given $(D SizedParameter).    
198     abstract void visit(SizedParameter node);
199 
200     /// Visits the given $(D SizeConstraint).    
201     abstract void visit(SizeConstraint node);
202 
203     /// Visits the given $(D StructParameter).    
204     abstract void visit(StructParameter node);
205 
206     /// Visits the given $(D ArrayParameter).    
207     abstract void visit(ArrayParameter node);
208 
209     /// Visits the given $(D ArrayRange).    
210     abstract void visit(ArrayRange node);
211 
212 }
213 
214 /// Represents an abstract syntax node.
215 abstract class SyntaxNode
216 {
217     /// Gets the $(D SyntaxKind) for this type of node.
218     abstract SyntaxKind syntaxKind() @property;
219 
220     /// Calls the $(S Visitor)'s analogous $(D Visitor.visit) method.
221     abstract void visit(Visitor visitor);
222 }
223 
224 /// Represents a module in the dclass system.
225 class Module : SyntaxNode
226 {
227     /// The optional name of this module.
228     string symbol;
229     /// Get the import statements in this module.
230     ImportDeclaration[] importDeclarations;
231 
232     /// The aliases defined in this module.
233     AliasDeclaration[] aliases;
234 
235     /// The classes defined in this module.
236     ClassDeclaration[] classes;
237 
238     /// The structs defined in this module.
239     StructDeclaration[] structs;
240 
241     /// The keywords defined in this module.
242     KeywordDeclaration[] keywords;
243 
244     /// The id of the last type defined in this module.
245     ushort lastTypeId;
246 
247     /// The id of the last field defined in this module.
248     ushort lastFieldId;
249 
250     mixin(generateSyntaxNode);
251 
252     /// Gets an array of `StructDeclaration` and `ClassDeclaration` objects
253     /// sorted by their id.
254     TypeDeclaration[] typesById() pure @safe nothrow
255     {
256         import std.array : array;
257         import std.conv : to;
258         import std.range : chain;
259 
260         // dfmt off
261         auto result = chain(classes, structs)
262                       .array // BAD: for some reason, we need this call to `array`...
263                       .sort!"a.id < b.id"
264                       .array;
265         // dfmt on
266 
267         return result;
268     }
269 
270     /// Finds a `ClassDeclaration` or a `StructDeclaration` with the given name.
271     TypeDeclaration findType(in string name) pure @safe nothrow
272     {
273         auto candidate = typesById.chain(aliases).filter!(x => x.symbol == name).takeOne;
274         if (candidate.empty)
275         {
276             return null;
277         }
278         return candidate.front;
279     }
280 
281     TypeDeclaration findType(in int id) pure @safe nothrow
282     {
283         auto candidate = typesById.chain(aliases).filter!(x => x.id == id).takeOne;
284         if (candidate.empty)
285         {
286             return null;
287         }
288         return candidate.front;
289     }
290 }
291 
292 /// Represents an import statement.
293 class ImportDeclaration : SyntaxNode
294 {
295     /// The package from which to import.
296     string packageName;
297 
298     /// The symbols to import.
299     string[] symbols;
300 
301     mixin(generateSyntaxNode);
302 }
303 
304 /// Base class for module-level type declarations.
305 /// A type is a keyword declaration, a class declaration,
306 /// a struct declaration, or an alias/typedef declaration.
307 abstract class TypeDeclaration : SyntaxNode
308 {
309     /// Represents a type of TypeDeclaration.
310     enum Kind
311     {
312         keywordDeclaration,
313         classDeclaration,
314         structDeclaration,
315         aliasDeclaration,
316         builtin,
317     }
318 
319     /// The id of this Type.
320     int id;
321 
322     /// The symbol name of this type.
323     string symbol;
324 
325     /// Gets the kind of TypeDeclaration this object represents.
326     abstract Kind kind();
327 
328     mixin(GenerateThis);
329 
330     /// Gets the `Type` associated with this `TypeDeclaration`.
331     abstract inout(Type) type() inout @safe pure nothrow @property;
332 
333     /// Gets all fields declared on this type.
334     abstract inout(FieldDeclaration[]) getFields() inout @safe pure nothrow @property;
335 
336     /// Find a field by its id.
337     final FieldDeclaration getField(int id)
338     {
339         return getFields.filter!(x => x.id == id).takeOne.front;
340     }
341 
342     /// Find a field with its name.
343     final FieldDeclaration getField(string symbol)
344     {
345         return getFields.filter!(x => x.name == symbol).takeOne.front;
346     }
347 }
348 
349 /// Represents a fundamental type.
350 class BuiltinType : TypeDeclaration
351 {
352     /// The type of this declaration.
353     Type _type;
354 
355     /// Ditto
356     override TypeDeclaration.Kind kind()
357     {
358         return TypeDeclaration.Kind.builtin;
359     }
360 
361     /// Ditto
362     override inout(Type) type() inout @safe pure nothrow @property
363     {
364         return _type;
365     }
366 
367     /// Ditto.
368     override inout(FieldDeclaration[]) getFields() inout @safe pure nothrow @property
369     {
370         return [];
371     }
372 
373     mixin(generateSyntaxNode);
374 }
375 
376 /// Represents a list of keywords attached to a field.
377 class KeywordList : SyntaxNode
378 {
379     /// The list of keywords.
380     string[] keywords;
381 
382     alias keywords this;
383 
384     mixin(generateSyntaxNode);
385 }
386 
387 /// Represents the value of a `keyword` statement.
388 class KeywordDeclaration : TypeDeclaration
389 {
390     /// Ditto
391     override TypeDeclaration.Kind kind()
392     {
393         return TypeDeclaration.Kind.keywordDeclaration;
394     }
395 
396     mixin(generateSyntaxNode);
397 
398     override inout(FieldDeclaration[]) getFields() inout @safe pure nothrow @property
399     {
400         return [];
401     }
402 
403     /// Ditto
404     override inout(Type) type() inout @safe pure nothrow @property
405     {
406         return Type.invalid;
407     }
408 }
409 
410 /// Represents a struct declaration.
411 class StructDeclaration : TypeDeclaration
412 {
413     override TypeDeclaration.Kind kind()
414     {
415         return TypeDeclaration.Kind.structDeclaration;
416     }
417 
418     /// The atomic parts of this struct.
419     ParameterField[] parameters;
420 
421     mixin(generateSyntaxNode);
422 
423     /// Ditto
424     override inout(Type) type() inout @safe pure nothrow @property
425     {
426         return Type.struct_;
427     }
428 
429     override inout(FieldDeclaration[]) getFields() inout @safe pure nothrow @property
430     {
431         return (() @trusted => cast(FieldDeclaration[]) parameters)();
432     }
433 }
434 
435 /// Represents a dclass declaration.
436 class ClassDeclaration : TypeDeclaration
437 {
438     override TypeDeclaration.Kind kind()
439     {
440         return TypeDeclaration.Kind.classDeclaration;
441     }
442 
443     /// The superclasses for this type.
444     @(This.Exclude)
445     ClassDeclaration[] superclasses;
446 
447     string[] superclassNames;
448 
449     /// Whether this $(D ClassDeclaration) should be generated as an
450     /// `interface`.
451     bool isInterface;
452 
453     /// The constructor for this type.
454     FieldDeclaration constructor;
455 
456     /// The fields and RPC methods defined on this class.
457     FieldDeclaration[] fields;
458 
459     mixin(generateSyntaxNode);
460 
461     /// Ditto
462     override inout(Type) type() inout @safe pure nothrow @property
463     {
464         return Type.struct_;
465     }
466 
467     /// Resolves superclasses.
468     void resolve(Module file) @safe nothrow
469     {
470         if (hasSuperclass())
471         {
472             foreach (superclass; superclassNames)
473             {
474                 superclasses ~= (() @trusted => cast(ClassDeclaration) file.findType(superclass))();
475             }
476         }
477     }
478 
479     /// Checks whether this ClassDeclaration has a super class.
480     bool hasSuperclass() pure nothrow inout @nogc @safe @property
481     {
482         return superclassNames.length > 0;
483     }
484 
485     /// Get the direct parents of this dclass.
486     ClassDeclaration[] parents() pure @safe @property
487     {
488         return superclasses;
489     }
490 
491     /// Gets whether this class has a constructor.
492     bool hasConstructor() pure @nogc @property
493     {
494         return constructor !is null;
495     }
496 
497     /// Ditto.
498     override inout(FieldDeclaration[]) getFields() inout @safe pure nothrow @property
499     {
500         return fields;
501     }
502 }
503 
504 /// Represents a typedef statement.
505 class AliasDeclaration : TypeDeclaration
506 {
507     override TypeDeclaration.Kind kind()
508     {
509         return TypeDeclaration.Kind.aliasDeclaration;
510     }
511 
512     /// The type to substitute the symbol for.
513     /// For example, `typedef doId uint32` would
514     /// set the aliasedTypeName to uint32.
515     string aliasedTypeName;
516 
517     @(This.Exclude)
518     TypeDeclaration aliasedType;
519 
520     mixin(generateSyntaxNode);
521 
522     /// Ditto
523     override inout(Type) type() inout @safe pure nothrow @property
524     {
525         enum types = genbuiltins;
526 
527         if (auto ret = aliasedTypeName in types)
528         {
529             return *ret;
530         }
531 
532         return Type.invalid;
533     }
534 
535     /// Ditto.
536     override inout(FieldDeclaration[]) getFields() inout @safe pure nothrow @property
537     {
538         return [];
539     }
540 }
541 
542 /// Abstract class representing a field.
543 abstract class FieldDeclaration : SyntaxNode
544 {
545     /// The id of this field.
546     int id;
547     mixin(GenerateThis);
548 
549     /// Gets the symbol name of this field.
550     abstract string name() @property;
551 
552     abstract string[] attributes() @property;
553 
554     final bool hasKeyword(string keyword)
555     {
556         return attributes.canFind(keyword);
557     }
558 }
559 
560 /// Represents a field which swizzles atomic fields.
561 class MolecularField : FieldDeclaration
562 {
563     /// The name of this field.
564     string symbol;
565 
566     /// The atomic fields which make up this field.
567     @(This.Exclude)
568     FieldDeclaration[] references;
569 
570     /// The names of the references. Used for resolution.
571     string[] referenceNames;
572 
573     mixin(generateSyntaxNode);
574 
575     /// Ditto
576     override string name() @property
577     {
578         return symbol;
579     }
580 
581     override string[] attributes() @property
582     {
583         return [];
584     }
585 }
586 
587 /// Represents a method.
588 class AtomicField : FieldDeclaration
589 {
590     /// The name of this field.
591     string symbol;
592 
593     /// The parameters for this field.
594     Parameter[] parameters;
595 
596     /// The keywords applied to this field.
597     KeywordList keywords;
598     mixin(generateSyntaxNode);
599 
600     /// Get the fundamental type of this field.
601     /// Returns: `Type.method`.
602     Type type()
603     {
604         return Type.method;
605     }
606 
607     /// Ditto
608     override string name() @property
609     {
610         return symbol;
611     }
612 
613     override string[] attributes() @property
614     {
615         return keywords;
616     }
617 }
618 
619 /// Represents a plain field.
620 class ParameterField : FieldDeclaration
621 {
622     /// Get the parameter for this field.
623     Parameter parameter;
624 
625     /// Get the keywords on this field.
626     KeywordList keywords;
627     mixin(generateSyntaxNode);
628 
629     /// Ditto
630     override string name() @property
631     {
632         return parameter.symbol;
633     }
634 
635     override string[] attributes() @property
636     {
637         return keywords;
638     }
639 }
640 
641 /// Abstract class representing a parameter.
642 class Parameter : SyntaxNode
643 {
644     /// Get the name of this parameter.
645     string symbol;
646 
647     /// Get the fundamental type of this parameter.
648     abstract Type parameterType() @property;
649     abstract string parameterTypeName() @property;
650 
651     mixin(GenerateThis);
652 }
653 
654 /// Represents a parameter of a numeric type.
655 class NumericParameter : Parameter
656 {
657     private @(This.Exclude)
658     {
659         double _origMod;
660     }
661 
662     /**
663      * The type of this parameter.
664      * 
665      * Remarks:
666      * May be `char`, `int8`, `int16`, `int32`,
667      * `int64`, `uint8`, `uint16`, `uint32`,
668      * `uint64`, `float32`, or `float64`.
669      */
670     string type;
671 
672     /// The divisor 
673     uint divisor = 1;
674 
675     private double _modulus;
676 
677     /// The possible range of this parameter.
678     /// This may be null.
679     NumericRange range;
680 
681     version (none)
682     {
683         // Represents any transforms present on this parameter.
684         // This may be null.    
685         NumericTransform transform;
686     }
687 
688     /// The default value of this parameter.
689     /// This may be null.    
690     NumericConstant defaultValue;
691 
692     mixin(generateSyntaxNode);
693 
694     bool hasRange()
695     {
696         import std.math : isNaN;
697 
698         return range !is null;
699     }
700 
701     double modulus() @property
702     {
703         return _modulus;
704     }
705 
706     bool modulus(double value) @property
707     {
708         import std.math : floor;
709 
710         if (value == double.nan)
711         {
712             _modulus = value;
713             return true;
714         }
715 
716         if (modulus <= 0.0)
717         {
718             return false;
719         }
720 
721         auto floatModulus = value * divisor;
722         auto uintModulus = cast(uint) floor(value * divisor + 0.5);
723 
724         switch (parameterType) with (Type)
725         {
726         case int8:
727             if (uintModulus < 1 || cast(ushort)(ubyte.max + 1 < uintModulus))
728             {
729                 return false;
730             }
731             _modulus = uintModulus;
732             break;
733         case int16:
734             if (uintModulus < 1 || cast(uint)(ushort.max + 1 < uintModulus))
735             {
736                 return false;
737             }
738             _modulus = uintModulus;
739             break;
740         case int32:
741             if (uintModulus < 1 || cast(ulong)(uint.max + 1 < uintModulus))
742             {
743                 return false;
744             }
745             _modulus = uintModulus;
746             break;
747         case int64:
748             if (uintModulus < 1)
749             {
750                 return false;
751             }
752             _modulus = uintModulus;
753             break;
754         case uint8:
755             if (uintModulus < 1 || cast(ushort)(ubyte.max + 1 < uintModulus))
756             {
757                 return false;
758             }
759             _modulus = uintModulus;
760             break;
761         case uint16:
762             if (uintModulus < 1 || cast(uint)(ushort.max + 1 < uintModulus))
763             {
764                 return false;
765             }
766             _modulus = uintModulus;
767             break;
768         case uint32:
769             if (uintModulus < 1 || cast(ulong)(uint.max + 1 < uintModulus))
770             {
771                 return false;
772             }
773             _modulus = uintModulus;
774             break;
775         case uint64:
776             if (uintModulus < 1)
777             {
778                 return false;
779             }
780             _modulus = uintModulus;
781             break;
782         case float32:
783         case float64:
784             _modulus = floatModulus;
785             break;
786         default:
787             assert(0);
788         }
789         _origMod = value;
790         return true;
791     }
792 
793     bool hasModulus()
794     {
795         import std.math : isNaN;
796 
797         return !isNaN(_modulus);
798     }
799 
800     override Type parameterType() @property
801     {
802         switch (type)
803         {
804         case "char":
805             return Type.char_;
806         case "int8":
807             return Type.int8;
808         case "int16":
809             return Type.int16;
810         case "int32":
811             return Type.int32;
812         case "int64":
813             return Type.int64;
814         case "uint8":
815             return Type.uint8;
816         case "uint16":
817             return Type.uint16;
818         case "uint32":
819             return Type.uint32;
820         case "uint64":
821             return Type.uint64;
822         case "float32":
823             return Type.float32;
824         case "float64":
825             return Type.float64;
826         default:
827             assert(0, "Invalid type " ~ type);
828         }
829     }
830 
831     override string parameterTypeName() @property
832     {
833         return type;
834     }
835 }
836 
837 /// Represents the minimum and maximum value of a NumericParameter.
838 class NumericRange : SyntaxNode
839 {
840     /// The minimum value of this range.
841     double min;
842 
843     /// The maximum value of this range.
844     double max;
845 
846     mixin(generateSyntaxNode);
847 }
848 
849 /// Represents a transformation on a NumericParameter or IntConstant.
850 class NumericTransform : SyntaxNode
851 {
852     /// The operator to apply.
853     Operator operator;
854 
855     /// The value to apply.
856     double value;
857 
858     /// The next transformation.
859     /// This may be null.    
860     NumericTransform next;
861 
862     /// Instantiates an IntTransform.
863     this(Operator op, double value, NumericTransform next)
864     {
865         operator = op;
866         this.value = value;
867         this.next = next;
868     }
869 
870     mixin(generateVisit);
871 }
872 
873 /// Represents an integer constant.
874 class NumericConstant : SyntaxNode
875 {
876     /// The value of this constant.
877     double value;
878 
879     /// Any transformations which need to be applied.
880     NumericTransform transform;
881 
882     mixin(generateSyntaxNode);
883 }
884 
885 /// Represents a blob or string parameter.
886 class SizedParameter : Parameter
887 {
888     /// The type of this parameter.
889     string type;
890 
891     /// The size constraints of this parameter.
892     /// If the minimum value equals the maximum value,
893     /// This is a fixed-sized parameter.  Otherwise,
894     /// it's a variable-sized parameter.
895     SizeConstraint size;
896 
897     /// The default value of this parameter.
898     /// This may be null.  This is only valid
899     /// on string-type parameters.
900     string defaultVal;
901 
902     mixin(generateSyntaxNode);
903 
904     bool hasRange()
905     {
906         // dfmt off
907         return size !is null 
908             && size.maxSize != 0;
909         // dfmt on
910     }
911 
912     override Type parameterType() @property
913     {
914         if (hasRange && size.isFixedLength)
915         {
916             if (type == "string")
917             {
918                 return Type.string_;
919             }
920             else if (type == "blob")
921             {
922                 return Type.blob;
923             }
924         }
925         else
926         {
927             if (type == "string")
928             {
929                 return Type.varstring;
930             }
931             else if (type == "blob")
932             {
933                 return Type.varblob;
934             }
935         }
936         assert(0);
937     }
938 
939     override string parameterTypeName() @property
940     {
941         return type;
942     }
943 }
944 
945 /// Represents the constraints on a SizedParameter.
946 class SizeConstraint : SyntaxNode
947 {
948     /// The minimum size of this parameter.
949     int minSize;
950 
951     /// The maximum size of this parameter.    
952     int maxSize;
953 
954     mixin(generateSyntaxNode);
955 
956     /// Gets whether this parameter is fixed-length.
957     bool isFixedLength() pure @property
958     {
959         return minSize == maxSize && maxSize > 1;
960     }
961 }
962 
963 class StructParameter : Parameter
964 {
965     string typeName;
966 
967     @(This.Exclude)
968     TypeDeclaration type;
969 
970     mixin(generateSyntaxNode);
971 
972     TypeDeclaration resolveType(Module mod)
973     {
974         return mod.findType(typeName);
975     }
976 
977     override Type parameterType() @property
978     {
979         return type.type;
980     }
981 
982     override string parameterTypeName() @property
983     {
984         return typeName;
985     }
986 }
987 
988 class ArrayParameter : Parameter
989 {
990     string type;
991     ArrayRange size;
992 
993     @(This.Exclude)
994     TypeDeclaration elementType;
995 
996     @(This.Exclude)
997     Parameter element;
998 
999     mixin(generateSyntaxNode);
1000 
1001     TypeDeclaration resolveType(Module mod)
1002     {
1003         return mod.findType(type);
1004     }
1005 
1006     bool hasRange()
1007     {
1008         // dfmt off
1009         return size !is null 
1010             && size.maxLength != 0;
1011         // dfmt on
1012     }
1013 
1014     override Type parameterType() @property
1015     {
1016         if (size.isFixedLength)
1017         {
1018             return Type.array;
1019         }
1020         else
1021         {
1022             return Type.vararray;
1023         }
1024     }
1025 
1026     override string parameterTypeName() @property
1027     {
1028         return type;
1029     }
1030 
1031 }
1032 
1033 class ArrayRange : SyntaxNode
1034 {
1035     int minLength;
1036     int maxLength;
1037 
1038     mixin(generateSyntaxNode);
1039 
1040     bool isFixedLength() pure @property
1041     {
1042         return minLength == maxLength && maxLength > 1;
1043     }
1044 }