Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 ChilliBits. All rights reserved. | ||
2 | |||
3 | #include "SymbolTableBuilder.h" | ||
4 | |||
5 | #include <SourceFile.h> | ||
6 | #include <ast/ASTBuilder.h> | ||
7 | #include <ast/Attributes.h> | ||
8 | #include <exception/SemanticError.h> | ||
9 | #include <global/GlobalResourceManager.h> | ||
10 | |||
11 | namespace spice::compiler { | ||
12 | |||
13 | 887 | SymbolTableBuilder::SymbolTableBuilder(GlobalResourceManager &resourceManager, SourceFile *sourceFile) | |
14 | 887 | : CompilerPass(resourceManager, sourceFile), rootScope(sourceFile->globalScope.get()) {} | |
15 | |||
16 | 887 | std::any SymbolTableBuilder::visitEntry(EntryNode *node) { | |
17 | // Initialize | ||
18 | 887 | currentScope = rootScope; | |
19 | |||
20 | // Visit children | ||
21 |
2/2✓ Branch 1 taken 871 times.
✓ Branch 2 taken 16 times.
|
887 | visitChildren(node); |
22 | |||
23 | // Check if the main function exists | ||
24 |
6/6✓ Branch 0 taken 360 times.
✓ Branch 1 taken 511 times.
✓ Branch 2 taken 358 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 356 times.
|
871 | if (sourceFile->isMainFile && !cliOptions.noEntryFct && !hasMainFunction) |
25 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
6 | throw SemanticError(node, MISSING_MAIN_FUNCTION, "No main function found", false); |
26 | |||
27 |
1/2✓ Branch 1 taken 869 times.
✗ Branch 2 not taken.
|
869 | return nullptr; |
28 | } | ||
29 | |||
30 | 361 | std::any SymbolTableBuilder::visitMainFctDef(MainFctDefNode *node) { | |
31 | // Visit attributes | ||
32 |
3/4✓ Branch 1 taken 361 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 360 times.
|
361 | if (node->attrs()) |
33 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | visit(node->attrs()); |
34 | |||
35 | // Check if the function is already defined | ||
36 |
3/4✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 359 times.
|
1440 | if (rootScope->lookupStrict(MAIN_FUNCTION_NAME)) |
37 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
3 | throw SemanticError(node, FUNCTION_DECLARED_TWICE, "Main function is declared twice"); |
38 | |||
39 | // Insert symbol for main function | ||
40 |
1/2✓ Branch 1 taken 359 times.
✗ Branch 2 not taken.
|
1077 | SymbolTableEntry *mainFctEntry = currentScope->insert(MAIN_FUNCTION_NAME, node); |
41 | 359 | mainFctEntry->used = true; | |
42 | |||
43 | // Create scope for main function body | ||
44 |
1/2✓ Branch 1 taken 359 times.
✗ Branch 2 not taken.
|
359 | const std::string &scopeId = MainFctDefNode::getScopeId(); |
45 |
1/2✓ Branch 1 taken 359 times.
✗ Branch 2 not taken.
|
359 | node->bodyScope = currentScope = rootScope->createChildScope(scopeId, ScopeType::FUNC_PROC_BODY, &node->codeLoc); |
46 | 359 | currentScope->isGenericScope = false; | |
47 | |||
48 | // Declare variable for the return value in the function scope | ||
49 |
1/2✓ Branch 1 taken 359 times.
✗ Branch 2 not taken.
|
1077 | SymbolTableEntry *resultVarEntry = node->bodyScope->insert(RETURN_VARIABLE_NAME, node); |
50 | 359 | resultVarEntry->used = true; | |
51 | |||
52 | // Visit arguments in new scope | ||
53 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 355 times.
|
359 | if (node->takesArgs) |
54 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | visit(node->paramLst()); |
55 | |||
56 | // Visit function body in new scope | ||
57 |
3/4✓ Branch 1 taken 359 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 358 times.
✓ Branch 5 taken 1 times.
|
359 | visit(node->body()); |
58 | |||
59 | // Return to root scope | ||
60 | 358 | currentScope = rootScope; | |
61 | |||
62 | 358 | hasMainFunction = true; | |
63 |
1/2✓ Branch 1 taken 358 times.
✗ Branch 2 not taken.
|
716 | return nullptr; |
64 | 359 | } | |
65 | |||
66 | 4249 | std::any SymbolTableBuilder::visitFctDef(FctDefNode *node) { | |
67 | // Visit attributes | ||
68 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 4238 times.
|
4249 | if (node->attrs()) |
69 |
2/4✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
|
11 | visit(node->attrs()); |
70 | |||
71 | // Build function specifiers | ||
72 |
2/2✓ Branch 1 taken 4101 times.
✓ Branch 2 taken 148 times.
|
4249 | if (const SpecifierLstNode *specifierLst = node->specifierLst(); specifierLst) { |
73 |
3/4✓ Branch 1 taken 4101 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 5218 times.
✓ Branch 9 taken 4101 times.
|
9319 | for (const SpecifierNode *specifier : specifierLst->specifiers()) { |
74 |
2/2✓ Branch 0 taken 1134 times.
✓ Branch 1 taken 4084 times.
|
5218 | if (specifier->type == SpecifierNode::TY_INLINE) |
75 | 1134 | node->specifiers.isInline = true; | |
76 |
2/2✓ Branch 0 taken 4079 times.
✓ Branch 1 taken 5 times.
|
4084 | else if (specifier->type == SpecifierNode::TY_PUBLIC) |
77 | 4079 | node->specifiers.isPublic = true; | |
78 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | else if (specifier->type == SpecifierNode::TY_CONST) |
79 | 5 | node->specifiers.isConst = true; | |
80 | else | ||
81 | ✗ | throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on a function definition"); | |
82 | 4101 | } | |
83 | } | ||
84 | |||
85 | // Change to struct scope if this function is a method | ||
86 |
2/2✓ Branch 0 taken 2364 times.
✓ Branch 1 taken 1885 times.
|
4249 | if (node->isMethod) { |
87 |
2/4✓ Branch 1 taken 2364 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2364 times.
✗ Branch 5 not taken.
|
2364 | node->structScope = currentScope = currentScope->getChildScope(STRUCT_SCOPE_PREFIX + node->name->structName); |
88 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2364 times.
|
2364 | if (!currentScope) |
89 | ✗ | throw SemanticError(node, REFERENCED_UNDEFINED_STRUCT, "Struct '" + node->name->structName + "' could not be found"); | |
90 | } | ||
91 | |||
92 | // Create scope for the function | ||
93 |
2/4✓ Branch 1 taken 4249 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4249 times.
✗ Branch 5 not taken.
|
4249 | node->scope = currentScope = currentScope->createChildScope(node->getScopeId(), ScopeType::FUNC_PROC_BODY, &node->codeLoc); |
94 |
6/6✓ Branch 0 taken 3550 times.
✓ Branch 1 taken 699 times.
✓ Branch 2 taken 2274 times.
✓ Branch 3 taken 1276 times.
✓ Branch 4 taken 640 times.
✓ Branch 5 taken 1634 times.
|
4249 | currentScope->isGenericScope = node->hasTemplateTypes || (node->structScope && node->structScope->isGenericScope); |
95 | |||
96 | // Create symbol for 'this' variable | ||
97 |
2/2✓ Branch 0 taken 2364 times.
✓ Branch 1 taken 1885 times.
|
4249 | if (node->isMethod) |
98 |
1/2✓ Branch 1 taken 2364 times.
✗ Branch 2 not taken.
|
9456 | currentScope->insert(THIS_VARIABLE_NAME, node); |
99 | |||
100 | // Create symbol for 'result' variable | ||
101 |
1/2✓ Branch 1 taken 4249 times.
✗ Branch 2 not taken.
|
12747 | currentScope->insert(RETURN_VARIABLE_NAME, node); |
102 | |||
103 | // Create symbols for the parameters | ||
104 |
2/2✓ Branch 0 taken 3002 times.
✓ Branch 1 taken 1247 times.
|
4249 | if (node->hasParams) |
105 |
2/4✓ Branch 1 taken 3002 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3002 times.
✗ Branch 5 not taken.
|
3002 | visit(node->paramLst()); |
106 | |||
107 | // Visit the function body | ||
108 |
2/4✓ Branch 1 taken 4249 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4249 times.
✗ Branch 5 not taken.
|
4249 | visit(node->body()); |
109 | |||
110 | // Leave function body scope | ||
111 | 4249 | currentScope = node->scope->parent; | |
112 | |||
113 | // Insert symbol for function into the symbol table | ||
114 |
1/2✓ Branch 1 taken 4249 times.
✗ Branch 2 not taken.
|
8498 | node->entry = currentScope->insert(node->getSymbolTableEntryName(), node); |
115 | |||
116 | // Add to external name registry | ||
117 | // if a function has overloads, they both refer to the same entry in the registry. So we only register the name once | ||
118 | 4249 | const NameRegistryEntry *existingRegistryEntry = sourceFile->getNameRegistryEntry(node->name->fqName); | |
119 |
3/4✓ Branch 0 taken 977 times.
✓ Branch 1 taken 3272 times.
✓ Branch 2 taken 977 times.
✗ Branch 3 not taken.
|
4249 | if (!existingRegistryEntry || existingRegistryEntry->targetEntry != node->entry) |
120 | 4249 | sourceFile->addNameRegistryEntry(node->name->fqName, TY_FUNCTION, node->entry, currentScope, true); | |
121 | |||
122 | // Leave the struct scope | ||
123 |
2/2✓ Branch 0 taken 2364 times.
✓ Branch 1 taken 1885 times.
|
4249 | if (node->isMethod) |
124 | 2364 | currentScope = node->structScope->parent; | |
125 | |||
126 |
1/2✓ Branch 1 taken 4249 times.
✗ Branch 2 not taken.
|
4249 | return nullptr; |
127 | } | ||
128 | |||
129 | 2705 | std::any SymbolTableBuilder::visitProcDef(ProcDefNode *node) { | |
130 | // Visit attributes | ||
131 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2704 times.
|
2705 | if (node->attrs()) |
132 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | visit(node->attrs()); |
133 | |||
134 | // Build procedure specifiers | ||
135 |
2/2✓ Branch 1 taken 2411 times.
✓ Branch 2 taken 293 times.
|
2704 | if (const SpecifierLstNode *specifierLst = node->specifierLst()) { |
136 |
3/4✓ Branch 1 taken 2411 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 2754 times.
✓ Branch 9 taken 2411 times.
|
5165 | for (const SpecifierNode *specifier : specifierLst->specifiers()) { |
137 |
2/2✓ Branch 0 taken 344 times.
✓ Branch 1 taken 2410 times.
|
2754 | if (specifier->type == SpecifierNode::TY_INLINE) |
138 | 344 | node->specifiers.isInline = true; | |
139 |
1/2✓ Branch 0 taken 2410 times.
✗ Branch 1 not taken.
|
2410 | else if (specifier->type == SpecifierNode::TY_PUBLIC) |
140 | 2410 | node->specifiers.isPublic = true; | |
141 | ✗ | else if (specifier->type == SpecifierNode::TY_CONST) | |
142 | ✗ | node->specifiers.isConst = true; | |
143 | else | ||
144 | ✗ | throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on a procedure definition"); | |
145 | 2411 | } | |
146 | } | ||
147 | |||
148 | // Change to struct scope if this procedure is a method | ||
149 |
2/2✓ Branch 0 taken 2271 times.
✓ Branch 1 taken 433 times.
|
2704 | if (node->isMethod) { |
150 |
2/4✓ Branch 1 taken 2271 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2271 times.
✗ Branch 5 not taken.
|
2271 | node->structScope = currentScope = currentScope->getChildScope(STRUCT_SCOPE_PREFIX + node->name->structName); |
151 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2270 times.
|
2271 | if (!currentScope) |
152 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, REFERENCED_UNDEFINED_STRUCT, "Struct '" + node->name->structName + "' could not be found"); |
153 | } | ||
154 | |||
155 | // Create scope for the procedure | ||
156 |
2/4✓ Branch 1 taken 2703 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2703 times.
✗ Branch 5 not taken.
|
2703 | node->scope = currentScope = currentScope->createChildScope(node->getScopeId(), ScopeType::FUNC_PROC_BODY, &node->codeLoc); |
157 |
6/6✓ Branch 0 taken 2189 times.
✓ Branch 1 taken 514 times.
✓ Branch 2 taken 2069 times.
✓ Branch 3 taken 120 times.
✓ Branch 4 taken 557 times.
✓ Branch 5 taken 1512 times.
|
2703 | currentScope->isGenericScope = node->hasTemplateTypes || (node->structScope && node->structScope->isGenericScope); |
158 |
4/4✓ Branch 0 taken 2270 times.
✓ Branch 1 taken 433 times.
✓ Branch 3 taken 89 times.
✓ Branch 4 taken 2181 times.
|
2703 | currentScope->isDtorScope = node->isMethod && node->name->name == DTOR_FUNCTION_NAME; |
159 | |||
160 | // Create symbol for 'this' variable | ||
161 |
2/2✓ Branch 0 taken 2270 times.
✓ Branch 1 taken 433 times.
|
2703 | if (node->isMethod) |
162 |
1/2✓ Branch 1 taken 2270 times.
✗ Branch 2 not taken.
|
9080 | currentScope->insert(THIS_VARIABLE_NAME, node); |
163 | |||
164 | // Create symbols for the parameters | ||
165 |
2/2✓ Branch 0 taken 1915 times.
✓ Branch 1 taken 788 times.
|
2703 | if (node->hasParams) |
166 |
2/4✓ Branch 1 taken 1915 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1915 times.
✗ Branch 5 not taken.
|
1915 | visit(node->paramLst()); |
167 | |||
168 | // Visit the procedure body | ||
169 |
2/4✓ Branch 1 taken 2703 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2703 times.
✗ Branch 5 not taken.
|
2703 | visit(node->body()); |
170 | |||
171 | // Leave procedure body scope | ||
172 | 2703 | currentScope = node->scope->parent; | |
173 | |||
174 | // Insert symbol for procedure into the symbol table | ||
175 |
1/2✓ Branch 1 taken 2703 times.
✗ Branch 2 not taken.
|
5406 | node->entry = currentScope->insert(node->getSymbolTableEntryName(), node); |
176 | |||
177 | // Add to external name registry | ||
178 | // if a procedure has overloads, they both refer to the same entry in the registry. So we only register the name once | ||
179 | 2703 | const NameRegistryEntry *existingRegistryEntry = sourceFile->getNameRegistryEntry(node->name->fqName); | |
180 |
3/4✓ Branch 0 taken 721 times.
✓ Branch 1 taken 1982 times.
✓ Branch 2 taken 721 times.
✗ Branch 3 not taken.
|
2703 | if (!existingRegistryEntry || existingRegistryEntry->targetEntry != node->entry) |
181 | 2703 | sourceFile->addNameRegistryEntry(node->name->fqName, TY_PROCEDURE, node->entry, currentScope, true); | |
182 | |||
183 | // Leave the struct scope | ||
184 |
2/2✓ Branch 0 taken 2270 times.
✓ Branch 1 taken 433 times.
|
2703 | if (node->isMethod) |
185 | 2270 | currentScope = node->structScope->parent; | |
186 | |||
187 | // Check if this is a constructor | ||
188 | 2703 | node->isCtor = node->name->nameFragments.back() == CTOR_FUNCTION_NAME; | |
189 | |||
190 |
1/2✓ Branch 1 taken 2703 times.
✗ Branch 2 not taken.
|
2703 | return nullptr; |
191 | } | ||
192 | |||
193 | 547 | std::any SymbolTableBuilder::visitStructDef(StructDefNode *node) { | |
194 | // Visit attributes | ||
195 |
2/2✓ Branch 1 taken 51 times.
✓ Branch 2 taken 496 times.
|
547 | if (node->attrs()) |
196 |
2/4✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
|
51 | visit(node->attrs()); |
197 | |||
198 | // Check if this name already exists | ||
199 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 546 times.
|
1094 | if (rootScope->lookupStrict(node->structName)) |
200 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->structName + "'"); |
201 | |||
202 | // Create scope for the struct | ||
203 | 546 | node->structScope = currentScope = | |
204 |
2/4✓ Branch 1 taken 546 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 546 times.
✗ Branch 5 not taken.
|
546 | rootScope->createChildScope(STRUCT_SCOPE_PREFIX + node->structName, ScopeType::STRUCT, &node->codeLoc); |
205 | 546 | currentScope->isGenericScope = node->hasTemplateTypes; | |
206 | |||
207 | // Insert implicit field for each interface type | ||
208 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 459 times.
|
546 | if (node->hasInterfaces) { |
209 |
4/6✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 87 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 87 times.
✓ Branch 11 taken 87 times.
|
174 | for (DataTypeNode *interfaceNode : node->interfaceTypeLst()->dataTypes()) { |
210 |
2/4✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 87 times.
✗ Branch 5 not taken.
|
87 | const std::string &interfaceName = interfaceNode->baseDataType()->customDataType()->typeNameFragments.back(); |
211 |
1/2✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
|
174 | SymbolTableEntry *interfaceFieldEntry = currentScope->insert("this." + interfaceName, interfaceNode); |
212 | 87 | interfaceFieldEntry->used = true; | |
213 | 87 | interfaceFieldEntry->isImplicitField = true; | |
214 | 87 | } | |
215 | } | ||
216 | |||
217 | // Visit children | ||
218 |
2/2✓ Branch 1 taken 545 times.
✓ Branch 2 taken 1 times.
|
546 | visitChildren(node); |
219 | |||
220 | // Leave the struct scope | ||
221 | 545 | currentScope = node->structScope->parent; | |
222 | |||
223 | // Build struct specifiers | ||
224 |
2/2✓ Branch 1 taken 409 times.
✓ Branch 2 taken 136 times.
|
545 | if (const SpecifierLstNode *specifierLst = node->specifierLst()) { |
225 |
3/4✓ Branch 1 taken 409 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 409 times.
✓ Branch 9 taken 409 times.
|
818 | for (const SpecifierNode *specifier : specifierLst->specifiers()) { |
226 |
1/2✓ Branch 0 taken 409 times.
✗ Branch 1 not taken.
|
409 | if (specifier->type == SpecifierNode::TY_PUBLIC) |
227 | 409 | node->structSpecifiers.isPublic = true; | |
228 | else | ||
229 | ✗ | throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on a struct definition"); | |
230 | 409 | } | |
231 | } | ||
232 | |||
233 | // Add the struct to the symbol table | ||
234 | 545 | node->entry = rootScope->insert(node->structName, node); | |
235 | // Register the name in the exported name registry | ||
236 | 545 | sourceFile->addNameRegistryEntry(node->structName, node->typeId, node->entry, node->structScope, true); | |
237 | |||
238 |
1/2✓ Branch 1 taken 545 times.
✗ Branch 2 not taken.
|
545 | return nullptr; |
239 | } | ||
240 | |||
241 | 76 | std::any SymbolTableBuilder::visitInterfaceDef(InterfaceDefNode *node) { | |
242 | // Visit attributes | ||
243 |
2/2✓ Branch 1 taken 53 times.
✓ Branch 2 taken 23 times.
|
76 | if (node->attrs()) |
244 |
2/4✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
|
53 | visit(node->attrs()); |
245 | |||
246 | // Check if this name already exists | ||
247 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 75 times.
|
152 | if (rootScope->lookupStrict(node->interfaceName)) |
248 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->interfaceName + "'"); |
249 | |||
250 | // Create scope for the interface | ||
251 | 75 | node->interfaceScope = currentScope = | |
252 |
2/4✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
|
75 | rootScope->createChildScope(INTERFACE_SCOPE_PREFIX + node->interfaceName, ScopeType::INTERFACE, &node->codeLoc); |
253 | |||
254 | // Visit signatures | ||
255 |
3/4✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 173 times.
✓ Branch 8 taken 75 times.
|
248 | for (SignatureNode *signature : node->signatures()) |
256 |
1/2✓ Branch 1 taken 173 times.
✗ Branch 2 not taken.
|
248 | visit(signature); |
257 | |||
258 | // Leave the interface scope | ||
259 | 75 | currentScope = node->interfaceScope->parent; | |
260 | |||
261 | // Build interface specifiers | ||
262 |
2/2✓ Branch 1 taken 60 times.
✓ Branch 2 taken 15 times.
|
75 | if (const SpecifierLstNode *specifierLst = node->specifierLst()) { |
263 |
3/4✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 60 times.
✓ Branch 9 taken 60 times.
|
120 | for (const SpecifierNode *specifier : specifierLst->specifiers()) { |
264 |
1/2✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
|
60 | if (specifier->type == SpecifierNode::TY_PUBLIC) |
265 | 60 | node->interfaceSpecifiers.isPublic = true; | |
266 | else | ||
267 | ✗ | throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on an interface definition"); | |
268 | 60 | } | |
269 | } | ||
270 | |||
271 | // Add the interface to the symbol table | ||
272 | 75 | node->entry = rootScope->insert(node->interfaceName, node); | |
273 | // Register the name in the exported name registry | ||
274 | 75 | sourceFile->addNameRegistryEntry(node->interfaceName, node->typeId, node->entry, node->interfaceScope, true); | |
275 | |||
276 |
1/2✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
|
75 | return nullptr; |
277 | } | ||
278 | |||
279 | 41 | std::any SymbolTableBuilder::visitEnumDef(EnumDefNode *node) { | |
280 | // Check if this name already exists | ||
281 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 40 times.
|
82 | if (rootScope->lookupStrict(node->enumName)) |
282 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->enumName + "'"); |
283 | |||
284 | // Create scope for the enum | ||
285 | 40 | node->enumScope = currentScope = | |
286 |
2/4✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
|
40 | rootScope->createChildScope(ENUM_SCOPE_PREFIX + node->enumName, ScopeType::ENUM, &node->codeLoc); |
287 | |||
288 | // Visit items | ||
289 |
3/4✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 1 times.
|
40 | visit(node->itemLst()); |
290 | |||
291 | // Leave the enum scope | ||
292 | 39 | currentScope = node->enumScope->parent; | |
293 | |||
294 | // Build enum specifiers | ||
295 |
2/2✓ Branch 1 taken 27 times.
✓ Branch 2 taken 12 times.
|
39 | if (node->specifierLst()) { |
296 |
4/6✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 27 times.
✓ Branch 12 taken 27 times.
|
54 | for (const SpecifierNode *specifier : node->specifierLst()->specifiers()) { |
297 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if (specifier->type == SpecifierNode::TY_PUBLIC) |
298 | 27 | node->enumSpecifiers.isPublic = true; | |
299 | else | ||
300 | ✗ | throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on an enum definition"); | |
301 | 27 | } | |
302 | } | ||
303 | |||
304 | // Add the enum to the symbol table | ||
305 | 39 | node->entry = rootScope->insert(node->enumName, node); | |
306 | // Register the name in the exported name registry | ||
307 | 39 | sourceFile->addNameRegistryEntry(node->enumName, node->typeId, node->entry, node->enumScope, true); | |
308 | |||
309 |
1/2✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
|
39 | return nullptr; |
310 | } | ||
311 | |||
312 | 724 | std::any SymbolTableBuilder::visitGenericTypeDef(GenericTypeDefNode *node) { | |
313 | // Check if this name already exists | ||
314 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 723 times.
|
1448 | if (rootScope->lookupStrict(node->typeName)) |
315 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->typeName + "'"); |
316 | |||
317 | // Create the generic type to the symbol table | ||
318 | 723 | node->entry = rootScope->insert(node->typeName, node); | |
319 | 723 | node->entry->used = true; // Generic types are always used | |
320 | |||
321 |
1/2✓ Branch 1 taken 723 times.
✗ Branch 2 not taken.
|
723 | return nullptr; |
322 | } | ||
323 | |||
324 | 32 | std::any SymbolTableBuilder::visitAliasDef(AliasDefNode *node) { | |
325 | // Check if this name already exists | ||
326 |
3/4✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 31 times.
|
64 | if (rootScope->lookupStrict(node->aliasName)) |
327 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->aliasName + "'"); |
328 | |||
329 | // Build alias specifiers | ||
330 |
3/4✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 29 times.
|
31 | if (const SpecifierLstNode *specifierLst = node->specifierLst()) { |
331 |
3/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 2 times.
|
4 | for (const SpecifierNode *specifier : specifierLst->specifiers()) { |
332 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (specifier->type == SpecifierNode::TY_PUBLIC) |
333 | 2 | node->aliasSpecifiers.isPublic = true; | |
334 | else | ||
335 | ✗ | throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on an alias definition"); | |
336 | 2 | } | |
337 | } | ||
338 | |||
339 | // Add the alias to the symbol table | ||
340 |
1/2✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
|
31 | node->entry = rootScope->insert(node->aliasName, node); |
341 | // Register the name in the exported name registry | ||
342 |
1/2✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
|
31 | sourceFile->addNameRegistryEntry(node->aliasName, node->typeId, node->entry, rootScope, true); |
343 | |||
344 | // Add another symbol for the aliased type container | ||
345 |
1/2✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
|
31 | const std::string aliasedTypeContainerName = node->aliasName + ALIAS_CONTAINER_SUFFIX; |
346 |
1/2✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
|
31 | node->aliasedTypeContainerEntry = rootScope->insert(aliasedTypeContainerName, node); |
347 | |||
348 |
1/2✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
|
62 | return nullptr; |
349 | 31 | } | |
350 | |||
351 | 739 | std::any SymbolTableBuilder::visitGlobalVarDef(GlobalVarDefNode *node) { | |
352 | // Check if this name already exists | ||
353 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 738 times.
|
1478 | if (rootScope->lookupStrict(node->varName)) |
354 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->varName + "'"); |
355 | |||
356 | // Check if global already exists in an imported source file | ||
357 |
5/8✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 738 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 738 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 115 times.
✓ Branch 13 taken 737 times.
|
852 | for (const auto &dependency : sourceFile->dependencies | std::views::values) |
358 |
3/4✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 114 times.
|
115 | if (dependency->exportedNameRegistry.contains(node->varName)) |
359 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, GLOBAL_DECLARED_TWICE, "Duplicate global variable '" + node->varName + "' in other module"); |
360 | |||
361 | // Add the global to the symbol table | ||
362 | 737 | node->entry = rootScope->insert(node->varName, node); | |
363 | // Register the name in the exported name registry | ||
364 | 737 | sourceFile->addNameRegistryEntry(node->varName, TY_INVALID, node->entry, currentScope, true); | |
365 | |||
366 |
1/2✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
|
737 | return nullptr; |
367 | } | ||
368 | |||
369 | 703 | std::any SymbolTableBuilder::visitExtDecl(ExtDeclNode *node) { | |
370 | // Visit attributes | ||
371 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 702 times.
|
703 | if (node->attrs()) |
372 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | visit(node->attrs()); |
373 | |||
374 | // Check if this name already exists | ||
375 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 702 times.
|
1406 | if (rootScope->lookupStrict(node->extFunctionName)) |
376 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->extFunctionName + "'"); |
377 | |||
378 | // Create scope for the external function (this is required in case of forceSubstantiation in FunctionManager::matchFunction) | ||
379 |
2/4✓ Branch 1 taken 702 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 702 times.
✗ Branch 5 not taken.
|
702 | rootScope->createChildScope(node->getScopeId(), ScopeType::FUNC_PROC_BODY, &node->codeLoc); |
380 | |||
381 | // Add the external declaration to the symbol table | ||
382 | 702 | node->entry = rootScope->insert(node->extFunctionName, node); | |
383 | // Register the name in the exported name registry | ||
384 |
2/2✓ Branch 1 taken 454 times.
✓ Branch 2 taken 248 times.
|
702 | const uint64_t typeId = node->returnType() ? TY_FUNCTION : TY_PROCEDURE; |
385 | 702 | sourceFile->addNameRegistryEntry(node->extFunctionName, typeId, node->entry, rootScope, /*keepNewOnCollision=*/true); | |
386 | |||
387 |
1/2✓ Branch 1 taken 702 times.
✗ Branch 2 not taken.
|
702 | return nullptr; |
388 | } | ||
389 | |||
390 | 1808 | std::any SymbolTableBuilder::visitUnsafeBlock(UnsafeBlockNode *node) { | |
391 | // Create scope for the unsafe block body | ||
392 | 1808 | node->bodyScope = currentScope = | |
393 |
2/4✓ Branch 2 taken 1808 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1808 times.
✗ Branch 6 not taken.
|
1808 | currentScope->createChildScope(node->getScopeId(), ScopeType::UNSAFE_BODY, &node->body()->codeLoc); |
394 | |||
395 | // Visit body | ||
396 |
2/4✓ Branch 1 taken 1808 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1808 times.
✗ Branch 5 not taken.
|
1808 | visit(node->body()); |
397 | |||
398 | // Leave thread body scope | ||
399 | 1808 | currentScope = node->bodyScope->parent; | |
400 | |||
401 |
1/2✓ Branch 1 taken 1808 times.
✗ Branch 2 not taken.
|
1808 | return nullptr; |
402 | } | ||
403 | |||
404 | 984 | std::any SymbolTableBuilder::visitForLoop(ForLoopNode *node) { | |
405 | // Create scope for the loop body | ||
406 | 984 | node->bodyScope = currentScope = | |
407 |
2/4✓ Branch 2 taken 984 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 984 times.
✗ Branch 6 not taken.
|
984 | currentScope->createChildScope(node->getScopeId(), ScopeType::FOR_BODY, &node->body()->codeLoc); |
408 | |||
409 | // Visit loop variable declaration | ||
410 |
2/4✓ Branch 1 taken 984 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 984 times.
✗ Branch 5 not taken.
|
984 | visit(node->initDecl()); |
411 | |||
412 | // Visit body | ||
413 |
2/4✓ Branch 1 taken 984 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 984 times.
✗ Branch 5 not taken.
|
984 | visit(node->body()); |
414 | |||
415 | // Leave for body scope | ||
416 | 984 | currentScope = node->bodyScope->parent; | |
417 | |||
418 |
1/2✓ Branch 1 taken 984 times.
✗ Branch 2 not taken.
|
984 | return nullptr; |
419 | } | ||
420 | |||
421 | 87 | std::any SymbolTableBuilder::visitForeachLoop(ForeachLoopNode *node) { | |
422 | // Create scope for the loop body | ||
423 | 87 | node->bodyScope = currentScope = | |
424 |
2/4✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 87 times.
✗ Branch 6 not taken.
|
87 | currentScope->createChildScope(node->getScopeId(), ScopeType::FOREACH_BODY, &node->body()->codeLoc); |
425 | |||
426 | // Visit index variable declaration | ||
427 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 81 times.
|
87 | if (node->idxVarDecl()) |
428 |
2/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | visit(node->idxVarDecl()); |
429 | |||
430 | // Visit item variable declaration | ||
431 |
2/4✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 87 times.
✗ Branch 5 not taken.
|
87 | visit(node->itemVarDecl()); |
432 | |||
433 | // Visit body | ||
434 |
2/4✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 87 times.
✗ Branch 5 not taken.
|
87 | visit(node->body()); |
435 | |||
436 | // Leave foreach body scope | ||
437 | 87 | currentScope = node->bodyScope->parent; | |
438 | |||
439 |
1/2✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
|
87 | return nullptr; |
440 | } | ||
441 | |||
442 | 398 | std::any SymbolTableBuilder::visitWhileLoop(WhileLoopNode *node) { | |
443 | // Create scope for the loop body | ||
444 | 398 | node->bodyScope = currentScope = | |
445 |
2/4✓ Branch 2 taken 398 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 398 times.
✗ Branch 6 not taken.
|
398 | currentScope->createChildScope(node->getScopeId(), ScopeType::WHILE_BODY, &node->body()->codeLoc); |
446 | |||
447 | // Visit condition | ||
448 |
2/4✓ Branch 1 taken 398 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 398 times.
✗ Branch 5 not taken.
|
398 | visit(node->condition()); |
449 | |||
450 | // Visit body | ||
451 |
2/4✓ Branch 1 taken 398 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 398 times.
✗ Branch 5 not taken.
|
398 | visit(node->body()); |
452 | |||
453 | // Leave while body scope | ||
454 | 398 | currentScope = node->bodyScope->parent; | |
455 | |||
456 |
1/2✓ Branch 1 taken 398 times.
✗ Branch 2 not taken.
|
398 | return nullptr; |
457 | } | ||
458 | |||
459 | 9 | std::any SymbolTableBuilder::visitDoWhileLoop(DoWhileLoopNode *node) { | |
460 | // Create scope for the loop body | ||
461 | 9 | node->bodyScope = currentScope = | |
462 |
2/4✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
|
9 | currentScope->createChildScope(node->getScopeId(), ScopeType::WHILE_BODY, &node->body()->codeLoc); |
463 | |||
464 | // Visit condition | ||
465 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | visit(node->condition()); |
466 | |||
467 | // Visit body | ||
468 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | visit(node->body()); |
469 | |||
470 | // Leave do-while body scope | ||
471 | 9 | currentScope = node->bodyScope->parent; | |
472 | |||
473 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | return nullptr; |
474 | } | ||
475 | |||
476 | 2918 | std::any SymbolTableBuilder::visitIfStmt(IfStmtNode *node) { | |
477 | // Create scope for the then body | ||
478 | 2918 | node->thenBodyScope = currentScope = | |
479 |
2/4✓ Branch 2 taken 2918 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2918 times.
✗ Branch 6 not taken.
|
2918 | currentScope->createChildScope(node->getScopeId(), ScopeType::IF_ELSE_BODY, &node->thenBody()->codeLoc); |
480 | |||
481 | // Visit condition | ||
482 |
2/4✓ Branch 1 taken 2918 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2918 times.
✗ Branch 5 not taken.
|
2918 | visit(node->condition()); |
483 | |||
484 | // Visit then body | ||
485 |
2/4✓ Branch 1 taken 2918 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2918 times.
✗ Branch 5 not taken.
|
2918 | visit(node->thenBody()); |
486 | |||
487 | // Leave then body scope | ||
488 | 2918 | currentScope = node->thenBodyScope->parent; | |
489 | |||
490 | // Visit else stmt | ||
491 |
2/2✓ Branch 1 taken 168 times.
✓ Branch 2 taken 2750 times.
|
2918 | if (node->elseStmt()) |
492 |
2/4✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 168 times.
✗ Branch 5 not taken.
|
168 | visit(node->elseStmt()); |
493 | |||
494 |
1/2✓ Branch 1 taken 2918 times.
✗ Branch 2 not taken.
|
2918 | return nullptr; |
495 | } | ||
496 | |||
497 | 168 | std::any SymbolTableBuilder::visitElseStmt(ElseStmtNode *node) { | |
498 | // Visit if statement in the case of an else if branch | ||
499 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 117 times.
|
168 | if (node->isElseIf) { |
500 |
2/4✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
|
51 | visit(node->ifStmt()); |
501 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
51 | return nullptr; |
502 | } | ||
503 | |||
504 | // Create scope for the else body | ||
505 | 117 | node->elseBodyScope = currentScope = | |
506 |
2/4✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 117 times.
✗ Branch 6 not taken.
|
117 | currentScope->createChildScope(node->getScopeId(), ScopeType::IF_ELSE_BODY, &node->body()->codeLoc); |
507 | |||
508 | // Visit else body | ||
509 |
2/4✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 117 times.
✗ Branch 5 not taken.
|
117 | visit(node->body()); |
510 | |||
511 | // Leave else body scope | ||
512 | 117 | currentScope = node->elseBodyScope->parent; | |
513 | |||
514 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | return nullptr; |
515 | } | ||
516 | |||
517 | 28 | std::any SymbolTableBuilder::visitCaseBranch(CaseBranchNode *node) { | |
518 | // Create scope for the case branch | ||
519 | 28 | node->bodyScope = currentScope = | |
520 |
2/4✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
|
28 | currentScope->createChildScope(node->getScopeId(), ScopeType::CASE_BODY, &node->body()->codeLoc); |
521 | |||
522 | // Visit case body | ||
523 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | visit(node->body()); |
524 | |||
525 | // Leave case body scope | ||
526 | 28 | currentScope = node->bodyScope->parent; | |
527 | |||
528 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | return nullptr; |
529 | } | ||
530 | |||
531 | 3 | std::any SymbolTableBuilder::visitDefaultBranch(DefaultBranchNode *node) { | |
532 | // Create scope for the default branch | ||
533 | 3 | node->bodyScope = currentScope = | |
534 |
2/4✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
3 | currentScope->createChildScope(node->getScopeId(), ScopeType::DEFAULT_BODY, &node->body()->codeLoc); |
535 | |||
536 | // Visit default body | ||
537 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | visit(node->body()); |
538 | |||
539 | // Leave default body scope | ||
540 | 3 | currentScope = node->bodyScope->parent; | |
541 | |||
542 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | return nullptr; |
543 | } | ||
544 | |||
545 | 13 | std::any SymbolTableBuilder::visitAnonymousBlockStmt(AnonymousBlockStmtNode *node) { | |
546 | // Create scope for the anonymous block body | ||
547 | 13 | node->bodyScope = currentScope = | |
548 |
2/4✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
|
13 | currentScope->createChildScope(node->getScopeId(), ScopeType::ANONYMOUS_BLOCK_BODY, &node->body()->codeLoc); |
549 | |||
550 | // Visit body | ||
551 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
|
13 | visit(node->body()); |
552 | |||
553 | // Leave anonymous block body scope | ||
554 | 13 | currentScope = node->bodyScope->parent; | |
555 | |||
556 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | return nullptr; |
557 | } | ||
558 | |||
559 | 438 | std::any SymbolTableBuilder::visitEnumItem(EnumItemNode *node) { | |
560 | // Check if enum item already exists in the same scope. | ||
561 |
3/4✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 437 times.
|
876 | if (currentScope->lookupStrict(node->itemName)) |
562 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, VARIABLE_DECLARED_TWICE, "The enum item '" + node->itemName + "' was declared more than once"); |
563 | |||
564 | // Add enum item entry to symbol table | ||
565 |
1/2✓ Branch 1 taken 437 times.
✗ Branch 2 not taken.
|
437 | SymbolTableEntry *enumItemEntry = currentScope->insert(node->itemName, node); |
566 | |||
567 | // Add external registry entry | ||
568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 437 times.
|
437 | assert(node->enumDef != nullptr); |
569 |
2/4✓ Branch 1 taken 437 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 437 times.
✗ Branch 5 not taken.
|
437 | const std::string name = node->enumDef->enumName + SCOPE_ACCESS_TOKEN + node->itemName; |
570 |
1/2✓ Branch 1 taken 437 times.
✗ Branch 2 not taken.
|
437 | sourceFile->addNameRegistryEntry(name, TY_INT, enumItemEntry, currentScope, true); |
571 | |||
572 |
1/2✓ Branch 1 taken 437 times.
✗ Branch 2 not taken.
|
874 | return nullptr; |
573 | 437 | } | |
574 | |||
575 | 1189 | std::any SymbolTableBuilder::visitField(FieldNode *node) { | |
576 | // Check if field already exists in the same scope. | ||
577 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1188 times.
|
2378 | if (currentScope->lookupStrict(node->fieldName)) |
578 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, VARIABLE_DECLARED_TWICE, "The field '" + node->fieldName + "' was declared more than once"); |
579 | |||
580 | // Add field entry to symbol table | ||
581 | 1188 | currentScope->insert(node->fieldName, node); | |
582 | |||
583 |
1/2✓ Branch 1 taken 1188 times.
✗ Branch 2 not taken.
|
1188 | return nullptr; |
584 | } | ||
585 | |||
586 | 173 | std::any SymbolTableBuilder::visitSignature(SignatureNode *node) { | |
587 | // Build signature specifiers | ||
588 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 165 times.
|
173 | if (const SpecifierLstNode *specifierLst = node->specifierLst()) { |
589 |
3/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 8 times.
|
16 | for (const SpecifierNode *specifier : specifierLst->specifiers()) { |
590 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (specifier->type == SpecifierNode::TY_INLINE) |
591 | ✗ | node->signatureSpecifiers.isInline = true; | |
592 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | else if (specifier->type == SpecifierNode::TY_PUBLIC) |
593 | 8 | node->signatureSpecifiers.isPublic = true; | |
594 | ✗ | else if (specifier->type == SpecifierNode::TY_CONST) | |
595 | ✗ | node->signatureSpecifiers.isConst = true; | |
596 | else | ||
597 | ✗ | throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on a signature definition"); | |
598 | 8 | } | |
599 | } | ||
600 | |||
601 | // Add signature entry to symbol table | ||
602 | 173 | node->entry = currentScope->insert(node->methodName, node); | |
603 | |||
604 |
1/2✓ Branch 1 taken 173 times.
✗ Branch 2 not taken.
|
173 | return nullptr; |
605 | } | ||
606 | |||
607 | 12670 | std::any SymbolTableBuilder::visitDeclStmt(DeclStmtNode *node) { | |
608 | // Check if variable already exists in the same scope. | ||
609 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 12669 times.
|
25340 | if (currentScope->lookupStrict(node->varName)) |
610 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, VARIABLE_DECLARED_TWICE, "The variable '" + node->varName + "' was declared more than once"); |
611 | |||
612 | // Visit the right side | ||
613 |
2/2✓ Branch 0 taken 5369 times.
✓ Branch 1 taken 7300 times.
|
12669 | if (node->hasAssignment) |
614 |
2/4✓ Branch 1 taken 5369 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5369 times.
✗ Branch 5 not taken.
|
5369 | visit(node->assignExpr()); |
615 | |||
616 | // Add variable entry to symbol table | ||
617 | 12669 | SymbolTableEntry *varEntry = currentScope->insert(node->varName, node); | |
618 | 12669 | varEntry->isParam = node->isParam; | |
619 | |||
620 |
1/2✓ Branch 1 taken 12669 times.
✗ Branch 2 not taken.
|
12669 | return nullptr; |
621 | } | ||
622 | |||
623 | 277 | std::any SymbolTableBuilder::visitModAttr(ModAttrNode *node) { | |
624 | // Visit attributes | ||
625 |
2/2✓ Branch 1 taken 276 times.
✓ Branch 2 taken 1 times.
|
277 | visitChildren(node); |
626 | |||
627 | // Retrieve attributes | ||
628 |
1/2✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
|
276 | const AttrLstNode *attrs = node->attrLst(); |
629 | |||
630 | // Collect linker flags | ||
631 | 276 | std::vector<const CompileTimeValue *> linkerFlagValues; | |
632 | // core.linker.flag | ||
633 |
2/4✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 276 times.
✗ Branch 5 not taken.
|
552 | std::vector<const CompileTimeValue *> values = attrs->getAttrValuesByName(ATTR_CORE_LINKER_FLAG); |
634 |
1/2✓ Branch 5 taken 276 times.
✗ Branch 6 not taken.
|
276 | linkerFlagValues.insert(linkerFlagValues.end(), values.begin(), values.end()); |
635 | // core.linux.linker.flag | ||
636 |
1/2✓ Branch 3 taken 276 times.
✗ Branch 4 not taken.
|
276 | if (sourceFile->targetMachine->getTargetTriple().isOSLinux()) { |
637 |
2/4✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 276 times.
✗ Branch 5 not taken.
|
552 | values = attrs->getAttrValuesByName(ATTR_CORE_LINUX_LINKER_FLAG); |
638 |
1/2✓ Branch 5 taken 276 times.
✗ Branch 6 not taken.
|
276 | linkerFlagValues.insert(linkerFlagValues.end(), values.begin(), values.end()); |
639 | } | ||
640 | // core.windows.linker.flag | ||
641 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 276 times.
|
276 | if (sourceFile->targetMachine->getTargetTriple().isOSWindows()) { |
642 | ✗ | values = attrs->getAttrValuesByName(ATTR_CORE_WINDOWS_LINKER_FLAG); | |
643 | ✗ | linkerFlagValues.insert(linkerFlagValues.end(), values.begin(), values.end()); | |
644 | } | ||
645 |
2/2✓ Branch 5 taken 209 times.
✓ Branch 6 taken 276 times.
|
485 | for (const CompileTimeValue *value : linkerFlagValues) |
646 |
2/4✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 209 times.
✗ Branch 5 not taken.
|
209 | resourceManager.linker.addLinkerFlag(resourceManager.compileTimeStringValues.at(value->stringValueOffset)); |
647 | |||
648 | // core.linker.additional_source | ||
649 |
4/6✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 276 times.
✗ Branch 5 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 276 times.
|
829 | for (const CompileTimeValue *value : attrs->getAttrValuesByName(ATTR_CORE_LINKER_ADDITIONAL_SOURCE)) { |
650 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const std::string &stringValue = resourceManager.compileTimeStringValues.at(value->stringValueOffset); |
651 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | const std::filesystem::path path = sourceFile->filePath.parent_path() / stringValue; |
652 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | resourceManager.linker.addAdditionalSourcePath(std::filesystem::canonical(path)); |
653 | 277 | } | |
654 | |||
655 |
1/2✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
|
552 | return nullptr; |
656 | 276 | } | |
657 | |||
658 | 661 | std::any SymbolTableBuilder::visitAttr(AttrNode *node) { | |
659 | // Check if this attribute exists | ||
660 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 660 times.
|
661 | if (!ATTR_CONFIGS.contains(node->key)) |
661 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, UNKNOWN_ATTR, "Unknown attribute '" + node->key + "'"); |
662 | |||
663 | // Check if the target is correct | ||
664 | 660 | const auto &[target, type] = ATTR_CONFIGS.at(node->key); | |
665 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 659 times.
|
660 | if ((node->target & target) == 0) |
666 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, INVALID_ATTR_TARGET, "Attribute '" + node->key + "' cannot be used on this target"); |
667 | |||
668 | // Check if a value is present | ||
669 |
6/6✓ Branch 1 taken 12 times.
✓ Branch 2 taken 647 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 658 times.
|
659 | if (!node->value() && type != AttrNode::TYPE_BOOL) |
670 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | throw SemanticError(node, MISSING_ATTR_VALUE, "Attribute '" + node->key + "' requires a value"); |
671 | |||
672 |
1/2✓ Branch 1 taken 658 times.
✗ Branch 2 not taken.
|
658 | return nullptr; |
673 | } | ||
674 | |||
675 | 9 | std::any SymbolTableBuilder::visitLambdaFunc(LambdaFuncNode *node) { | |
676 | // Create scope for the lambda body | ||
677 | 9 | const CodeLoc &codeLoc = node->body()->codeLoc; | |
678 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | node->bodyScope = currentScope = currentScope->createChildScope(node->getScopeId(), ScopeType::LAMBDA_BODY, &codeLoc); |
679 | // Requires capturing because the LLVM IR will end up in a separate function | ||
680 | 9 | currentScope->symbolTable.setCapturingRequired(); | |
681 | // Set to async scope if this is an async lambda | ||
682 |
5/24✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 9 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 9 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 9 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
|
9 | if (node->lambdaAttr() && node->lambdaAttr()->attrLst()->hasAttr(ATTR_ASYNC)) |
683 | ✗ | node->bodyScope->isAsyncScope = node->lambdaAttr()->attrLst()->getAttrValueByName(ATTR_ASYNC)->boolValue; | |
684 | |||
685 | // Create symbol for 'result' variable | ||
686 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
27 | currentScope->insert(RETURN_VARIABLE_NAME, node); |
687 | |||
688 | // Create symbols for the parameters | ||
689 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
|
9 | if (node->hasParams) |
690 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | visit(node->paramLst()); |
691 | |||
692 | // Visit body | ||
693 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | visit(node->body()); |
694 | |||
695 | // Leave anonymous block body scope | ||
696 | 9 | currentScope = node->bodyScope->parent; | |
697 | |||
698 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | return nullptr; |
699 | } | ||
700 | |||
701 | 27 | std::any SymbolTableBuilder::visitLambdaProc(LambdaProcNode *node) { | |
702 | // Create scope for the lambda body | ||
703 | 27 | const CodeLoc &codeLoc = node->body()->codeLoc; | |
704 |
2/4✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
27 | node->bodyScope = currentScope = currentScope->createChildScope(node->getScopeId(), ScopeType::LAMBDA_BODY, &codeLoc); |
705 | // Requires capturing because the LLVM IR will end up in a separate function | ||
706 | 27 | currentScope->symbolTable.setCapturingRequired(); | |
707 | // Set to async scope if this is an async lambda | ||
708 |
14/24✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 11 times.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 16 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 16 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 16 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 16 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 16 times.
✓ Branch 20 taken 11 times.
✓ Branch 22 taken 16 times.
✓ Branch 23 taken 11 times.
✓ Branch 24 taken 16 times.
✓ Branch 25 taken 11 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
|
59 | if (node->lambdaAttr() && node->lambdaAttr()->attrLst()->hasAttr(ATTR_ASYNC)) |
709 |
2/4✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
|
48 | node->bodyScope->isAsyncScope = node->lambdaAttr()->attrLst()->getAttrValueByName(ATTR_ASYNC)->boolValue; |
710 | |||
711 | // Create symbols for the parameters | ||
712 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 20 times.
|
27 | if (node->hasParams) |
713 |
2/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | visit(node->paramLst()); |
714 | |||
715 | // Visit body | ||
716 |
2/4✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
27 | visit(node->body()); |
717 | |||
718 | // Leave anonymous block body scope | ||
719 | 27 | currentScope = node->bodyScope->parent; | |
720 | |||
721 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | return nullptr; |
722 | } | ||
723 | |||
724 | 1 | std::any SymbolTableBuilder::visitLambdaExpr(LambdaExprNode *node) { | |
725 | // Create scope for the anonymous block body | ||
726 | 1 | const CodeLoc &codeLoc = node->lambdaExpr()->codeLoc; | |
727 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | node->bodyScope = currentScope = currentScope->createChildScope(node->getScopeId(), ScopeType::LAMBDA_BODY, &codeLoc); |
728 | // Requires capturing because the LLVM IR will end up in a separate function | ||
729 | 1 | currentScope->symbolTable.setCapturingRequired(); | |
730 | |||
731 | // Create symbols for the parameters | ||
732 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (node->hasParams) |
733 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | visit(node->paramLst()); |
734 | |||
735 | // Visit lambda expression | ||
736 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | visit(node->lambdaExpr()); |
737 | |||
738 | // Leave anonymous block body scope | ||
739 | 1 | currentScope = node->bodyScope->parent; | |
740 | |||
741 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | return nullptr; |
742 | } | ||
743 | |||
744 | } // namespace spice::compiler | ||
745 |