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