1 module ddoc.types;
2 
3 import ddoc.lexer;
4 import ddoc.sections;
5 
6 struct Comment
7 {
8 	bool isDitto() const @property
9 	{
10 		import std..string : strip, toLower;
11 
12 		return sections.length == 2 && sections[0].content.strip().toLower() == "ditto";
13 	}
14 
15 	Section[] sections;
16 
17 	/**
18 	 * Creates a Comment object without expanding the sections.
19 	 *
20 	 * Use $(LREF parse) with a function pointer to $(REF highlight, ddoc,highlight)
21 	 * or $(REF parseComment, ddoc,comments) to parse a comment while also
22 	 * expanding sections.
23 	 */
24 	static Comment parseUnexpanded(string text)
25 	{
26 		import ddoc.unhighlight : unhighlight;
27 
28 		return parse(text, null, false, &unhighlight);
29 	}
30 
31 	static Comment parse(string text, string[string] macros, bool removeUnknown,
32 		string function(string) highlightFn)
33 	{
34 		import std.functional : toDelegate;
35 
36 		return parse(text, macros, removeUnknown, toDelegate(highlightFn));
37 	}
38 
39 	static Comment parse(string text, string[string] macros, bool removeUnknown,
40 		string delegate(string) highlightFn)
41 	out(retVal)
42 	{
43 		assert(retVal.sections.length >= 2);
44 	}
45 	do
46 	{
47 		import std.algorithm : find;
48 		import ddoc.macros : expand;
49 
50 		auto sections = splitSections(text);
51 		string[string] sMacros = macros;
52 		auto m = sections.find!(p => p.name == "Macros");
53 		const e = sections.find!(p => p.name == "Escapes");
54 		auto p = sections.find!(p => p.name == "Params");
55 		if (m.length)
56 		{
57 			if (!doMapping(m[0]))
58 				throw new DdocParseException("Unable to parse Key/Value pairs", m[0].content);
59 			foreach (kv; m[0].mapping)
60 				sMacros[kv[0]] = kv[1];
61 		}
62 		if (e.length)
63 		{
64 			assert(0, "Escapes not handled yet");
65 		}
66 		if (p.length)
67 		{
68 			if (!doMapping(p[0]))
69 				throw new DdocParseException("Unable to parse Key/Value pairs", p[0].content);
70 			foreach (ref kv; p[0].mapping)
71 				kv[1] = expand(Lexer(highlightFn(kv[1])), sMacros, removeUnknown);
72 		}
73 
74 		foreach (ref Section sec; sections)
75 		{
76 			if (sec.name != "Macros" && sec.name != "Escapes" && sec.name != "Params")
77 				sec.content = expand(Lexer(highlightFn(sec.content)), sMacros, removeUnknown);
78 		}
79 		return Comment(sections);
80 	}
81 }
82 
83 private:
84 bool doMapping(ref Section s)
85 {
86 	import ddoc.macros : KeyValuePair, parseKeyValuePair;
87 
88 	auto lex = Lexer(s.content);
89 	KeyValuePair[] pairs;
90 	if (parseKeyValuePair(lex, pairs))
91 	{
92 		foreach (idx, kv; pairs)
93 			s.mapping ~= kv;
94 		return true;
95 	}
96 	return false;
97 }