1
2
3
4
5
6 #include <cpp2cm/cpp2cm/Project.hpp>
7 #include <cpp2cm/cpp2cm/Merge.hpp>
8 #include <cpp2cm/cpp2cm/Converter.hpp>
9 #include <cpp2cm/cpp2cm/PatchFileParser.hpp>
10 #include <sngcpp/pp/Evaluator.hpp>
11 #include <sngcpp/ast/SourceFile.hpp>
12 #include <sngcpp/lexer/CppLexer.hpp>
13 #include <sngcpp/parser/SourceFile.hpp>
14 #include <sngcpp/symbols/SymbolCreator.hpp>
15 #include <sngcpp/binder/StatementBinder.hpp>
16 #include <sngcpp/binder/VirtualBinder.hpp>
17 #include <sngcpp/ast/Reader.hpp>
18 #include <sngcpp/ast/Writer.hpp>
19 #include <sngcm/cmlexer/CmajorLexer.hpp>
20 #include <sngcm/cmparser/CompileUnit.hpp>
21 #include <sngcm/ast/SourceWriter.hpp>
22 #include <sngcm/ast/Merge.hpp>
23 #include <sngxml/dom/Parser.hpp>
24 #include <sngxml/dom/Element.hpp>
25 #include <sngxml/xpath/XPathEvaluate.hpp>
26 #include <soulng/lexer/TrivialLexer.hpp>
27 #include <soulng/util/Path.hpp>
28 #include <soulng/util/Unicode.hpp>
29 #include <soulng/util/Util.hpp>
30 #include <boost/filesystem.hpp>
31 #include <iostream>
32
33 namespace cpp2cm {
34
35 using namespace soulng::util;
36 using namespace soulng::unicode;
37
38 Project::Project(const std::string& systemXmlFilePath_, const std::string& xmlFilePath_, bool nothrowStatus_) :
39 systemXmlFilePath(systemXmlFilePath_), systemRootDir(Path::GetDirectoryName(systemXmlFilePath)),
40 xmlFilePath(xmlFilePath_), projectRootDir(GetFullPath(Path::GetDirectoryName(xmlFilePath))), doc(sngxml::dom::ReadDocument(xmlFilePath)), verbose(false), system(false),
41 nothrowList(nothrowStatus_)
42 {
43 sngxml::dom::Element* projectElement = doc->DocumentElement();
44 name = projectElement->GetAttribute(U"name");
45 if (name.empty())
46 {
47 throw std::runtime_error("project name not set in '" + xmlFilePath + "'");
48 }
49 type = projectElement->GetAttribute(U"type");
50 if (type.empty())
51 {
52 type = U"library";
53 }
54 targetName = projectElement->GetAttribute(U"targetName");
55 if (targetName.empty())
56 {
57 targetName = name;
58 }
59 mergeDir = Path::Combine(projectRootDir, "merge");
60 SetStageDir();
61 SetAstFilePath();
62 }
63
64 void Project::Process(bool verbose, ProcessType processType)
65 {
66 this->verbose = verbose;
67 ReadFilter();
68 ReadNothrowList();
69 ReadVCXProjectFilePath();
70 ReadSources();
71 ReadTextFiles();
72 ReadMergeDirFiles();
73 ReadIncludePath();
74 ReadTargetDir();
75 ReadInstallDir();
76 ReadMap();
77 ReadReferences();
78 BuildAst();
79 WriteAst();
80 Import();
81 BuildSymbolTable();
82 WriteSymbolTableXml();
83 Convert(processType);
84 }
85
86 void Project::ReadVCXProjectFilePath()
87 {
88 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/vcxproject", doc.get());
89 if (result)
90 {
91 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
92 {
93 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
94 int n = nodeSet->Length();
95 for (int i = 0; i < n; ++i)
96 {
97 sngxml::dom::Node* node = (*nodeSet)[i];
98 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
99 {
100 sngxml::dom::Element* vcxprojectElement = static_cast<sngxml::dom::Element*>(node);
101 std::u32string fileAttr = vcxprojectElement->GetAttribute(U"file");
102 if (!fileAttr.empty())
103 {
104 vcxprojectFilePath = GetFullPath(Path::Combine(projectRootDir, Path::MakeCanonical(ToUtf8(fileAttr))));
105 vcxprojectRootDir = Path::GetDirectoryName(vcxprojectFilePath);
106 }
107 }
108 }
109 }
110 }
111 }
112
113 void Project::ReadSources()
114 {
115 if (!vcxprojectFilePath.empty())
116 {
117 ReadVCSources();
118 return;
119 }
120 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/source", doc.get());
121 if (result)
122 {
123 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
124 {
125 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
126 int n = nodeSet->Length();
127 for (int i = 0; i < n; ++i)
128 {
129 sngxml::dom::Node* node = (*nodeSet)[i];
130 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
131 {
132 sngxml::dom::Element* sourceElement = static_cast<sngxml::dom::Element*>(node);
133 std::u32string fileAttr = sourceElement->GetAttribute(U"file");
134 if (!fileAttr.empty())
135 {
136 File file(fileAttr, GetFullPath(Path::Combine(projectRootDir, ToUtf8(fileAttr))));
137 filters.Apply(file);
138 if (file.Included())
139 {
140 files.push_back(file);
141 }
142 }
143 }
144 }
145 }
146 }
147 }
148
149 void Project::ReadVCSources()
150 {
151 if (verbose)
152 {
153 std::cout << ToUtf8(name) + "> " << vcxprojectFilePath << std::endl;
154 }
155 std::unique_ptr<sngxml::dom::Document> vcxProjectDoc = sngxml::dom::ReadDocument(vcxprojectFilePath);
156 std::unique_ptr<sngxml::xpath::XPathObject> hppResult = sngxml::xpath::Evaluate(U"/Project/ItemGroup/ClInclude", vcxProjectDoc.get());
157 if (hppResult)
158 {
159 if (hppResult->Type() == sngxml::xpath::XPathObjectType::nodeSet)
160 {
161 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(hppResult.get());
162 int n = nodeSet->Length();
163 for (int i = 0; i < n; ++i)
164 {
165 sngxml::dom::Node* node = (*nodeSet)[i];
166 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
167 {
168 sngxml::dom::Element* includeFileElement = static_cast<sngxml::dom::Element*>(node);
169 std::u32string hppFileName = includeFileElement->GetAttribute(U"Include");
170 if (!hppFileName.empty())
171 {
172 File hppFile(hppFileName, GetFullPath(Path::Combine(vcxprojectRootDir, ToUtf8(hppFileName))));
173 filters.Apply(hppFile);
174 if (hppFile.Included())
175 {
176 files.push_back(hppFile);
177 headerFiles.AddProjectHeaderFile(hppFile.Path());
178 }
179 }
180 }
181 }
182 }
183 }
184 std::unique_ptr<sngxml::xpath::XPathObject> cppResult = sngxml::xpath::Evaluate(U"/Project/ItemGroup/ClCompile", vcxProjectDoc.get());
185 if (cppResult)
186 {
187 if (cppResult->Type() == sngxml::xpath::XPathObjectType::nodeSet)
188 {
189 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(cppResult.get());
190 int n = nodeSet->Length();
191 for (int i = 0; i < n; ++i)
192 {
193 sngxml::dom::Node* node = (*nodeSet)[i];
194 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
195 {
196 sngxml::dom::Element* includeFileElement = static_cast<sngxml::dom::Element*>(node);
197 std::u32string cppFileName = includeFileElement->GetAttribute(U"Include");
198 if (!cppFileName.empty())
199 {
200 File cppFile(cppFileName, GetFullPath(Path::Combine(vcxprojectRootDir, ToUtf8(cppFileName))));
201 filters.Apply(cppFile);
202 if (cppFile.Included())
203 {
204 files.push_back(cppFile);
205 }
206 }
207 }
208 }
209 }
210 }
211 }
212
213 void Project::ReadTextFiles()
214 {
215 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/text/file", doc.get());
216 if (result)
217 {
218 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
219 {
220 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
221 int n = nodeSet->Length();
222 for (int i = 0; i < n; ++i)
223 {
224 sngxml::dom::Node* node = (*nodeSet)[i];
225 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
226 {
227 sngxml::dom::Element* textFileElement = static_cast<sngxml::dom::Element*>(node);
228 std::u32string nameAttribute = textFileElement->GetAttribute(U"name");
229 if (!nameAttribute.empty())
230 {
231 textFiles.push_back(nameAttribute);
232 }
233 }
234 }
235 }
236 }
237 }
238
239 void Project::ReadIncludePath()
240 {
241 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/include", doc.get());
242 if (result)
243 {
244 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
245 {
246 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
247 int n = nodeSet->Length();
248 for (int i = 0; i < n; ++i)
249 {
250 sngxml::dom::Node* node = (*nodeSet)[i];
251 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
252 {
253 sngxml::dom::Element* sourceElement = static_cast<sngxml::dom::Element*>(node);
254 std::u32string pathAttr = sourceElement->GetAttribute(U"path");
255 if (!pathAttr.empty())
256 {
257 includePath = ToUtf8(pathAttr);
258 }
259 }
260 }
261 }
262 }
263 }
264
265 void Project::ReadTargetDir()
266 {
267 if (system) return;
268 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/target", doc.get());
269 if (result)
270 {
271 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
272 {
273 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
274 int n = nodeSet->Length();
275 for (int i = 0; i < n; ++i)
276 {
277 sngxml::dom::Node* node = (*nodeSet)[i];
278 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
279 {
280 sngxml::dom::Element* targetElement = static_cast<sngxml::dom::Element*>(node);
281 std::u32string dirAttr = targetElement->GetAttribute(U"dir");
282 if (!dirAttr.empty())
283 {
284 targetDir = GetFullPath(Path::Combine(projectRootDir, ToUtf8(dirAttr)));
285 }
286 }
287 }
288 }
289 }
290 if (targetDir.empty())
291 {
292 throw std::runtime_error("project target directory not set");
293 }
294 }
295
296 void Project::ReadInstallDir()
297 {
298 if (system) return;
299 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/install", doc.get());
300 if (result)
301 {
302 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
303 {
304 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
305 int n = nodeSet->Length();
306 for (int i = 0; i < n; ++i)
307 {
308 sngxml::dom::Node* node = (*nodeSet)[i];
309 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
310 {
311 sngxml::dom::Element* installElement = static_cast<sngxml::dom::Element*>(node);
312 std::u32string dirAttr = installElement->GetAttribute(U"dir");
313 if (!dirAttr.empty())
314 {
315 installDir = GetFullPath(Path::Combine(projectRootDir, Path::MakeCanonical(ToUtf8(dirAttr))));
316 }
317 }
318 }
319 }
320 }
321 if (installDir.empty())
322 {
323 throw std::runtime_error("project install directory not set");
324 }
325 }
326
327 void Project::ReadFilter()
328 {
329 std::unique_ptr<sngxml::xpath::XPathObject> fileResult = sngxml::xpath::Evaluate(U"/project/filter/file", doc.get());
330 if (fileResult)
331 {
332 if (fileResult->Type() == sngxml::xpath::XPathObjectType::nodeSet)
333 {
334 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(fileResult.get());
335 for (int i = 0; i < nodeSet->Length(); ++i)
336 {
337 sngxml::dom::Node* node = (*nodeSet)[i];
338 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
339 {
340 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
341 std::u32string excludePattern = element->GetAttribute(U"exclude");
342 if (!excludePattern.empty())
343 {
344 Filter filter(context, Filter::Type::exclude, excludePattern);
345 filters.Add(filter);
346 }
347 else
348 {
349 std::u32string includePattern = element->GetAttribute(U"include");
350 if (!includePattern.empty())
351 {
352 Filter filter(context, Filter::Type::include, includePattern);
353 filters.Add(filter);
354 }
355 }
356 }
357 }
358 }
359 }
360 std::unique_ptr<sngxml::xpath::XPathObject> functionResult = sngxml::xpath::Evaluate(U"/project/filter/function", doc.get());
361 if (functionResult)
362 {
363 if (functionResult->Type() == sngxml::xpath::XPathObjectType::nodeSet)
364 {
365 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(functionResult.get());
366 for (int i = 0; i < nodeSet->Length(); ++i)
367 {
368 sngxml::dom::Node* node = (*nodeSet)[i];
369 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
370 {
371 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
372 std::u32string excludeAttr = element->GetAttribute(U"exclude");
373 if (!excludeAttr.empty())
374 {
375 excludedFunctions.insert(excludeAttr);
376 }
377 }
378 }
379 }
380 }
381 std::unique_ptr<sngxml::xpath::XPathObject> classResult = sngxml::xpath::Evaluate(U"/project/filter/class", doc.get());
382 if (classResult)
383 {
384 if (classResult->Type() == sngxml::xpath::XPathObjectType::nodeSet)
385 {
386 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(classResult.get());
387 for (int i = 0; i < nodeSet->Length(); ++i)
388 {
389 sngxml::dom::Node* node = (*nodeSet)[i];
390 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
391 {
392 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
393 std::u32string excludeAttr = element->GetAttribute(U"exclude");
394 if (!excludeAttr.empty())
395 {
396 excludedClasses.insert(excludeAttr);
397 }
398 }
399 }
400 }
401 }
402 }
403
404 void Project::ReadNothrowList()
405 {
406 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/nothrow/item", doc.get());
407 if (result)
408 {
409 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
410 {
411 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
412 for (int i = 0; i < nodeSet->Length(); ++i)
413 {
414 sngxml::dom::Node* node = (*nodeSet)[i];
415 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
416 {
417 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
418 std::u32string typeText = element->GetAttribute(U"type");
419 Item::Type type = Item::Type::none;
420 if (typeText.empty())
421 {
422 throw std::runtime_error("nothrow item type not specified");
423 }
424 if (typeText == U"file")
425 {
426 type = Item::Type::file;
427 }
428 else if (typeText == U"class")
429 {
430 type = Item::Type::class_;
431 }
432 else if (typeText == U"function")
433 {
434 type = Item::Type::function;
435 }
436 else
437 {
438 throw std::runtime_error("unknonwn nothrow item type '" + ToUtf8(typeText) + "'");
439 }
440 std::u32string excludePattern = element->GetAttribute(U"exclude");
441 if (!excludePattern.empty())
442 {
443 NothrowPattern pattern(context, NothrowPattern::Kind::exclude, type, excludePattern);
444 nothrowList.AddPattern(pattern);
445 }
446 else
447 {
448 std::u32string includePattern = element->GetAttribute(U"include");
449 if (!includePattern.empty())
450 {
451 NothrowPattern pattern(context, NothrowPattern::Kind::include, type, includePattern);
452 nothrowList.AddPattern(pattern);
453 }
454 else
455 {
456 throw std::runtime_error("nothrow pattern kind not specified");
457 }
458 }
459 }
460 }
461 }
462 }
463 }
464
465 void Project::ReadMap()
466 {
467 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/map", doc.get());
468 if (result)
469 {
470 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
471 {
472 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
473 for (int i = 0; i < nodeSet->Length(); ++i)
474 {
475 sngxml::dom::Node* node = (*nodeSet)[i];
476 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
477 {
478 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
479 std::u32string mapFileAttr = element->GetAttribute(U"file");
480 if (!mapFileAttr.empty())
481 {
482 std::string mapFilePath = GetFullPath(Path::Combine(projectRootDir, ToUtf8(mapFileAttr)));
483 if (verbose)
484 {
485 std::cout << ToUtf8(name) << "> " << mapFilePath << std::endl;
486 }
487 std::unique_ptr<sngxml::dom::Document> mapDoc = sngxml::dom::ReadDocument(mapFilePath);
488 MapNamespaces(mapDoc.get());
489 }
490 }
491 }
492 }
493 }
494 }
495
496 void Project::ReadReferences()
497 {
498 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/references/reference", doc.get());
499 if (result)
500 {
501 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
502 {
503 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
504 for (int i = 0; i < nodeSet->Length(); ++i)
505 {
506 sngxml::dom::Node* node = (*nodeSet)[i];
507 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
508 {
509 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
510 std::u32string projectAttr = element->GetAttribute(U"project");
511 if (!projectAttr.empty())
512 {
513 std::u32string kindAttr = element->GetAttribute(U"kind");
514 if (kindAttr == U"install")
515 {
516 installReferences.push_back(projectAttr);
517 }
518 else if (kindAttr == U"stage")
519 {
520 stageReferences.push_back(projectAttr);
521 }
522 else
523 {
524 installReferences.push_back(projectAttr);
525 stageReferences.push_back(projectAttr);
526 }
527 }
528 }
529 }
530 }
531 }
532 }
533
534 void Project::MapNamespaces(sngxml::dom::Document* mapDoc)
535 {
536 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/map/namespace", mapDoc);
537 if (result)
538 {
539 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
540 {
541 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
542 for (int i = 0; i < nodeSet->Length(); ++i)
543 {
544 sngxml::dom::Node* node = (*nodeSet)[i];
545 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
546 {
547 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
548 std::u32string source = element->GetAttribute(U"source");
549 std::u32string target = element->GetAttribute(U"target");
550 map.MapNs(source, target);
551 }
552 }
553 }
554 }
555 }
556
557 void Project::SetStageDir()
558 {
559 stageDir = Path::Combine(projectRootDir, "stage");
560 boost::filesystem::create_directories(stageDir);
561 }
562
563 void Project::SetAstFilePath()
564 {
565 astFilePath = GetFullPath(Path::Combine(stageDir, ToUtf8(name) + ".ast"));
566 }
567
568 void Project::BuildAst()
569 {
570 sngcpp::pp::EvaluationContext evaluationContext;
571 int fileIndex = 0;
572 for (const File& file : files)
573 {
574 if (file.Included())
575 {
576 std::unique_ptr<sngcpp::ast::SourceFileNode> sourceFile;
577 std::unique_ptr<CppLexer> lexer;
578 if (verbose)
579 {
580 std::cout << ToUtf8(name) + "> " << file.Path() << std::endl;
581 }
582 sngcpp::pp::PP pp(evaluationContext);
583 pp.root = vcxprojectRootDir;
584 pp.includePath = Split(includePath, ';');
585 pp.projectHeaderFileSet = &headerFiles;
586 pp.Define(sngcpp::pp::ndebug);
587 if (verbose)
588 {
589 pp.verbose = true;
590 }
591 Preprocess(file.Path(), &pp);
592 std::unique_ptr<std::u32string> content(new std::u32string(std::move(pp.ctext)));
593 lexer.reset(new CppLexer(content->c_str(), content->c_str() + content->length(), file.Path(), fileIndex));
594 lexer->SetSeparatorChar('\n');
595 sourceFile.reset(new sngcpp::ast::SourceFileNode(lexer->GetSpan(), file.Path(), ToUtf8(file.Name()), name));
596 sourceFile->SetSourceFileIndex(fileIndex);
597 SourceFileParser::Parse(*lexer, sourceFile.get());
598 sourceFile->SetHeaderFilePaths(std::move(pp.headerFilePaths));
599 sourceFile->SetText(std::move(*content));
600 sourceFile->ComputeLineStarts();
601 if (ast)
602 {
603 soulng::lexer::Span span = ast->GetSpan();
604 ast.reset(new sngcpp::ast::SourceFileSequenceNode(span, ast.release(), sourceFile.release()));
605 }
606 else
607 {
608 ast.reset(sourceFile.release());
609 }
610 ++fileIndex;
611 lexers.push_back(std::unique_ptr<soulng::lexer::Lexer>(lexer.release()));
612 }
613 }
614 }
615
616 void Project::WriteAst()
617 {
618 if (!ast) return;
619 std::vector<soulng::lexer::Lexer*> lx;
620 for (const auto& lexer : lexers)
621 {
622 lx.push_back(lexer.get());
623 }
624 soulng::util::BinaryWriter binaryWriter(astFilePath);
625 sngcpp::ast::Writer writer(lx, binaryWriter);
626 ast->Write(writer);
627 if (verbose)
628 {
629 std::cout << ToUtf8(name) << "==> " << astFilePath << std::endl;
630 }
631 }
632
633 void Project::ReadAst()
634 {
635 if (!boost::filesystem::exists(astFilePath)) return;
636 if (verbose)
637 {
638 std::cout << ToUtf8(name) + "> " << astFilePath << std::endl;
639 }
640 soulng::util::BinaryReader binaryReder(astFilePath);
641 sngcpp::ast::Reader reader(binaryReder);
642 ast.reset(reader.ReadNode());
643 }
644
645 void Project::Import()
646 {
647 ReadSystemProjects();
648 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/imports/import", doc.get());
649 if (result)
650 {
651 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
652 {
653 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
654 int n = nodeSet->Length();
655 for (int i = 0; i < n; ++i)
656 {
657 sngxml::dom::Node* node = (*nodeSet)[i];
658 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
659 {
660 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
661 std::u32string nameAttr = element->GetAttribute(U"name");
662 if (!nameAttr.empty())
663 {
664 auto it = projectMap.find(nameAttr);
665 if (it != projectMap.cend())
666 {
667 Project* importProject = it->second;
668 importProject->system = true;
669 imports.push_back(importProject);
670 }
671 else
672 {
673 throw std::runtime_error("project '" + ToUtf8(nameAttr) + "' not found");
674 }
675 }
676 else
677 {
678 std::u32string projectAttr = element->GetAttribute(U"project");
679 if (!projectAttr.empty())
680 {
681 std::string projectXmlFilePath = GetFullPath(Path::Combine(projectRootDir, ToUtf8(projectAttr)));
682 std::unique_ptr<Project> project(new Project(systemXmlFilePath, projectXmlFilePath, nothrowList.Verbose()));
683 if (verbose)
684 {
685 project->verbose = true;
686 }
687 projectMap[project->name] = project.get();
688 imports.push_back(project.get());
689 projects.push_back(std::move(project));
690 }
691 else
692 {
693 throw std::runtime_error("import must have either 'name' or 'project' attribute");
694 }
695 }
696 }
697 }
698 }
699 }
700 }
701
702 void Project::ReadSystemProjects()
703 {
704 if (system) return;
705 std::unique_ptr<sngxml::dom::Document> systemXmlDoc = sngxml::dom::ReadDocument(systemXmlFilePath);
706 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/cpp2cm/projects/project", systemXmlDoc.get());
707 if (result)
708 {
709 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
710 {
711 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
712 int n = nodeSet->Length();
713 for (int i = 0; i < n; ++i)
714 {
715 sngxml::dom::Node* node = (*nodeSet)[i];
716 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
717 {
718 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
719 std::u32string fileAttr = element->GetAttribute(U"file");
720 if (!fileAttr.empty())
721 {
722 std::string projectXmlFilePath = GetFullPath(Path::Combine(systemRootDir, ToUtf8(fileAttr)));
723 std::unique_ptr<Project> project(new Project(systemXmlFilePath, projectXmlFilePath, nothrowList.Verbose()));
724 if (verbose)
725 {
726 project->verbose = true;
727 }
728 projectMap[project->name] = project.get();
729 projects.push_back(std::move(project));
730 }
731 }
732 }
733 }
734 }
735 }
736
737 void Project::BuildSymbolTable()
738 {
739 if (!ast) return;
740 sngcpp::ast::ResolveSourceFiles(ast.get(), sourceFiles);
741 for (auto& sourceFile : sourceFiles)
742 {
743 sourceFileMap[sourceFile->SourceFilePath()] = sourceFile;
744 }
745 int n = imports.size();
746 for (int i = 0; i < n; ++i)
747 {
748 Project* importProject = imports[i];
749 importProject->ReadAst();
750 sngcpp::symbols::SymbolCreator symbolCreator(symbolTable, importProject->name);
751 importProject->ast->Accept(symbolCreator);
752 sngcpp::binder::TypeBinder typeBinder(symbolTable, this);
753 importProject->ast->Accept(typeBinder);
754 }
755 sngcpp::symbols::SymbolCreator symbolCreator(symbolTable, name);
756 if (system)
757 {
758 symbolCreator.SetCpp2CmMode();
759 }
760 ast->Accept(symbolCreator);
761 sngcpp::binder::TypeBinder typeBinder(symbolTable, this);
762 ast->Accept(typeBinder);
763 std::vector<std::std::unique_ptr<sngcpp::binder::BoundSourceFile>>boundSourceFiles=typeBinder.SourceFiles();
764 sngcpp::binder::ResolveOverrideSets(typeBinder.ClassesHavingVirtualFunctions());
765 std::unordered_map<sngcpp::ast::SourceFileNode*, sngcpp::binder::BoundSourceFile*> boundSourceFileMap = typeBinder.SourceFileMap();
766 sngcpp::binder::StatementBinder statementBinder(symbolTable, boundSourceFileMap);
767 ast->Accept(statementBinder);
768 }
769
770 void Project::WriteSymbolTableXml()
771 {
772 std::string symbolTableXmlFilePath = GetFullPath(Path::Combine(stageDir, ToUtf8(name) + ".xml"));
773 std::unique_ptr<sngxml::dom::Document> symbolTableXmlDoc = symbolTable.ToDomDocument();
774 if (system)
775 {
776 if (boost::filesystem::exists(symbolTableXmlFilePath))
777 {
778 std::unique_ptr<sngxml::dom::Document> stageSymbolTableXmlDoc = sngxml::dom::ReadDocument(symbolTableXmlFilePath);
779 symbolTableXmlDoc = Merge(symbolTableXmlDoc.get(), stageSymbolTableXmlDoc);
780 }
781 }
782 std::ofstream symbolTableXmlFile(symbolTableXmlFilePath);
783 soulng::util::CodeFormatter formatter(symbolTableXmlFile);
784 symbolTableXmlDoc->Write(formatter);
785 if (verbose)
786 {
787 std::cout << ToUtf8(name) + "==> " << symbolTableXmlFilePath << std::endl;
788 }
789 }
790
791 void Project::ReadSymbolTableXml()
792 {
793 std::string symbolTableXmlFilePath = GetFullPath(Path::Combine(stageDir, ToUtf8(name) + ".xml"));
794 symbolTableXmlDoc = sngxml::dom::ReadDocument(symbolTableXmlFilePath);
795 }
796
797 void Project::Convert(ProcessType processType)
798 {
799 if (system) return;
800 std::string dir;
801 if (processType == ProcessType::stage)
802 {
803 dir = targetDir;
804 }
805 else if (processType == ProcessType::install)
806 {
807 dir = installDir;
808 }
809 boost::filesystem::create_directories(dir);
810 map.SetCurrentProjectName(name);
811 Converter converter(verbose, targetDir, symbolTable, map, excludedClasses, excludedFunctions, nothrowList);
812 map.SetSymbolTable(&symbolTable);
813 for (Project* importProject : imports)
814 {
815 if (importProject->system)
816 {
817 importProject->ReadSymbolTableXml();
818 map.AddSourceXmlDoc(importProject->symbolTableXmlDoc.get(), importProject->name);
819 }
820 }
821 ast->Accept(converter);
822 converter.Write();
823 ReadPatchFiles();
824 SourceFiles& sourceFiles = converter.GetSourceFiles();
825 sourceFiles.Sort();
826 if (!patchFiles.empty())
827 {
828 if (verbose)
829 {
830 std::cout << "patching:" << std::endl;
831 }
832 for (const auto& patchFile : patchFiles)
833 {
834 if (verbose)
835 {
836 std::cout << "> " << patchFile->Path() << std::endl;
837 }
838 sourceFiles.Apply(patchFile.get());
839 }
840 }
841 sourceFiles.Write();
842 if (boost::filesystem::exists(mergeDir))
843 {
844 if (verbose)
845 {
846 std::cout << "merging:" << std::endl;
847 }
848 for (const auto& sourceFile : sourceFiles.Get())
849 {
850 std::string sourceFilePath = GetFullPath(Path::Combine(mergeDir, ToUtf8(sourceFile->Name())));
851 if (boost::filesystem::exists(sourceFilePath))
852 {
853 auto it = mergeFileMap.find(sourceFile->Name());
854 if (it != mergeFileMap.cend())
855 {
856 File* mergeFile = it->second;
857 mergeFile->SetIncluded(true);
858 }
859 std::string sourceContent = ReadFile(sourceFilePath);
860 CmajorLexer sourceLexer(ToUtf32(sourceContent), sourceFilePath, 0);
861 ParsingContext sourceCtx;
862 std::unique_ptr<sngcm::ast::CompileUnitNode> sourceCu = CompileUnitParser::Parse(sourceLexer, &sourceCtx);
863 std::string targetFilePath = sourceFile->Path();
864 std::string targetContent = ReadFile(targetFilePath);
865 CmajorLexer targetLexer(ToUtf32(targetContent), targetFilePath, 0);
866 ParsingContext targetCtx;
867 std::unique_ptr<sngcm::ast::CompileUnitNode> targetCu = CompileUnitParser::Parse(targetLexer, &targetCtx);
868 sngcm::ast::Merge(*sourceCu, *targetCu);
869 sngcm::ast::ArrangeClassMembers(*targetCu);
870 std::ofstream targetFile(targetFilePath);
871 CodeFormatter formatter(targetFile);
872 sngcm::ast::SourceWriter sourceWriter(formatter);
873 targetCu->Accept(sourceWriter);
874 if (verbose)
875 {
876 std::cout << "==> " << targetFilePath << " <- " << sourceFilePath << std::endl;
877 }
878 }
879 }
880 for (const auto& mergeFile : mergeDirFiles)
881 {
882 if (!mergeFile->Included())
883 {
884 std::string sourceFilePath = mergeFile->Path();
885 if (boost::filesystem::exists(sourceFilePath))
886 {
887 std::string sourceContent = ReadFile(sourceFilePath);
888 CmajorLexer sourceLexer(ToUtf32(sourceContent), sourceFilePath, 0);
889 ParsingContext sourceCtx;
890 std::unique_ptr<sngcm::ast::CompileUnitNode> cu = CompileUnitParser::Parse(sourceLexer, &sourceCtx);
891 File* target = new File(mergeFile->Name(), GetFullPath(Path::Combine(targetDir, Path::GetFileName(mergeFile->Path()))));
892 std::string targetFilePath = target->Path();
893 std::ofstream targetFile(targetFilePath);
894 CodeFormatter formatter(targetFile);
895 sngcm::ast::SourceWriter sourceWriter(formatter);
896 cu->Accept(sourceWriter);
897 extraFiles.push_back(std::unique_ptr<File>(target));
898 if (verbose)
899 {
900 std::cout << "==> " << targetFilePath << " <- " << sourceFilePath << std::endl;
901 }
902 }
903 }
904 }
905 }
906 if (processType == ProcessType::install)
907 {
908 if (verbose)
909 {
910 std::cout << "installing:" << std::endl;
911 }
912 for (const auto& sourceFile : sourceFiles.Get())
913 {
914 std::string targetFilePath = Path::Combine(dir, ToUtf8(sourceFile->Name()));
915 if (boost::filesystem::exists(targetFilePath))
916 {
917 boost::filesystem::remove(targetFilePath);
918 }
919 boost::filesystem::copy_file(sourceFile->Path(), targetFilePath);
920 if (verbose)
921 {
922 std::cout << sourceFile->Path() << " -> " << targetFilePath << std::endl;
923 }
924 }
925 for (const auto& extraFile : extraFiles)
926 {
927 std::string targetFilePath = Path::Combine(dir, ToUtf8(extraFile->Name()));
928 if (boost::filesystem::exists(targetFilePath))
929 {
930 boost::filesystem::remove(targetFilePath);
931 }
932 boost::filesystem::copy_file(extraFile->Path(), targetFilePath);
933 if (verbose)
934 {
935 std::cout << extraFile->Path() << " -> " << targetFilePath << std::endl;
936 }
937 }
938 }
939 if (verbose)
940 {
941 std::cout << "creating project file:" << std::endl;
942 }
943 std::string projectFilePath = Path::Combine(dir, ToUtf8(targetName) + ".cmp");
944 std::ofstream projectFile(projectFilePath);
945 CodeFormatter formatter(projectFile);
946 formatter.WriteLine("project " + ToUtf8(targetName) + ";");
947 if (type == U"library")
948 {
949 formatter.WriteLine("target=library;");
950 }
951 else if (type == U"program")
952 {
953 formatter.WriteLine("target=program;");
954 }
955 if (processType == ProcessType::stage)
956 {
957 for (const auto& reference : stageReferences)
958 {
959 formatter.WriteLine("reference <" + ToUtf8(reference) + ">;");
960 }
961 }
962 else if (processType == ProcessType::install)
963 {
964 for (const auto& reference : installReferences)
965 {
966 formatter.WriteLine("reference <" + ToUtf8(reference) + ">;");
967 }
968 }
969 std::vector<std::u32string> sourceFileNames;
970 for (const auto& sourceFile : sourceFiles.Get())
971 {
972 sourceFileNames.push_back(sourceFile->Name());
973 }
974 for (const auto& extraFile : extraFiles)
975 {
976 sourceFileNames.push_back(extraFile->Name());
977 }
978 for (const auto& textFile : textFiles)
979 {
980 sourceFileNames.push_back(textFile);
981 }
982 std::sort(sourceFileNames.begin(), sourceFileNames.end());
983 for (const auto& sourceFileName : sourceFileNames)
984 {
985 if (Path::GetExtension(ToUtf8(sourceFileName)) == ".cm")
986 {
987 formatter.WriteLine("source <" + ToUtf8(sourceFileName) + ">;");
988 }
989 else
990 {
991 formatter.WriteLine("text <" + ToUtf8(sourceFileName) + ">;");
992 }
993 }
994 if (verbose)
995 {
996 std::cout << "==> " << projectFilePath << std::endl;
997 }
998 }
999
1000 void Project::ReadPatchFiles()
1001 {
1002 int index = 0;
1003 std::unique_ptr<sngxml::xpath::XPathObject> result = sngxml::xpath::Evaluate(U"/project/patches/patch", doc.get());
1004 if (result)
1005 {
1006 if (result->Type() == sngxml::xpath::XPathObjectType::nodeSet)
1007 {
1008 sngxml::xpath::XPathNodeSet* nodeSet = static_cast<sngxml::xpath::XPathNodeSet*>(result.get());
1009 int n = nodeSet->Length();
1010 for (int i = 0; i < n; ++i)
1011 {
1012 sngxml::dom::Node* node = (*nodeSet)[i];
1013 if (node->GetNodeType() == sngxml::dom::NodeType::elementNode)
1014 {
1015 sngxml::dom::Element* element = static_cast<sngxml::dom::Element*>(node);
1016 std::u32string file = element->GetAttribute(U"file");
1017 if (!file.empty())
1018 {
1019 std::string patchFilePath = GetFullPath(Path::Combine(projectRootDir, ToUtf8(file)));
1020 std::string content = ReadFile(patchFilePath);
1021 std::u32string text = ToUtf32(content);
1022 if (!text.empty())
1023 {
1024 TrivialLexer lexer(text, patchFilePath, index++);
1025 std::unique_ptr<cpp2cm::PatchFile> patchFile = PatchFileParser::Parse(lexer);
1026 patchFiles.push_back(std::move(patchFile));
1027 }
1028 }
1029 }
1030 }
1031 }
1032 }
1033 }
1034
1035 void Project::ReadMergeDirFiles()
1036 {
1037 if (!boost::filesystem::exists(mergeDir)) return;
1038 boost::filesystem::directory_iterator it = boost::filesystem::directory_iterator(mergeDir);
1039 while (it != boost::filesystem::directory_iterator())
1040 {
1041 const boost::filesystem::directory_entry& entry = *it;
1042 if (entry.status().type() == boost::filesystem::file_type::regular_file)
1043 {
1044 std::string filePath = entry.path().generic_string();
1045 if (Path::GetExtension(filePath) == ".cm")
1046 {
1047 File* file = new File(ToUtf32(Path::GetFileName(filePath)), GetFullPath(filePath));
1048 file->SetIncluded(false);
1049 mergeDirFiles.push_back(std::unique_ptr<File>(file));
1050 mergeFileMap[file->Name()] = file;
1051 }
1052 }
1053 ++it;
1054 }
1055 }
1056
1057 sngcpp::ast::SourceFileNode* Project::GetSourceFile(const std::string& sourceFilePath) const
1058 {
1059 auto it = sourceFileMap.find(sourceFilePath);
1060 if (it != sourceFileMap.cend())
1061 {
1062 return it->second;
1063 }
1064 else
1065 {
1066 return nullptr;
1067 }
1068 }
1069
1070 }