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 }