1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <sng2html/sng2html/GrammarHtmlGenerator.hpp>
  7 #include <sng2html/sng2html/Domain.hpp>
  8 #include <sng2html/sng2html/Symbol.hpp>
  9 #include <sng2html/sng2html/RegEx.hpp>
 10 #include <sngxml/dom/Document.hpp>
 11 #include <sngxml/dom/Element.hpp>
 12 #include <sngxml/dom/CharacterData.hpp>
 13 #include <soulng/util/Unicode.hpp>
 14 #include <soulng/util/TextUtils.hpp>
 15 #include <fstream>
 16 #include <iostream>
 17 
 18 namespace sng2html { namespace sng2html {
 19 
 20 using namespace soulng::util;
 21 using namespace soulng::unicode;
 22 
 23 void AppendRuleName(sngxml::dom::Element* parentconst std::u32string& name)
 24 {
 25     for (char32_t c : name)
 26     {
 27         switch (c)
 28         {
 29             case '-': parent->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::EntityReference(U"#8209"))); break;
 30             default: parent->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(std::u32string(1c))));
 31         }
 32     }
 33 }
 34 
 35 GrammarHtmlGeneratorVisitor::GrammarHtmlGeneratorVisitor(bool verbose_std::std::unordered_map<GrammarParser*Grammar*>&parserGrammarMap_std::std::unordered_map<RuleParser*Rule*>&parserRuleMap_
 36     std::std::unordered_map<LexerFile*Grammar*>&lexerGrammarMap_std::std::unordered_map<Expression*Rule*>&lexerRuleMap_
 37     std::std::unordered_map<std::u32stringLexerFile*>&lexerMap_conststd::u32string&styleFilePath_):
 38     verbose(verbose_)parserGrammarMap(parserGrammarMap_)parserRuleMap(parserRuleMap_)
 39     lexerGrammarMap(lexerGrammarMap_)lexerRuleMap(lexerRuleMap_)
 40     lexerMap(lexerMap_)styleFilePath(styleFilePath_)ruleTable(nullptr)ruleBodyElement(nullptr)currentGrammar(nullptr)
 41     lexerFile(nullptr)
 42 {
 43 }
 44 
 45 void GrammarHtmlGeneratorVisitor::Visit(Char& symbol)
 46 {
 47     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
 48     spanElement->SetAttribute(U"class"U"ruleChar");
 49     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(CharStr(symbol.Chr()))));
 50     ruleBodyElement->AppendChild(std::move(spanElement));
 51 }
 52 
 53 void GrammarHtmlGeneratorVisitor::Visit(Any& symbol)
 54 {
 55     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
 56     spanElement->SetAttribute(U"class"U"ruleOp");
 57     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U".")));
 58     ruleBodyElement->AppendChild(std::move(spanElement));
 59 }
 60 
 61 void GrammarHtmlGeneratorVisitor::Visit(Range& symbol)
 62 {
 63     if (symbol.Start() == symbol.End())
 64     {
 65         std::unique_ptr<sngxml::dom::Element> startSpanElement(new sngxml::dom::Element(U"span"));
 66         startSpanElement->SetAttribute(U"class"U"ruleCharSet");
 67         startSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(CharStr(symbol.Start()))));
 68         ruleBodyElement->AppendChild(std::move(startSpanElement));
 69     }
 70     else
 71     {
 72         std::unique_ptr<sngxml::dom::Element> startSpanElement(new sngxml::dom::Element(U"span"));
 73         startSpanElement->SetAttribute(U"class"U"ruleCharSet");
 74         startSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(CharStr(symbol.Start()))));
 75         ruleBodyElement->AppendChild(std::move(startSpanElement));
 76         std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
 77         spanElement->SetAttribute(U"class"U"ruleOp");
 78         spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::EntityReference(U"#8209")));
 79         ruleBodyElement->AppendChild(std::move(spanElement));
 80         std::unique_ptr<sngxml::dom::Element> endSpanElement(new sngxml::dom::Element(U"span"));
 81         endSpanElement->SetAttribute(U"class"U"ruleCharSet");
 82         endSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(CharStr(symbol.End()))));
 83         ruleBodyElement->AppendChild(std::move(endSpanElement));
 84     }
 85 }
 86 
 87 void GrammarHtmlGeneratorVisitor::Visit(Class& symbol)
 88 {
 89     std::unique_ptr<sngxml::dom::Element> leftSpanElement(new sngxml::dom::Element(U"span"));
 90     leftSpanElement->SetAttribute(U"class"U"ruleOp");
 91     leftSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"[")));
 92     if (symbol.Inverse())
 93     {
 94         leftSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"^")));
 95     }
 96     ruleBodyElement->AppendChild(std::move(leftSpanElement));
 97     for (const auto& symbol : symbol.Symbols())
 98     {
 99         symbol->Accept(*this);
100     }
101     std::unique_ptr<sngxml::dom::Element> rightSpanElement(new sngxml::dom::Element(U"span"));
102     rightSpanElement->SetAttribute(U"class"U"ruleOp");
103     rightSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"]")));
104     ruleBodyElement->AppendChild(std::move(rightSpanElement));
105 }
106 
107 void GrammarHtmlGeneratorVisitor::Visit(Alt& alt)
108 {
109     alt.Left()->Accept(*this);
110     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
111     spanElement->SetAttribute(U"class"U"ruleOp");
112     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" | ")));
113     ruleBodyElement->AppendChild(std::move(spanElement));
114     alt.Right()->Accept(*this);
115 }
116 
117 void GrammarHtmlGeneratorVisitor::Visit(Cat& cat)
118 {
119     bool chars = cat.Left()->IsCharSymbolExpr() && cat.Right()->IsCharSymbolExpr();
120     cat.Left()->Accept(*this);
121     if (!chars)
122     {
123         std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
124         spanElement->SetAttribute(U"class"U"ruleOp");
125         spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
126         ruleBodyElement->AppendChild(std::move(spanElement));
127     }
128     cat.Right()->Accept(*this);
129 }
130 
131 void GrammarHtmlGeneratorVisitor::Visit(Kleene& kleene)
132 {
133     kleene.Child()->Accept(*this);
134     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
135     spanElement->SetAttribute(U"class"U"ruleOp");
136     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"*")));
137     ruleBodyElement->AppendChild(std::move(spanElement));
138 }
139 
140 void GrammarHtmlGeneratorVisitor::Visit(Pos& pos)
141 {
142     pos.Child()->Accept(*this);
143     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
144     spanElement->SetAttribute(U"class"U"ruleOp");
145     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"+")));
146     ruleBodyElement->AppendChild(std::move(spanElement));
147 }
148 
149 void GrammarHtmlGeneratorVisitor::Visit(Opt& opt)
150 {
151     opt.Child()->Accept(*this);
152     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
153     spanElement->SetAttribute(U"class"U"ruleOp");
154     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"?")));
155     ruleBodyElement->AppendChild(std::move(spanElement));
156 }
157 
158 void GrammarHtmlGeneratorVisitor::Visit(ParenExpr& parenExpr)
159 {
160     std::unique_ptr<sngxml::dom::Element> leftSpanElement(new sngxml::dom::Element(U"span"));
161     leftSpanElement->SetAttribute(U"class"U"ruleOp");
162     leftSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"(")));
163     ruleBodyElement->AppendChild(std::move(leftSpanElement));
164     parenExpr.Child()->Accept(*this);
165     std::unique_ptr<sngxml::dom::Element> rightSpanElement(new sngxml::dom::Element(U"span"));
166     rightSpanElement->SetAttribute(U"class"U"ruleOp");
167     rightSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U")")));
168     ruleBodyElement->AppendChild(std::move(rightSpanElement));
169 }
170 
171 void GrammarHtmlGeneratorVisitor::Visit(SymbolExpr& symbolExpr)
172 {
173     symbolExpr.GetSymbol()->Accept(*this);
174 }
175 
176 void GrammarHtmlGeneratorVisitor::Visit(RefExpr& refExpr)
177 {
178     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
179     spanElement->SetAttribute(U"class"U"lexerRule");
180     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
181     linkElement->SetAttribute(U"class"U"lexerRule");
182     std::u32string linkText;
183     auto grammarIt = lexerGrammarMap.find(lexerFile);
184     if (grammarIt != lexerGrammarMap.cend())
185     {
186         Grammar* grammar = grammarIt->second;
187         linkText.append(grammar->HtmlFileName());
188     }
189     else
190     {
191         throw std::runtime_error("lexical grammar not found");
192     }
193     Expression* expression = lexerFile->GetExpressions()->Get(refExpr.ExprId());
194     Rule* rule = nullptr;
195     auto ruleIt = lexerRuleMap.find(expression);
196     if (ruleIt != lexerRuleMap.cend())
197     {
198         rule = ruleIt->second;
199         linkText.append(U"#").append(rule->Name());
200     }
201     else
202     {
203         throw std::runtime_error("lexical rule not found");
204     }
205     linkElement->SetAttribute(U"href"linkText);
206     AppendRuleName(linkElement.get()rule->Name());
207     spanElement->AppendChild(std::move(linkElement));
208     ruleBodyElement->AppendChild(std::move(spanElement));
209 }
210 
211 void GrammarHtmlGeneratorVisitor::Visit(EmptyParser& parser)
212 {
213     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
214     spanElement->SetAttribute(U"class"U"ruleOp");
215     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"<empty>")));
216     ruleBodyElement->AppendChild(std::move(spanElement));
217 }
218 
219 void GrammarHtmlGeneratorVisitor::Visit(TokenParser& parser)
220 {
221     std::u32string keyword;
222     if (lexerFile)
223     {
224         Keywords* keywords = lexerFile->GetKeywords();
225         if (keywords)
226         {
227             keyword = keywords->GetKeyword(parser.TokenName());
228         }
229     }
230     if (!keyword.empty())
231     {
232         std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
233         spanElement->SetAttribute(U"class"U"ruleKeyword");
234         spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(keyword)));
235         ruleBodyElement->AppendChild(std::move(spanElement));
236     }
237     else
238     {
239         RegExpression* regEx = nullptr;
240         if (lexerFile)
241         {
242             LexerStatement* statement = lexerFile->GetLexer()->GetStatement(parser.TokenName());
243             if (statement)
244             {
245                 regEx = statement->RegEx();
246             }
247         }
248         if (regEx)
249         {
250             regEx->Accept(*this);
251         }
252         else
253         {
254             std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
255             spanElement->SetAttribute(U"class"U"ruleString");
256             spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(parser.TokenName())));
257             ruleBodyElement->AppendChild(std::move(spanElement));
258         }
259     }
260 }
261 
262 void GrammarHtmlGeneratorVisitor::Visit(CharParser& parser)
263 {
264     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
265     spanElement->SetAttribute(U"class"U"ruleChar");
266     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(CharStr(parser.Chr()))));
267     ruleBodyElement->AppendChild(std::move(spanElement));
268 }
269 
270 void GrammarHtmlGeneratorVisitor::Visit(StringParser& parser)
271 {
272     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
273     spanElement->SetAttribute(U"class"U"ruleString");
274     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(StringStr(parser.Str()))));
275     ruleBodyElement->AppendChild(std::move(spanElement));
276 }
277 
278 void GrammarHtmlGeneratorVisitor::Visit(CharSetParser& parser)
279 {
280     std::u32string text = U"[";
281     if (parser.Set().Inverse())
282     {
283         text.append(U"^");
284     }
285     for (const auto& range : parser.Set().Ranges())
286     {
287         text.append(CharStr(static_cast<char32_t>(range.first)));
288         if (range.last != range.first)
289         {
290             text.append(1'-').append(CharStr(static_cast<char32_t>(range.last)));
291         }
292     }
293     text.append(1']');
294     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
295     spanElement->SetAttribute(U"class"U"ruleCharSet");
296     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(text)));
297     ruleBodyElement->AppendChild(std::move(spanElement));
298 }
299 
300 void GrammarHtmlGeneratorVisitor::Visit(OptionalParser& parser)
301 {
302     parser.Child()->Accept(*this);
303     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
304     spanElement->SetAttribute(U"class"U"ruleOp");
305     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"?")));
306     ruleBodyElement->AppendChild(std::move(spanElement));
307 }
308 
309 void GrammarHtmlGeneratorVisitor::Visit(KleeneParser& parser)
310 {
311     parser.Child()->Accept(*this);
312     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
313     spanElement->SetAttribute(U"class"U"ruleOp");
314     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"*")));
315     ruleBodyElement->AppendChild(std::move(spanElement));
316 }
317 
318 void GrammarHtmlGeneratorVisitor::Visit(PositiveParser& parser)
319 {
320     parser.Child()->Accept(*this);
321     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
322     spanElement->SetAttribute(U"class"U"ruleOp");
323     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"+")));
324     ruleBodyElement->AppendChild(std::move(spanElement));
325 }
326 
327 void GrammarHtmlGeneratorVisitor::Visit(ExpectationParser& parser)
328 {
329     parser.Child()->Accept(*this);
330 }
331 
332 void GrammarHtmlGeneratorVisitor::Visit(GroupingParser& parser)
333 {
334     if (!parser.Parent() || parser.Parent()->IsAction() || ((parser.Parent()->IsPostfix() || parser.ParentIsList()) && parser.Child()->IsAction()))
335     {
336         parser.Child()->Accept(*this);
337     }
338     else
339     {
340         std::unique_ptr<sngxml::dom::Element> leftSpanElement(new sngxml::dom::Element(U"span"));
341         leftSpanElement->SetAttribute(U"class"U"ruleOp");
342         leftSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U"(")));
343         ruleBodyElement->AppendChild(std::move(leftSpanElement));
344         parser.Child()->Accept(*this);
345         std::unique_ptr<sngxml::dom::Element> rightSpanElement(new sngxml::dom::Element(U"span"));
346         rightSpanElement->SetAttribute(U"class"U"ruleOp");
347         rightSpanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U")")));
348         ruleBodyElement->AppendChild(std::move(rightSpanElement));
349     }
350 }
351 
352 void GrammarHtmlGeneratorVisitor::Visit(SequenceParser& parser)
353 {
354     if (parser.Left()->IsEmptyOrEmptyActionParser())
355     {
356         if (!parser.Right()->IsEmptyOrEmptyActionParser())
357         {
358             parser.Right()->Accept(*this);
359         }
360     }
361     else if (parser.Right()->IsEmptyOrEmptyActionParser())
362     {
363         if (!parser.Left()->IsEmptyOrEmptyActionParser())
364         {
365             parser.Left()->Accept(*this);
366         }
367     }
368     else
369     {
370         parser.Left()->Accept(*this);
371         std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
372         spanElement->SetAttribute(U"class"U"ruleOp");
373         spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
374         ruleBodyElement->AppendChild(std::move(spanElement));
375         parser.Right()->Accept(*this);
376     }
377 }
378 
379 void GrammarHtmlGeneratorVisitor::Visit(AlternativeParser& parser)
380 {
381     parser.Left()->Accept(*this);
382     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
383     spanElement->SetAttribute(U"class"U"ruleOp");
384     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" | ")));
385     ruleBodyElement->AppendChild(std::move(spanElement));
386     parser.Right()->Accept(*this);
387 }
388 
389 void GrammarHtmlGeneratorVisitor::Visit(DifferenceParser& parser)
390 {
391     parser.Left()->Accept(*this);
392     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
393     spanElement->SetAttribute(U"class"U"ruleOp");
394     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
395     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::EntityReference(U"minus")));
396     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" ")));
397     ruleBodyElement->AppendChild(std::move(spanElement));
398     parser.Right()->Accept(*this);
399 }
400 
401 void GrammarHtmlGeneratorVisitor::Visit(ListParser& parser)
402 {
403     parser.Left()->Accept(*this);
404     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
405     spanElement->SetAttribute(U"class"U"ruleOp");
406     spanElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(U" % ")));
407     ruleBodyElement->AppendChild(std::move(spanElement));
408     parser.Right()->Accept(*this);
409 }
410 
411 void GrammarHtmlGeneratorVisitor::Visit(ActionParser& parser)
412 {
413     parser.Child()->Accept(*this);
414 }
415 
416 void GrammarHtmlGeneratorVisitor::Visit(NonterminalParser& parser)
417 {
418     std::unique_ptr<sngxml::dom::Element> spanElement(new sngxml::dom::Element(U"span"));
419     spanElement->SetAttribute(U"class"U"ruleLink");
420     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
421     linkElement->SetAttribute(U"class"U"ruleLink");
422     RuleParser* ruleParser = parser.Rule();
423     GrammarParser* grammarParser = ruleParser->GetGrammar();
424     Rule* rule = GetRule(ruleParser);
425     std::u32string linkText;
426     if (grammarParser == currentGrammar)
427     {
428         linkText.append(U"#").append(rule->Name());
429     }
430     else
431     {
432         Grammar* grammar = GetGrammar(grammarParser);
433         linkText.append(grammar->HtmlFileName()).append(U"#").append(rule->Name());
434     }
435     linkElement->SetAttribute(U"href"linkText);
436     AppendRuleName(linkElement.get()rule->Name());
437     spanElement->AppendChild(std::move(linkElement));
438     ruleBodyElement->AppendChild(std::move(spanElement));
439 }
440 
441 void GrammarHtmlGeneratorVisitor::Visit(RuleParser& parser)
442 {
443     std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
444     Rule* rule = GetRule(&parser);
445     trElement->SetAttribute(U"id"rule->Name());
446     std::unique_ptr<sngxml::dom::Element> tdNameElement(new sngxml::dom::Element(U"td"));
447     tdNameElement->SetAttribute(U"class"U"grammarFirstCol");
448     std::unique_ptr<sngxml::dom::Element> ruleSpanElement(new sngxml::dom::Element(U"span"));
449     ruleSpanElement->SetAttribute(U"class"U"rule");
450     AppendRuleName(ruleSpanElement.get()rule->Name());
451     tdNameElement->AppendChild(std::move(ruleSpanElement));
452     trElement->AppendChild(std::move(tdNameElement));
453     std::unique_ptr<sngxml::dom::Element> tdArrowElement(new sngxml::dom::Element(U"td"));
454     tdArrowElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::EntityReference(U"rarr")));
455     tdArrowElement->SetAttribute(U"class"U"grammarSecondCol");
456     trElement->AppendChild(std::move(tdArrowElement));
457     std::unique_ptr<sngxml::dom::Element> tdRuleBodyElement(new sngxml::dom::Element(U"td"));
458     tdRuleBodyElement->SetAttribute(U"class"U"grammarThirdCol");
459     tdRuleBodyElement->SetAttribute(U"xml:space"U"preserve");
460     ruleBodyElement = tdRuleBodyElement.get();
461     parser.Definition()->Accept(*this);
462     trElement->AppendChild(std::move(tdRuleBodyElement));
463     ruleTable->AppendChild(std::move(trElement));
464 }
465 
466 void GrammarHtmlGeneratorVisitor::Visit(GrammarParser& parser)
467 {
468     Grammar* grammar = GetGrammar(&parser);
469     GrammarParser* prevGrammar = currentGrammar;
470     currentGrammar = &parser;
471     LexerFile* prevLexerFile = lexerFile;
472     auto it = lexerMap.find(parser.Lexer());
473     if (it != lexerMap.cend())
474     {
475         lexerFile = it->second;
476     }
477     std::unique_ptr<sngxml::dom::Document> grammarDoc(new sngxml::dom::Document());
478     std::unique_ptr<sngxml::dom::Element> htmlElement(new sngxml::dom::Element(U"html"));
479     std::unique_ptr<sngxml::dom::Element> headElement(new sngxml::dom::Element(U"head"));
480     std::unique_ptr<sngxml::dom::Element> metaElement(new sngxml::dom::Element(U"meta"));
481     metaElement->SetAttribute(U"charset"U"utf-8");
482     headElement->AppendChild(std::move(metaElement));
483     std::unique_ptr<sngxml::dom::Element> titleElement(new sngxml::dom::Element(U"title"));
484     titleElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(grammar->Title())));
485     headElement->AppendChild(std::move(titleElement));
486     std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"link"));
487     linkElement->SetAttribute(U"rel"U"stylesheet");
488     linkElement->SetAttribute(U"type"U"text/css");
489     linkElement->SetAttribute(U"href"styleFilePath);
490     headElement->AppendChild(std::move(linkElement));
491     htmlElement->AppendChild(std::move(headElement));
492     std::unique_ptr<sngxml::dom::Element> bodyElement(new sngxml::dom::Element(U"body"));
493     std::unique_ptr<sngxml::dom::Element> headerElement(new sngxml::dom::Element(U"h1"));
494     headerElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(grammar->Title())));
495     bodyElement->AppendChild(std::move(headerElement));
496     std::unique_ptr<sngxml::dom::Element> tableElement(new sngxml::dom::Element(U"table"));
497     tableElement->SetAttribute(U"class"U"grammar");
498     ruleTable = tableElement.get();
499     int n = parser.Rules().size();
500     for (int i = 0; i < n; ++i)
501     {
502         parser.Rules()[i]->Accept(*this);
503     }
504     bodyElement->AppendChild(std::move(tableElement));
505     htmlElement->AppendChild(std::move(bodyElement));
506     grammarDoc->AppendChild(std::move(htmlElement));
507     std::ofstream htmlFile(grammar->HtmlFilePath());
508     CodeFormatter formatter(htmlFile);
509     formatter.SetIndentSize(1);
510     grammarDoc->Write(formatter);
511     currentGrammar = prevGrammar;
512     lexerFile = prevLexerFile;
513     if (verbose)
514     {
515         std::cout << "==> " << grammar->HtmlFilePath() << std::endl;
516     }
517 }
518 
519 void GrammarHtmlGeneratorVisitor::Visit(ParserFile& parserFile)
520 {
521     for (const auto& grammar : parserFile.Parsers())
522     {
523         grammar->Accept(*this);
524     }
525 }
526 
527 void GrammarHtmlGeneratorVisitor::Visit(Domain& domain)
528 {
529     for (const auto& parserFile : domain.ParserFiles())
530     {
531         parserFile->Accept(*this);
532     }
533 }
534 
535 void GrammarHtmlGeneratorVisitor::Visit(LexerFile& lexerFile)
536 {
537     this->lexerFile = &lexerFile;
538     auto it = lexerGrammarMap.find(this->lexerFile);
539     if (it != lexerGrammarMap.cend())
540     {
541         Grammar* grammar = it->second;
542         std::unique_ptr<sngxml::dom::Document> grammarDoc(new sngxml::dom::Document());
543         std::unique_ptr<sngxml::dom::Element> htmlElement(new sngxml::dom::Element(U"html"));
544         std::unique_ptr<sngxml::dom::Element> headElement(new sngxml::dom::Element(U"head"));
545         std::unique_ptr<sngxml::dom::Element> metaElement(new sngxml::dom::Element(U"meta"));
546         metaElement->SetAttribute(U"charset"U"utf-8");
547         headElement->AppendChild(std::move(metaElement));
548         std::unique_ptr<sngxml::dom::Element> titleElement(new sngxml::dom::Element(U"title"));
549         titleElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(grammar->Title())));
550         headElement->AppendChild(std::move(titleElement));
551         std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"link"));
552         linkElement->SetAttribute(U"rel"U"stylesheet");
553         linkElement->SetAttribute(U"type"U"text/css");
554         linkElement->SetAttribute(U"href"styleFilePath);
555         headElement->AppendChild(std::move(linkElement));
556         htmlElement->AppendChild(std::move(headElement));
557         std::unique_ptr<sngxml::dom::Element> bodyElement(new sngxml::dom::Element(U"body"));
558         std::unique_ptr<sngxml::dom::Element> headerElement(new sngxml::dom::Element(U"h1"));
559         headerElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(grammar->Title())));
560         bodyElement->AppendChild(std::move(headerElement));
561         std::unique_ptr<sngxml::dom::Element> tableElement(new sngxml::dom::Element(U"table"));
562         tableElement->SetAttribute(U"class"U"grammar");
563         ruleTable = tableElement.get();
564         int n = grammar->Rules().size();
565         for (int i = 0; i < n; ++i)
566         {
567             Rule* rule = grammar->Rules()[i].get();
568             std::unique_ptr<sngxml::dom::Element> trElement(new sngxml::dom::Element(U"tr"));
569             trElement->SetAttribute(U"id"rule->Name());
570             std::unique_ptr<sngxml::dom::Element> tdNameElement(new sngxml::dom::Element(U"td"));
571             tdNameElement->SetAttribute(U"class"U"grammarFirstCol");
572             std::unique_ptr<sngxml::dom::Element> ruleSpanElement(new sngxml::dom::Element(U"span"));
573             ruleSpanElement->SetAttribute(U"class"U"rule");
574             AppendRuleName(ruleSpanElement.get()rule->Name());
575             tdNameElement->AppendChild(std::move(ruleSpanElement));
576             trElement->AppendChild(std::move(tdNameElement));
577             std::unique_ptr<sngxml::dom::Element> tdArrowElement(new sngxml::dom::Element(U"td"));
578             tdArrowElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::EntityReference(U"rarr")));
579             tdArrowElement->SetAttribute(U"class"U"grammarSecondCol");
580             trElement->AppendChild(std::move(tdArrowElement));
581             std::unique_ptr<sngxml::dom::Element> tdRuleBodyElement(new sngxml::dom::Element(U"td"));
582             tdRuleBodyElement->SetAttribute(U"class"U"grammarThirdCol");
583             tdRuleBodyElement->SetAttribute(U"xml:space"U"preserve");
584             ruleBodyElement = tdRuleBodyElement.get();
585             rule->GetExpression()->RegEx()->Accept(*this);
586             trElement->AppendChild(std::move(tdRuleBodyElement));
587             ruleTable->AppendChild(std::move(trElement));
588         }
589         bodyElement->AppendChild(std::move(tableElement));
590         htmlElement->AppendChild(std::move(bodyElement));
591         grammarDoc->AppendChild(std::move(htmlElement));
592         std::ofstream htmlFile(grammar->HtmlFilePath());
593         CodeFormatter formatter(htmlFile);
594         formatter.SetIndentSize(1);
595         grammarDoc->Write(formatter);
596         if (verbose)
597         {
598             std::cout << "==> " << grammar->HtmlFilePath() << std::endl;
599         }
600 
601     }
602     else
603     {
604         throw std::runtime_error("lexical grammar not found");
605     }
606 }
607 
608 Grammar* GrammarHtmlGeneratorVisitor::GetGrammar(GrammarParser* parser) const
609 {
610     auto it = parserGrammarMap.find(parser);
611     if (it != parserGrammarMap.cend())
612     {
613         return it->second;
614     }
615     else
616     {
617         throw std::runtime_error("grammar for parser '" + ToUtf8(parser->Name()) + "' not found");
618     }
619 }
620 
621 Rule* GrammarHtmlGeneratorVisitor::GetRule(RuleParser* parser) const
622 {
623     auto it = parserRuleMap.find(parser);
624     if (it != parserRuleMap.cend())
625     {
626         return it->second;
627     }
628     else
629     {
630         throw std::runtime_error("rule for parser '" + ToUtf8(parser->Name()) + "' not found");
631     }
632 }
633 
634 } } // namespace sng2html::sng2html