1 /** 2 * D Documentation Generator 3 * Copyright: © 2014 Economic Modeling Specialists, Intl. 4 * Authors: Brian Schott 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt Boost License 1.0) 6 */ 7 8 module unittest_preprocessor; 9 10 import std.typecons; 11 import dparse.ast; 12 import dparse.lexer; 13 14 /** 15 * $(UL $(LI First field: the byte index of the opening brace of the unittest) 16 * $(LI Second field: the byte index of the closing brace of the unittest) 17 * $(LI Third field: the comment attached to the unittest)) 18 */ 19 alias TestRange = Tuple!(size_t, size_t, string); 20 21 /** 22 * Params: 23 * m = the module 24 * Returns: A mapping of declaration addresses to an array of documentation 25 * unittest blocks for that declaration 26 */ 27 TestRange[][size_t] getUnittestMap(const Module m) 28 { 29 UnittestVisitor visitor = new UnittestVisitor; 30 visitor.visit(m); 31 return visitor.mapping; 32 } 33 34 private: 35 36 class UnittestVisitor : ASTVisitor 37 { 38 alias visit = ASTVisitor.visit; 39 40 override void visit(const ModuleDeclaration modDec) 41 { 42 setPrevNode(modDec); 43 } 44 45 override void visit(const Unittest uTest) 46 { 47 setUnittest(uTest); 48 } 49 50 override void visit(const FunctionDeclaration fd) 51 { 52 setPrevNode(fd); 53 } 54 55 override void visit(const TemplateDeclaration td) 56 { 57 setPrevNode(td); 58 pushScope(); 59 td.accept(this); 60 popScope(); 61 } 62 63 mixin template VisitScope(T) 64 { 65 override void visit(const T s) 66 { 67 pushScope(); 68 s.accept(this); 69 popScope(); 70 } 71 } 72 73 mixin VisitScope!Module; 74 mixin VisitScope!BlockStatement; 75 mixin VisitScope!StructBody; 76 77 mixin template VisitAggregate(T) 78 { 79 override void visit(const T d) 80 { 81 setPrevNode(d); 82 d.accept(this); 83 } 84 } 85 86 mixin VisitAggregate!ClassDeclaration; 87 mixin VisitAggregate!InterfaceDeclaration; 88 mixin VisitAggregate!StructDeclaration; 89 mixin VisitAggregate!UnionDeclaration; 90 91 private: 92 93 void setUnittest(const Unittest test) 94 { 95 // import std.stdio; 96 if (test.comment is null) 97 return; 98 if (prevNodeStack.length == 0) 99 return; 100 if (prevNodeStack[$ - 1] == 0) 101 return; 102 // writeln("Mapping unittest at ", test.blockStatement.startLocation, 103 // " to declaration at ", prevNodeStack[$ - 1]); 104 mapping[prevNodeStack[$ - 1]] ~= TestRange( 105 test.blockStatement.startLocation, 106 test.blockStatement.endLocation, 107 test.comment); 108 } 109 110 void pushScope() 111 { 112 prevNodeStack.length = prevNodeStack.length + 1; 113 prevNodeStack[$ - 1] = 0; 114 } 115 116 void popScope() 117 { 118 prevNodeStack = prevNodeStack[0 .. $ - 1]; 119 } 120 121 void setPrevNode(T)(const T node) 122 { 123 prevNodeStack[$ - 1] = cast(size_t) (cast(void*) node); 124 } 125 126 size_t[] prevNodeStack; 127 TestRange[][size_t] mapping; 128 }