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