Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2025 ChilliBits. All rights reserved. | ||
2 | |||
3 | #include "ImportCollector.h" | ||
4 | |||
5 | #include <SourceFile.h> | ||
6 | #include <ast/ASTNodes.h> | ||
7 | #include <ast/Attributes.h> | ||
8 | #include <exception/SemanticError.h> | ||
9 | #include <util/FileUtil.h> | ||
10 | |||
11 | namespace spice::compiler { | ||
12 | |||
13 | 1015 | std::any ImportCollector::visitEntry(EntryNode *node) { | |
14 | // Visit all module attributes | ||
15 |
2/2✓ Branch 0 (9→4) taken 294 times.
✓ Branch 1 (9→10) taken 1015 times.
|
1309 | for (ModAttrNode *attr : node->modAttrs) |
16 |
1/2✓ Branch 0 (5→6) taken 294 times.
✗ Branch 1 (5→21) not taken.
|
294 | visit(attr); |
17 | |||
18 | // Visit all import defs | ||
19 |
2/2✓ Branch 0 (17→12) taken 476 times.
✓ Branch 1 (17→18) taken 1010 times.
|
1486 | for (ImportDefNode *importDef : node->importDefs) |
20 |
2/2✓ Branch 0 (13→14) taken 471 times.
✓ Branch 1 (13→23) taken 5 times.
|
476 | visit(importDef); |
21 | |||
22 |
1/2✓ Branch 0 (18→19) taken 1010 times.
✗ Branch 1 (18→25) not taken.
|
1010 | return nullptr; |
23 | } | ||
24 | |||
25 | 476 | std::any ImportCollector::visitImportDef(ImportDefNode *node) { | |
26 | 476 | const bool isStd = node->importPath.starts_with("std/"); | |
27 | 476 | const bool isBootstrap = node->importPath.starts_with("bootstrap/"); | |
28 | |||
29 | 476 | std::filesystem::path basePath; | |
30 |
2/2✓ Branch 0 (5→6) taken 427 times.
✓ Branch 1 (5→27) taken 49 times.
|
476 | if (isStd) { // Include source file from standard library |
31 | // Find std library | ||
32 |
1/2✓ Branch 0 (6→7) taken 427 times.
✗ Branch 1 (6→171) not taken.
|
427 | const std::filesystem::path stdPath = FileUtil::getStdDir(); |
33 |
1/2✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→17) taken 427 times.
|
427 | if (stdPath.empty()) |
34 | ✗ | throw CompilerError(STD_NOT_FOUND, "Standard library could not be found. Check if the env var SPICE_STD_DIR exists"); | |
35 | // Format: /dir/to/path/file | ||
36 |
3/6✓ Branch 0 (18→19) taken 427 times.
✗ Branch 1 (18→166) not taken.
✓ Branch 2 (19→20) taken 427 times.
✗ Branch 3 (19→164) not taken.
✓ Branch 4 (20→21) taken 427 times.
✗ Branch 5 (20→162) not taken.
|
427 | basePath = stdPath / node->importPath.substr(node->importPath.find("std/") + 4); |
37 |
2/2✓ Branch 0 (27→28) taken 18 times.
✓ Branch 1 (27→49) taken 31 times.
|
476 | } else if (isBootstrap) { // Include source file from bootstrap library |
38 | // Find bootstrap library | ||
39 |
1/2✓ Branch 0 (28→29) taken 18 times.
✗ Branch 1 (28→190) not taken.
|
18 | const std::filesystem::path bootstrapPath = FileUtil::getBootstrapDir(); |
40 |
1/2✗ Branch 0 (30→31) not taken.
✓ Branch 1 (30→39) taken 18 times.
|
18 | if (bootstrapPath.empty()) |
41 | ✗ | throw CompilerError(BOOTSTRAP_NOT_FOUND, | |
42 | ✗ | "Bootstrap compiler could not be found. Check if the env var SPICE_BOOTSTRAP_DIR exists"); | |
43 | // Format: /dir/to/path/file | ||
44 |
3/6✓ Branch 0 (40→41) taken 18 times.
✗ Branch 1 (40→185) not taken.
✓ Branch 2 (41→42) taken 18 times.
✗ Branch 3 (41→183) not taken.
✓ Branch 4 (42→43) taken 18 times.
✗ Branch 5 (42→181) not taken.
|
18 | basePath = bootstrapPath / node->importPath.substr(node->importPath.find("bootstrap/") + 10); |
45 | 18 | } else { // Include own source file | |
46 | // Format: /dir/to/path/file | ||
47 |
3/6✓ Branch 0 (49→50) taken 31 times.
✗ Branch 1 (49→196) not taken.
✓ Branch 2 (50→51) taken 31 times.
✗ Branch 3 (50→193) not taken.
✓ Branch 4 (51→52) taken 31 times.
✗ Branch 5 (51→191) not taken.
|
31 | basePath = sourceFile->filePath.parent_path() / node->importPath; |
48 | } | ||
49 | 476 | basePath.make_preferred(); | |
50 | |||
51 | // Format: /dir/to/path/file.spice | ||
52 |
1/2✓ Branch 0 (58→59) taken 476 times.
✗ Branch 1 (58→282) not taken.
|
476 | std::filesystem::path defaultPath = basePath; |
53 |
5/10✓ Branch 0 (59→60) taken 476 times.
✗ Branch 1 (59→206) not taken.
✓ Branch 2 (60→61) taken 476 times.
✗ Branch 3 (60→204) not taken.
✓ Branch 4 (61→62) taken 476 times.
✗ Branch 5 (61→202) not taken.
✓ Branch 6 (62→63) taken 476 times.
✗ Branch 7 (62→200) not taken.
✓ Branch 8 (63→64) taken 476 times.
✗ Branch 9 (63→198) not taken.
|
476 | defaultPath.replace_filename(basePath.stem().string() + ".spice"); |
54 | // Format: /dir/to/path/file_linux.spice | ||
55 |
1/2✓ Branch 0 (68→69) taken 476 times.
✗ Branch 1 (68→280) not taken.
|
476 | std::filesystem::path osPath = basePath; |
56 |
7/14✓ Branch 0 (69→70) taken 476 times.
✗ Branch 1 (69→222) not taken.
✓ Branch 2 (70→71) taken 476 times.
✗ Branch 3 (70→220) not taken.
✓ Branch 4 (71→72) taken 476 times.
✗ Branch 5 (71→218) not taken.
✓ Branch 6 (72→73) taken 476 times.
✗ Branch 7 (72→216) not taken.
✓ Branch 8 (73→74) taken 476 times.
✗ Branch 9 (73→214) not taken.
✓ Branch 10 (74→75) taken 476 times.
✗ Branch 11 (74→212) not taken.
✓ Branch 12 (75→76) taken 476 times.
✗ Branch 13 (75→210) not taken.
|
476 | osPath.replace_filename(basePath.stem().string() + "_" + cliOptions.targetOs + ".spice"); |
57 | // Format: /dir/to/path/file_linux_x86_64.spice | ||
58 |
1/2✓ Branch 0 (82→83) taken 476 times.
✗ Branch 1 (82→278) not taken.
|
476 | std::filesystem::path osArchPath = basePath; |
59 |
9/18✓ Branch 0 (83→84) taken 476 times.
✗ Branch 1 (83→244) not taken.
✓ Branch 2 (84→85) taken 476 times.
✗ Branch 3 (84→242) not taken.
✓ Branch 4 (85→86) taken 476 times.
✗ Branch 5 (85→240) not taken.
✓ Branch 6 (86→87) taken 476 times.
✗ Branch 7 (86→238) not taken.
✓ Branch 8 (87→88) taken 476 times.
✗ Branch 9 (87→236) not taken.
✓ Branch 10 (88→89) taken 476 times.
✗ Branch 11 (88→234) not taken.
✓ Branch 12 (89→90) taken 476 times.
✗ Branch 13 (89→232) not taken.
✓ Branch 14 (90→91) taken 476 times.
✗ Branch 15 (90→230) not taken.
✓ Branch 16 (91→92) taken 476 times.
✗ Branch 17 (91→228) not taken.
|
476 | osArchPath.replace_filename(basePath.stem().string() + "_" + cliOptions.targetOs + "_" + cliOptions.targetArch + ".spice"); |
60 | |||
61 | // Check which source file to import | ||
62 | 476 | std::filesystem::path importPath; | |
63 |
3/10✓ Branch 0 (101→102) taken 476 times.
✗ Branch 1 (101→274) not taken.
✗ Branch 2 (102→103) not taken.
✓ Branch 3 (102→106) taken 476 times.
✗ Branch 4 (103→104) not taken.
✗ Branch 5 (103→274) not taken.
✗ Branch 6 (104→105) not taken.
✗ Branch 7 (104→106) not taken.
✗ Branch 8 (107→108) not taken.
✓ Branch 9 (107→109) taken 476 times.
|
476 | if (exists(osArchPath) && !equivalent(sourceFile->filePath, osArchPath)) // file_os_arch.spice is first choice |
64 | ✗ | importPath = osArchPath; | |
65 |
7/10✓ Branch 0 (109→110) taken 476 times.
✗ Branch 1 (109→274) not taken.
✓ Branch 2 (110→111) taken 20 times.
✓ Branch 3 (110→114) taken 456 times.
✓ Branch 4 (111→112) taken 20 times.
✗ Branch 5 (111→274) not taken.
✓ Branch 6 (112→113) taken 20 times.
✗ Branch 7 (112→114) not taken.
✓ Branch 8 (115→116) taken 20 times.
✓ Branch 9 (115→117) taken 456 times.
|
476 | else if (exists(osPath) && !equivalent(sourceFile->filePath, osPath)) // file_os.spice is second choice |
66 |
1/2✓ Branch 0 (116→127) taken 20 times.
✗ Branch 1 (116→274) not taken.
|
20 | importPath = osPath; |
67 |
3/4✓ Branch 0 (117→118) taken 456 times.
✗ Branch 1 (117→274) not taken.
✓ Branch 2 (118→119) taken 454 times.
✓ Branch 3 (118→120) taken 2 times.
|
456 | else if (exists(defaultPath)) // file.spice is third choice |
68 |
1/2✓ Branch 0 (119→127) taken 454 times.
✗ Branch 1 (119→274) not taken.
|
454 | importPath = defaultPath; |
69 | else | ||
70 |
3/6✓ Branch 0 (121→122) taken 2 times.
✗ Branch 1 (121→257) not taken.
✓ Branch 2 (122→123) taken 2 times.
✗ Branch 3 (122→255) not taken.
✓ Branch 4 (123→124) taken 2 times.
✗ Branch 5 (123→252) not taken.
|
2 | throw SemanticError(node, IMPORTED_FILE_NOT_EXISTING, "The source file '" + node->importPath + ".spice' does not exist"); |
71 | |||
72 | // Check if the import already exists | ||
73 |
1/2✓ Branch 0 (127→128) taken 474 times.
✗ Branch 1 (127→274) not taken.
|
474 | SymbolTableEntry *importEntry = rootScope->lookupStrict(node->importName); |
74 |
2/2✓ Branch 0 (130→131) taken 2 times.
✓ Branch 1 (130→138) taken 472 times.
|
474 | if (importEntry != nullptr) |
75 |
3/6✓ Branch 0 (132→133) taken 2 times.
✗ Branch 1 (132→266) not taken.
✓ Branch 2 (133→134) taken 2 times.
✗ Branch 3 (133→264) not taken.
✓ Branch 4 (134→135) taken 2 times.
✗ Branch 5 (134→261) not taken.
|
2 | throw SemanticError(node, DUPLICATE_IMPORT_NAME, "Duplicate import '" + node->importName + "'"); |
76 | |||
77 | // Create symbol for import | ||
78 |
1/2✓ Branch 0 (138→139) taken 472 times.
✗ Branch 1 (138→274) not taken.
|
472 | node->entry = rootScope->insert(node->importName, node); |
79 | |||
80 | // Create the imported source file | ||
81 |
1/2✓ Branch 0 (141→142) taken 472 times.
✗ Branch 1 (141→274) not taken.
|
472 | const auto importedSourceFile = resourceManager.createSourceFile(sourceFile, node->importName, importPath, isStd); |
82 | // Register it as a dependency to the current source file | ||
83 |
3/4✓ Branch 0 (142→143) taken 472 times.
✗ Branch 1 (142→272) not taken.
✓ Branch 2 (143→144) taken 471 times.
✓ Branch 3 (143→270) taken 1 times.
|
473 | sourceFile->addDependency(importedSourceFile, node, node->importName, importPath.generic_string()); |
84 | |||
85 |
1/2✓ Branch 0 (145→146) taken 471 times.
✗ Branch 1 (145→273) not taken.
|
942 | return nullptr; |
86 | 496 | } | |
87 | |||
88 | 294 | std::any ImportCollector::visitModAttr(ModAttrNode *node) { | |
89 | // !!! Only bool attributes allowed here, due to missing attribute value checks being executed in a later stage !!! | ||
90 | |||
91 | // core.compiler.keep-on-name-collision | ||
92 |
4/6✓ Branch 0 (4→5) taken 294 times.
✗ Branch 1 (4→35) not taken.
✓ Branch 2 (5→6) taken 294 times.
✗ Branch 3 (5→33) not taken.
✓ Branch 4 (8→9) taken 286 times.
✓ Branch 5 (8→16) taken 8 times.
|
882 | if (node->attrLst->hasAttr(ATTR_CORE_COMPILER_KEEP_ON_NAME_COLLISION)) { |
93 |
2/4✓ Branch 0 (11→12) taken 286 times.
✗ Branch 1 (11→41) not taken.
✓ Branch 2 (12→13) taken 286 times.
✗ Branch 3 (12→39) not taken.
|
572 | const bool keepOnCollision = node->attrLst->getAttrValueByName(ATTR_CORE_COMPILER_KEEP_ON_NAME_COLLISION)->boolValue; |
94 | 286 | sourceFile->alwaysKeepSymbolsOnNameCollision = keepOnCollision; | |
95 | } | ||
96 | |||
97 | // core.compiler.warnings.ignore | ||
98 |
4/6✓ Branch 0 (18→19) taken 294 times.
✗ Branch 1 (18→47) not taken.
✓ Branch 2 (19→20) taken 294 times.
✗ Branch 3 (19→45) not taken.
✓ Branch 4 (22→23) taken 2 times.
✓ Branch 5 (22→30) taken 292 times.
|
882 | if (node->attrLst->hasAttr(ATTR_CORE_COMPILER_WARNINGS_IGNORE)) { |
99 |
2/4✓ Branch 0 (25→26) taken 2 times.
✗ Branch 1 (25→53) not taken.
✓ Branch 2 (26→27) taken 2 times.
✗ Branch 3 (26→51) not taken.
|
4 | const bool ignoreWarnings = node->attrLst->getAttrValueByName(ATTR_CORE_COMPILER_WARNINGS_IGNORE)->boolValue; |
100 | 2 | sourceFile->ignoreWarnings = ignoreWarnings; | |
101 | } | ||
102 | |||
103 |
1/2✓ Branch 0 (30→31) taken 294 times.
✗ Branch 1 (30→57) not taken.
|
294 | return nullptr; |
104 | } | ||
105 | |||
106 | } // namespace spice::compiler | ||
107 |