1 // Copyright Brian Schott (Hackerpilot) 2012. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module dparse.astprinter; 7 8 import std.array; 9 import std.stdio; 10 import std.string; 11 12 import dparse.ast; 13 import dparse.formatter; 14 import dparse.lexer; 15 16 17 /** 18 * AST visitor that outputs an XML representation of the AST to its file. 19 */ 20 class XMLPrinter : ASTVisitor 21 { 22 override void visit(const AddExpression addExpression) 23 { 24 output.writeln("<addExpression operator=\"", str(addExpression.operator), "\">"); 25 output.writeln("<left>"); 26 visit(addExpression.left); 27 output.writeln("</left>"); 28 if (addExpression.right !is null) 29 { 30 output.writeln("<right>"); 31 visit(addExpression.right); 32 output.writeln("</right>"); 33 } 34 output.writeln("</addExpression>"); 35 } 36 37 override void visit(const AliasDeclaration aliasDeclaration) 38 { 39 output.writeln("<aliasDeclaration>"); 40 writeDdoc(aliasDeclaration.comment); 41 aliasDeclaration.accept(this); 42 output.writeln("</aliasDeclaration>"); 43 } 44 45 override void visit(const AlignAttribute alignAttribute) 46 { 47 if (alignAttribute.assignExpression is null) 48 output.writeln("<alignAttribute/>"); 49 else 50 { 51 output.write("<alignAttribute align=\""); 52 format(output.lockingTextWriter, alignAttribute.assignExpression); 53 output.writeln("\"/>"); 54 } 55 } 56 57 override void visit(const AndAndExpression andAndExpression) 58 { 59 output.writeln("<andAndExpression>"); 60 output.writeln("<left>"); 61 visit(andAndExpression.left); 62 output.writeln("</left>"); 63 if (andAndExpression.right !is null) 64 { 65 output.writeln("<right>"); 66 visit(andAndExpression.right); 67 output.writeln("</right>"); 68 } 69 output.writeln("</andAndExpression>"); 70 } 71 72 override void visit(const AndExpression andExpression) 73 { 74 output.writeln("<andExpression>"); 75 output.writeln("<left>"); 76 visit(andExpression.left); 77 output.writeln("</left>"); 78 if (andExpression.right !is null) 79 { 80 output.writeln("<right>"); 81 visit(andExpression.right); 82 output.writeln("</right>"); 83 } 84 output.writeln("</andExpression>"); 85 } 86 87 override void visit(const AsmInstruction asmInstruction) 88 { 89 output.writeln("<asmInstruction>"); 90 if (asmInstruction.hasAlign) 91 { 92 output.writeln("<align>"); 93 visit(asmInstruction.identifierOrIntegerOrOpcode); 94 output.writeln("</align>"); 95 } 96 if (asmInstruction.asmInstruction !is null) 97 { 98 output.writeln("<label label=\"", 99 asmInstruction.identifierOrIntegerOrOpcode.text, "\"/>"); 100 asmInstruction.asmInstruction.accept(this); 101 } 102 else if (asmInstruction.identifierOrIntegerOrOpcode != tok!"") 103 visit(asmInstruction.identifierOrIntegerOrOpcode); 104 if (asmInstruction.operands !is null) 105 { 106 visit(asmInstruction.operands); 107 } 108 output.writeln("</asmInstruction>"); 109 } 110 111 override void visit(const AssignExpression assignExpression) 112 { 113 if (assignExpression.expression is null) 114 output.writeln("<expression>"); 115 else 116 output.writeln("<expression operator=\"", 117 xmlAttributeEscape(str(assignExpression.operator)), "\">"); 118 assignExpression.accept(this); 119 output.writeln("</expression>"); 120 } 121 122 override void visit(const AtAttribute atAttribute) 123 { 124 output.writeln("<atAttribute>"); 125 if (atAttribute.identifier.type != tok!"") 126 output.writeln("<identifier>", atAttribute.identifier.text, "</identifier>"); 127 atAttribute.accept(this); 128 output.writeln("</atAttribute>"); 129 } 130 131 override void visit(const Attribute attribute) 132 { 133 if (attribute.attribute == tok!"") 134 { 135 output.writeln("<attribute>"); 136 attribute.accept(this); 137 output.writeln("</attribute>"); 138 } 139 else if (attribute.identifierChain is null) 140 output.writeln("<attribute attribute=\"", str(attribute.attribute.type), "\"/>"); 141 else 142 { 143 output.writeln("<attribute attribute=\"", str(attribute.attribute.type), "\">"); 144 visit(attribute.identifierChain); 145 output.writeln("</attribute>"); 146 } 147 } 148 149 override void visit(const AutoDeclaration autoDec) 150 { 151 output.writeln("<autoDeclaration>"); 152 output.writeln("<storageClasses>"); 153 foreach (sc; autoDec.storageClasses) 154 visit(sc); 155 output.writeln("</storageClasses>"); 156 157 foreach (part; autoDec.parts) 158 visit(part); 159 output.writeln("</autoDeclaration>"); 160 } 161 162 override void visit(const AutoDeclarationPart part) 163 { 164 output.writeln("<autoDeclarationPart>"); 165 166 output.writeln("<item>"); 167 output.writeln("<name line=\"", part.identifier.line, "\">", part.identifier.text, "</name>"); 168 visit(part.initializer); 169 output.writeln("</item>"); 170 output.writeln("</autoDeclarationPart>"); 171 } 172 173 override void visit(const BreakStatement breakStatement) 174 { 175 if (breakStatement.label.type == tok!"") 176 output.writeln("<breakStatement/>"); 177 else 178 output.writeln("<breakStatement label=\"", breakStatement.label.text, "\"/>"); 179 } 180 181 override void visit(const BitfieldWidth bitfieldWidth) 182 { 183 output.writeln("<bitfieldWidth>"); 184 bitfieldWidth.accept(this); 185 output.writeln("</bitfieldWidth>"); 186 } 187 188 override void visit(const CaseRangeStatement caseRangeStatement) 189 { 190 output.writeln("<caseRangeStatement>"); 191 if (caseRangeStatement.low !is null) 192 { 193 output.writeln("<low>"); 194 visit(caseRangeStatement.low); 195 output.writeln("</low>"); 196 } 197 if (caseRangeStatement.high !is null) 198 { 199 output.writeln("<high>"); 200 visit(caseRangeStatement.high); 201 output.writeln("</high>"); 202 } 203 if (caseRangeStatement.declarationsAndStatements !is null) 204 visit(caseRangeStatement.declarationsAndStatements); 205 output.writeln("</caseRangeStatement>"); 206 } 207 208 override void visit(const Catch catch_) 209 { 210 output.writeln("<catch>"); 211 catch_.accept(this); 212 output.writeln("</catch>"); 213 } 214 215 override void visit(const ClassDeclaration classDec) 216 { 217 output.writeln("<classDeclaration line=\"", classDec.name.line, "\">"); 218 writeName(classDec.name.text); 219 writeDdoc(classDec.comment); 220 classDec.accept(this); 221 output.writeln("</classDeclaration>"); 222 } 223 224 override void visit(const ConditionalDeclaration conditionalDeclaration) 225 { 226 output.writeln("<conditionalDeclaration>"); 227 visit(conditionalDeclaration.compileCondition); 228 output.writeln("<trueDeclarations style=\"", conditionalDeclaration.trueStyle, "\">"); 229 foreach (dec; conditionalDeclaration.trueDeclarations) 230 visit(dec); 231 output.writeln("</trueDeclarations>"); 232 if (conditionalDeclaration.falseDeclarations.length > 0) 233 { 234 output.writeln("<falseDeclarations style=\"", conditionalDeclaration.trueStyle, "\">"); 235 foreach (dec; conditionalDeclaration.falseDeclarations) 236 visit(dec); 237 output.writeln("</falseDeclarations>"); 238 } 239 output.writeln("</conditionalDeclaration>"); 240 } 241 242 override void visit(const ConditionalStatement conditionalStatement) 243 { 244 output.writeln("<conditionalStatement>"); 245 visit(conditionalStatement.compileCondition); 246 output.writeln("<trueStatement>"); 247 visit(conditionalStatement.trueStatement); 248 output.writeln("</trueStatement>"); 249 if (conditionalStatement.falseStatement !is null) 250 { 251 output.writeln("<falseStatement>"); 252 visit(conditionalStatement.falseStatement); 253 output.writeln("</falseStatement>"); 254 } 255 output.writeln("</conditionalStatement>"); 256 } 257 258 override void visit(const ContinueStatement continueStatement) 259 { 260 if (continueStatement.label.type == tok!"") 261 output.writeln("<continueStatement/>"); 262 else 263 output.writeln("<continueStatement label=\"", continueStatement.label.text, "\"/>"); 264 } 265 266 override void visit(const DebugCondition debugCondition) 267 { 268 if (debugCondition.identifierOrInteger.type == tok!"") 269 output.writeln("<debugCondition/>"); 270 else 271 output.writeln("<debugCondition condition=\"", 272 debugCondition.identifierOrInteger.text, "\"/>"); 273 } 274 275 override void visit(const DebugSpecification debugSpecification) 276 { 277 if (debugSpecification.identifierOrInteger.type == tok!"") 278 output.writeln("<debugSpecification/>"); 279 else 280 output.writeln("<debugSpecification condition=\"", 281 debugSpecification.identifierOrInteger.text, "\"/>"); 282 } 283 284 override void visit(const Declarator declarator) 285 { 286 output.writeln("<declarator line=\"", declarator.name.line, "\">"); 287 writeName(declarator.name.text); 288 writeDdoc(declarator.comment); 289 declarator.accept(this); 290 output.writeln("</declarator>"); 291 } 292 293 override void visit(const Deprecated deprecated_) 294 { 295 if (deprecated_.assignExpression !is null) 296 { 297 output.writeln("<deprecated>"); 298 visit(deprecated_.assignExpression); 299 output.writeln("</deprecated>"); 300 } 301 else 302 output.writeln("<deprecated/>"); 303 } 304 305 override void visit(const EnumDeclaration enumDec) 306 { 307 output.writeln("<enumDeclaration line=\"", enumDec.name.line, "\">"); 308 writeDdoc(enumDec.comment); 309 if (enumDec.name.type == tok!"identifier") 310 writeName(enumDec.name.text); 311 enumDec.accept(this); 312 output.writeln("</enumDeclaration>"); 313 } 314 315 override void visit(const AnonymousEnumMember enumMember) 316 { 317 output.writeln("<anonymousEnumMember line=\"", enumMember.name.line, "\">"); 318 writeDdoc(enumMember.comment); 319 if (enumMember.type !is null) 320 visit(enumMember.type); 321 output.write("<name>", enumMember.name.text, "</name>"); 322 if (enumMember.assignExpression !is null) 323 visit(enumMember.assignExpression); 324 output.writeln("</anonymousEnumMember>"); 325 } 326 327 override void visit(const EnumMember enumMem) 328 { 329 output.writeln("<enumMember line=\"", enumMem.name.line, "\">"); 330 writeDdoc(enumMem.comment); 331 enumMem.accept(this); 332 output.writeln("</enumMember>"); 333 } 334 335 override void visit(const EqualExpression equalExpression) 336 { 337 output.writeln("<equalExpression operator=\"", str(equalExpression.operator), "\">"); 338 output.writeln("<left>"); 339 visit(equalExpression.left); 340 output.writeln("</left>"); 341 output.writeln("<right>"); 342 visit(equalExpression.right); 343 output.writeln("</right>"); 344 output.writeln("</equalExpression>"); 345 } 346 347 override void visit(const Finally finally_) 348 { 349 output.writeln("<finally>"); 350 finally_.accept(this); 351 output.writeln("</finally>"); 352 } 353 354 override void visit(const ForStatement forStatement) 355 { 356 output.writeln("<forStatement>"); 357 if (forStatement.initialization !is null) 358 { 359 output.writeln("<initialization>"); 360 visit(forStatement.initialization); 361 output.writeln("</initialization>"); 362 } 363 if (forStatement.test !is null) 364 { 365 output.writeln("<test>"); 366 visit(forStatement.test); 367 output.writeln("</test>"); 368 } 369 if (forStatement.increment !is null) 370 { 371 output.writeln("<increment>"); 372 visit(forStatement.increment); 373 output.writeln("</increment>"); 374 } 375 if (forStatement.declarationOrStatement !is null) 376 visit(forStatement.declarationOrStatement); 377 output.writeln("</forStatement>"); 378 } 379 380 override void visit(const ForeachStatement foreachStatement) 381 { 382 output.writeln("<foreachStatement type=\"", str(foreachStatement.type), "\">"); 383 if (foreachStatement.foreachType !is null) 384 visit(foreachStatement.foreachType); 385 if (foreachStatement.foreachTypeList !is null) 386 visit(foreachStatement.foreachTypeList); 387 output.writeln("<low>"); 388 visit(foreachStatement.low); 389 output.writeln("</low>"); 390 if (foreachStatement.high !is null) 391 { 392 output.writeln("<high>"); 393 visit(foreachStatement.high); 394 output.writeln("</high>"); 395 } 396 visit(foreachStatement.declarationOrStatement); 397 output.writeln("</foreachStatement>"); 398 } 399 400 override void visit(const ForeachType foreachType) 401 { 402 output.writeln("<foreachType>"); 403 if (foreachType.isAlias) output.writeln("<alias/>"); 404 if (foreachType.isEnum) output.writeln("<enum/>"); 405 if (foreachType.isRef) output.writeln("<ref/>"); 406 if (foreachType.isScope) output.writeln("<scope/>"); 407 foreach (constructor; foreachType.typeConstructors) 408 { 409 output.writeln("<typeConstructor>", str(constructor), "</typeConstructor>"); 410 } 411 if (foreachType.type !is null) 412 visit(foreachType.type); 413 visit(foreachType.identifier); 414 output.writeln("</foreachType>"); 415 416 } 417 418 override void visit(const FunctionDeclaration functionDec) 419 { 420 output.writeln("<functionDeclaration line=\"", functionDec.name.line, "\">"); 421 writeName(functionDec.name.text); 422 writeDdoc(functionDec.comment); 423 if (functionDec.hasAuto) 424 output.writeln("<auto/>"); 425 if (functionDec.hasRef) 426 output.writeln("<ref/>"); 427 functionDec.accept(this); 428 output.writeln("</functionDeclaration>"); 429 } 430 431 override void visit(const FunctionLiteralExpression functionLiteralExpression) 432 { 433 with (functionLiteralExpression) 434 { 435 output.write("<functionLiteralExpression type=\"", 436 functionOrDelegate != tok!"" ? str(functionOrDelegate) : "auto", 437 "\""); 438 if (identifier.type != tok!"") 439 output.write(" identifier=\"", identifier, "\""); 440 output.write(" line=\"", line, "\""); 441 output.write(" column=\"", column, "\""); 442 final switch (returnRefType) with (ReturnRefType) 443 { 444 case noRef: break; 445 case ref_: output.write(" ref=\"ref\""); break; 446 case autoRef: output.write(" ref=\"auto ref\""); break; 447 } 448 output.writeln(">"); 449 accept(this); 450 output.writeln("</functionLiteralExpression>"); 451 } 452 } 453 454 override void visit(const GotoStatement gotoStatement) 455 { 456 if (gotoStatement.label.type == tok!"default") 457 output.writeln("<gotoStatement default=\"true\"/>"); 458 else if (gotoStatement.label.type == tok!"identifier") 459 output.writeln("<gotoStatement label=\"", gotoStatement.label.text, "\"/>"); 460 else 461 { 462 output.writeln("<gotoStatement>"); 463 output.writeln("<case>"); 464 if (gotoStatement.expression) 465 visit(gotoStatement.expression); 466 output.writeln("</case>"); 467 output.writeln("</gotoStatement>"); 468 } 469 } 470 471 override void visit(const IdentityExpression identityExpression) 472 { 473 if (identityExpression.negated) 474 output.writeln("<identityExpression operator=\"!is\">"); 475 else 476 output.writeln("<identityExpression operator=\"is\">"); 477 output.writeln("<left>"); 478 visit(identityExpression.left); 479 output.writeln("</left>"); 480 output.writeln("<right>"); 481 visit(identityExpression.right); 482 output.writeln("</right>"); 483 output.writeln("</identityExpression>"); 484 } 485 486 override void visit(const IfStatement ifStatement) 487 { 488 output.writeln("<ifStatement>"); 489 490 ifStatement.condition.accept(this); 491 492 output.writeln("<then>"); 493 ifStatement.thenStatement.accept(this); 494 output.writeln("</then>"); 495 496 if (ifStatement.elseStatement !is null) 497 { 498 output.writeln("<else>"); 499 ifStatement.elseStatement.accept(this); 500 output.writeln("</else>"); 501 } 502 output.writeln("</ifStatement>"); 503 } 504 505 override void visit(const IfCondition ifCondition) 506 { 507 output.writeln("<condition>"); 508 foreach (constructor; ifCondition.typeCtors) 509 { 510 output.writeln("<typeConstructor>", str(constructor), "</typeConstructor>"); 511 } 512 if (ifCondition.identifier.type != tok!"") 513 { 514 if (ifCondition.scope_) 515 output.writeln("<scope/>"); 516 else if (ifCondition.type is null) 517 output.writeln("<auto/>"); 518 519 // in case `scope T` is possible eventually, check type separately 520 if (ifCondition.type) 521 visit(ifCondition.type); 522 visit(ifCondition.identifier); 523 } 524 ifCondition.expression.accept(this); 525 output.writeln("</condition>"); 526 } 527 528 override void visit(const ImportBind importBind) 529 { 530 if (importBind.right.type == tok!"") 531 output.writeln("<importBind symbol=\"", importBind.left.text, "\"/>"); 532 else 533 output.writeln("<importBind symbol=\"", importBind.right.text, 534 "\" rename=\"", importBind.left.text, "\"/>"); 535 } 536 537 override void visit(const InExpression inExpression) 538 { 539 if (inExpression.negated) 540 output.writeln("<inExpression operator=\"!in\">"); 541 else 542 output.writeln("<inExpression operator=\"in\">"); 543 output.writeln("<left>"); 544 visit(inExpression.left); 545 output.writeln("</left>"); 546 output.writeln("<right>"); 547 visit(inExpression.right); 548 output.writeln("</right>"); 549 output.writeln("</inExpression>"); 550 } 551 552 override void visit(const Initialize initialize) 553 { 554 if (initialize.statementNoCaseNoDefault is null) 555 output.writeln("<initialize/>"); 556 else 557 { 558 output.writeln("<initialize>"); 559 visit(initialize.statementNoCaseNoDefault); 560 output.writeln("</initialize>"); 561 } 562 } 563 564 override void visit(const Initializer initializer) 565 { 566 if (initializer.nonVoidInitializer is null) 567 output.writeln("<initializer void=\"true\"/>"); 568 else 569 { 570 output.writeln("<initializer>"); 571 visit(initializer.nonVoidInitializer); 572 output.writeln("</initializer>"); 573 } 574 } 575 576 override void visit(const InterfaceDeclaration interfaceDec) 577 { 578 output.writeln("<interfaceDeclaration line=\"", interfaceDec.name.line, "\">"); 579 writeName(interfaceDec.name.text); 580 writeDdoc(interfaceDec.comment); 581 interfaceDec.accept(this); 582 output.writeln("</interfaceDeclaration>"); 583 } 584 585 override void visit(const Invariant invariant_) 586 { 587 output.writeln("<invariant>"); 588 writeDdoc(invariant_.comment); 589 invariant_.accept(this); 590 output.writeln("</invariant>"); 591 } 592 593 override void visit(const IsExpression isExpression) 594 { 595 output.writeln("<isExpression>"); 596 visit(isExpression.type); 597 if (isExpression.identifier.type != tok!"") 598 visit(isExpression.identifier); 599 if (isExpression.typeSpecialization !is null) 600 { 601 if (isExpression.equalsOrColon == tok!":") 602 output.writeln("<colon/>"); 603 else 604 output.writeln("<equals/>"); 605 visit(isExpression.typeSpecialization); 606 if (isExpression.templateParameterList !is null) 607 visit(isExpression.templateParameterList); 608 } 609 output.writeln("</isExpression>"); 610 } 611 612 override void visit(const KeyValuePair keyValuePair) 613 { 614 output.writeln("<keyValuePair>"); 615 output.writeln("<key>"); 616 visit(keyValuePair.key); 617 output.writeln("</key>"); 618 output.writeln("<value>"); 619 visit(keyValuePair.value); 620 output.writeln("</value>"); 621 output.writeln("</keyValuePair>"); 622 } 623 624 override void visit(const LabeledStatement labeledStatement) 625 { 626 output.writeln("<labeledStatement label=\"", labeledStatement.identifier.text, "\">"); 627 if (labeledStatement.declarationOrStatement !is null) 628 visit(labeledStatement.declarationOrStatement); 629 output.writeln("</labeledStatement>"); 630 } 631 632 override void visit(const LinkageAttribute linkageAttribute) 633 { 634 if (linkageAttribute.hasPlusPlus) 635 { 636 output.write("<linkageAttribute linkage=\"C++\""); 637 if (linkageAttribute.typeIdentifierPart !is null && linkageAttribute.typeIdentifierPart.typeIdentifierPart !is null) 638 { 639 output.write(" namespace=\""); 640 format(output.lockingTextWriter, linkageAttribute.typeIdentifierPart); 641 output.writeln("\"/>"); 642 } 643 else if (linkageAttribute.classOrStruct == tok!"class") 644 output.writeln(" mangleAs=\"class\"/>"); 645 else if (linkageAttribute.classOrStruct == tok!"struct") 646 output.writeln(" mangleAs=\"struct\"/>"); 647 else 648 output.writeln("/>"); 649 } 650 else if (linkageAttribute.identifier.text == "Objective") 651 output.writeln("<linkageAttribute linkage=\"Objective-C\"/>"); 652 else 653 output.writeln("<linkageAttribute linkage=\"", 654 linkageAttribute.identifier.text, "\"/>"); 655 } 656 657 override void visit(const MemberFunctionAttribute memberFunctionAttribute) 658 { 659 output.writeln("<memberFunctionAttribute>"); 660 if (memberFunctionAttribute.atAttribute is null) 661 output.writeln(str(memberFunctionAttribute.tokenType)); 662 else 663 memberFunctionAttribute.accept(this); 664 output.writeln("</memberFunctionAttribute>"); 665 } 666 667 override void visit(const Module module_) 668 { 669 output.writeln("<?xml version=\"1.0\"?>"); 670 output.writeln("<module>"); 671 module_.accept(this); 672 output.writeln("</module>"); 673 } 674 675 override void visit(const MulExpression mulExpression) 676 { 677 output.writeln("<mulExpression operator=\"", str(mulExpression.operator), "\">"); 678 output.writeln("<left>"); 679 visit(mulExpression.left); 680 output.writeln("</left>"); 681 if (mulExpression.right !is null) 682 { 683 output.writeln("<right>"); 684 visit(mulExpression.right); 685 output.writeln("</right>"); 686 } 687 output.writeln("</mulExpression>"); 688 } 689 690 override void visit(const OrOrExpression orOrExpression) 691 { 692 output.writeln("<orOrExpression>"); 693 output.writeln("<left>"); 694 visit(orOrExpression.left); 695 output.writeln("</left>"); 696 if (orOrExpression.right !is null) 697 { 698 output.writeln("<right>"); 699 visit(orOrExpression.right); 700 output.writeln("</right>"); 701 } 702 output.writeln("</orOrExpression>"); 703 } 704 705 override void visit(const ParameterAttribute pa) 706 { 707 output.writeln("<parameterAttribute>"); 708 if (pa.atAttribute) 709 visit(pa.atAttribute); 710 else 711 writeln(str(pa.idType)); 712 output.writeln("</parameterAttribute>"); 713 } 714 715 override void visit(const Parameter param) 716 { 717 output.writeln("<parameter>"); 718 if (param.name.type == tok!"identifier") 719 writeName(param.name.text); 720 param.accept(this); 721 if (param.vararg) 722 output.writeln("<vararg/>"); 723 output.writeln("</parameter>"); 724 } 725 726 override void visit(const PowExpression powExpression) 727 { 728 output.writeln("<powExpression>"); 729 output.writeln("<left>"); 730 visit(powExpression.left); 731 output.writeln("</left>"); 732 if (powExpression.right !is null) 733 { 734 output.writeln("<right>"); 735 visit(powExpression.right); 736 output.writeln("</right>"); 737 } 738 output.writeln("</powExpression>"); 739 } 740 741 override void visit(const RelExpression relExpression) 742 { 743 output.writeln("<relExpression operator=\"", 744 xmlAttributeEscape(str(relExpression.operator)), "\">"); 745 output.writeln("<left>"); 746 visit(relExpression.left); 747 output.writeln("</left>"); 748 output.writeln("<right>"); 749 visit(relExpression.right); 750 output.writeln("</right>"); 751 output.writeln("</relExpression>"); 752 } 753 754 override void visit(const ReturnStatement returnStatement) 755 { 756 if (returnStatement.expression is null) 757 output.writeln("<returnStatement/>"); 758 else 759 { 760 output.writeln("<returnStatement>"); 761 returnStatement.accept(this); 762 output.writeln("</returnStatement>"); 763 } 764 } 765 766 override void visit(const ShiftExpression shiftExpression) 767 { 768 output.writeln("<shiftExpression operator=\"", 769 xmlAttributeEscape(str(shiftExpression.operator)), "\">"); 770 output.writeln("<left>"); 771 visit(shiftExpression.left); 772 output.writeln("</left>"); 773 output.writeln("<right>"); 774 visit(shiftExpression.right); 775 output.writeln("</right>"); 776 output.writeln("</shiftExpression>"); 777 } 778 779 override void visit(const SingleImport singleImport) 780 { 781 if (singleImport.rename.type == tok!"") 782 output.writeln("<singleImport>"); 783 else 784 output.writeln("<singleImport rename=\"", singleImport.rename.text, "\">"); 785 visit(singleImport.identifierChain); 786 output.writeln("</singleImport>"); 787 } 788 789 override void visit(const StructDeclaration structDec) 790 { 791 output.writeln("<structDeclaration line=\"", structDec.name.line, "\">"); 792 writeName(structDec.name.text); 793 writeDdoc(structDec.comment); 794 structDec.accept(this); 795 output.writeln("</structDeclaration>"); 796 } 797 798 override void visit(const TemplateAliasParameter templateAliasParameter) 799 { 800 output.writeln("<templateAliasParameter>"); 801 if (templateAliasParameter.type !is null) 802 visit(templateAliasParameter.type); 803 visit(templateAliasParameter.identifier); 804 if (templateAliasParameter.colonExpression !is null) 805 { 806 output.writeln("<specialization>"); 807 visit(templateAliasParameter.colonExpression); 808 output.writeln("</specialization>"); 809 } 810 else if (templateAliasParameter.colonType !is null) 811 { 812 output.writeln("<specialization>"); 813 visit(templateAliasParameter.colonType); 814 output.writeln("</specialization>"); 815 } 816 817 if (templateAliasParameter.assignExpression !is null) 818 { 819 output.writeln("<default>"); 820 visit(templateAliasParameter.assignExpression); 821 output.writeln("</default>"); 822 } 823 else if (templateAliasParameter.assignType !is null) 824 { 825 output.writeln("<default>"); 826 visit(templateAliasParameter.assignType); 827 output.writeln("</default>"); 828 } 829 830 output.writeln("</templateAliasParameter>"); 831 } 832 833 override void visit(const TemplateDeclaration templateDeclaration) 834 { 835 writeDdoc(templateDeclaration.comment); 836 output.writeln("<templateDeclaration line=\"", templateDeclaration.name.line, "\">"); 837 writeName(templateDeclaration.name.text); 838 visit(templateDeclaration.templateParameters); 839 if (templateDeclaration.constraint !is null) 840 visit(templateDeclaration.constraint); 841 foreach (dec; templateDeclaration.declarations) 842 { 843 if (dec !is null) 844 visit(dec); 845 } 846 output.writeln("</templateDeclaration>"); 847 } 848 849 override void visit(const Token token) 850 { 851 string tagName; 852 switch (token.type) 853 { 854 case tok!"": 855 return; 856 case tok!"identifier": 857 tagName = "identifier"; 858 break; 859 case tok!"doubleLiteral": 860 tagName = "doubleLiteral"; 861 break; 862 case tok!"idoubleLiteral": 863 tagName = "idoubleLiteral"; 864 break; 865 case tok!"floatLiteral": 866 tagName = "floatLiteral"; 867 break; 868 case tok!"ifloatLiteral": 869 tagName = "ifloatLiteral"; 870 break; 871 case tok!"intLiteral": 872 tagName = "intLiteral"; 873 break; 874 case tok!"uintLiteral": 875 tagName = "uintLiteral"; 876 break; 877 case tok!"longLiteral": 878 tagName = "longLiteral"; 879 break; 880 case tok!"ulongLiteral": 881 tagName = "ulongLiteral"; 882 break; 883 case tok!"realLiteral": 884 tagName = "realLiteral"; 885 break; 886 case tok!"irealLiteral": 887 tagName = "irealLiteral"; 888 break; 889 case tok!"characterLiteral": 890 tagName = "characterLiteral"; 891 break; 892 case tok!"stringLiteral": 893 tagName = "stringLiteral"; 894 break; 895 case tok!"dstringLiteral": 896 tagName = "dstringLiteral"; 897 break; 898 case tok!"wstringLiteral": 899 tagName = "wstringLiteral"; 900 break; 901 case tok!"scriptLine": 902 tagName = "scriptLine"; 903 break; 904 case tok!"$": 905 output.writeln("<dollar/>"); 906 return; 907 case tok!".": 908 output.writeln("<dot/>"); 909 return; 910 default: 911 output.writeln("<", str(token.type), "/>"); 912 return; 913 } 914 output.writeln("<", tagName, ">", xmlEscape(token.text), "</", tagName, ">"); 915 } 916 917 override void visit(const Type type) 918 { 919 auto app = appender!string(); 920 auto formatter = new Formatter!(typeof(app))(app); 921 formatter.format(type); 922 output.writeln("<type pretty=\"", xmlAttributeEscape(app.data), "\">"); 923 type.accept(this); 924 output.writeln("</type>"); 925 } 926 927 override void visit(const Type2 type2) 928 { 929 if (type2.builtinType != tok!"") 930 { 931 output.writeln("<type2>", str(type2.builtinType), "</type2>"); 932 if (type2.typeIdentifierPart !is null) 933 visit(type2.typeIdentifierPart); 934 } 935 else 936 { 937 output.writeln("<type2>"); 938 type2.accept(this); 939 output.writeln("</type2>"); 940 } 941 } 942 943 override void visit(const TypeSuffix typeSuffix) 944 { 945 if (typeSuffix.star != tok!"") 946 output.writeln("<typeSuffix type=\"*\"/>"); 947 else if (typeSuffix.array) 948 { 949 if (typeSuffix.low is null && typeSuffix.type is null) 950 output.writeln("<typeSuffix type=\"[]\"/>"); 951 else 952 { 953 if (typeSuffix.low is null) 954 { 955 output.writeln("<typeSuffix type=\"[]\">"); 956 visit(typeSuffix.type); 957 output.writeln("</typeSuffix>"); 958 } 959 else 960 { 961 output.writeln("<typeSuffix type=\"[]\">"); 962 if (typeSuffix.high !is null) 963 { 964 output.writeln("<low>"); 965 visit(typeSuffix.low); 966 output.writeln("</low>"); 967 output.writeln("<high>"); 968 visit(typeSuffix.high); 969 output.writeln("</high>"); 970 } 971 else 972 visit(typeSuffix.low); 973 output.writeln("</typeSuffix>"); 974 } 975 } 976 } 977 else 978 { 979 visit(typeSuffix.delegateOrFunction); 980 visit(typeSuffix.parameters); 981 foreach (attr; typeSuffix.memberFunctionAttributes) 982 { 983 if (attr !is null) 984 visit(attr); 985 } 986 } 987 } 988 989 override void visit(const UnaryExpression unaryExpression) 990 { 991 output.writeln("<unaryExpression>"); 992 if (unaryExpression.prefix != tok!"") 993 { 994 output.writeln("<prefix>", xmlEscape(str(unaryExpression.prefix.type)), "</prefix>"); 995 unaryExpression.unaryExpression.accept(this); 996 } 997 else 998 { 999 if (unaryExpression.suffix != tok!"") 1000 { 1001 assert(unaryExpression.suffix.text == ""); 1002 unaryExpression.unaryExpression.accept(this); 1003 output.writeln("<suffix>", str(unaryExpression.suffix.type), "</suffix>"); 1004 } 1005 else 1006 unaryExpression.accept(this); 1007 } 1008 output.writeln("</unaryExpression>"); 1009 } 1010 1011 override void visit(const UnionDeclaration unionDeclaration) 1012 { 1013 output.writeln("<unionDeclaration line=\"", unionDeclaration.name.line, "\">"); 1014 if (unionDeclaration.name != tok!"") 1015 writeName(unionDeclaration.name.text); 1016 if (unionDeclaration.templateParameters !is null) 1017 visit(unionDeclaration.templateParameters); 1018 if (unionDeclaration.constraint !is null) 1019 visit(unionDeclaration.constraint); 1020 if (unionDeclaration.structBody !is null) 1021 visit(unionDeclaration.structBody); 1022 output.writeln("</unionDeclaration>"); 1023 } 1024 1025 override void visit(const Unittest unittest_) 1026 { 1027 output.writeln("<unittest>"); 1028 unittest_.accept(this); 1029 output.writeln("</unittest>"); 1030 } 1031 1032 override void visit(const VariableDeclaration variableDeclaration) 1033 { 1034 output.writeln("<variableDeclaration>"); 1035 writeDdoc(variableDeclaration.comment); 1036 variableDeclaration.accept(this); 1037 output.writeln("</variableDeclaration>"); 1038 } 1039 1040 override void visit(const XorExpression xorExpression) 1041 { 1042 output.writeln("<xorExpression>"); 1043 output.writeln("<left>"); 1044 visit(xorExpression.left); 1045 output.writeln("</left>"); 1046 if (xorExpression.right !is null) 1047 { 1048 output.writeln("<right>"); 1049 visit(xorExpression.right); 1050 output.writeln("</right>"); 1051 } 1052 output.writeln("</xorExpression>"); 1053 } 1054 1055 override void visit(const Index index) 1056 { 1057 output.writeln("<index>"); 1058 if (index.high) 1059 { 1060 output.writeln("<low>"); 1061 visit(index.low); 1062 output.writeln("</low>"); 1063 1064 output.writeln("<high>"); 1065 visit(index.high); 1066 output.writeln("</high>"); 1067 } 1068 else 1069 visit(index.low); 1070 output.writeln("</index>"); 1071 } 1072 1073 // dfmt off 1074 override void visit(const AliasInitializer aliasInitializer) { mixin (tagAndAccept!"aliasInitializer"); } 1075 override void visit(const AliasThisDeclaration aliasThisDeclaration) { mixin (tagAndAccept!"aliasThisDeclaration"); } 1076 override void visit(const AnonymousEnumDeclaration anonymousEnumDeclaration) { mixin (tagAndAccept!"anonymousEnumDeclaration"); } 1077 override void visit(const ArgumentList argumentList) { mixin (tagAndAccept!"argumentList"); } 1078 override void visit(const Arguments arguments) { mixin (tagAndAccept!"arguments"); } 1079 override void visit(const ArrayInitializer arrayInitializer) { mixin (tagAndAccept!"arrayInitializer"); } 1080 override void visit(const ArrayLiteral arrayLiteral) { mixin (tagAndAccept!"arrayLiteral"); } 1081 override void visit(const ArrayMemberInitialization arrayMemberInitialization) { mixin (tagAndAccept!"arrayMemberInitialization"); } 1082 override void visit(const AsmAddExp asmAddExp) { mixin (tagAndAccept!"asmAddExp"); } 1083 override void visit(const AsmAndExp asmAndExp) { mixin (tagAndAccept!"asmAndExp"); } 1084 override void visit(const AsmBrExp asmBrExp) { mixin (tagAndAccept!"asmBrExp"); } 1085 override void visit(const AsmEqualExp asmEqualExp) { mixin (tagAndAccept!"asmEqualExp"); } 1086 override void visit(const AsmExp asmExp) { mixin (tagAndAccept!"asmExp"); } 1087 override void visit(const AsmLogAndExp asmLogAndExp) { mixin (tagAndAccept!"asmLogAndExp"); } 1088 override void visit(const AsmLogOrExp asmLogOrExp) { mixin (tagAndAccept!"asmLogOrExp"); } 1089 override void visit(const AsmMulExp asmMulExp) { mixin (tagAndAccept!"asmMulExp"); } 1090 override void visit(const AsmOrExp asmOrExp) { mixin (tagAndAccept!"asmOrExp"); } 1091 override void visit(const AsmPrimaryExp asmPrimaryExp) { mixin (tagAndAccept!"asmPrimaryExp"); } 1092 override void visit(const AsmRelExp asmRelExp) { mixin (tagAndAccept!"asmRelExp"); } 1093 override void visit(const AsmShiftExp asmShiftExp) { mixin (tagAndAccept!"asmShiftExp"); } 1094 override void visit(const AsmStatement asmStatement) { mixin (tagAndAccept!"asmStatement"); } 1095 override void visit(const AsmTypePrefix asmTypePrefix) { mixin (tagAndAccept!"asmTypePrefix"); } 1096 override void visit(const AsmUnaExp asmUnaExp) { mixin (tagAndAccept!"asmUnaExp"); } 1097 override void visit(const AsmXorExp asmXorExp) { mixin (tagAndAccept!"asmXorExp"); } 1098 override void visit(const AssocArrayLiteral assocArrayLiteral) { mixin (tagAndAccept!"assocArrayLiteral"); } 1099 override void visit(const AssertExpression assertExpression) { mixin (tagAndAccept!"assertExpression"); } 1100 override void visit(const AssertArguments assertArguments) { mixin (tagAndAccept!"assertArguments"); } 1101 override void visit(const AttributeDeclaration attributeDeclaration) { mixin (tagAndAccept!"attributeDeclaration"); } 1102 override void visit(const BaseClass baseClass) { mixin (tagAndAccept!"baseClass"); } 1103 override void visit(const BaseClassList baseClassList) { mixin (tagAndAccept!"baseClassList"); } 1104 override void visit(const BlockStatement blockStatement) { mixin (tagAndAccept!"blockStatement"); } 1105 override void visit(const CaseStatement caseStatement) { mixin (tagAndAccept!"caseStatement"); } 1106 override void visit(const CastExpression castExpression) { mixin (tagAndAccept!"castExpression"); } 1107 override void visit(const CastQualifier castQualifier) { mixin (tagAndAccept!"castQualifier"); } 1108 override void visit(const Catches catches) { mixin (tagAndAccept!"catches"); } 1109 override void visit(const CmpExpression cmpExpression) { mixin (tagAndAccept!"cmpExpression"); } 1110 override void visit(const CompileCondition compileCondition) { mixin (tagAndAccept!"compileCondition"); } 1111 override void visit(const Constraint constraint) { mixin (tagAndAccept!"constraint"); } 1112 override void visit(const Constructor constructor) { mixin (tagAndAccept!"constructor"); } 1113 override void visit(const Declaration declaration) { mixin (tagAndAccept!"declaration"); } 1114 override void visit(const DeclarationOrStatement declarationOrStatement) { mixin (tagAndAccept!"declarationOrStatement"); } 1115 override void visit(const DeclarationsAndStatements declarationsAndStatements) { mixin (tagAndAccept!"declarationsAndStatements"); } 1116 override void visit(const DeclaratorIdentifierList declaratorIdentifierList) { mixin (tagAndAccept!"declaratorIdentifierList"); } 1117 override void visit(const DefaultStatement defaultStatement) { mixin (tagAndAccept!"defaultStatement"); } 1118 override void visit(const DeleteExpression deleteExpression) { mixin (tagAndAccept!"deleteExpression"); } 1119 override void visit(const DeleteStatement deleteStatement) { mixin (tagAndAccept!"deleteStatement"); } 1120 override void visit(const Destructor destructor) { mixin (tagAndAccept!"destructor"); } 1121 override void visit(const DoStatement doStatement) { mixin (tagAndAccept!"doStatement"); } 1122 override void visit(const EnumBody enumBody) { mixin (tagAndAccept!"enumBody"); } 1123 override void visit(const EponymousTemplateDeclaration eponymousTemplateDeclaration) { mixin (tagAndAccept!"eponymousTemplateDeclaration"); } 1124 override void visit(const Expression expression) { mixin (tagAndAccept!"expression"); } 1125 override void visit(const ExpressionStatement expressionStatement) { mixin (tagAndAccept!"expressionStatement"); } 1126 override void visit(const FinalSwitchStatement finalSwitchStatement) { mixin (tagAndAccept!"finalSwitchStatement"); } 1127 override void visit(const ForeachTypeList foreachTypeList) { mixin (tagAndAccept!"foreachTypeList"); } 1128 override void visit(const FunctionAttribute functionAttribute) { mixin (tagAndAccept!"functionAttribute"); } 1129 override void visit(const FunctionBody functionBody) { mixin (tagAndAccept!"functionBody"); } 1130 override void visit(const FunctionCallExpression functionCallExpression) { mixin (tagAndAccept!"functionCallExpression"); } 1131 override void visit(const IdentifierChain identifierChain) { mixin (tagAndAccept!"identifierChain"); } 1132 override void visit(const IdentifierOrTemplateChain identifierOrTemplateChain) { mixin (tagAndAccept!"identifierOrTemplateChain"); } 1133 override void visit(const IdentifierOrTemplateInstance identifierOrTemplateInstance) { mixin (tagAndAccept!"identifierOrTemplateInstance"); } 1134 override void visit(const ImportBindings importBindings) { mixin (tagAndAccept!"importBindings"); } 1135 override void visit(const ImportDeclaration importDeclaration) { mixin (tagAndAccept!"importDeclaration"); } 1136 override void visit(const ImportExpression importExpression) { mixin (tagAndAccept!"importExpression"); } 1137 override void visit(const IndexExpression indexExpression) { mixin (tagAndAccept!"indexExpression"); } 1138 override void visit(const InStatement inStatement) { mixin (tagAndAccept!"inStatement"); } 1139 override void visit(const InContractExpression inContractExpression) { mixin (tagAndAccept!"inContractExpression"); } 1140 override void visit(const InOutContractExpression inOutContractExpression) { mixin (tagAndAccept!"inOutContractExpression"); } 1141 override void visit(const KeyValuePairs keyValuePairs) { mixin (tagAndAccept!"keyValuePairs"); } 1142 override void visit(const MixinExpression mixinExpression) { mixin (tagAndAccept!"mixinExpression"); } 1143 override void visit(const MixinTemplateDeclaration mixinTemplateDeclaration) { mixin (tagAndAccept!"mixinTemplateDeclaration"); } 1144 override void visit(const MixinTemplateName mixinTemplateName) { mixin (tagAndAccept!"mixinTemplateName"); } 1145 override void visit(const ModuleDeclaration moduleDeclaration) { mixin (tagAndAccept!"moduleDeclaration"); } 1146 override void visit(const LastCatch lastCatch) { mixin (tagAndAccept!"lastCatch"); } 1147 override void visit(const NewExpression newExpression) { mixin (tagAndAccept!"newExpression"); } 1148 override void visit(const NonVoidInitializer nonVoidInitializer) { mixin (tagAndAccept!"nonVoidInitializer"); } 1149 override void visit(const Operands operands) { mixin (tagAndAccept!"operands"); } 1150 override void visit(const OrExpression orExpression) { mixin (tagAndAccept!"orExpression"); } 1151 override void visit(const OutStatement outStatement) { mixin (tagAndAccept!"outStatement"); } 1152 override void visit(const MixinDeclaration mixinDeclaration) { mixin (tagAndAccept!"mixinDeclaration"); } 1153 override void visit(const OutContractExpression outContractExpression) { mixin (tagAndAccept!"outContractExpression"); } 1154 override void visit(const Parameters parameters) { mixin (tagAndAccept!"parameters"); } 1155 override void visit(const Postblit postblit) { mixin (tagAndAccept!"postblit"); } 1156 override void visit(const NewAnonClassExpression newAnonClassExpression) { mixin (tagAndAccept!"newAnonClassExpression"); } 1157 override void visit(const PragmaDeclaration pragmaDeclaration) { mixin (tagAndAccept!"pragmaDeclaration"); } 1158 override void visit(const PragmaExpression pragmaExpression) { mixin (tagAndAccept!"pragmaExpression"); } 1159 override void visit(const PrimaryExpression primaryExpression) { mixin (tagAndAccept!"primaryExpression"); } 1160 override void visit(const Register register) { mixin (tagAndAccept!"register"); } 1161 override void visit(const ScopeGuardStatement scopeGuardStatement) { mixin (tagAndAccept!"scopeGuardStatement"); } 1162 override void visit(const SharedStaticConstructor sharedStaticConstructor) { mixin (tagAndAccept!"sharedStaticConstructor"); } 1163 override void visit(const SharedStaticDestructor sharedStaticDestructor) { mixin (tagAndAccept!"sharedStaticDestructor"); } 1164 override void visit(const ShortenedFunctionBody shortenedFunctionBody) { mixin (tagAndAccept!"shortenedFunctionBody"); } 1165 override void visit(const StatementNoCaseNoDefault statementNoCaseNoDefault) { mixin (tagAndAccept!"statementNoCaseNoDefault"); } 1166 override void visit(const StaticAssertDeclaration staticAssertDeclaration) { mixin (tagAndAccept!"staticAssertDeclaration"); } 1167 override void visit(const StaticAssertStatement staticAssertStatement) { mixin (tagAndAccept!"staticAssertStatement"); } 1168 override void visit(const StaticConstructor staticConstructor) { mixin (tagAndAccept!"staticConstructor"); } 1169 override void visit(const StaticDestructor staticDestructor) { mixin (tagAndAccept!"staticDestructor"); } 1170 override void visit(const StaticIfCondition staticIfCondition) { mixin (tagAndAccept!"staticIfCondition"); } 1171 override void visit(const StorageClass storageClass) { mixin (tagAndAccept!"storageClass"); } 1172 override void visit(const StructBody structBody) { mixin (tagAndAccept!"structBody"); } 1173 override void visit(const StructInitializer structInitializer) { mixin (tagAndAccept!"structInitializer"); } 1174 override void visit(const StructMemberInitializers structMemberInitializers) { mixin (tagAndAccept!"structMemberInitializers"); } 1175 override void visit(const StructMemberInitializer structMemberInitializer) { mixin (tagAndAccept!"structMemberInitializer"); } 1176 override void visit(const SwitchStatement switchStatement) { mixin (tagAndAccept!"switchStatement"); } 1177 override void visit(const Symbol symbol) { mixin (tagAndAccept!"symbol"); } 1178 override void visit(const SynchronizedStatement synchronizedStatement) { mixin (tagAndAccept!"synchronizedStatement"); } 1179 override void visit(const Statement statement) { mixin (tagAndAccept!"statement"); } 1180 override void visit(const TemplateArgumentList templateArgumentList) { mixin (tagAndAccept!"templateArgumentList"); } 1181 override void visit(const TemplateArguments templateArguments) { mixin (tagAndAccept!"templateArguments"); } 1182 override void visit(const TemplateArgument templateArgument) { mixin (tagAndAccept!"templateArgument"); } 1183 override void visit(const TemplateMixinExpression templateMixinExpression) { mixin (tagAndAccept!"templateMixinExpression"); } 1184 override void visit(const TemplateParameterList templateParameterList) { mixin (tagAndAccept!"templateParameterList"); } 1185 override void visit(const TemplateParameters templateParameters) { mixin (tagAndAccept!"templateParameters"); } 1186 override void visit(const TemplateParameter templateParameter) { mixin (tagAndAccept!"templateParameter"); } 1187 override void visit(const TemplateSingleArgument templateSingleArgument) { mixin (tagAndAccept!"templateSingleArgument"); } 1188 override void visit(const TemplateThisParameter templateThisParameter) { mixin (tagAndAccept!"templateThisParameter"); } 1189 override void visit(const TemplateTupleParameter templateTupleParameter) { mixin (tagAndAccept!"templateTupleParameter"); } 1190 override void visit(const TemplateTypeParameter templateTypeParameter) { mixin (tagAndAccept!"templateTypeParameter"); } 1191 override void visit(const TemplateValueParameterDefault templateValueParameterDefault) { mixin (tagAndAccept!"templateValueParameterDefault"); } 1192 override void visit(const TemplateValueParameter templateValueParameter) { mixin (tagAndAccept!"templateValueParameter"); } 1193 override void visit(const TernaryExpression ternaryExpression) { mixin (tagAndAccept!"ternaryExpression"); } 1194 override void visit(const TypeIdentifierPart typeIdentifierPart) { mixin (tagAndAccept!"typeIdentifierPart"); } 1195 override void visit(const ThrowExpression throwExpression) { mixin (tagAndAccept!"throwExpression"); } 1196 override void visit(const TryStatement tryStatement) { mixin (tagAndAccept!"tryStatement"); } 1197 override void visit(const TemplateInstance templateInstance) { mixin (tagAndAccept!"templateInstance"); } 1198 override void visit(const TypeofExpression typeofExpression) { mixin (tagAndAccept!"typeofExpression"); } 1199 override void visit(const TypeSpecialization typeSpecialization) { mixin (tagAndAccept!"typeSpecialization"); } 1200 override void visit(const TraitsExpression traitsExpression) { mixin (tagAndAccept!"traitsExpression"); } 1201 override void visit(const Vector vector) { mixin (tagAndAccept!"vector"); } 1202 override void visit(const VersionCondition versionCondition) { mixin (tagAndAccept!"versionCondition"); } 1203 override void visit(const VersionSpecification versionSpecification) { mixin (tagAndAccept!"versionSpecification"); } 1204 override void visit(const WhileStatement whileStatement) { mixin (tagAndAccept!"whileStatement"); } 1205 override void visit(const WithStatement withStatement) { mixin (tagAndAccept!"withStatement"); } 1206 override void visit(const TypeidExpression typeidExpression) { mixin (tagAndAccept!"typeidExpression"); } 1207 // dfmt on 1208 1209 alias visit = ASTVisitor.visit; 1210 1211 private static string xmlEscape(string s) 1212 { 1213 return s.translate(['<' : "<", '>' : ">", '&' : "&"]); 1214 } 1215 1216 private static string xmlAttributeEscape(string s) 1217 { 1218 return s.translate(['<' : "<", '>' : ">", '&' : "&", '\"' 1219 : """, '\'' : "'"]); 1220 } 1221 1222 private void writeName(string name) 1223 { 1224 output.writeln("<name>", name, "</name>"); 1225 } 1226 1227 private void writeDdoc(string comment) 1228 { 1229 if (comment.ptr is null) 1230 return; 1231 output.writeln("<ddoc>", xmlEscape(comment), "</ddoc>"); 1232 } 1233 1234 /** 1235 * File that output is written to. 1236 */ 1237 File output; 1238 } 1239 1240 private: 1241 1242 template tagAndAccept(string tagName) 1243 { 1244 immutable tagAndAccept = `output.writeln("<` ~ tagName ~ `>");` ~ tagName 1245 ~ `.accept(this);` ~ `output.writeln("</` ~ tagName ~ `>");`; 1246 }