|
ferencd@0
|
1 /*
|
|
ferencd@0
|
2 * This project is licensed under the MIT license. For more information see the
|
|
ferencd@0
|
3 * LICENSE file.
|
|
ferencd@0
|
4 */
|
|
ferencd@0
|
5 #pragma once
|
|
ferencd@0
|
6
|
|
ferencd@0
|
7 // -----------------------------------------------------------------------------
|
|
ferencd@0
|
8
|
|
ferencd@0
|
9 #include <functional>
|
|
ferencd@0
|
10 #include <sstream>
|
|
ferencd@0
|
11 #include <string>
|
|
ferencd@0
|
12 // windows compatibility includes
|
|
ferencd@0
|
13 #include <cctype>
|
|
ferencd@0
|
14 #include <algorithm>
|
|
ferencd@0
|
15
|
|
ferencd@0
|
16 // -----------------------------------------------------------------------------
|
|
ferencd@0
|
17
|
|
ferencd@0
|
18 namespace maddy {
|
|
ferencd@0
|
19
|
|
ferencd@0
|
20 // -----------------------------------------------------------------------------
|
|
ferencd@0
|
21
|
|
ferencd@0
|
22 /**
|
|
ferencd@0
|
23 * BlockParser
|
|
ferencd@0
|
24 *
|
|
ferencd@0
|
25 * The code expects every child to have the following static function to be
|
|
ferencd@0
|
26 * implemented:
|
|
ferencd@0
|
27 * `static bool IsStartingLine(const std::string& line)`
|
|
ferencd@0
|
28 *
|
|
ferencd@0
|
29 * @class
|
|
ferencd@0
|
30 */
|
|
ferencd@0
|
31 class BlockParser
|
|
ferencd@0
|
32 {
|
|
ferencd@0
|
33 public:
|
|
ferencd@0
|
34 /**
|
|
ferencd@0
|
35 * ctor
|
|
ferencd@0
|
36 *
|
|
ferencd@0
|
37 * @method
|
|
ferencd@0
|
38 * @param {std::function<void(std::string&)>} parseLineCallback
|
|
ferencd@0
|
39 * @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
|
ferencd@0
|
40 */
|
|
ferencd@0
|
41 BlockParser(
|
|
ferencd@0
|
42 std::function<void(std::string&)> parseLineCallback,
|
|
ferencd@0
|
43 std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
|
ferencd@0
|
44 )
|
|
ferencd@0
|
45 : result("", std::ios_base::ate | std::ios_base::in | std::ios_base::out)
|
|
ferencd@0
|
46 , childParser(nullptr)
|
|
ferencd@0
|
47 , parseLineCallback(parseLineCallback)
|
|
ferencd@0
|
48 , getBlockParserForLineCallback(getBlockParserForLineCallback)
|
|
ferencd@0
|
49 {}
|
|
ferencd@0
|
50
|
|
ferencd@0
|
51 /**
|
|
ferencd@0
|
52 * dtor
|
|
ferencd@0
|
53 *
|
|
ferencd@0
|
54 * @method
|
|
ferencd@0
|
55 */
|
|
ferencd@0
|
56 virtual ~BlockParser() {}
|
|
ferencd@0
|
57
|
|
ferencd@0
|
58 /**
|
|
ferencd@0
|
59 * AddLine
|
|
ferencd@0
|
60 *
|
|
ferencd@0
|
61 * Adding a line which has to be parsed.
|
|
ferencd@0
|
62 *
|
|
ferencd@0
|
63 * @method
|
|
ferencd@0
|
64 * @param {std::string&} line
|
|
ferencd@0
|
65 * @return {void}
|
|
ferencd@0
|
66 */
|
|
ferencd@0
|
67 virtual void
|
|
ferencd@0
|
68 AddLine(std::string& line)
|
|
ferencd@0
|
69 {
|
|
ferencd@0
|
70 this->parseBlock(line);
|
|
ferencd@0
|
71
|
|
ferencd@0
|
72 if (this->isInlineBlockAllowed() && !this->childParser)
|
|
ferencd@0
|
73 {
|
|
ferencd@0
|
74 this->childParser = this->getBlockParserForLine(line);
|
|
ferencd@0
|
75 }
|
|
ferencd@0
|
76
|
|
ferencd@0
|
77 if (this->childParser)
|
|
ferencd@0
|
78 {
|
|
ferencd@0
|
79 this->childParser->AddLine(line);
|
|
ferencd@0
|
80
|
|
ferencd@0
|
81 if (this->childParser->IsFinished())
|
|
ferencd@0
|
82 {
|
|
ferencd@0
|
83 this->result << this->childParser->GetResult().str();
|
|
ferencd@0
|
84 this->childParser = nullptr;
|
|
ferencd@0
|
85 }
|
|
ferencd@0
|
86
|
|
ferencd@0
|
87 return;
|
|
ferencd@0
|
88 }
|
|
ferencd@0
|
89
|
|
ferencd@0
|
90 if (this->isLineParserAllowed())
|
|
ferencd@0
|
91 {
|
|
ferencd@0
|
92 this->parseLine(line);
|
|
ferencd@0
|
93 }
|
|
ferencd@0
|
94
|
|
ferencd@0
|
95 this->result << line;
|
|
ferencd@0
|
96 }
|
|
ferencd@0
|
97
|
|
ferencd@0
|
98 /**
|
|
ferencd@0
|
99 * IsFinished
|
|
ferencd@0
|
100 *
|
|
ferencd@0
|
101 * Check if the BlockParser is done
|
|
ferencd@0
|
102 *
|
|
ferencd@0
|
103 * @method
|
|
ferencd@0
|
104 * @return {bool}
|
|
ferencd@0
|
105 */
|
|
ferencd@0
|
106 virtual bool IsFinished() const = 0;
|
|
ferencd@0
|
107
|
|
ferencd@0
|
108 /**
|
|
ferencd@0
|
109 * GetResult
|
|
ferencd@0
|
110 *
|
|
ferencd@0
|
111 * Get the parsed HTML output.
|
|
ferencd@0
|
112 *
|
|
ferencd@0
|
113 * @method
|
|
ferencd@0
|
114 * @return {std::stringstream}
|
|
ferencd@0
|
115 */
|
|
ferencd@0
|
116 std::stringstream&
|
|
ferencd@0
|
117 GetResult()
|
|
ferencd@0
|
118 {
|
|
ferencd@0
|
119 return this->result;
|
|
ferencd@0
|
120 }
|
|
ferencd@0
|
121
|
|
ferencd@0
|
122 /**
|
|
ferencd@0
|
123 * Clear
|
|
ferencd@0
|
124 *
|
|
ferencd@0
|
125 * Clear the result to reuse the parser object.
|
|
ferencd@0
|
126 *
|
|
ferencd@0
|
127 * It is only used by one test for now.
|
|
ferencd@0
|
128 *
|
|
ferencd@0
|
129 * @method
|
|
ferencd@0
|
130 * @return {void}
|
|
ferencd@0
|
131 */
|
|
ferencd@0
|
132 void
|
|
ferencd@0
|
133 Clear()
|
|
ferencd@0
|
134 {
|
|
ferencd@0
|
135 this->result.str("");
|
|
ferencd@0
|
136 }
|
|
ferencd@0
|
137
|
|
ferencd@0
|
138 protected:
|
|
ferencd@0
|
139 std::stringstream result;
|
|
ferencd@0
|
140 std::shared_ptr<BlockParser> childParser;
|
|
ferencd@0
|
141
|
|
ferencd@0
|
142 virtual bool isInlineBlockAllowed() const = 0;
|
|
ferencd@0
|
143 virtual bool isLineParserAllowed() const = 0;
|
|
ferencd@0
|
144 virtual void parseBlock(std::string& line) = 0;
|
|
ferencd@0
|
145
|
|
ferencd@0
|
146 void
|
|
ferencd@0
|
147 parseLine(std::string& line)
|
|
ferencd@0
|
148 {
|
|
ferencd@0
|
149 if (parseLineCallback)
|
|
ferencd@0
|
150 {
|
|
ferencd@0
|
151 parseLineCallback(line);
|
|
ferencd@0
|
152 }
|
|
ferencd@0
|
153 }
|
|
ferencd@0
|
154
|
|
ferencd@0
|
155 uint32_t
|
|
ferencd@0
|
156 getIndentationWidth(const std::string& line) const
|
|
ferencd@0
|
157 {
|
|
ferencd@0
|
158 bool hasMetNonSpace = false;
|
|
ferencd@0
|
159
|
|
ferencd@0
|
160 uint32_t indentation = static_cast<uint32_t>(
|
|
ferencd@0
|
161 std::count_if(
|
|
ferencd@0
|
162 line.begin(),
|
|
ferencd@0
|
163 line.end(),
|
|
ferencd@0
|
164 [&hasMetNonSpace](unsigned char c)
|
|
ferencd@0
|
165 {
|
|
ferencd@0
|
166 if (hasMetNonSpace)
|
|
ferencd@0
|
167 {
|
|
ferencd@0
|
168 return false;
|
|
ferencd@0
|
169 }
|
|
ferencd@0
|
170
|
|
ferencd@0
|
171 if (std::isspace(c))
|
|
ferencd@0
|
172 {
|
|
ferencd@0
|
173 return true;
|
|
ferencd@0
|
174 }
|
|
ferencd@0
|
175
|
|
ferencd@0
|
176 hasMetNonSpace = true;
|
|
ferencd@0
|
177 return false;
|
|
ferencd@0
|
178 }
|
|
ferencd@0
|
179 )
|
|
ferencd@0
|
180 );
|
|
ferencd@0
|
181
|
|
ferencd@0
|
182 return indentation;
|
|
ferencd@0
|
183 }
|
|
ferencd@0
|
184
|
|
ferencd@0
|
185 std::shared_ptr<BlockParser>
|
|
ferencd@0
|
186 getBlockParserForLine(const std::string& line)
|
|
ferencd@0
|
187 {
|
|
ferencd@0
|
188 if (getBlockParserForLineCallback)
|
|
ferencd@0
|
189 {
|
|
ferencd@0
|
190 return getBlockParserForLineCallback(line);
|
|
ferencd@0
|
191 }
|
|
ferencd@0
|
192
|
|
ferencd@0
|
193 return nullptr;
|
|
ferencd@0
|
194 }
|
|
ferencd@0
|
195
|
|
ferencd@0
|
196 private:
|
|
ferencd@0
|
197 std::function<void(std::string&)> parseLineCallback;
|
|
ferencd@0
|
198 std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback;
|
|
ferencd@0
|
199 }; // class BlockParser
|
|
ferencd@0
|
200
|
|
ferencd@0
|
201 // -----------------------------------------------------------------------------
|
|
ferencd@0
|
202
|
|
ferencd@0
|
203 } // namespace maddy
|