1 /** 2 * Copyright: © 2014 Economic Modeling Specialists, Intl. 3 * Authors: Brian Schott 4 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt Boost License 1.0) 5 */ 6 module ddoc.comments; 7 import ddoc.sections; 8 import ddoc.lexer; 9 10 public import ddoc.types; 11 12 Comment parseComment(string text, string[string] macros, bool removeUnknown = true) 13 out(retVal) 14 { 15 assert(retVal.sections.length >= 2); 16 } 17 do 18 { 19 import ddoc.highlight : highlight; 20 21 return Comment.parse(text, macros, removeUnknown, &highlight); 22 } 23 24 unittest 25 { 26 // Issue #21 27 Comment test = parseComment("\nParams:\n dg = \n", null); 28 assert(test.sections.length == 3); 29 assert(test.sections[2].name == "Params"); 30 } 31 32 unittest 33 { 34 import std.conv : text; 35 36 auto macros = ["A" : "<a href=\"$0\">"]; 37 auto comment = `Best-comment-ever © 2014 38 39 I thought the same. I was considering writing it, actually. 40 Imagine how having the $(A tool) would have influenced the "final by 41 default" discussion. Amongst others, of course. 42 43 It essentially comes down to persistent compiler-as-a-library 44 issue. Tools like dscanner can help with some of more simple 45 transition cases but anything more complicated is likely to 46 require full semantic analysis. 47 Params: 48 a = $(A param) 49 Returns: 50 nothing of consequence 51 `; 52 53 Comment c = parseComment(comment, macros); 54 import std.string : format; 55 56 assert(c.sections.length == 4, format("%d", c.sections.length)); 57 assert(c.sections[0].name is null); 58 assert(c.sections[0].content == "Best-comment-ever © 2014", c.sections[0].content); 59 assert(c.sections[1].name is null); 60 assert(c.sections[2].name == "Params"); 61 assert(c.sections[2].mapping[0][0] == "a"); 62 assert(c.sections[2].mapping[0][1] == `<a href="param">`, c.sections[2].mapping[0][1]); 63 assert(c.sections[3].name == "Returns"); 64 } 65 66 unittest 67 { 68 auto macros = ["A" : "<a href=\"$0\">"]; 69 auto comment = `Best $(Unknown comment) ever`; 70 71 Comment c = parseComment(comment, macros, true); 72 73 assert(c.sections.length >= 1); 74 assert(c.sections[0].name is null); 75 assert(c.sections[0].content == "Best ever", c.sections[0].content); 76 } 77 78 unittest 79 { 80 auto macros = ["A" : "<a href=\"$0\">"]; 81 auto comment = `Best $(Unknown comment) ever`; 82 83 Comment c = parseComment(comment, macros, false); 84 85 assert(c.sections.length >= 1); 86 assert(c.sections[0].name is null); 87 assert(c.sections[0].content == "Best $(Unknown comment) ever", c.sections[0].content); 88 } 89 90 unittest 91 { 92 auto comment = `--- 93 auto subcube(T...)(T values); 94 --- 95 Creates a new cube in a similar way to whereCube, but allows the user to 96 define a new root for specific dimensions.`c; 97 string[string] macros; 98 const Comment c = parseComment(comment, macros); 99 } 100 101 /// 102 unittest 103 { 104 import std.conv : text; 105 106 auto s1 = `Stop the world 107 108 This function tells the Master to stop the world, taking effect immediately. 109 110 Params: 111 reason = Explanation to give to the $(B Master) 112 duration = Time for which the world $(UNUSED)would be stopped (as time itself stop, this is always $(F double.infinity)) 113 114 --- 115 void main() { 116 import std.datetime : msecs; 117 import master.universe.control; 118 stopTheWorld("Too fast", 42.msecs); 119 assert(0); // Will never be reached. 120 } 121 --- 122 123 Returns: 124 Nothing, because nobody can restart it. 125 126 Macros: 127 F= $0`; 128 129 immutable expected = `<pre class="d_code"><font color=blue>void</font> main() { 130 <font color=blue>import</font> std.datetime : msecs; 131 <font color=blue>import</font> master.universe.control; 132 stopTheWorld(<font color=red>"Too fast"</font>, 42.msecs); 133 <font color=blue>assert</font>(0); <font color=green>// Will never be reached.</font> 134 }</pre>`; 135 136 auto c = parseComment(s1, null); 137 138 assert(c.sections.length == 6, text(c.sections.length)); 139 assert(c.sections[0].name is null, c.sections[0].name); 140 assert(c.sections[0].content == "Stop the world", c.sections[0].content); 141 142 assert(c.sections[1].name is null, c.sections[1].name); 143 assert( 144 c.sections[1].content == `This function tells the Master to stop the world, taking effect immediately.`, 145 c.sections[1].content); 146 147 assert(c.sections[2].name == "Params", c.sections[2].name); 148 // writeln(c.sections[2].mapping); 149 assert(c.sections[2].mapping[0][0] == "reason", c.sections[2].mapping[0][0]); 150 assert(c.sections[2].mapping[0][1] == "Explanation to give to the <b>Master</b>", 151 c.sections[2].mapping[0][1]); 152 assert(c.sections[2].mapping[1][0] == "duration", c.sections[2].mapping[0][1]); 153 assert( 154 c.sections[2].mapping[1][1] == "Time for which the world would be stopped (as time itself stop, this is always double.infinity)", 155 c.sections[2].mapping[1][1]); 156 157 assert(c.sections[3].name == "Examples", c.sections[3].name); 158 assert(c.sections[3].content == expected, c.sections[3].content); 159 160 assert(c.sections[4].name == "Returns", c.sections[4].name); 161 assert(c.sections[4].content == `Nothing, because nobody can restart it.`, 162 c.sections[4].content); 163 164 assert(c.sections[5].name == "Macros", c.sections[5].name); 165 assert(c.sections[5].mapping[0][0] == "F", c.sections[5].mapping[0][0]); 166 assert(c.sections[5].mapping[0][1] == "$0", c.sections[5].mapping[0][1]); 167 } 168 169 unittest 170 { 171 import std.stdio : writeln, writefln; 172 173 auto comment = `Unrolled Linked List. 174 175 Nodes are (by default) sized to fit within a 64-byte cache line. The number 176 of items stored per node can be read from the $(B nodeCapacity) field. 177 See_also: $(LINK http://en.wikipedia.org/wiki/Unrolled_linked_list) 178 Params: 179 T = the element type 180 supportGC = true to ensure that the GC scans the nodes of the unrolled 181 list, false if you are sure that no references to GC-managed memory 182 will be stored in this container. 183 cacheLineSize = Nodes will be sized to fit within this number of bytes.`; 184 185 auto parsed = parseComment(comment, null); 186 assert(parsed.sections[3].name == "Params"); 187 assert(parsed.sections[3].mapping.length == 3); 188 assert(parsed.sections[3].mapping[1][0] == "supportGC"); 189 assert(parsed.sections[3].mapping[1][1][0] == 't', "<<" ~ parsed.sections[3].mapping[1][1] ~ ">>"); 190 }