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))lexerFilePathindex++);
 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))parserFilePathindex++);
 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<ustringLexerFile*>.ConstIterator it = lexerMap.CFind(sourceAttribute);
213                                     if (it != lexerMap.CEnd())
214                                     {
215                                         lexerFile = it->second;
216                                         grammar.Reset(new Grammar(grammarNametitleAttributeGetFullPath(Path.Combine(outDirToUtf8(grammarName) + ".html"))lexerFile));
217                                         lexerGrammarMap[lexerFile] = grammar.Get();
218                                     }
219                                 }
220                                 else
221                                 {
222                                     grammarParser = domain.GetParser(sourceAttribute);
223                                     grammar.Reset(new Grammar(grammarNametitleAttributeGetFullPath(Path.Combine(outDirToUtf8(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(nameAttributeexpression));
252                                                 lexerRuleMap[expression] = rule.Get();
253                                             }
254                                             else
255                                             {
256                                                 RuleParser* ruleParser = grammarParser->GetRule(sourceAttribute);
257                                                 rule.Reset(new Rule(nameAttributeruleParser));
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(verboseparserGrammarMapparserRuleMaplexerGrammarMaplexerRuleMaplexerMapstyleFilePath);
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(verboseparserGrammarMapparserRuleMaplexerGrammarMaplexerRuleMaplexerMapstyleFilePath);
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<ustringLexerFile*> 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 } // namespace soulcm.scm2html