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