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