1
2
3
4
5
6 #include <sng2html/sng2html/Project.hpp>
7 #include <sng2html/sng2html/LinkerVisitor.hpp>
8 #include <sng2html/sng2html/GrammarHtmlGenerator.hpp>
9 #include <sngxml/xpath/XPathEvaluate.hpp>
10 #include <sngxml/dom/Element.hpp>
11 #include <soulng/util/Path.hpp>
12 #include <soulng/util/Unicode.hpp>
13 #include <sng2html/sng2html/LexerFileLexer.hpp>
14 #include <sng2html/sng2html/LexerFileParser.hpp>
15 #include <sng2html/sng2html/ParserFileLexer.hpp>
16 #include <sng2html/sng2html/ParserFileParser.hpp>
17 #include <boost/filesystem.hpp>
18 #include <iostream>
19
20 namespace sng2html { namespace sng2html {
21
22 using namespace soulng::unicode;
23
24 Project::Project(bool verbose_, const std::string& xmlFilePath_) :
25 verbose(verbose_), xmlFilePath(xmlFilePath_), rootDir(Path::GetDirectoryName(GetFullPath(xmlFilePath))), xmlDoc(sngxml::dom::ReadDocument(xmlFilePath)),
26 lexerContext(IdentifierClassKind::unicode)
27 {
28 }
29
30 void Project::Process()
31 {
32 ReadLexerFiles();
33 ReadParserFiles();
34 ReadOutDir();
35 ReadStyleFilePath();
36 Link();
37 ParseLexerFiles();
38 ReadGrammarFiles();
39 GenerateHtml();
40 }
41
42 void Project::ReadLexerFiles()
43 {
44 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/lexer", xmlDoc.get());
45 if (result)
46 {
47 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
48 {
49 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
50 int n = nodeSet->Length();
51 for (int i = 0; i < n; ++i)
52 {
53 sngxml::dom::Node* node = (*nodeSet)[i];
54 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
55 {
56 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
57 std::u32string fileAttribute = element->GetAttribute(U"file");
58 if (!fileAttribute.empty())
59 {
60 std::string lexerFilePath = GetFullPath(Path::Combine(rootDir, Path::MakeCanonical(ToUtf8(fileAttribute))));
61 if (verbose)
62 {
63 std::cout << "> " << lexerFilePath << std::endl;
64 }
65 LexerFileLexer lexerFileLexer(ToUtf32(ReadFile(lexerFilePath)), lexerFilePath, 0);
66 std::unique_ptr<LexerFile> lexerFile = LexerFileParser::Parse(lexerFileLexer);
67 lexerMap[lexerFile->GetLexer()->Name()] = lexerFile.get();
68 lexerFiles.push_back(std::move(lexerFile));
69 }
70 }
71 }
72 }
73 }
74 }
75
76 void Project::ReadParserFiles()
77 {
78 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/parser", xmlDoc.get());
79 if (result)
80 {
81 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
82 {
83 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
84 int n = nodeSet->Length();
85 for (int i = 0; i < n; ++i)
86 {
87 sngxml::dom::Node* node = (*nodeSet)[i];
88 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
89 {
90 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
91 std::u32string fileAttribute = element->GetAttribute(U"file");
92 if (!fileAttribute.empty())
93 {
94 std::string parserFilePath = GetFullPath(Path::Combine(rootDir, Path::MakeCanonical(ToUtf8(fileAttribute))));
95 if (verbose)
96 {
97 std::cout << "> " << parserFilePath << std::endl;
98 }
99 ParserFileLexer parserFileLexer(ToUtf32(ReadFile(parserFilePath)), parserFilePath, 0);
100 std::unique_ptr<ParserFile> parserFile = ParserFileParser::Parse(parserFileLexer);
101 domain.AddParserFile(parserFile.get());
102 parserFiles.push_back(std::move(parserFile));
103 }
104 }
105 }
106 }
107 }
108 }
109
110 void Project::ReadOutDir()
111 {
112 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/out", xmlDoc.get());
113 if (result)
114 {
115 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
116 {
117 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
118 int n = nodeSet->Length();
119 for (int i = 0; i < n; ++i)
120 {
121 sngxml::dom::Node* node = (*nodeSet)[i];
122 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
123 {
124 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
125 std::u32string dirAttribute = element->GetAttribute(U"dir");
126 if (!dirAttribute.empty())
127 {
128 if (outDir.empty())
129 {
130 outDir = GetFullPath(Path::Combine(rootDir, Path::MakeCanonical(ToUtf8(dirAttribute))));
131 }
132 else
133 {
134 throw std::runtime_error("output directory already specified");
135 }
136 }
137 }
138 }
139 }
140 }
141 if (outDir.empty())
142 {
143 throw std::runtime_error("output directory not specified");
144 }
145 boost::filesystem::create_directories(outDir);
146 }
147
148 void Project::ReadStyleFilePath()
149 {
150 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/style", xmlDoc.get());
151 if (result)
152 {
153 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
154 {
155 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
156 int n = nodeSet->Length();
157 for (int i = 0; i < n; ++i)
158 {
159 sngxml::dom::Node* node = (*nodeSet)[i];
160 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
161 {
162 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
163 std::u32string fileAttribute = element->GetAttribute(U"file");
164 if (!fileAttribute.empty())
165 {
166 if (styleFilePath.empty())
167 {
168 styleFilePath = fileAttribute;
169 }
170 else
171 {
172 throw std::runtime_error("style file path already specified");
173 }
174 }
175 else
176 {
177 throw std::runtime_error("style file path is empty");
178 }
179 }
180 }
181 }
182 }
183 if (styleFilePath.empty())
184 {
185 throw std::runtime_error("style file path not specified");
186 }
187 }
188
189 void Project::ReadGrammarFiles()
190 {
191 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/grammar", xmlDoc.get());
192 if (result)
193 {
194 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
195 {
196 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
197 int n = nodeSet->Length();
198 for (int i = 0; i < n; ++i)
199 {
200 sngxml::dom::Node* node = (*nodeSet)[i];
201 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
202 {
203 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
204 std::u32string fileAttribute = element->GetAttribute(U"file");
205 if (!fileAttribute.empty())
206 {
207 std::u32string grammarName = ToUtf32(Path::GetFileNameWithoutExtension(ToUtf8(fileAttribute)));
208 std::string grammarFilePath = GetFullPath(Path::Combine(rootDir, Path::MakeCanonical(ToUtf8(fileAttribute))));
209 std::unique_ptr<sngxml::dom::Document> grammarDoc = sngxml::dom::ReadDocument(grammarFilePath);
210 std::u32string kindAttribute = grammarDoc->DocumentElement()->GetAttribute(U"kind");
211 std::u32string sourceAttribute = grammarDoc->DocumentElement()->GetAttribute(U"source");
212 std::u32string titleAttribute = grammarDoc->DocumentElement()->GetAttribute(U"title");
213 if (sourceAttribute.empty())
214 {
215 throw std::runtime_error("grammar source not specified");
216 }
217 if (titleAttribute.empty())
218 {
219 throw std::runtime_error("grammar title not specified");
220 }
221 std::unique_ptr<Grammar> grammar;
222 GrammarParser* grammarParser = nullptr;
223 LexerFile* lexerFile = nullptr;
224 if (kindAttribute == U"lexical")
225 {
226 auto it = lexerMap.find(sourceAttribute);
227 if (it != lexerMap.cend())
228 {
229 lexerFile = it->second;
230 grammar.reset(new Grammar(grammarName, titleAttribute, GetFullPath(Path::Combine(outDir, ToUtf8(grammarName) + ".html")), lexerFile));
231 lexerGrammarMap[lexerFile] = grammar.get();
232 }
233 else
234 {
235 throw std::runtime_error("lexer '" + ToUtf8(sourceAttribute) + "' not found");
236 }
237 }
238 else
239 {
240 grammarParser = domain.GetParser(sourceAttribute);
241 grammar.reset(new Grammar(grammarName, titleAttribute, GetFullPath(Path::Combine(outDir, ToUtf8(grammarName) + ".html")), grammarParser));
242 parserGrammarMap[grammarParser] = grammar.get();
243 }
244 std::unique_ptr<sngxml::xpath::XPathObject> ruleResult = sngxml::xpath::Evaluate(U"/grammar/rule", grammarDoc.get());
245 if (ruleResult)
246 {
247 if (ruleResult->Type() == sngxml::xpath::XPathObjectType::nodeSet)
248 {
249 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(ruleResult.get());
250 int n = nodeSet->Length();
251 for (int i = 0; i < n; ++i)
252 {
253 sngxml::dom::Node* node = (*nodeSet)[i];
254 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
255 {
256 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
257 std::u32string sourceAttribute = element->GetAttribute(U"source");
258 std::u32string nameAttribute = element->GetAttribute(U"name");
259 if (sourceAttribute.empty())
260 {
261 throw std::runtime_error("rule source not specified");
262 }
263 if (nameAttribute.empty())
264 {
265 throw std::runtime_error("rule name not specified");
266 }
267 std::unique_ptr<Rule> rule;
268 if (kindAttribute == U"lexical")
269 {
270 Expression* expression = lexerFile->GetExpressions()->Get(sourceAttribute);
271 rule.reset(new Rule(nameAttribute, expression));
272 lexerRuleMap[expression] = rule.get();
273 }
274 else
275 {
276 RuleParser* ruleParser = grammarParser->GetRule(sourceAttribute);
277 rule.reset(new Rule(nameAttribute, ruleParser));
278 parserRuleMap[ruleParser] = rule.get();
279 }
280 grammar->AddRule(rule.release());
281 }
282 }
283 }
284 }
285 grammars.push_back(std::move(grammar));
286 }
287 }
288 }
289 }
290 }
291 }
292
293 void Project::Link()
294 {
295 LinkerVisitor visitor;
296 domain.Accept(visitor);
297 }
298
299 void Project::ParseLexerFiles()
300 {
301 for (auto& lexerFile : lexerFiles)
302 {
303 lexerFile->Parse(lexerContext);
304 }
305 }
306
307 void Project::GenerateHtml()
308 {
309 GrammarHtmlGeneratorVisitor domainVisitor(verbose, parserGrammarMap, parserRuleMap, lexerGrammarMap, lexerRuleMap, lexerMap, styleFilePath);
310 domain.Accept(domainVisitor);
311 for (auto& lexerFile : lexerFiles)
312 {
313 auto it = lexerGrammarMap.find(lexerFile.get());
314 if (it != lexerGrammarMap.cend())
315 {
316 Grammar* grammar = it->second;
317 Expression* idStartExpression = lexerFile->GetExpressions()->Get(U"idstart");
318 Rule* idStartRule = new Rule(U"idstart", idStartExpression);
319 grammar->AddRule(idStartRule);
320 lexerRuleMap[idStartExpression] = idStartRule;
321 Expression* idContExpression = lexerFile->GetExpressions()->Get(U"idcont");
322 Rule* idContRule = new Rule(U"idcont", idContExpression);
323 grammar->AddRule(idContRule);
324 lexerRuleMap[idContExpression] = idContRule;
325 }
326 GrammarHtmlGeneratorVisitor lexerFileVisitor(verbose, parserGrammarMap, parserRuleMap, lexerGrammarMap, lexerRuleMap, lexerMap, styleFilePath);
327 lexerFile->Accept(lexerFileVisitor);
328 }
329 }
330
331 } }