1 module dadt.parser; 2 import pegged.grammar; 3 import std.algorithm; 4 import std.format; 5 import std.string; 6 import std.stdio; 7 import std.array; 8 import std.ascii; 9 import dadt.util; 10 11 mixin(grammar(` 12 DADT: 13 TypeDeclare < "type" BaseConstructor "=" ConstructorList Deriving? 14 15 BaseConstructor < TypeNameWithArgs / TypeNameWithoutArgs 16 17 TypeName <~ !Keyword [A-Z_] [a-zA-Z0-9_]* 18 19 Field < FieldOfDelegate / FieldOfFunction / FieldOfArray / FieldWithArgs / FieldName 20 FieldArgs < "()" / :"(" Field ("," Field)* :")" 21 FieldWithArgs < FieldName "!" FieldArgs 22 FieldOfArray < (FieldWithArgs / FieldName) ArrayBracket+ 23 FieldOfDelegate < "[" Field ("->" Field)+ "]" 24 FieldOfFunction < "<" Field ("->" Field)+ ">" 25 FieldName <~ !Keyword [a-zA-Z_] [a-zA-Z0-9_]* 26 27 ArrayBracket < UnsizedBracket / SizedBracket 28 29 UnsizedBracket < "[]" 30 SizedBracket < "[" ArraySize "]" 31 ArraySize <~ [a-zA-Z0-9_]* 32 33 TypeNameWithoutArgs < TypeName 34 TypeNameWithArgs < TypeName ParameterList 35 ParameterList < "()" / :"(" TypeName ("," TypeName)* :")" 36 37 RecordField < FieldName ":" Field 38 RecordFields < (RecordField ";"?)+ 39 Record < "{" RecordFields "}" 40 41 ConstructorWithRecord< "|"? TypeName "of" Record 42 ConstructorWithField < "|"? TypeName "of" Field ("*" Field)* 43 Constructor < "|"? TypeName 44 ConstructorDeclare < ConstructorWithRecord / ConstructorWithField / Constructor 45 ConstructorList < ConstructorDeclare+ 46 47 Deriving < "[@@deriving" DerivingArgs "]" 48 DerivingArgs < DerivingArg ("," DerivingArg)* 49 DerivingArg <~ !Keyword [a-zA-Z_] [a-zA-Z0-9_]* 50 51 Keyword <~ "of" 52 Integer <~ digit+ 53 `)); 54 55 interface ASTElement { 56 } 57 58 class BaseConstructor : ASTElement { 59 TypeName baseName; 60 ParameterList parameterList; 61 62 this(TypeName baseName) { 63 this.baseName = baseName; 64 this.parameterList = new ParameterList([]); 65 } 66 67 this(TypeName baseName, ParameterList parameterList) { 68 this.baseName = baseName; 69 this.parameterList = parameterList; 70 } 71 } 72 73 class TypeName : ASTElement { 74 string name; 75 76 this(string name) { 77 this.name = name; 78 } 79 } 80 81 interface Field : ASTElement { 82 const string typeString(); 83 } 84 85 class FieldName : Field { 86 string fieldName; 87 88 this(string fieldName) { 89 this.fieldName = fieldName; 90 } 91 92 override const string typeString() { 93 return fieldName; 94 } 95 } 96 97 class FieldArgs : ASTElement { 98 Field[] fields; 99 100 this(Field[] fields) { 101 this.fields = fields; 102 } 103 } 104 105 class FieldWithArgs : Field { 106 FieldName fieldName; 107 FieldArgs fieldArgs; 108 109 this(FieldName fieldName, FieldArgs fieldArgs) { 110 this.fieldName = fieldName; 111 this.fieldArgs = fieldArgs; 112 } 113 114 override const string typeString() { 115 const string baseType = fieldName.typeString; 116 string[] fields; 117 string argsStr; 118 foreach (field; fieldArgs.fields) { 119 fields ~= field.typeString; 120 } 121 if (fields.length) { 122 argsStr = "!(" ~ fields.join(", ") ~ ")"; 123 124 return baseType ~ argsStr; 125 } else { 126 return baseType; 127 } 128 } 129 } 130 131 interface ArrayBracket : ASTElement { 132 const bool isSized(); 133 } 134 135 class ArraySize : ASTElement { 136 string size; 137 138 this(string size) { 139 this.size = size; 140 } 141 } 142 143 class SizedBracket : ArrayBracket { 144 ArraySize size; 145 146 this(ArraySize size) { 147 this.size = size; 148 } 149 150 override const bool isSized() { 151 return true; 152 } 153 } 154 155 class UnsizedBracket : ArrayBracket { 156 this() { 157 } 158 159 override const bool isSized() { 160 return false; 161 } 162 } 163 164 class FieldOfArray : Field { 165 Field field; 166 ArrayBracket bracket; 167 168 this(Field field, ArrayBracket bracket) { 169 this.field = field; 170 this.bracket = bracket; 171 } 172 173 override const string typeString() { 174 string baseType = field.typeString; 175 176 if (this.bracket.isSized) { 177 SizedBracket sb = cast(SizedBracket)bracket; 178 return baseType ~ "[%s]".format(sb.size.size); 179 } else { 180 return baseType ~ "[]"; 181 } 182 } 183 } 184 185 class FieldOfDelegate : Field { 186 Field retType; 187 Field[] args; 188 189 this(Field retType, Field[] args) { 190 this.retType = retType; 191 this.args = args; 192 } 193 194 override const string typeString() { 195 string args_str = this.args.map!(arg => arg.typeString()).join(", "); 196 if (args_str == "void") { 197 args_str = ""; 198 } 199 return "%s delegate(%s)".format(this.retType.typeString(), args_str); 200 } 201 } 202 203 class FieldOfFunction : Field { 204 Field retType; 205 Field[] args; 206 207 this(Field retType, Field[] args) { 208 this.retType = retType; 209 this.args = args; 210 } 211 212 override const string typeString() { 213 string args_str = this.args.map!(arg => arg.typeString()).join(", "); 214 if (args_str == "void") { 215 args_str = ""; 216 } 217 return "%s function(%s)".format(this.retType.typeString(), args_str); 218 } 219 } 220 221 class ParameterList : ASTElement { 222 TypeName[] parameters; 223 224 this(TypeName[] parameters) { 225 this.parameters = parameters; 226 } 227 } 228 229 class TypeDeclare : ASTElement { 230 BaseConstructor baseConstructor; 231 ConstructorList constructorList; 232 Deriving deriving; 233 234 this(BaseConstructor baseConstructor, ConstructorList constructorList) { 235 this.baseConstructor = baseConstructor; 236 this.constructorList = constructorList; 237 } 238 239 this(BaseConstructor baseConstructor, ConstructorList constructorList, Deriving deriving) { 240 this.baseConstructor = baseConstructor; 241 this.constructorList = constructorList; 242 this.deriving = deriving; 243 } 244 } 245 246 class ConstructorList : ASTElement { 247 Constructor[] constructors; 248 249 this(Constructor[] constructors) { 250 this.constructors = constructors; 251 } 252 } 253 254 class RecordField : ASTElement { 255 FieldName name; 256 Field field; 257 258 this(FieldName name, Field field) { 259 this.name = name; 260 this.field = field; 261 } 262 263 string getFieldTypeString() const { 264 return this.field.typeString(); 265 } 266 267 string getFieldName() const { 268 return this.name.fieldName; 269 } 270 } 271 272 class RecordFields : ASTElement { 273 RecordField[] fields; 274 this(RecordField[] fields) { 275 this.fields = fields; 276 } 277 } 278 279 enum ConstructorType { 280 Single, 281 Fields, 282 Record 283 } 284 285 class Constructor : ASTElement { 286 TypeName typeName; 287 Field[] fields; 288 RecordFields record; 289 ConstructorType type; 290 291 this(TypeName typeName) { 292 this.typeName = typeName; 293 this.type = ConstructorType.Single; 294 } 295 296 this(TypeName typeName, Field[] fields) { 297 this.typeName = typeName; 298 this.fields = fields; 299 this.type = ConstructorType.Fields; 300 } 301 302 this(TypeName typeName, RecordFields record) { 303 this.typeName = typeName; 304 this.record = record; 305 this.type = ConstructorType.Record; 306 } 307 308 string getTypeName() const { 309 return this.typeName.name; 310 } 311 } 312 313 enum DerivingType { 314 Show, 315 Ord, 316 Eq 317 } 318 319 enum DerivingMap = [ 320 "show" : DerivingType.Show, "ord" : DerivingType.Ord, "eq" : DerivingType.Eq 321 ]; 322 323 class DerivingArg : ASTElement { 324 DerivingType type; 325 326 this(DerivingType type) { 327 this.type = type; 328 } 329 } 330 331 class DerivingArgs : ASTElement { 332 DerivingArg[] args; 333 334 this(DerivingArg[] args) { 335 this.args = args; 336 } 337 } 338 339 class Deriving : ASTElement { 340 DerivingArgs args; 341 342 this(DerivingArgs args) { 343 this.args = args; 344 } 345 } 346 347 ASTElement buildAST(ParseTree p) { 348 /* 349 if (!__ctfe) { 350 writeln("p.name : ", p.name); 351 } 352 */ 353 354 final switch (p.name) { 355 case "DADT": 356 auto e = p.children[0]; 357 return buildAST(e); 358 case "DADT.BaseConstructor": 359 auto e = p.children[0]; 360 return buildAST(e); 361 case "DADT.TypeDeclare": 362 BaseConstructor baseConstructor = cast(BaseConstructor)buildAST(p.children[0]); 363 364 if (baseConstructor is null) { 365 throw new Error("Error in %s!".format(p.name)); 366 } 367 368 ConstructorList constructorList = cast(ConstructorList)buildAST(p.children[1]); 369 370 if (constructorList is null) { 371 throw new Error("Error in %s!".format(p.name)); 372 } 373 374 if (p.children.length == 2) { 375 return new TypeDeclare(baseConstructor, constructorList); 376 } else { 377 Deriving deriving = cast(Deriving)buildAST(p.children[2]); 378 379 if (deriving is null) { 380 throw new Error("Error in %s!".format(p.name)); 381 } 382 383 return new TypeDeclare(baseConstructor, constructorList, deriving); 384 } 385 case "DADT.TypeName": 386 string typeName = p.matches[0]; 387 return new TypeName(typeName); 388 case "DADT.TypeNameWithoutArgs": 389 TypeName baseName = cast(TypeName)buildAST(p.children[0]); 390 391 if (baseName is null) { 392 throw new Error("Error in %s!".format(p.name)); 393 } 394 395 return new BaseConstructor(baseName); 396 case "DADT.TypeNameWithArgs": 397 TypeName baseName = cast(TypeName)buildAST(p.children[0]); 398 ParameterList parameterList = cast(ParameterList)buildAST(p.children[1]); 399 if (baseName is null || parameterList is null) { 400 throw new Error("Error in %s!".format(p.name)); 401 } 402 403 return new BaseConstructor(baseName, parameterList); 404 405 case "DADT.Field": 406 auto e = p.children[0]; 407 return buildAST(e); 408 case "DADT.FieldWithArgs": 409 FieldName fieldName = cast(FieldName)buildAST(p.children[0]); 410 if (fieldName is null) { 411 throw new Error("Error in %s!".format(p.name)); 412 } 413 414 FieldArgs fieldArgs = cast(FieldArgs)buildAST(p.children[1]); 415 if (fieldArgs is null) { 416 throw new Error("Error in %s!".format(p.name)); 417 } 418 419 return new FieldWithArgs(fieldName, fieldArgs); 420 case "DADT.FieldArgs": 421 Field[] fields; 422 423 foreach (child; p.children) { 424 Field field = cast(Field)buildAST(child); 425 if (field is null) { 426 throw new Error("Error in %s!".format(p.name)); 427 } 428 fields ~= field; 429 } 430 431 return new FieldArgs(fields); 432 case "DADT.FieldOfArray": 433 Field field = cast(Field)buildAST(p.children[0]); 434 if (field is null) { 435 throw new Error("Error in %s!".format(p.name)); 436 } 437 438 ArrayBracket ab = cast(ArrayBracket)buildAST(p.children[1]); 439 if (ab is null) { 440 throw new Error("Error in %s!".format(p.name)); 441 } 442 443 return new FieldOfArray(field, ab); 444 case "DADT.ArrayBracket": 445 auto e = p.children[0]; 446 return buildAST(e); 447 case "DADT.ArraySize": 448 string size = p.matches[0]; 449 return new ArraySize(size); 450 case "DADT.SizedBracket": 451 ArraySize size = cast(ArraySize)buildAST(p.children[0]); 452 if (size is null) { 453 throw new Error("Error in %s!".format(p.name)); 454 } 455 456 return new SizedBracket(size); 457 case "DADT.UnsizedBracket": 458 return new UnsizedBracket; 459 case "DADT.FieldOfDelegate": 460 Field[] fields; 461 foreach (child; p.children) { 462 Field field = cast(Field)buildAST(child); 463 if (field is null) { 464 throw new Error("Error in %s!".format(p.name)); 465 } 466 fields ~= field; 467 } 468 Field retType = fields[$ - 1]; 469 return new FieldOfDelegate(retType, fields[0 .. $ - 1]); 470 case "DADT.FieldOfFunction": 471 Field[] fields; 472 foreach (child; p.children) { 473 Field field = cast(Field)buildAST(child); 474 if (field is null) { 475 throw new Error("Error in %s!".format(p.name)); 476 } 477 fields ~= field; 478 } 479 Field retType = fields[$ - 1]; 480 return new FieldOfFunction(retType, fields[0 .. $ - 1]); 481 case "DADT.FieldName": 482 string fieldName = p.matches[0]; 483 return new FieldName(fieldName); 484 case "DADT.ParameterList": 485 TypeName[] parameters; 486 foreach (child; p.children) { 487 TypeName typeName = cast(TypeName)buildAST(child); 488 if (typeName is null) { 489 throw new Error("Error in %s!".format(p.name)); 490 } 491 492 parameters ~= typeName; 493 } 494 495 return new ParameterList(parameters); 496 case "DADT.ConstructorList": 497 Constructor[] constructors; 498 foreach (child; p.children) { 499 Constructor constructor = cast(Constructor)buildAST(child); 500 if (constructor is null) { 501 throw new Error("Error in %s!".format(p.name)); 502 } 503 constructors ~= constructor; 504 } 505 506 return new ConstructorList(constructors); 507 case "DADT.ConstructorDeclare": 508 auto e = p.children[0]; 509 return buildAST(e); 510 case "DADT.RecordField": 511 FieldName name = cast(FieldName)buildAST(p.children[0]); 512 if (name is null) { 513 throw new Error("Error in %s!".format(p.name)); 514 } 515 Field field = cast(Field)buildAST(p.children[1]); 516 if (field is null) { 517 throw new Error("Error in %s!".format(p.name)); 518 } 519 520 return new RecordField(name, field); 521 case "DADT.RecordFields": 522 RecordField[] fields; 523 foreach (child; p.children) { 524 RecordField field = cast(RecordField)buildAST(child); 525 if (field is null) { 526 throw new Error("Error in %s!".format(p.name)); 527 } 528 fields ~= field; 529 } 530 return new RecordFields(fields); 531 case "DADT.Record": 532 return buildAST(p.children[0]); 533 case "DADT.ConstructorWithRecord": 534 TypeName constructorName = cast(TypeName)buildAST(p.children[0]); 535 if (constructorName is null) { 536 throw new Error("Error in %s!".format(p.name)); 537 } 538 // RecordFields 539 RecordFields record = cast(RecordFields)buildAST(p.children[1]); 540 if (record is null) { 541 throw new Error("Error in %s!".format(p.name)); 542 } 543 return new Constructor(constructorName, record); 544 case "DADT.ConstructorWithField": 545 TypeName constructorName = cast(TypeName)buildAST(p.children[0]); 546 if (constructorName is null) { 547 throw new Error("Error in %s!".format(p.name)); 548 } 549 Field[] fields; 550 foreach (child; p.children[1 .. $]) { 551 Field field = cast(Field)buildAST(child); 552 if (field is null) { 553 throw new Error("Error in %s!".format(p.name)); 554 } 555 fields ~= field; 556 } 557 558 return new Constructor(constructorName, fields); 559 case "DADT.Constructor": 560 TypeName constructorName = cast(TypeName)buildAST(p.children[0]); 561 if (constructorName is null) { 562 throw new Error("Error in %s!".format(p.name)); 563 } 564 return new Constructor(constructorName); 565 case "DADT.Deriving": 566 DerivingArgs args = cast(DerivingArgs)buildAST(p.children[0]); 567 568 if (args is null) { 569 throw new Error("Error in %s!".format(p.name)); 570 } 571 572 return new Deriving(args); 573 case "DADT.DerivingArg": 574 string k = p.matches[0].toLower; 575 576 if (k in DerivingMap) { 577 return new DerivingArg(DerivingMap[k]); 578 } else { 579 throw new Error("Unkown deriving target was given : %s".format(p.matches[0])); 580 } 581 case "DADT.DerivingArgs": 582 DerivingArg[] args; 583 584 foreach (child; p.children) { 585 DerivingArg arg = cast(DerivingArg)buildAST(child); 586 587 if (arg is null) { 588 throw new Error("Error in %s!".format(p.name)); 589 } 590 591 args ~= arg; 592 } 593 594 return new DerivingArgs(args); 595 } 596 } 597 598 string genCode(const TypeDeclare td) { 599 string code; 600 string interface_name = td.baseConstructor.baseName.name; 601 const string[] interface_args = td.baseConstructor.parameterList.parameters.map!( 602 (const TypeName tn) => tn.name).array; 603 string args_str; 604 string interface_args_str; 605 if (interface_args.length) { 606 interface_args_str = "(" ~ interface_args.join(", ") ~ ")"; 607 args_str = "!" ~ interface_args_str; 608 } 609 610 string[] enum_elements; 611 foreach (i, constructor; td.constructorList.constructors) { 612 if (i > 0) { 613 enum_elements ~= " " ~ constructor.getTypeName(); 614 } else { 615 enum_elements ~= constructor.getTypeName(); 616 } 617 } 618 619 // dfmt off 620 code ~= 621 ` 622 enum #{interface_name}#Type { 623 #{enum_elements}# 624 } 625 `.patternReplaceWithTable([ 626 "interface_name" : interface_name, 627 "enum_elements" : enum_elements.join(",\n") 628 ]); 629 // dfmt on 630 631 // dfmt off 632 code ~= 633 ` 634 interface #{interface_name}##{interface_args_str}# { 635 #{interface_name}#Type type(); 636 } 637 `.patternReplaceWithTable([ 638 "interface_name" : interface_name, 639 "interface_args_str" : interface_args_str]); 640 // dfmt on 641 642 foreach (constructor; td.constructorList.constructors) { 643 string constructor_name = constructor.getTypeName(); 644 645 string[] field_names; 646 string[string] field_info; 647 string field_code; 648 string[] field_type_and_names; 649 650 if (constructor.type == ConstructorType.Record) { 651 foreach (field; constructor.record.fields) { 652 string field_name = field.getFieldName(); 653 field_names ~= field_name; 654 field_info[field_name] = field.getFieldTypeString(); 655 } 656 } else { 657 foreach (i, fieldType; constructor.fields) { 658 string field_name = "_%d".format(i); 659 field_names ~= field_name; 660 field_info[field_name] = fieldType.typeString(); 661 } 662 } 663 664 foreach (field_name; field_names) { 665 string field_type = field_info[field_name]; 666 field_type_and_names ~= "%s %s".format(field_type, field_name); 667 } 668 foreach (field_type_and_name; field_type_and_names) { 669 field_code ~= field_type_and_name ~ ";"; 670 } 671 672 string this_code; 673 string this_argument = field_type_and_names.join(", "); 674 string initialize_list; 675 foreach (field_name; field_names) { 676 initialize_list ~= "this.%s = %s;".format(field_name, field_name); 677 } 678 679 // dfmt off 680 this_code = ` 681 this(#{this_argument}#) { 682 #{initialize_list}# 683 }`.patternReplaceWithTable([ 684 "this_argument" : this_argument, 685 "initialize_list" : initialize_list]); 686 687 string type_code = ` 688 #{interface_name}#Type type() { 689 return #{interface_name}#Type.#{constructor_name}#; 690 } 691 `.patternReplaceWithTable([ 692 "interface_name" : interface_name, 693 "constructor_name" : constructor_name 694 ]); 695 696 code ~= ` 697 class #{constructor_name}##{interface_args_str}# : #{interface_name}##{args_str}# { 698 #{field_code}# 699 #{this_code}# 700 #{type_code}# 701 }`.patternReplaceWithTable([ 702 "constructor_name" : constructor_name, 703 "interface_args_str" : interface_args_str, 704 "interface_name" : interface_name, 705 "args_str" : args_str, 706 "field_code" : field_code, 707 "this_code" : this_code, 708 "type_code" : type_code]); 709 // dfmt on 710 711 string helper_code; 712 string helper_returnType = constructor_name ~ args_str; 713 string interface_returnType = interface_name ~ args_str; 714 string helper_name = constructor_name.toLower; 715 string helper_typeParameters; 716 717 if (interface_args.length) { 718 helper_typeParameters = "(" ~ interface_args.join(", ") ~ ")"; 719 } 720 721 string[] helper_arguments; 722 string[] helper_variables; 723 724 if (constructor.type == ConstructorType.Record) { 725 foreach (field; constructor.record.fields) { 726 helper_arguments ~= "%s %s".format(field.getFieldTypeString(), field.getFieldName()); 727 helper_variables ~= "%s".format(field.getFieldName()); 728 } 729 } else { 730 foreach (i, field; constructor.fields) { 731 helper_arguments ~= "%s _%d".format(field.typeString(), i); 732 helper_variables ~= "_%d".format(i); 733 } 734 } 735 736 // dfmt off 737 helper_code = ` 738 #{interface_returnType}# #{helper_name}##{helper_typeParameters}#(#{helper_arguments}#) { 739 return new #{helper_returnType}#(#{helper_variables}#); 740 } 741 `.patternReplaceWithTable([ 742 "helper_returnType" : helper_returnType, 743 "interface_returnType" : interface_returnType, 744 "helper_name" : helper_name, 745 "helper_typeParameters" : helper_typeParameters, 746 "helper_arguments" : helper_arguments.join(", "), 747 "helper_variables" : helper_variables.join(", ")]); 748 // dfmt on 749 750 code ~= helper_code; 751 } 752 753 string match_returnType = "_RETURN_TYPE_OF_MATCH_WITH_%s".format(interface_name); 754 // dfmt off 755 string match_header = "#{match_returnType}# matchWith#{interface_name}#(#{match_returnType}#, #{interface_args}# choices...)(#{interface_name}##{args_str}# arg) {".patternReplaceWithTable([ 756 "match_returnType" : match_returnType, 757 "interface_name" : interface_name, 758 "interface_args" : interface_args.join(", ") ~ (interface_args.length > 0 ? "," : ""), 759 "interface_name" : interface_name, "args_str":args_str]); 760 // dfmt on 761 762 string match_static_routers; 763 764 foreach (constructor; td.constructorList.constructors) { 765 string type_signature = constructor.getTypeName() ~ args_str; 766 string[] field_names; 767 if (constructor.type == ConstructorType.Record) { 768 foreach (field; constructor.record.fields) { 769 field_names ~= field.getFieldName(); 770 } 771 } else { 772 foreach (i, fieldType; constructor.fields) { 773 string field_name = "x._%d".format(i); 774 field_names ~= field_name; 775 } 776 } 777 778 // dfmt off 779 match_static_routers ~= ` 780 static if (is(#{type_signature}# == params[0])) { 781 #{type_signature}# x = cast(#{type_signature}#)arg; 782 783 static if (is(ReturnType!(choice) == #{match_returnType}#)) { 784 static if (is(#{match_returnType}# == void)) { 785 choice(x); 786 } else { 787 return choice(x); 788 } 789 } else { 790 static if (isCallable!(ReturnType!(choice))) { 791 return cast(#{match_returnType}#)choice(x)#{field_args}#; 792 } else { 793 return cast(#{match_returnType}#)choice(x); 794 } 795 } 796 } 797 `.patternReplaceWithTable([ 798 "type_signature" : type_signature, 799 "match_returnType" : match_returnType, 800 "field_args" : field_names.length > 0 ? `(` ~ field_names.join(", ") ~ `)` : "()"]); 801 // dfmt on 802 } 803 804 // dfmt off 805 string match_code = ` 806 #{match_header}# 807 import std.traits; 808 #{match_returnType}# delegate() otherwise = null; 809 810 foreach (choice; choices) { 811 alias params = Parameters!choice; 812 static if (params.length < 1) { 813 otherwise = () => choice(); 814 } 815 816 if (cast(params[0])(arg) !is null) { 817 #{match_static_routers}# 818 } 819 } 820 821 if (otherwise !is null) { 822 static if (is(#{match_returnType}# == void)) { 823 otherwise(); 824 return; 825 } else { 826 return otherwise(); 827 } 828 } 829 830 static if (!is(#{match_returnType}# == void)) { 831 return null; 832 } 833 } 834 `.patternReplaceWithTable([ 835 "match_header" : match_header, 836 "match_returnType" : match_returnType, 837 "match_static_routers" : match_static_routers 838 ]); 839 // dfmt on 840 code ~= match_code; 841 842 if (td.deriving !is null) { 843 bool ord_is_generated = false; 844 845 foreach (arg; td.deriving.args.args) { 846 string deriving_code; 847 final switch (arg.type) with (DerivingType) { 848 case Show: 849 string show_code; 850 851 // dfmt off 852 string show_header = `string show_#{interface_name}##{interface_args_str}#(#{interface_name}##{args_str}# arg, string function(#{interface_name}##{args_str}#) conv = null) {`.patternReplaceWithTable([ 853 "interface_name" : interface_name, 854 "interface_args_str" : interface_args_str, 855 "args_str" : args_str]); 856 857 string show_middle_header = 858 ` if (conv !is null) { 859 return conv(arg); 860 } 861 import std.string; 862 string[] interface_args = [#{interface_args}#]; 863 string constructor_arg; 864 if (interface_args.length) { 865 constructor_arg = "!(" ~ interface_args.join(", ") ~ ")"; 866 } 867 `.patternReplaceWithTable(["interface_args" : interface_args.map!(iarg => iarg ~ ".stringof").join(", ")]); 868 // dfmt on 869 870 string show_constructors = ` 871 final switch (arg.type) {`; 872 873 foreach (constructor; td.constructorList.constructors) { 874 string constructor_name = constructor.getTypeName(); 875 string type_signature = constructor.getTypeName() ~ args_str; 876 string[] field_names; 877 if (constructor.type == ConstructorType.Record) { 878 foreach (field; constructor.record.fields) { 879 field_names ~= "x." ~ field.getFieldName(); 880 } 881 } else { 882 foreach (i, fieldType; constructor.fields) { 883 string field_name = "x._%d".format(i); 884 field_names ~= field_name; 885 } 886 } 887 888 string ret_line; 889 890 if (field_names.length) { 891 string[] field_formatters; 892 foreach (_; field_names) { 893 field_formatters ~= "%s"; 894 } 895 // dfmt off 896 ret_line = `return "#{constructor_name}#" ~ constructor_arg ~ "(#{field_formatters}#)".format(#{field_names}#);`.patternReplaceWithTable([ 897 "constructor_name" : constructor_name, 898 "field_formatters" : field_formatters.join(", "), 899 "field_names" : field_names.join(", ")]); 900 // dfmt on 901 } else { 902 ret_line = `return "%s" ~ constructor_arg;`.format(constructor_name); 903 } 904 905 // dfmt off 906 show_constructors ~= ` 907 case #{interface_name}#Type.#{constructor_name}#: 908 #{type_signature}# x = cast(#{type_signature}#)arg; 909 910 #{ret_line}#`.patternReplaceWithTable([ 911 "interface_name" : interface_name, 912 "constructor_name" : constructor_name, 913 "type_signature" : type_signature, 914 "ret_line" : ret_line]); 915 // dfmt on 916 } 917 918 string show_footer = ` }`; 919 // dfmt off 920 show_code = 921 ` 922 #{show_header}# 923 #{show_middle_header}# 924 #{show_constructors}# 925 #{show_footer}# 926 } 927 `.patternReplaceWithTable([ 928 "show_header" : show_header, 929 "show_middle_header" : show_middle_header, 930 "show_constructors" : show_constructors, 931 "show_footer" : show_footer 932 ]); 933 // dfmt on 934 deriving_code ~= show_code; 935 break; 936 case Ord: 937 if (ord_is_generated) { 938 break; 939 } 940 ord_is_generated = true; 941 // dfmt off 942 string ord_header = `int compare_#{interface_name}##{interface_args_str}#(#{interface_name}##{args_str}# _lhs, #{interface_name}##{args_str}# _rhs) {`.patternReplaceWithTable([ 943 "interface_name" : interface_name, 944 "interface_args_str" : interface_args_str, 945 "args_str" : args_str]); 946 // dfmt on 947 string ord_precomp = ` 948 #{interface_name}#Type lhs_type = _lhs.type, 949 rhs_type = _rhs.type; 950 951 if (lhs_type < rhs_type) { 952 return -1; 953 } 954 if (lhs_type > rhs_type) { 955 return 1; 956 } 957 `.patternReplaceWithTable([ 958 "interface_name": interface_name 959 ]); 960 961 string ord_compbody = ` 962 final switch (lhs_type) {`; 963 964 foreach (constructor; td.constructorList.constructors) { 965 string constructor_name = constructor.getTypeName(); 966 string type_signature = constructor.getTypeName() ~ args_str; 967 string field_comps; 968 969 if (constructor.type == ConstructorType.Record) { 970 foreach (field; constructor.record.fields) { 971 string field_name = field.getFieldName(); 972 973 field_comps ~= ` 974 if (lhs.#{field_name}# < rhs.#{field_name}#) { 975 return -1; 976 } 977 if (lhs.#{field_name}# > rhs.#{field_name}#) { 978 return 1; 979 }`.patternReplaceWithTable([ 980 "field_name": field_name 981 ]); 982 } 983 } else { 984 foreach (i, fieldType; constructor.fields) { 985 string field_name = "_%d".format(i); 986 987 field_comps ~= ` 988 if (lhs.#{field_name}# < rhs.#{field_name}#) { 989 return -1; 990 } 991 if (lhs.#{field_name}# > rhs.#{field_name}#) { 992 return 1; 993 }`.patternReplaceWithTable([ 994 "field_name": field_name 995 ]); 996 } 997 } 998 999 // dfmt off 1000 ord_compbody ~= ` 1001 case #{interface_name}#Type.#{constructor_name}#: 1002 #{type_signature}# lhs = cast(#{type_signature}#)_lhs, 1003 rhs = cast(#{type_signature}#)_rhs; 1004 1005 #{field_comps}# 1006 1007 return 0;`.patternReplaceWithTable([ 1008 "interface_name" : interface_name, 1009 "constructor_name" : constructor_name, 1010 "type_signature" : type_signature, 1011 "field_comps" : field_comps 1012 ]); 1013 // dfmt on 1014 } 1015 1016 string ord_footer = ` } 1017 }`; 1018 // dfmt off 1019 string ord_code = ` 1020 #{ord_header}# 1021 #{ord_precomp}# 1022 #{ord_compbody}# 1023 #{ord_footer}# 1024 `.patternReplaceWithTable([ 1025 "ord_header" : ord_header, 1026 "ord_precomp" : ord_precomp, 1027 "ord_compbody" : ord_compbody, 1028 "ord_footer" : ord_footer 1029 ]); 1030 // dfmt on 1031 deriving_code ~= ord_code; 1032 break; 1033 case Eq: 1034 // dfmt off 1035 string eq_header = `bool equal_#{interface_name}##{interface_args_str}#(#{interface_name}##{args_str}# _lhs, #{interface_name}##{args_str}# _rhs) {`.patternReplaceWithTable([ 1036 "interface_name" : interface_name, 1037 "interface_args_str" : interface_args_str, 1038 "args_str" : args_str]); 1039 string eq_body = ` return compare_#{interface_name}##{args_str}#(_lhs, _rhs) == 0;`.patternReplaceWithTable([ 1040 "interface_name" : interface_name, 1041 "args_str" : args_str]); 1042 string eq_footer = "}"; 1043 string eq_code = 1044 ` 1045 #{eq_header}# 1046 #{eq_body}# 1047 #{eq_footer}# 1048 `.patternReplaceWithTable([ 1049 "eq_header" : eq_header, 1050 "eq_body" : eq_body, 1051 "eq_footer" : eq_footer]); 1052 deriving_code ~= eq_code; 1053 // dfmt on 1054 if (!ord_is_generated) { 1055 goto case Ord; 1056 } else { 1057 break; 1058 } 1059 } 1060 code ~= deriving_code; 1061 } 1062 } 1063 1064 return code; 1065 } 1066 1067 string genCodeFromSource(string source) { 1068 auto ast = DADT(source); 1069 TypeDeclare td = cast(TypeDeclare)buildAST(ast); 1070 return genCode(td); 1071 }