1 /// Author: Aziz Köksal 2 /// License: GPL3 3 /// $(Maturity low) 4 module dil.ast.ASTPrinter; 5 6 import dil.ast.Visitor, 7 dil.ast.Node, 8 dil.ast.Declarations, 9 dil.ast.Expressions, 10 dil.ast.Statements, 11 dil.ast.Types, 12 dil.ast.Parameters, 13 dil.ast.Precedence; 14 import dil.lexer.IdTable, 15 dil.lexer.Funcs; 16 import dil.semantic.TypesEnum; 17 import dil.Compilation; 18 import dil.String; 19 import dil.Enums; 20 import dil.Array; 21 import common; 22 23 /// Converts expressions like "TokenList.XYZ" to "toToken(TOK.XYZ)". 24 static struct TokenList 25 { 26 static Token* opDispatch(string kind)() 27 { 28 return mixin("toToken(TOK."~kind~")"); 29 } 30 } 31 32 /// Traverses a Node tree and constructs a string representation. 33 class ASTPrinter : Visitor2 34 { 35 char[] text; /// The printed text. 36 TokenArray tarray; /// The pre-built tokens of the text (Lexer not required.) 37 cchar* prevEnd; /// End pointer of the previous token (t.end). 38 bool buildTokens; /// True if the tokens should be built. 39 uint_t lineNum; /// Current line number. 40 Token nlToken; /// Provides a newline token (depends on the platform). 41 cstring spaces; /// The current whitespace string. 42 cstring indent; /// The current indendation string. 43 cstring indentStep; /// The string used to increase the indentation level. 44 TemplateDecl currentTplDecl; /// Set by a wrapping TemplateDecl. 45 46 CompilationContext cc; 47 alias T = TokenList; 48 49 /// Constructs an ASTPrinter. 50 this(bool buildTokens, CompilationContext cc) 51 { 52 this.buildTokens = buildTokens; 53 this.cc = cc; 54 this.indentStep = " "; 55 // A newline token with a platform dependent string as its text. 56 nlToken.kind = TOK.Newline; 57 version(Windows) 58 const nl = "\r\n"; 59 else version(OSX) 60 const nl = "\r"; 61 else 62 const nl = "\n"; 63 nlToken.text = nl; 64 } 65 66 /// Returns the tokens as a list. 67 Token[] tokens() 68 { 69 return tarray[][1..$-1]; // Exclude Newline and EOF. 70 } 71 72 /// Increments the line number and returns the newline token. 73 Token* Newline() 74 { 75 nlToken.nlval = cc.tables.lxtables.lookupNewline(++lineNum); 76 return &nlToken; 77 } 78 79 /// Starts the printer. 80 char[] print(Node n) 81 { 82 text = null; 83 tarray.len = 0; 84 tarray.cap = 2; 85 prevEnd = null; 86 spaces = null; 87 indent = null; 88 // First newline token. 89 auto t = *Newline; 90 t.text = null; 91 writeToken(&t); 92 // Start traversing the tree. 93 visitN(n); 94 // Terminate with EOF. 95 t = Token(TOK.EOF, null, null, null, null); 96 writeToken(&t); 97 fixTokens(); 98 return text; 99 } 100 101 /// Constructs a new Token with the given parameters and pushes to an array. 102 void pushToken(TOK k, size_t start, size_t end, void* value) 103 { // Create new token and set its members. 104 if (tarray.rem == 0) 105 tarray.growX1_5(); 106 assert(tarray.rem >= 1); 107 auto t = tarray.cur++; 108 t.kind = k; 109 t.ws = start ? prevEnd : null; 110 t.start = prevEnd + start; 111 t.end = prevEnd + end; 112 t.pvoid = value; 113 prevEnd += end; 114 } 115 116 /// When the emitted text is complete, the pointers in the tokens 117 /// are updated to point to the correct text fragments. 118 /// (Considering the text buffer might get relocated when appending to it.) 119 void fixTokens() 120 { 121 if (!buildTokens || !tarray.len) 122 return; 123 const offset = cast(size_t)text.ptr; 124 foreach (ref t; tarray[]) 125 { 126 if (t.ws) 127 t.ws += offset; 128 t.start += offset; 129 t.end += offset; 130 } 131 } 132 133 /// Returns the token kind for p. 134 TOK protToTOK(PROT p) 135 { 136 TOK tk; 137 final switch (p) 138 { 139 case Protection.Private: tk = TOK.Private; break; 140 case Protection.Protected: tk = TOK.Protected; break; 141 case Protection.Package: tk = TOK.Package; break; 142 case Protection.Public: tk = TOK.Public; break; 143 case Protection.Export: tk = TOK.Export; break; 144 case Protection.None: 145 } 146 return tk; 147 } 148 149 /// Writes str to the text buffer. 150 void writeS(cstring str) 151 { 152 text ~= str; 153 } 154 155 /// Writes a list of tokens. 156 void write(Token*[] ts...) 157 { 158 foreach (t; ts) 159 writeToken(t); 160 } 161 162 /// Writes the contents of a token to the text. 163 void writeToken(Token* t) 164 { 165 if (t.kind == TOK.Invalid) 166 { // Special whitespace token? 167 spaces ~= t.text; 168 return; 169 } 170 auto tokenText = t.text; 171 if (buildTokens) 172 { 173 auto start = spaces.length; 174 auto end = start + tokenText.length; 175 pushToken(t.kind, start, end, t.pvoid); 176 } 177 writeS(spaces); 178 writeS(tokenText); 179 spaces = null; // Clear whitespace. 180 } 181 182 /// Writes the tokens between b and e (inclusive.) 183 void writeSpan(Token* b, Token* e) 184 { 185 for (auto t = b; t <= e; t++) 186 if (!t.isWhitespace()) 187 writeToken(t); 188 } 189 190 /// Shortcuts. 191 alias w = write; 192 /// ditto 193 alias v = visitN; 194 195 /// Returns a new token containing 'n' number of whitespace characters. 196 Token* ws(uint n) @property 197 { 198 auto s = String(" ") * n; 199 auto t = new Token; 200 t.start = s.ptr; 201 t.end = s.end; 202 return t; 203 } 204 205 /// Returns a new token containing a single whitespace character. 206 Token* ws() @property 207 { 208 auto t = new Token; 209 t.text = " "; 210 return t; 211 } 212 213 /// Returns the current indentation as a token. 214 Token* ind() @property 215 { 216 auto t = new Token; 217 t.text = indent; 218 return t; 219 } 220 221 /// Returns a Token for an Identifier. 222 Token* id(Identifier* id) 223 { 224 auto t = new Token; 225 t.kind = TOK.Identifier; 226 t.text = id.str; 227 t.ident = id; 228 return t; 229 } 230 231 /// Increases/decreases indentation on construction/destruction. 232 scope class IndentLevel 233 { 234 this() 235 { 236 indent ~= indentStep; 237 } 238 ~this() 239 { 240 indent = indent[0 .. $-indentStep.length]; 241 } 242 } 243 244 /// Decreases/increases indentation on construction/destruction. 245 scope class UnindentLevel 246 { 247 this() 248 { 249 assert(indent.length >= indentStep.length); 250 indent = indent[0 .. $-indentStep.length]; 251 } 252 ~this() 253 { 254 indent ~= indentStep; 255 } 256 } 257 258 /// Sets/restores indentation on construction/destruction. 259 scope class SetIndentLevel 260 { 261 cstring old; 262 this(cstring i) 263 { 264 old = indent; 265 indent = i; 266 } 267 ~this() 268 { 269 indent = old; 270 } 271 } 272 273 /// Returns the currentTplDecl member and nulls it. 274 TemplateDecl getTplDecl() 275 { 276 auto n = currentTplDecl; 277 currentTplDecl = null; 278 return n; 279 } 280 281 /// Writes the template parameters and if-constraint of a TemplateDecl. 282 void writeTParams(TemplateDecl n) 283 { 284 v(n.tparams); 285 if (n.constraint) 286 { 287 w(ws, T.If, T.LParen); 288 v(n.constraint); 289 w(T.RParen); 290 } 291 } 292 293 void writeTParamsOnly(TemplateDecl n) 294 { 295 v(n.tparams); 296 } 297 298 void writeTConstraint(TemplateDecl n) 299 { 300 if (n.constraint) 301 { 302 w(ws, T.If, T.LParen); 303 v(n.constraint); 304 w(T.RParen); 305 } 306 } 307 308 /// Writes an expression, wrapped in parentheses if necessary. 309 void write(Expression n, PREC prec) 310 { 311 auto nextP = n.kind.precOf(); 312 if (prec > nextP) 313 { 314 w(T.LParen); 315 v(n); 316 w(T.RParen); 317 } 318 else 319 v(n); 320 } 321 322 /// Writes a comma-separated list of Expressions. 323 void write(Expression[] es) 324 { 325 foreach (i, e; es) 326 { 327 if (i) 328 w(T.Comma, ws); 329 w(e, PREC.Assignment); 330 } 331 } 332 333 /// Writes a binary expression. 334 void write(BinaryExpr n) 335 { 336 auto prec = n.kind.precOf(); 337 w(n.lhs, prec); 338 w(ws, n.optok, ws); 339 w(n.rhs, prec); 340 } 341 342 /// Writes a unary expression. 343 void write(UnaryExpr n) 344 { 345 w(n.una, n.kind.precOf()); 346 } 347 348 void writeBlock(Node n) 349 { 350 w(Newline, ind, T.LBrace, Newline); 351 { 352 scope il = new IndentLevel; 353 v(n); 354 } 355 w(ind, T.RBrace, Newline); 356 } 357 358 void writeAggregateBody(Node n) 359 { 360 if (n is null) 361 w(T.Semicolon, Newline); 362 else 363 writeBlock(n); 364 } 365 366 /// Writes specification and/or default values. 367 void writeSpecDef(Node s, Node d) 368 { 369 if (s) { 370 w(ws, T.Colon, ws); 371 v(s); 372 } 373 if (d) { 374 w(ws, T.Equal, ws); 375 v(d); 376 } 377 } 378 379 void writeAttrDecl(Declaration n) 380 { 381 switch (n.kind) 382 { 383 case NodeKind.ProtectionDecl, 384 NodeKind.StorageClassDecl, 385 NodeKind.LinkageDecl, 386 NodeKind.AlignDecl, 387 NodeKind.PragmaDecl, 388 NodeKind.VariablesDecl: 389 { 390 scope il = new SetIndentLevel(" "); 391 v(n); 392 } 393 break; 394 case NodeKind.ColonBlockDecl: 395 v(n); 396 break; 397 case NodeKind.CompoundDecl: 398 writeBlock(n); 399 break; 400 case NodeKind.EmptyDecl: 401 w(T.Semicolon, Newline); 402 break; 403 default: 404 w(Newline); 405 v(n); 406 } 407 } 408 409 override: 410 411 void visit(IllegalDecl n) 412 { 413 assert(0); 414 } 415 416 void visit(CompoundDecl n) 417 { 418 foreach (x; n.decls) 419 v(x); 420 } 421 422 void visit(ColonBlockDecl n) 423 { 424 w(T.Colon, Newline); 425 v(n.decls); 426 } 427 428 void visit(EmptyDecl n) 429 { 430 w(ind, T.Semicolon, Newline); 431 } 432 433 void visit(ModuleDecl n) 434 { 435 w(T.Module); 436 if (n.type) 437 w(ws, T.LParen, n.type, T.RParen); 438 w(ws, n.fqn[0]); 439 foreach (ident; n.fqn[1..$]) 440 w(T.Dot, ident); 441 w(T.Semicolon, Newline, Newline); 442 } 443 444 void visit(ImportDecl n) 445 { 446 w(ind); 447 if (n.isStatic) 448 w(T.Static, ws); 449 w(T.Import, ws); 450 foreach (i, fqn; n.moduleFQNs) 451 { 452 if (i) 453 w(T.Comma, ws); 454 if (auto aliasId = n.moduleAliases[i]) 455 w(aliasId, ws, T.Equal, ws); 456 foreach (j, ident; fqn) 457 { 458 if (j) 459 w(T.Dot); 460 w(ident); 461 } 462 } 463 foreach (i, bindName; n.bindNames) 464 { 465 if (i == 0) 466 w(ws, T.Colon, ws); 467 else 468 w(T.Comma, ws); 469 if (auto bindAlias = n.bindAliases[i]) 470 w(bindAlias, ws, T.Equal, ws); 471 w(bindName); 472 } 473 w(T.Semicolon, Newline); 474 } 475 476 void visit(AliasDecl n) 477 { 478 w(ind, T.Alias); 479 scope il = new SetIndentLevel(" "); 480 v(n.decl); 481 } 482 483 void visit(AliasesDecl n) 484 { 485 w(ind, T.Alias); 486 foreach (i, name; n.idents) 487 { 488 if (i) 489 w(T.Comma); 490 w(ws, name, ws, T.Equal, ws); 491 v(n.types[i]); 492 } 493 w(T.Semicolon, Newline); 494 } 495 496 void visit(AliasThisDecl n) 497 { 498 w(ind, T.Alias, ws, n.name, ws, T.This, T.Semicolon, Newline); 499 } 500 501 void visit(TypedefDecl n) 502 { 503 w(ind, T.Typedef); 504 scope il = new SetIndentLevel(" "); 505 v(n.decl); 506 } 507 508 void visit(EnumDecl n) 509 { 510 w(ind, T.Enum); 511 if (n.name) 512 w(ws, n.name); 513 if (n.baseType) { 514 w(ws, T.Colon, ws); 515 v(n.baseType); 516 } 517 if (!n.members) 518 w(T.Semicolon, Newline); 519 else 520 { 521 w(Newline, ind, T.LBrace, Newline); 522 { 523 scope il = new IndentLevel; 524 foreach (i, m; n.members) 525 { 526 if (i) 527 w(T.Comma, Newline); 528 v(m); 529 } 530 } 531 w(Newline, ind, T.RBrace, Newline); 532 } 533 w(Newline); 534 } 535 536 void visit(EnumMemberDecl n) 537 { 538 if (n.type) { 539 w(ind); 540 v(n.type); 541 w(ws, n.name); 542 } 543 else 544 w(ind, n.name); 545 if (n.value) { 546 w(ws, T.Equal, ws); 547 v(n.value); 548 } 549 } 550 551 void visit(TemplateDecl n) 552 { 553 if (n.isWrapper) 554 { 555 currentTplDecl = n; 556 v(n.decls); 557 return; 558 } 559 w(ind); 560 if (n.isMixin) 561 w(T.Mixin, ws); 562 w(T.Template, ws, n.name); 563 v(n.tparams); 564 if (n.constraint) 565 { 566 w(ws, T.If, T.LParen); 567 v(n.constraint); 568 w(T.RParen); 569 } 570 writeBlock(n.decls); 571 w(Newline); 572 } 573 574 void visit(ClassDecl n) 575 { 576 auto tplDecl = getTplDecl(); 577 w(ind, T.Class, ws, n.name); 578 if (tplDecl) 579 writeTParams(tplDecl); 580 if (n.bases) 581 { 582 w(ws, T.Colon, ws); 583 foreach (i, b; n.bases) 584 { 585 if (i) 586 w(T.Comma, ws); 587 v(b); 588 } 589 } 590 writeAggregateBody(n.decls); 591 w(Newline); 592 } 593 594 void visit(InterfaceDecl n) 595 { 596 auto tplDecl = getTplDecl(); 597 w(ind, T.Interface, ws, n.name); 598 if (tplDecl) 599 writeTParams(tplDecl); 600 if (n.bases) 601 { 602 w(ws, T.Colon, ws); 603 foreach (i, b; n.bases) 604 { 605 if (i) 606 w(T.Comma, ws); 607 v(b); 608 } 609 } 610 writeAggregateBody(n.decls); 611 w(Newline); 612 } 613 614 void visit(StructDecl n) 615 { 616 auto tplDecl = getTplDecl(); 617 w(ind, T.Struct); 618 if (n.name) 619 w(ws, n.name); 620 if (tplDecl) 621 writeTParams(tplDecl); 622 writeAggregateBody(n.decls); 623 w(Newline); 624 } 625 626 void visit(UnionDecl n) 627 { 628 auto tplDecl = getTplDecl(); 629 w(ind, T.Union); 630 if (n.name) 631 w(ws, n.name); 632 if (tplDecl) 633 writeTParams(tplDecl); 634 writeAggregateBody(n.decls); 635 w(Newline); 636 } 637 638 void visit(ConstructorDecl n) 639 { 640 auto tplDecl = getTplDecl(); 641 w(ind, T.This); 642 if (tplDecl) 643 writeTParamsOnly(tplDecl); 644 v(n.params); 645 if (tplDecl) 646 writeTConstraint(tplDecl); 647 v(n.funcBody); 648 } 649 650 void visit(StaticCtorDecl n) 651 { 652 w(ind, T.Static, ws, T.This, T.LParen, T.RParen); 653 v(n.funcBody); 654 } 655 656 void visit(DestructorDecl n) 657 { 658 w(ind, T.Tilde, T.This, T.LParen, T.RParen); 659 v(n.funcBody); 660 } 661 662 void visit(StaticDtorDecl n) 663 { 664 w(ind, T.Static, ws, T.Tilde, T.This, T.LParen, T.RParen); 665 v(n.funcBody); 666 } 667 668 void visit(FunctionDecl n) 669 { 670 auto tplDecl = getTplDecl(); 671 w(ind); 672 if (n.returnType) 673 v(n.returnType); 674 else 675 w(T.Auto); 676 w(ws); 677 w(n.name); 678 if (tplDecl) 679 writeTParamsOnly(tplDecl); 680 v(n.params); 681 if (tplDecl) 682 writeTConstraint(tplDecl); 683 v(n.funcBody); 684 } 685 686 void visit(VariablesDecl n) 687 { 688 w(ind); 689 if (n.type) { 690 v(n.type); 691 w(ws); 692 } 693 //else // Emitted by visit(StorageClassDecl). 694 // w(T.Auto, ws); 695 foreach (i, name; n.names) 696 { 697 if (i) 698 w(T.Comma, ws); 699 w(name); 700 if (auto init = n.inits[i]) { 701 w(ws, T.Equal, ws); 702 v(init); 703 } 704 } 705 w(T.Semicolon, Newline, Newline); 706 } 707 708 void visit(InvariantDecl n) 709 { 710 w(ind, T.Invariant, T.LParen, T.RParen); 711 v(n.funcBody); 712 } 713 714 void visit(UnittestDecl n) 715 { 716 w(ind, T.Unittest); 717 v(n.funcBody); 718 } 719 720 void visit(DebugDecl n) 721 { 722 w(ind, T.Debug); 723 if (n.isSpecification()) 724 w(ws, T.Equal, ws, n.spec, T.Semicolon, Newline); 725 else 726 { 727 if (n.cond) 728 w(T.LParen, n.cond, T.RParen); 729 writeBlock(n.decls); 730 if (n.elseDecls) { 731 w(T.Else); 732 writeBlock(n.elseDecls); 733 } 734 } 735 w(Newline); 736 } 737 738 void visit(VersionDecl n) 739 { 740 w(ind, T.Version); 741 if (n.isSpecification()) 742 w(ws, T.Equal, ws, n.spec, T.Semicolon, Newline); 743 else 744 { 745 w(T.LParen, n.cond, T.RParen); 746 writeBlock(n.decls); 747 if (n.elseDecls) { 748 w(T.Else); 749 writeBlock(n.elseDecls); 750 } 751 } 752 w(Newline); 753 } 754 755 void visit(StaticIfDecl n) 756 { 757 w(ind, T.Static, T.If, T.LParen); 758 v(n.condition); 759 w(T.RParen, Newline); 760 v(n.ifDecls); 761 if (n.elseDecls) { 762 w(T.Else, Newline); 763 v(n.elseDecls); 764 } 765 w(Newline, Newline); 766 } 767 768 void visit(StaticAssertDecl n) 769 { 770 w(ind, T.Static, ws, T.Assert, T.LParen); 771 v(n.condition); 772 if (n.message) { 773 w(T.Comma, ws); 774 v(n.message); 775 } 776 w(T.RParen, Newline, Newline); 777 } 778 779 void visit(NewDecl n) 780 { 781 w(ind, T.New); 782 v(n.params); 783 v(n.funcBody); 784 } 785 786 void visit(DeleteDecl n) 787 { 788 w(ind, T.Delete); 789 v(n.params); 790 v(n.funcBody); 791 } 792 793 void visit(ProtectionDecl n) 794 { 795 w(ind, protToTOK(n.prot).toToken()); 796 writeAttrDecl(n.decls); 797 } 798 799 void visit(StorageClassDecl n) 800 { 801 w(ind); 802 TOK t; 803 Identifier* i; 804 final switch (n.stc) 805 { 806 case STC.Abstract: t = TOK.Abstract; break; 807 case STC.Auto: t = TOK.Auto; break; 808 case STC.Const: t = TOK.Const; break; 809 case STC.Deprecated: t = TOK.Deprecated; break; 810 case STC.Extern: t = TOK.Extern; break; 811 case STC.Final: t = TOK.Final; break; 812 case STC.Override: t = TOK.Override; break; 813 case STC.Scope: t = TOK.Scope; break; 814 case STC.Static: t = TOK.Static; break; 815 case STC.Synchronized: t = TOK.Synchronized; break; 816 case STC.In: t = TOK.In; break; 817 case STC.Out: t = TOK.Out; break; 818 case STC.Ref: t = TOK.Ref; break; 819 case STC.Lazy: t = TOK.Lazy; break; 820 case STC.Variadic: assert(0); break; 821 case STC.Immutable: t = TOK.Immutable; break; 822 case STC.Manifest: t = TOK.Enum; break; 823 case STC.Nothrow: t = TOK.Nothrow; break; 824 case STC.Pure: t = TOK.Pure; break; 825 case STC.Shared: t = TOK.Shared; break; 826 case STC.Gshared: t = TOK.Gshared; break; 827 case STC.Inout: t = TOK.Inout; break; 828 case STC.Disable: i = Ident.disable; break; 829 case STC.Property: i = Ident.property; break; 830 case STC.Safe: i = Ident.safe; break; 831 case STC.System: i = Ident.system; break; 832 case STC.Trusted: i = Ident.trusted; break; 833 case STC.None: assert(0); 834 } 835 if (i) 836 w(T.At, id(i)); 837 else 838 w(t.toToken()); 839 writeAttrDecl(n.decls); 840 } 841 842 void visit(LinkageDecl n) 843 { 844 w(ind, T.Extern, T.LParen); 845 final switch (n.linkageType) 846 { 847 case LINK.C: w(id(Ident.C)); break; 848 case LINK.Cpp: w(id(Ident.C), T.Plus2); break; 849 case LINK.D: w(id(Ident.D)); break; 850 case LINK.Windows: w(id(Ident.Windows)); break; 851 case LINK.Pascal: w(id(Ident.Pascal)); break; 852 case LINK.System: w(id(Ident.System)); break; 853 case LINK.None: assert(0); 854 } 855 w(T.RParen); 856 writeAttrDecl(n.decls); 857 } 858 859 void visit(AlignDecl n) 860 { 861 w(ind, T.Align); 862 if (n.sizetok) 863 w(T.LParen, n.sizetok, T.RParen); 864 writeAttrDecl(n.decls); 865 } 866 867 void visit(PragmaDecl n) 868 { 869 w(ind, T.Pragma, T.LParen, n.name); 870 if (n.args) { 871 w(T.Comma); 872 w(n.args); 873 } 874 w(T.RParen); 875 writeAttrDecl(n.decls); 876 } 877 878 void visit(MixinDecl n) 879 { 880 w(ind, T.Mixin); 881 if (n.isMixinExpr) 882 { 883 w(T.LParen); 884 v(n.argument); 885 w(T.RParen); 886 } 887 else 888 { 889 w(ws); 890 v(n.templateExpr); 891 if (n.mixinIdent) 892 w(ws, n.mixinIdent); 893 } 894 } 895 896 897 // Statements: 898 void visit(IllegalStmt n) 899 { 900 assert(0); 901 } 902 903 void visit(CompoundStmt n) 904 { 905 foreach (x; n.stmnts) 906 v(x); 907 } 908 909 void visit(EmptyStmt n) 910 { 911 w(ind, T.Semicolon, Newline); 912 } 913 914 void visit(FuncBodyStmt n) 915 { 916 if (n.isEmpty()) 917 w(T.Semicolon, Newline); 918 else 919 { 920 if (n.inBody) { 921 w(Newline); 922 w(ind, T.In); 923 writeBlock(n.inBody); 924 } 925 if (n.outBody) { 926 if (!n.inBody) 927 w(Newline); 928 w(ind, T.Out); 929 if (n.outIdent) 930 w(T.LParen, n.outIdent, T.RParen); 931 writeBlock(n.outBody); 932 } 933 if (n.inBody || n.outBody) 934 w(ind, T.Body); 935 writeBlock(n.funcBody); 936 } 937 w(Newline); 938 } 939 940 void visit(ScopeStmt n) 941 { 942 v(n.stmnt); 943 } 944 945 void visit(LabeledStmt n) 946 { 947 { 948 scope ul = new UnindentLevel; 949 w(ind, n.label, T.Colon, Newline); 950 } 951 v(n.stmnt); 952 } 953 954 void visit(ExpressionStmt n) 955 { 956 w(ind); 957 v(n.expr); 958 w(T.Semicolon, Newline); 959 } 960 961 void visit(DeclarationStmt n) 962 { 963 v(n.decl); 964 } 965 966 void visit(IfStmt n) 967 { 968 w(ind, T.If, T.LParen); 969 if (auto var = n.variable ? n.variable.to!VariablesDecl : null) 970 { 971 if (var.type) 972 v(var.type); 973 else 974 w(T.Auto); 975 w(ws, var.names[0], ws, T.Equal, ws); 976 v(var.inits[0]); 977 } 978 else 979 v(n.condition); 980 w(T.RParen); 981 writeBlock(n.ifBody); 982 if (n.elseBody) 983 { 984 w(ind, T.Else); 985 writeBlock(n.elseBody); 986 } 987 } 988 989 void visit(WhileStmt n) 990 { 991 w(ind, T.While, T.LParen); 992 v(n.condition); 993 w(T.RParen); 994 writeBlock(n.whileBody); 995 } 996 997 void visit(DoWhileStmt n) 998 { 999 w(ind, T.Do); 1000 writeBlock(n.doBody); 1001 w(ind, T.While, T.LParen); 1002 v(n.condition); 1003 version(D1) 1004 w(T.RParen, Newline); 1005 else 1006 w(T.RParen, T.Semicolon, Newline); 1007 } 1008 1009 void visit(ForStmt n) 1010 { 1011 w(ind, T.For, T.LParen); 1012 if (n.init) 1013 { 1014 scope il = new SetIndentLevel(""); 1015 v(n.init); 1016 // FIXME: remove trailing newlines. 1017 } 1018 else 1019 w(T.Semicolon); 1020 if (n.condition) { 1021 w(ws); 1022 v(n.condition); 1023 } 1024 w(T.Semicolon); 1025 if (n.increment) { 1026 w(ws); 1027 v(n.increment); 1028 } 1029 w(T.RParen); 1030 writeBlock(n.forBody); 1031 } 1032 1033 void visit(ForeachStmt n) 1034 { 1035 w(ind, n.tok.toToken(), T.LParen); 1036 foreach (i, param; n.params.items()) 1037 { 1038 if (i) 1039 w(T.Comma, ws); 1040 v(param); 1041 } 1042 w(T.Semicolon, ws); 1043 v(n.aggregate); 1044 w(T.RParen); 1045 writeBlock(n.forBody); 1046 } 1047 1048 void visit(SwitchStmt n) 1049 { 1050 w(ind); 1051 if (n.isFinal) 1052 w(T.Final, ws); 1053 w(T.Switch, T.LParen); 1054 v(n.condition); 1055 w(T.RParen,); 1056 writeBlock(n.switchBody); 1057 } 1058 1059 void visit(CaseStmt n) 1060 { 1061 scope ul = new UnindentLevel; 1062 w(ind, T.Case, ws); 1063 foreach (i, value; n.values) 1064 { 1065 if (i) 1066 w(T.Comma, ws); 1067 v(value); 1068 } 1069 w(T.Colon, Newline); 1070 scope il = new IndentLevel; 1071 v(n.caseBody); 1072 } 1073 1074 void visit(CaseRangeStmt n) 1075 { 1076 scope ul = new UnindentLevel; 1077 w(ind, T.Case, ws); 1078 v(n.left); 1079 w(T.Dot2); 1080 v(n.right); 1081 w(T.Colon, Newline); 1082 scope il = new IndentLevel; 1083 v(n.caseBody); 1084 } 1085 1086 void visit(DefaultStmt n) 1087 { 1088 scope ul = new UnindentLevel; 1089 w(ind, T.Default, T.Colon, Newline); 1090 scope il = new IndentLevel; 1091 v(n.defaultBody); 1092 } 1093 1094 void visit(ContinueStmt n) 1095 { 1096 w(ind, T.Continue); 1097 if (n.label) 1098 w(ws, n.label); 1099 w(T.Semicolon, Newline); 1100 } 1101 1102 void visit(BreakStmt n) 1103 { 1104 w(ind, T.Break); 1105 if (n.label) 1106 w(ws, n.label); 1107 w(T.Semicolon, Newline); 1108 } 1109 1110 void visit(ReturnStmt n) 1111 { 1112 w(ind, T.Return); 1113 if (n.expr) { 1114 w(ws); 1115 v(n.expr); 1116 } 1117 w(T.Semicolon, Newline); 1118 } 1119 1120 void visit(GotoStmt n) 1121 { 1122 w(ind, T.Goto, ws); 1123 if (n.isGotoLabel) 1124 w(n.ident); 1125 else if (n.isGotoCase) 1126 { 1127 if (n.expr) 1128 v(n.expr); 1129 } 1130 else 1131 w(T.Default); 1132 w(T.Semicolon, Newline); 1133 } 1134 1135 void visit(WithStmt n) 1136 { 1137 w(ind, T.With, T.LParen); 1138 v(n.expr); 1139 w(T.RParen); 1140 writeBlock(n.withBody); 1141 } 1142 1143 void visit(SynchronizedStmt n) 1144 { 1145 w(ind, T.Synchronized); 1146 if (n.expr) 1147 { 1148 w(T.LParen); 1149 v(n.expr); 1150 w(T.RParen); 1151 } 1152 writeBlock(n.syncBody); 1153 } 1154 1155 void visit(TryStmt n) 1156 { 1157 w(ind, T.Try); 1158 writeBlock(n.tryBody); 1159 foreach (b; n.catchBodies) 1160 v(b); 1161 if (n.finallyBody) 1162 v(n.finallyBody); 1163 } 1164 1165 void visit(CatchStmt n) 1166 { 1167 w(ind, T.Catch); 1168 if (n.param) 1169 { 1170 w(T.LParen); 1171 v(n.param); 1172 w(T.RParen); 1173 } 1174 writeBlock(n.catchBody); 1175 } 1176 1177 void visit(FinallyStmt n) 1178 { 1179 w(ind, T.Finally); 1180 writeBlock(n.finallyBody); 1181 } 1182 1183 void visit(ScopeGuardStmt n) 1184 { 1185 w(ind, T.Scope, T.LParen, n.condition, T.RParen); 1186 writeBlock(n.scopeBody); 1187 } 1188 1189 void visit(ThrowStmt n) 1190 { 1191 w(ind, T.Throw, ws); 1192 v(n.expr); 1193 w(T.Semicolon, Newline); 1194 } 1195 1196 void visit(VolatileStmt n) 1197 { 1198 w(ind, T.Volatile); 1199 writeBlock(n.volatileBody); 1200 } 1201 1202 void visit(AsmBlockStmt n) 1203 { 1204 w(ind, T.LBrace); 1205 scope il = new IndentLevel; 1206 v(n.statements); 1207 w(T.RBrace); 1208 } 1209 1210 void visit(AsmStmt n) 1211 { 1212 w(ind, n.opcode); 1213 foreach (i, o; n.operands) 1214 { 1215 if (i) 1216 w(T.Comma, ws); 1217 v(o); 1218 } 1219 w(T.Semicolon, Newline); 1220 } 1221 1222 void visit(AsmAlignStmt n) 1223 { 1224 w(ind, T.Align, n.numtok, T.Semicolon, Newline); 1225 } 1226 1227 void visit(IllegalAsmStmt n) 1228 { 1229 assert(0); 1230 } 1231 1232 void visit(PragmaStmt n) 1233 { 1234 w(ind, T.Pragma, T.LParen, n.name); 1235 if (n.args) { 1236 w(T.Comma); 1237 w(n.args); 1238 } 1239 w(T.RParen); 1240 writeBlock(n.pragmaBody); 1241 } 1242 1243 void visit(MixinStmt n) 1244 { 1245 w(ind, T.Mixin, ws); 1246 v(n.templateExpr); 1247 if (n.mixinIdent) 1248 w(ws, n.mixinIdent); 1249 w(T.Semicolon, Newline); 1250 } 1251 1252 void visit(StaticIfStmt n) 1253 { 1254 w(ind, T.Static, ws, T.If, T.LParen); 1255 v(n.condition); 1256 w(T.RParen); 1257 writeBlock(n.ifBody); 1258 if (n.elseBody) { 1259 w(ind, T.Else); 1260 writeBlock(n.elseBody); 1261 } 1262 } 1263 1264 void visit(StaticAssertStmt n) 1265 { 1266 w(ind, T.Static, ws, T.Assert, T.LParen); 1267 v(n.condition); 1268 if (n.message) { 1269 w(T.Comma, ws); 1270 v(n.message); 1271 } 1272 w(T.RParen, Newline); 1273 } 1274 1275 void visit(DebugStmt n) 1276 { 1277 w(ind, T.Debug); 1278 if (n.cond) 1279 w(T.LParen, n.cond, T.RParen); 1280 writeBlock(n.mainBody); 1281 if (n.elseBody) 1282 { 1283 w(ind, T.Else); 1284 writeBlock(n.elseBody); 1285 } 1286 } 1287 1288 void visit(VersionStmt n) 1289 { 1290 w(ind, T.Version, T.LParen, n.cond, T.RParen); 1291 writeBlock(n.mainBody); 1292 if (n.elseBody) 1293 { 1294 w(ind, T.Else); 1295 writeBlock(n.elseBody); 1296 } 1297 } 1298 1299 1300 // Expressions: 1301 void visit(IllegalExpr n) 1302 { 1303 assert(0); 1304 } 1305 1306 void visit(CondExpr n) 1307 { 1308 w(n.condition, PREC.LogicalOr); 1309 w(ws, T.Question, ws); 1310 w(n.lhs, PREC.Expression); 1311 w(ws, T.Colon, ws); 1312 w(n.rhs, PREC.Conditional); 1313 } 1314 1315 void visit(CommaExpr n) 1316 { // lhs may be another CommaExpr. 1317 w(n.lhs, PREC.Expression); 1318 w(n.optok, ws); 1319 w(n.rhs, PREC.Assignment); 1320 } 1321 1322 void visit(OrOrExpr n) 1323 { 1324 w(n); 1325 } 1326 1327 void visit(AndAndExpr n) 1328 { 1329 w(n); 1330 } 1331 1332 void visit(OrExpr n) 1333 { 1334 w(n); 1335 } 1336 1337 void visit(XorExpr n) 1338 { 1339 w(n); 1340 } 1341 1342 void visit(AndExpr n) 1343 { 1344 w(n); 1345 } 1346 1347 void visit(EqualExpr n) 1348 { 1349 w(n); 1350 } 1351 1352 void visit(IdentityExpr n) 1353 { 1354 w(n.lhs, PREC.Relational); 1355 if (n.optok.kind == TOK.Exclaim) 1356 w(ws, T.Exclaim, T.Is, ws); 1357 else 1358 w(ws, T.Is, ws); 1359 w(n.rhs, PREC.Relational); 1360 } 1361 1362 void visit(RelExpr n) 1363 { 1364 w(n); 1365 } 1366 1367 void visit(InExpr n) 1368 { 1369 w(n.lhs, PREC.Relational); 1370 if (n.optok.kind == TOK.Exclaim) 1371 w(ws, T.Exclaim, T.In, ws); 1372 else 1373 w(ws, T.In, ws); 1374 w(n.rhs, PREC.Relational); 1375 } 1376 1377 void visit(LShiftExpr n) 1378 { 1379 w(n); 1380 } 1381 1382 void visit(RShiftExpr n) 1383 { 1384 w(n); 1385 } 1386 1387 void visit(URShiftExpr n) 1388 { 1389 w(n); 1390 } 1391 1392 void visit(PlusExpr n) 1393 { 1394 w(n); 1395 } 1396 1397 void visit(MinusExpr n) 1398 { 1399 w(n); 1400 } 1401 1402 void visit(CatExpr n) 1403 { 1404 w(n); 1405 } 1406 1407 void visit(MulExpr n) 1408 { 1409 w(n); 1410 } 1411 1412 void visit(DivExpr n) 1413 { 1414 w(n); 1415 } 1416 1417 void visit(ModExpr n) 1418 { 1419 w(n); 1420 } 1421 1422 void visit(PowExpr n) 1423 { 1424 w(n); 1425 } 1426 1427 void visit(AssignExpr n) 1428 { 1429 w(n); 1430 } 1431 1432 void visit(LShiftAssignExpr n) 1433 { 1434 w(n); 1435 } 1436 1437 void visit(RShiftAssignExpr n) 1438 { 1439 w(n); 1440 } 1441 1442 void visit(URShiftAssignExpr n) 1443 { 1444 w(n); 1445 } 1446 1447 void visit(OrAssignExpr n) 1448 { 1449 w(n); 1450 } 1451 1452 void visit(AndAssignExpr n) 1453 { 1454 w(n); 1455 } 1456 1457 void visit(PlusAssignExpr n) 1458 { 1459 w(n); 1460 } 1461 1462 void visit(MinusAssignExpr n) 1463 { 1464 w(n); 1465 } 1466 1467 void visit(DivAssignExpr n) 1468 { 1469 w(n); 1470 } 1471 1472 void visit(MulAssignExpr n) 1473 { 1474 w(n); 1475 } 1476 1477 void visit(ModAssignExpr n) 1478 { 1479 w(n); 1480 } 1481 1482 void visit(XorAssignExpr n) 1483 { 1484 w(n); 1485 } 1486 1487 void visit(CatAssignExpr n) 1488 { 1489 w(n); 1490 } 1491 1492 void visit(PowAssignExpr n) 1493 { 1494 w(n); 1495 } 1496 1497 void visit(RangeExpr n) 1498 { 1499 w(n); 1500 } 1501 1502 void visit(AddressExpr n) 1503 { 1504 w(T.Amp); 1505 w(n); 1506 } 1507 1508 void visit(PreIncrExpr n) 1509 { 1510 w(T.Plus2); 1511 w(n); 1512 } 1513 1514 void visit(PreDecrExpr n) 1515 { 1516 w(T.Minus2); 1517 w(n); 1518 } 1519 1520 void visit(PostIncrExpr n) 1521 { 1522 w(n); 1523 w(T.Plus2); 1524 } 1525 1526 void visit(PostDecrExpr n) 1527 { 1528 w(n); 1529 w(T.Minus2); 1530 } 1531 1532 void visit(DerefExpr n) 1533 { 1534 w(T.Star); 1535 w(n); 1536 } 1537 1538 void visit(SignExpr n) 1539 { 1540 if (n.isPos) 1541 w(T.Plus); 1542 else 1543 w(T.Minus); 1544 w(n); 1545 } 1546 1547 void visit(NotExpr n) 1548 { 1549 w(T.Exclaim); 1550 w(n); 1551 } 1552 1553 void visit(CompExpr n) 1554 { 1555 w(T.Tilde); 1556 w(n); 1557 } 1558 1559 void visit(CallExpr n) 1560 { 1561 w(n); 1562 w(T.LParen); 1563 w(n.args); 1564 w(T.RParen); 1565 } 1566 1567 void visit(NewExpr n) 1568 { 1569 if (n.frame) { 1570 v(n.frame); 1571 w(T.Dot); 1572 } 1573 w(T.New); 1574 if (n.newArgs) 1575 { 1576 w(T.LParen); 1577 w(n.newArgs); 1578 w(T.RParen); 1579 } 1580 w(ws); 1581 v(n.type); 1582 if (n.ctorArgs) 1583 { 1584 w(T.LParen); 1585 w(n.ctorArgs); 1586 w(T.RParen); 1587 } 1588 } 1589 1590 void visit(NewClassExpr n) 1591 { 1592 if (n.frame) { 1593 v(n.frame); 1594 w(T.Dot); 1595 } 1596 w(T.New); 1597 if (n.newArgs) 1598 { 1599 w(T.LParen); 1600 w(n.newArgs); 1601 w(T.RParen); 1602 } 1603 w(ws); 1604 w(T.Class); 1605 if (n.ctorArgs) 1606 { 1607 w(T.LParen); 1608 w(n.ctorArgs); 1609 w(T.RParen); 1610 } 1611 if (n.bases) 1612 { 1613 w(ws); 1614 foreach (i, b; n.bases) 1615 { 1616 if (i) 1617 w(T.Comma, ws); 1618 v(b); 1619 } 1620 } 1621 writeAggregateBody(n.decls); 1622 } 1623 1624 void visit(DeleteExpr n) 1625 { 1626 w(T.Delete); 1627 v(n.una); 1628 } 1629 1630 void visit(CastExpr n) 1631 { 1632 w(T.Cast, T.LParen); 1633 if (n.type) 1634 v(n.type); 1635 w(T.RParen); 1636 w(n); 1637 } 1638 1639 void visit(IndexExpr n) 1640 { 1641 w(n); 1642 w(T.LBracket); 1643 w(n.args); 1644 w(T.RBracket); 1645 } 1646 1647 void visit(SliceExpr n) 1648 { 1649 w(n); 1650 w(T.LBracket); 1651 if (n.range) 1652 w(n.range.to!RangeExpr); 1653 w(T.RBracket); 1654 } 1655 1656 void visit(ModuleScopeExpr n) 1657 { 1658 w(T.Dot); 1659 } 1660 1661 void visit(IdentifierExpr n) 1662 { 1663 if (n.next) { 1664 w(n.next, PREC.Primary); 1665 if (!n.next.Is!(ModuleScopeExpr)) 1666 w(T.Dot); 1667 } 1668 w(n.name); 1669 } 1670 1671 void visit(SpecialTokenExpr n) 1672 { 1673 w(n.specialToken); 1674 } 1675 1676 void visit(TmplInstanceExpr n) 1677 { 1678 if (n.next) { 1679 w(n.next, PREC.Primary); 1680 if (!n.next.Is!(ModuleScopeExpr)) 1681 w(T.Dot); 1682 } 1683 w(n.name, T.Exclaim, T.LParen); 1684 v(n.targs); 1685 w(T.RParen); 1686 } 1687 1688 void visit(ThisExpr n) 1689 { 1690 w(T.This); 1691 } 1692 1693 void visit(SuperExpr n) 1694 { 1695 w(T.Super); 1696 } 1697 1698 void visit(NullExpr n) 1699 { 1700 w(T.Null); 1701 } 1702 1703 void visit(DollarExpr n) 1704 { 1705 w(T.Dollar); 1706 } 1707 1708 void visit(BoolExpr n) 1709 { 1710 w(n.toBool ? T.True : T.False); 1711 } 1712 1713 void visit(IntExpr n) 1714 { 1715 if (auto t = n.begin) // Write the original Token if available. 1716 if (t.kind.In(TOK.Int32, TOK.Int64, TOK.UInt32, TOK.UInt64)) 1717 return w(t); 1718 1719 void writeCast(TOK k) 1720 { 1721 w(T.Cast, T.LParen, k.toToken(), T.RParen); 1722 } 1723 1724 cstring txt; 1725 TOK k; 1726 auto num = n.number; 1727 1728 if (n.type) 1729 switch (n.type.tid) 1730 { 1731 case TYP.Int8: writeCast(TOK.Byte); goto case TYP.Int32; 1732 case TYP.Int16: writeCast(TOK.Short); goto case TYP.Int32; 1733 case TYP.Int32: txt = "{}"; k = TOK.Int32; break; 1734 case TYP.Int64: txt = "{}L"; k = TOK.Int64; break; 1735 case TYP.UInt8: writeCast(TOK.Ubyte); goto case TYP.UInt32; 1736 case TYP.UInt16: writeCast(TOK.Ushort); goto case TYP.UInt32; 1737 case TYP.UInt32: txt = "{}U"; k = TOK.UInt32; break; 1738 case TYP.UInt64: txt = "{}LU"; k = TOK.UInt32; break; 1739 default: 1740 assert(0, "unhandled int type"); 1741 } 1742 else 1743 { 1744 txt = "{}"; 1745 if (num & 0x8000_0000_0000_0000) { 1746 txt = "0x{:X}"; 1747 k = TOK.UInt64; 1748 } 1749 else if (num & 0xFFFF_FFFF_0000_0000) 1750 k = TOK.Int64; 1751 else if (num & 0x8000_0000) { 1752 txt = "0x{:X}"; 1753 k = TOK.UInt32; 1754 } 1755 else 1756 k = TOK.Int32; 1757 } 1758 assert(k); 1759 1760 txt = Format(txt, num); // Convert to text. 1761 1762 // Finally construct the integer Token. 1763 Token t; 1764 t.kind = k; 1765 t.text = txt; 1766 1767 if (k == TOK.Int64 || k == TOK.UInt64) 1768 { 1769 version(X86_64) 1770 t.intval.ulong_ = num; 1771 else 1772 t.intval = cc.tables.lxtables.lookupUlong(num); 1773 } 1774 else 1775 t.uint_ = cast(uint)num; 1776 1777 w(&t); 1778 } 1779 1780 void visit(FloatExpr n) 1781 { 1782 if (auto t = n.begin) // Write the original Token if available. 1783 if (t.kind.In(TOK.Float32, TOK.Float64, TOK.Float80, 1784 TOK.IFloat32, TOK.IFloat64, TOK.IFloat80)) 1785 return w(t); 1786 1787 cstring txt; 1788 TOK k = TOK.Float64; 1789 1790 // FIXME: inaccurate conversion 1791 txt = Format("{}", n.number); 1792 1793 if (auto type = n.type) 1794 { 1795 type = type.baseType(); 1796 switch (n.type.tid) 1797 { 1798 case TYP.Float32, TYP.IFloat32, TYP.CFloat32: 1799 txt ~= 'F'; k = TOK.Float32; break; 1800 case TYP.Float80, TYP.IFloat80, TYP.CFloat80: 1801 txt ~= 'L'; k = TOK.Float80; break; 1802 default: 1803 assert(0, "unhandled float type"); 1804 } 1805 if (type.isImaginary) 1806 txt ~= 'i'; 1807 } 1808 1809 Token t; 1810 t.kind = k; 1811 t.text = txt; 1812 t.mpfloat = n.number; 1813 1814 w(&t); 1815 } 1816 1817 void visit(ComplexExpr n) 1818 { 1819 w(T.LParen); 1820 auto c = n.number; 1821 auto re = new FloatExpr(c.re, n.reType); 1822 auto im = new FloatExpr(c.im, n.imType); 1823 v(re); 1824 w(ws, c.im.isNeg ? T.Minus : T.Plus, ws); 1825 v(im); 1826 w(T.RParen); 1827 } 1828 1829 void visit(CharExpr n) 1830 { 1831 auto c = n.charValue; 1832 cstring txt = `'`; 1833 txt ~= (c == '\'') ? `\'` : (c == '\\') ? `\\` : escapeNonPrintable(c); 1834 txt ~= `'`; 1835 1836 Token t; 1837 t.kind = TOK.Character; 1838 t.text = txt; 1839 t.dchar_ = c; 1840 1841 w(&t); 1842 } 1843 1844 void visit(StringExpr n) 1845 { 1846 if (n.begin && n.end) 1847 { // Write original tokens if available. 1848 writeSpan(n.begin, n.end); 1849 return; 1850 } 1851 1852 // NB: could be optimized to copying the string if no escaping is needed. 1853 // FIXME: the string might not be in UTF-8. 1854 auto s = n.getString(); 1855 char[] txt = `"`.dup; 1856 1857 foreach (c; s) 1858 txt ~= (c == '\"') ? `\"` : (c == '\\') ? `\\` : escapeNonPrintable(c); 1859 1860 txt ~= `"`; 1861 1862 if (auto pf = n.postfix) 1863 txt ~= pf; 1864 1865 Token t; 1866 t.kind = TOK.String; 1867 t.text = txt; 1868 // FIXME: look up in lxtables. 1869 auto sv = new Token.StringValue; 1870 sv.str = cast(cbinstr)s; 1871 t.strval = sv; 1872 1873 w(&t); 1874 } 1875 1876 void visit(ArrayLiteralExpr n) 1877 { 1878 w(T.LBracket); 1879 w(n.values); 1880 w(T.RBracket); 1881 } 1882 1883 void visit(AArrayLiteralExpr n) 1884 { 1885 w(T.LBracket); 1886 foreach (i, value; n.values) 1887 { 1888 if (i) 1889 w(T.Comma, ws); 1890 w(n.keys[i], PREC.Assignment); 1891 w(T.Colon, ws); 1892 w(value, PREC.Assignment); 1893 } 1894 w(T.RBracket); 1895 } 1896 1897 void visit(AssertExpr n) 1898 { 1899 w(T.Assert, T.LParen); 1900 w(n.expr, PREC.Assignment); 1901 if (n.msg) { 1902 w(T.Comma, ws); 1903 w(n.expr, PREC.Assignment); 1904 } 1905 w(T.RParen); 1906 } 1907 1908 void visit(MixinExpr n) 1909 { 1910 w(T.Mixin, T.LParen); 1911 v(n.expr); 1912 w(T.RParen); 1913 } 1914 1915 void visit(ImportExpr n) 1916 { 1917 w(T.Import, T.LParen); 1918 v(n.expr); 1919 w(T.RParen); 1920 } 1921 1922 void visit(TypeExpr n) 1923 { 1924 v(n.typeNode); 1925 } 1926 1927 void visit(TypeofExpr n) 1928 { 1929 v(n.type); 1930 } 1931 1932 void visit(TypeDotIdExpr n) 1933 { 1934 w(T.LParen); 1935 v(n.type); 1936 w(T.RParen, T.Dot, n.ident); 1937 } 1938 1939 void visit(TypeidExpr n) 1940 { 1941 w(T.Typeid, T.LParen); 1942 v(n.type); 1943 w(T.RParen); 1944 } 1945 1946 void visit(IsExpr n) 1947 { 1948 w(T.Is, T.LParen); 1949 v(n.type); 1950 if (n.name) 1951 w(ws, n.name); 1952 if (n.opTok) 1953 { 1954 w(ws, n.opTok, ws); 1955 if (n.specTok) 1956 w(n.specTok); 1957 else 1958 v(n.specType); 1959 } 1960 if (n.name && n.specType && n.tparams) 1961 { 1962 w(T.Comma, ws); 1963 foreach (i, param; n.tparams.items()) 1964 { 1965 if (i) 1966 w(T.Comma, ws); 1967 v(param); 1968 } 1969 } 1970 w(T.RParen); 1971 } 1972 1973 void visit(ParenExpr n) 1974 { 1975 w(T.LParen); 1976 v(n.next); 1977 w(T.RParen); 1978 } 1979 1980 void visit(FuncLiteralExpr n) 1981 { 1982 if (n.tok) 1983 w(n.tok, ws); 1984 if (n.returnType) 1985 v(n.returnType), w(ws); 1986 if (n.params) 1987 v(n.params), w(ws); 1988 // TODO: print n.params.postSTCs 1989 if (auto fb = n.funcBody.Is!FuncBodyStmt) 1990 { 1991 w(T.LBrace, Newline); 1992 { 1993 scope il = new IndentLevel; 1994 v(fb.funcBody); // FIXME: fb can have in/out contracts. 1995 } 1996 w(ind, T.RBrace); 1997 } 1998 else 1999 { 2000 assert(n.funcBody.isExpression); 2001 w(T.EqlGreater, ws); 2002 w(cast(Expression)n.funcBody, PREC.Assignment); 2003 } 2004 } 2005 2006 void visit(LambdaExpr n) 2007 { 2008 if (n.params.length == 1 && 2009 !n.params.items[0].stcs && // No STCs. 2010 !n.params.items[0].type && // No type. 2011 !n.params.items[0].defValue) // No default value. 2012 w(n.params.items[0].name); // Single argument. 2013 else 2014 v(n.params); 2015 w(ws, T.EqlGreater, ws); 2016 w(n.expr, PREC.Assignment); 2017 } 2018 2019 void visit(TraitsExpr n) 2020 { 2021 w(T.Traits, T.LParen, n.name); 2022 if (n.targs) { 2023 w(T.Comma); 2024 v(n.targs); 2025 } 2026 w(T.RParen); 2027 } 2028 2029 void visit(VoidInitExpr n) 2030 { 2031 w(T.Void); 2032 } 2033 2034 void visit(ArrayInitExpr n) 2035 { 2036 w(T.LBracket); 2037 foreach (i, value; n.values) 2038 { 2039 if (i) 2040 w(T.Comma, ws); 2041 if (auto key = n.keys[i]) { 2042 w(key, PREC.Assignment); 2043 w(T.Colon, ws); 2044 } 2045 w(value, PREC.Assignment); 2046 } 2047 w(T.RBracket); 2048 } 2049 2050 void visit(StructInitExpr n) 2051 { 2052 w(T.LBrace); 2053 foreach (i, value; n.values) 2054 { 2055 if (i) 2056 w(T.Comma, ws); 2057 if (auto ident = n.idents[i]) 2058 w(ident, T.Colon, ws); 2059 w(value, PREC.Assignment); 2060 } 2061 w(T.RBrace); 2062 } 2063 2064 void visit(AsmTypeExpr n) 2065 { 2066 w(n.prefix, ws, id(Ident.ptr), ws); 2067 w(n.una, PREC.Unary); 2068 } 2069 2070 void visit(AsmOffsetExpr n) 2071 { 2072 w(id(Ident.offsetof)); 2073 w(n.una, PREC.Unary); 2074 } 2075 2076 void visit(AsmSegExpr n) 2077 { 2078 w(id(Ident.seg)); 2079 w(n.una, PREC.Unary); 2080 } 2081 2082 void visit(AsmPostBracketExpr n) 2083 { 2084 w(n.una, PREC.Unary); 2085 w(T.LBracket); 2086 w(n.index, PREC.Expression); 2087 w(T.RBracket); 2088 } 2089 2090 void visit(AsmBracketExpr n) 2091 { 2092 w(T.LBracket); 2093 w(n.expr, PREC.Expression); 2094 w(T.RBracket); 2095 } 2096 2097 void visit(AsmLocalSizeExpr n) 2098 { 2099 w(id(Ident.__LOCAL_SIZE)); 2100 } 2101 2102 void visit(AsmRegisterExpr n) 2103 { 2104 w(n.register); 2105 if (n.number) 2106 { 2107 if (n.register.ident is Ident.ST && n.number) 2108 { 2109 w(T.LBracket); 2110 v(n.number); 2111 w(T.RBracket); 2112 } 2113 else 2114 { 2115 w(T.Colon); 2116 w(n.number, PREC.Expression); 2117 } 2118 } 2119 } 2120 2121 2122 // Types: 2123 void visit(IllegalType n) 2124 { 2125 assert(0); 2126 } 2127 2128 void visit(IntegralType n) 2129 { 2130 w(n.tok.toToken()); 2131 } 2132 2133 void visit(ModuleScopeType n) 2134 { 2135 w(T.Dot); 2136 } 2137 2138 void visit(IdentifierType n) 2139 { 2140 if (n.next) { 2141 v(n.next); 2142 if (!n.next.Is!(ModuleScopeType)) 2143 w(T.Dot); 2144 } 2145 w(n.name); 2146 } 2147 2148 void visit(TypeofType n) 2149 { 2150 w(T.Typeof, T.LParen); 2151 if (n.isTypeofReturn) 2152 w(T.Return); 2153 else 2154 v(n.expr); 2155 w(T.RParen); 2156 } 2157 2158 void visit(TmplInstanceType n) 2159 { 2160 if (n.next) { 2161 v(n.next); 2162 if (!n.next.Is!(ModuleScopeType)) 2163 w(T.Dot); 2164 } 2165 w(n.name, T.Exclaim, T.LParen); 2166 v(n.targs); 2167 w(T.RParen); 2168 } 2169 2170 void visit(PointerType n) 2171 { 2172 v(n.next); 2173 w(T.Star); 2174 } 2175 2176 void visit(ArrayType n) 2177 { 2178 v(n.next); 2179 w(T.LBracket); 2180 if (n.assocType) 2181 v(n.assocType); 2182 else if (n.index1) 2183 { 2184 v(n.index1); 2185 if (n.index2) { 2186 w(T.Dot2); 2187 v(n.index2); 2188 } 2189 } 2190 w(T.RBracket); 2191 } 2192 2193 void visit(FunctionType n) 2194 { 2195 v(n.next); 2196 w(ws, T.Function); 2197 v(n.params); 2198 } 2199 2200 void visit(DelegateType n) 2201 { 2202 v(n.next); 2203 w(ws, T.Delegate); 2204 v(n.params); 2205 } 2206 2207 void visit(BaseClassType n) 2208 { 2209 if (auto tok = protToTOK(n.prot)) 2210 w(tok.toToken(), ws); 2211 v(n.next); 2212 } 2213 2214 void visit(ModifierType n) 2215 { 2216 w(n.mod); 2217 if (n.hasParen) 2218 { 2219 w(T.LParen); 2220 v(n.next); 2221 w(T.RParen); 2222 } 2223 else if (n.next) 2224 { 2225 w(ws); 2226 v(n.next); 2227 } 2228 } 2229 2230 // Parameters: 2231 void visit(Parameter n) 2232 { 2233 if (n.isCVariadic) 2234 return w(T.Dot3); 2235 if (n.stcs) 2236 { 2237 for (auto i = STC.max; i; i >>= 1) 2238 if (auto stc = n.stcs & i) 2239 { 2240 TOK t; 2241 switch (stc) 2242 { 2243 case STC.Const: t = TOK.Const; break; 2244 case STC.Immutable: t = TOK.Immutable; break; 2245 case STC.Inout: t = TOK.Inout; break; 2246 case STC.Shared: t = TOK.Shared; break; 2247 case STC.Final: t = TOK.Final; break; 2248 case STC.Scope: t = TOK.Scope; break; 2249 case STC.Static: t = TOK.Static; break; 2250 case STC.Auto: t = TOK.Auto; break; 2251 case STC.In: t = TOK.In; break; 2252 case STC.Out: t = TOK.Out; break; 2253 case STC.Ref: t = TOK.Ref; break; 2254 case STC.Variadic: continue; 2255 default: 2256 assert(0, EnumString(stc)); 2257 } 2258 w(t.toToken(), ws); 2259 } 2260 } 2261 if (n.type) 2262 v(n.type); 2263 if (n.hasName) 2264 { 2265 if (n.type) 2266 w(ws); 2267 w(n.name); 2268 } 2269 if (n.defValue) { 2270 w(ws, T.Equal, ws); 2271 v(n.defValue); 2272 } 2273 if (n.isDVariadic) 2274 w(T.Dot3); 2275 } 2276 2277 void visit(Parameters n) 2278 { 2279 w(T.LParen); 2280 foreach (i, param; n.items()) 2281 { 2282 if (i) 2283 w(T.Comma, ws); 2284 v(param); 2285 } 2286 w(T.RParen); 2287 } 2288 2289 void visit(TemplateAliasParam n) 2290 { 2291 w(T.Alias, ws, n.name); 2292 writeSpecDef(n.spec, n.def); 2293 } 2294 2295 void visit(TemplateTypeParam n) 2296 { 2297 w(n.name); 2298 writeSpecDef(n.specType, n.defType); 2299 } 2300 2301 void visit(TemplateThisParam n) 2302 { 2303 w(T.This, ws, n.name); 2304 writeSpecDef(n.specType, n.defType); 2305 } 2306 2307 void visit(TemplateValueParam n) 2308 { 2309 v(n.valueType); 2310 w(ws, n.name); 2311 writeSpecDef(n.specValue, n.defValue); 2312 } 2313 2314 void visit(TemplateTupleParam n) 2315 { 2316 w(n.name, T.Dot3); 2317 } 2318 2319 void visit(TemplateParameters n) 2320 { 2321 w(T.LParen); 2322 foreach (i, param; n.items()) 2323 { 2324 if (i) 2325 w(T.Comma, ws); 2326 v(param); 2327 } 2328 w(T.RParen); 2329 } 2330 2331 void visit(TemplateArguments n) 2332 { 2333 foreach (i, x; n.items) 2334 { 2335 if (i) 2336 w(T.Comma, ws); 2337 v(x); 2338 } 2339 } 2340 }