src/symboltablebuilder/SymbolTable.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | #include "SymbolTable.h" | ||
| 4 | |||
| 5 | #include <SourceFile.h> | ||
| 6 | #include <ast/ASTNodes.h> | ||
| 7 | #include <symboltablebuilder/Scope.h> | ||
| 8 | #include <symboltablebuilder/SymbolTableBuilder.h> | ||
| 9 | #include <util/CodeLoc.h> | ||
| 10 | #include <util/CompilerWarning.h> | ||
| 11 | |||
| 12 | namespace spice::compiler { | ||
| 13 | |||
| 14 | /** | ||
| 15 | * Insert a new symbol into the current symbol table. If it is a parameter, append its name to the paramNames vector | ||
| 16 | * | ||
| 17 | * @param name Name of the symbol | ||
| 18 | * @param declNode AST node where the symbol is declared | ||
| 19 | * @param isAnonymousSymbol If this symbol should be anonymous | ||
| 20 | * @return Inserted entry | ||
| 21 | */ | ||
| 22 | 65975 | SymbolTableEntry *SymbolTable::insert(const std::string &name, ASTNode *declNode, bool isAnonymousSymbol) { | |
| 23 | 65975 | const bool isGlobal = parent == nullptr; | |
| 24 | 65975 | size_t orderIndex = SIZE_MAX; | |
| 25 |
2/2✓ Branch 2 → 3 taken 63384 times.
✓ Branch 2 → 5 taken 2591 times.
|
65975 | if (!isAnonymousSymbol) |
| 26 | 527610 | orderIndex = std::ranges::count_if(symbols, [](const auto &entry) { return !entry.second.anonymous; }); | |
| 27 | // Insert into symbols map. The type is 'dyn', because concrete types are determined by the type checker later on | ||
| 28 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 65975 times.
|
65975 | assert(!symbols.contains(name)); |
| 29 |
4/8✓ Branch 8 → 9 taken 65975 times.
✗ Branch 8 → 41 not taken.
✓ Branch 9 → 10 taken 65975 times.
✗ Branch 9 → 40 not taken.
✓ Branch 10 → 11 taken 65975 times.
✗ Branch 10 → 38 not taken.
✓ Branch 11 → 12 taken 65975 times.
✗ Branch 11 → 36 not taken.
|
65975 | symbols.emplace(name, SymbolTableEntry(name, QualType(TY_INVALID), scope, declNode, orderIndex, isGlobal)); |
| 30 | // Set entry to declared | ||
| 31 | 65975 | SymbolTableEntry *entry = &symbols.at(name); | |
| 32 |
1/2✓ Branch 15 → 16 taken 65975 times.
✗ Branch 15 → 43 not taken.
|
65975 | entry->updateState(DECLARED, declNode); |
| 33 | |||
| 34 | // Check if shadowed | ||
| 35 |
10/10✓ Branch 16 → 17 taken 54034 times.
✓ Branch 16 → 24 taken 11941 times.
✓ Branch 18 → 19 taken 938 times.
✓ Branch 18 → 24 taken 53096 times.
✓ Branch 20 → 21 taken 14 times.
✓ Branch 20 → 24 taken 924 times.
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 24 taken 12 times.
✓ Branch 25 → 26 taken 2 times.
✓ Branch 25 → 34 taken 65973 times.
|
65975 | if (parent != nullptr && parent->lookup(name) != nullptr && !declNode->isParam() && name != RETURN_VARIABLE_NAME) { |
| 36 |
2/4✓ Branch 26 → 27 taken 2 times.
✗ Branch 26 → 46 not taken.
✓ Branch 27 → 28 taken 2 times.
✗ Branch 27 → 44 not taken.
|
2 | const std::string warningMsg = "Variable '" + name + "' shadows a variable in a parent scope"; |
| 37 |
1/2✓ Branch 29 → 30 taken 2 times.
✗ Branch 29 → 49 not taken.
|
2 | const CompilerWarning warning(declNode->codeLoc, SHADOWED_VARIABLE, warningMsg); |
| 38 |
1/2✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 47 not taken.
|
2 | scope->sourceFile->compilerOutput.warnings.push_back(warning); |
| 39 | 2 | } | |
| 40 | |||
| 41 | 65975 | return entry; | |
| 42 | } | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Insert a new anonymous symbol into the current symbol table. | ||
| 46 | * The anonymous symbol will be identified via the definition code location | ||
| 47 | * | ||
| 48 | * @param qualType Type of the symbol | ||
| 49 | * @param declNode AST node where the anonymous symbol is declared | ||
| 50 | * @param numericSuffix Custom numeric suffix | ||
| 51 | * @return Inserted entry | ||
| 52 | */ | ||
| 53 | 2601 | SymbolTableEntry *SymbolTable::insertAnonymous(const QualType &qualType, ASTNode *declNode, size_t numericSuffix) { | |
| 54 | // Check if the anonymous entry already exists | ||
| 55 |
3/4✓ Branch 2 → 3 taken 2601 times.
✗ Branch 2 → 34 not taken.
✓ Branch 3 → 4 taken 10 times.
✓ Branch 3 → 5 taken 2591 times.
|
2601 | if (SymbolTableEntry *anonSymbol = lookupAnonymous(declNode, numericSuffix)) |
| 56 | 10 | return anonSymbol; | |
| 57 | // Otherwise, create an anonymous entry | ||
| 58 |
1/2✓ Branch 5 → 6 taken 2591 times.
✗ Branch 5 → 34 not taken.
|
2591 | std::stringstream name; |
| 59 |
5/10✓ Branch 6 → 7 taken 2591 times.
✗ Branch 6 → 32 not taken.
✓ Branch 7 → 8 taken 2591 times.
✗ Branch 7 → 26 not taken.
✓ Branch 8 → 9 taken 2591 times.
✗ Branch 8 → 24 not taken.
✓ Branch 9 → 10 taken 2591 times.
✗ Branch 9 → 24 not taken.
✓ Branch 10 → 11 taken 2591 times.
✗ Branch 10 → 24 not taken.
|
2591 | name << "anon." << declNode->codeLoc.toString() << "." << reinterpret_cast<size_t>(declNode); |
| 60 |
2/2✓ Branch 12 → 13 taken 50 times.
✓ Branch 12 → 15 taken 2541 times.
|
2591 | if (numericSuffix > 0) |
| 61 |
2/4✓ Branch 13 → 14 taken 50 times.
✗ Branch 13 → 32 not taken.
✓ Branch 14 → 15 taken 50 times.
✗ Branch 14 → 32 not taken.
|
50 | name << "." << numericSuffix; |
| 62 |
2/4✓ Branch 15 → 16 taken 2591 times.
✗ Branch 15 → 29 not taken.
✓ Branch 16 → 17 taken 2591 times.
✗ Branch 16 → 27 not taken.
|
2591 | SymbolTableEntry *anonSymbol = insert(name.str(), declNode, true); |
| 63 |
1/2✓ Branch 18 → 19 taken 2591 times.
✗ Branch 18 → 32 not taken.
|
2591 | anonSymbol->updateType(qualType, false); |
| 64 |
1/2✓ Branch 19 → 20 taken 2591 times.
✗ Branch 19 → 30 not taken.
|
2591 | anonSymbol->updateState(DECLARED, declNode); |
| 65 |
1/2✓ Branch 20 → 21 taken 2591 times.
✗ Branch 20 → 31 not taken.
|
2591 | anonSymbol->updateState(INITIALIZED, declNode); |
| 66 | 2591 | anonSymbol->anonymous = true; | |
| 67 | 2591 | anonSymbol->used = true; | |
| 68 | 2591 | return anonSymbol; | |
| 69 | 2591 | } | |
| 70 | |||
| 71 | /** | ||
| 72 | * Copy a symbol by its name | ||
| 73 | * | ||
| 74 | * @param originalName Original symbol name | ||
| 75 | * @param newName New symbol name | ||
| 76 | * @return Copied entry | ||
| 77 | */ | ||
| 78 | 4016 | SymbolTableEntry *SymbolTable::copySymbol(const std::string &originalName, const std::string &newName) { | |
| 79 |
1/2✓ Branch 2 → 3 taken 4016 times.
✗ Branch 2 → 14 not taken.
|
4016 | SymbolTableEntry *entryToCopy = lookupStrict(originalName); |
| 80 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4016 times.
|
4016 | assert(entryToCopy != nullptr); |
| 81 |
1/2✓ Branch 5 → 6 taken 4016 times.
✗ Branch 5 → 14 not taken.
|
4016 | auto [it, success] = symbols.emplace(newName, *entryToCopy); |
| 82 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 4016 times.
|
4016 | assert(success); |
| 83 | 8032 | return &it->second; | |
| 84 | } | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Check if a symbol exists in the current or any parent scope and return it if possible | ||
| 88 | * | ||
| 89 | * @param name Name of the desired symbol | ||
| 90 | * @return Desired symbol / nullptr if the symbol was not found | ||
| 91 | */ | ||
| 92 | 327027 | SymbolTableEntry *SymbolTable::lookup(const std::string &name) { // NOLINT(misc-no-recursion) | |
| 93 | // Check if the symbol exists in the current scope. If yes, take it | ||
| 94 |
2/2✓ Branch 3 → 4 taken 103141 times.
✓ Branch 3 → 5 taken 223886 times.
|
327027 | if (SymbolTableEntry *entry = lookupStrict(name)) |
| 95 | 103141 | return entry; | |
| 96 | |||
| 97 | // Symbol was not found in the current scope | ||
| 98 | // We reached the root scope, the symbol does not exist at all | ||
| 99 |
2/2✓ Branch 5 → 6 taken 90655 times.
✓ Branch 5 → 7 taken 133231 times.
|
223886 | if (!parent) |
| 100 | 90655 | return nullptr; | |
| 101 | // If we search for the result variable, we want to stop the search when exiting a lambda body | ||
| 102 |
6/6✓ Branch 8 → 9 taken 7876 times.
✓ Branch 8 → 11 taken 125355 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 7875 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 133230 times.
|
133231 | if (name == RETURN_VARIABLE_NAME && scope->type == ScopeType::LAMBDA_BODY) |
| 103 | 1 | return nullptr; | |
| 104 | // If there is a parent scope, continue the search there | ||
| 105 | 133230 | SymbolTableEntry *entry = parent->lookup(name); | |
| 106 | // Symbol was also not found in all the parent scopes, return nullptr | ||
| 107 |
2/2✓ Branch 15 → 16 taken 66383 times.
✓ Branch 15 → 17 taken 66847 times.
|
133230 | if (!entry) |
| 108 | 66383 | return nullptr; | |
| 109 | // Check if this scope requires capturing and capture the variable if appropriate | ||
| 110 |
9/14✓ Branch 17 → 18 taken 23 times.
✓ Branch 17 → 24 taken 66824 times.
✓ Branch 18 → 19 taken 23 times.
✗ Branch 18 → 37 not taken.
✓ Branch 19 → 20 taken 23 times.
✗ Branch 19 → 24 not taken.
✓ Branch 20 → 21 taken 23 times.
✗ Branch 20 → 37 not taken.
✓ Branch 21 → 22 taken 23 times.
✗ Branch 21 → 37 not taken.
✓ Branch 22 → 23 taken 23 times.
✗ Branch 22 → 24 not taken.
✓ Branch 25 → 26 taken 23 times.
✓ Branch 25 → 35 taken 66824 times.
|
66847 | if (capturingRequired && !captures.contains(name) && !entry->getQualType().isOneOf({TY_IMPORT, TY_FUNCTION, TY_PROCEDURE})) { |
| 111 | // We need to make the symbol volatile if we are in an async scope and try to access a symbol that is not in an async scope | ||
| 112 |
3/4✓ Branch 27 → 28 taken 7 times.
✓ Branch 27 → 31 taken 16 times.
✓ Branch 29 → 30 taken 7 times.
✗ Branch 29 → 31 not taken.
|
23 | entry->isVolatile = scope->isInAsyncScope() && !entry->scope->isInAsyncScope(); |
| 113 | // Add the capture to the current scope | ||
| 114 |
2/4✓ Branch 32 → 33 taken 23 times.
✗ Branch 32 → 38 not taken.
✓ Branch 33 → 34 taken 23 times.
✗ Branch 33 → 38 not taken.
|
23 | captures.emplace(name, Capture(entry)); |
| 115 | } | ||
| 116 | 66847 | return entry; | |
| 117 | } | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Check if a symbol exists in the current or any parent scope and return it if possible. | ||
| 121 | * If the target symbol is an alias symbol, resolve the alias container entry. | ||
| 122 | * | ||
| 123 | * @param name Name of the desired symbol | ||
| 124 | * @return Desired symbol / nullptr if the symbol was not found + alias or not | ||
| 125 | */ | ||
| 126 | 19486 | std::pair<SymbolTableEntry *, bool> SymbolTable::lookupWithAliasResolution(const std::string &name) { | |
| 127 |
1/2✓ Branch 2 → 3 taken 19486 times.
✗ Branch 2 → 30 not taken.
|
19486 | SymbolTableEntry *entry = lookup(name); |
| 128 |
8/10✓ Branch 3 → 4 taken 4358 times.
✓ Branch 3 → 7 taken 15128 times.
✓ Branch 4 → 5 taken 4358 times.
✗ Branch 4 → 30 not taken.
✓ Branch 5 → 6 taken 4358 times.
✗ Branch 5 → 30 not taken.
✓ Branch 6 → 7 taken 4356 times.
✓ Branch 6 → 8 taken 2 times.
✓ Branch 9 → 10 taken 19484 times.
✓ Branch 9 → 13 taken 2 times.
|
19486 | if (!entry || !entry->getQualType().is(TY_ALIAS)) |
| 129 | 19484 | return {entry, false}; | |
| 130 | |||
| 131 | // We have an alias type here, resolve it | ||
| 132 |
1/2✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 2 times.
|
4 | assert(entry->scope->isRootScope()); |
| 133 | 2 | entry->used = true; | |
| 134 |
1/2✓ Branch 17 → 18 taken 2 times.
✗ Branch 17 → 30 not taken.
|
2 | const std::string aliasedContainerEntryName = entry->name + ALIAS_CONTAINER_SUFFIX; |
| 135 |
1/2✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 28 not taken.
|
2 | SymbolTableEntry *aliasedTypeContainerEntry = entry->scope->lookupStrict(aliasedContainerEntryName); |
| 136 |
1/2✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 2 times.
|
2 | assert(aliasedTypeContainerEntry != nullptr); |
| 137 | 2 | return {aliasedTypeContainerEntry, true}; | |
| 138 | 2 | } | |
| 139 | |||
| 140 | /** | ||
| 141 | * Check if a symbol exists in the current scope and return it if possible | ||
| 142 | * | ||
| 143 | * @param symbolName Name of the desired symbol | ||
| 144 | * @return Desired symbol / nullptr if the symbol was not found | ||
| 145 | */ | ||
| 146 | 532319 | SymbolTableEntry *SymbolTable::lookupStrict(const std::string &symbolName) { | |
| 147 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 532319 times.
|
532319 | if (symbolName.empty()) |
| 148 | ✗ | return nullptr; | |
| 149 | // Check if a symbol with this name exists in this scope | ||
| 150 |
3/4✓ Branch 5 → 6 taken 532319 times.
✗ Branch 5 → 21 not taken.
✓ Branch 8 → 9 taken 275369 times.
✓ Branch 8 → 11 taken 256950 times.
|
532319 | if (const auto it = symbols.find(symbolName); it != symbols.end()) |
| 151 | 275369 | return &it->second; | |
| 152 | // Check if a capture with this name exists in this scope | ||
| 153 |
3/4✓ Branch 11 → 13 taken 256950 times.
✗ Branch 11 → 22 not taken.
✓ Branch 15 → 16 taken 3 times.
✓ Branch 15 → 18 taken 256947 times.
|
256950 | if (const auto it = captures.find(symbolName); it != captures.end()) |
| 154 | 3 | return it->second.capturedSymbol; | |
| 155 | // Otherwise, return a nullptr | ||
| 156 | 256947 | return nullptr; | |
| 157 | } | ||
| 158 | |||
| 159 | /** | ||
| 160 | * Check if a symbol exists in one of the composed field scopes of the current scope and return it if possible. | ||
| 161 | * This only works if the current scope is a struct scope. | ||
| 162 | * | ||
| 163 | * @param name Name of the desired symbol | ||
| 164 | * @param indexPath How to index the found symbol using order indices (e.g. for GEP) | ||
| 165 | * @return Desired symbol / nullptr if the symbol was not found | ||
| 166 | */ | ||
| 167 | 37948 | SymbolTableEntry *SymbolTable::lookupInComposedFields(const std::string &name, // NOLINT(misc-no-recursion) | |
| 168 | std::vector<size_t> &indexPath) { | ||
| 169 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 37948 times.
|
37948 | assert(scope->type == ScopeType::STRUCT); |
| 170 | |||
| 171 | // Check if we have a symbol with this name in the current scope | ||
| 172 |
2/2✓ Branch 5 → 6 taken 37855 times.
✓ Branch 5 → 8 taken 93 times.
|
37948 | if (SymbolTableEntry *result = lookupStrict(name)) { |
| 173 | 37855 | indexPath.push_back(result->orderIndex); | |
| 174 | 37855 | return result; | |
| 175 | } | ||
| 176 | |||
| 177 | // If it was not found in the current scope, loop through all composed fields in this scope | ||
| 178 |
2/2✓ Branch 25 → 9 taken 105 times.
✓ Branch 25 → 26 taken 13 times.
|
118 | for (size_t i = 0; i < scope->getFieldCount(); i++) { |
| 179 | 105 | const SymbolTableEntry *fieldEntry = lookupStrictByIndex(i); | |
| 180 | |||
| 181 | // Skip all fields that are not composition fields | ||
| 182 |
2/2✓ Branch 12 → 13 taken 14 times.
✓ Branch 12 → 14 taken 91 times.
|
105 | if (!fieldEntry->getQualType().isComposition()) |
| 183 | 14 | continue; | |
| 184 | |||
| 185 | // Add the current field's order index to the index path | ||
| 186 | 91 | indexPath.push_back(fieldEntry->orderIndex); | |
| 187 | |||
| 188 | // Search in the composed field's body scope | ||
| 189 | 91 | Scope *searchScope = fieldEntry->getQualType().getBodyScope(); | |
| 190 |
1/2✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 91 times.
|
91 | assert(searchScope != nullptr); |
| 191 |
2/2✓ Branch 20 → 21 taken 80 times.
✓ Branch 20 → 22 taken 11 times.
|
91 | if (SymbolTableEntry *result = searchScope->symbolTable.lookupInComposedFields(name, indexPath)) |
| 192 | 80 | return result; | |
| 193 | |||
| 194 | // Remove the current field's order index from the index path | ||
| 195 | 11 | indexPath.pop_back(); | |
| 196 | } | ||
| 197 | |||
| 198 | // Symbol was not found in current scope, return nullptr | ||
| 199 | 13 | return nullptr; | |
| 200 | } | ||
| 201 | |||
| 202 | /** | ||
| 203 | * Check if an order index exists in the current or any parent scope and returns it if possible. | ||
| 204 | * Warning: Unlike the `lookup` method, this one doesn't consider the parent scopes | ||
| 205 | * | ||
| 206 | * @param orderIndex Order index of the desired symbol | ||
| 207 | * @return Desired symbol / nullptr if the symbol was not found | ||
| 208 | */ | ||
| 209 | 46618 | SymbolTableEntry *SymbolTable::lookupStrictByIndex(unsigned int orderIndex) { | |
| 210 |
4/8✓ Branch 2 → 3 taken 46618 times.
✗ Branch 2 → 14 not taken.
✓ Branch 3 → 4 taken 46618 times.
✗ Branch 3 → 14 not taken.
✓ Branch 4 → 5 taken 46618 times.
✗ Branch 4 → 14 not taken.
✓ Branch 11 → 6 taken 456254 times.
✗ Branch 11 → 12 not taken.
|
456254 | for (auto &val : symbols | std::views::values) { |
| 211 |
2/2✓ Branch 7 → 8 taken 46618 times.
✓ Branch 7 → 9 taken 409636 times.
|
456254 | if (val.orderIndex == orderIndex) |
| 212 | 46618 | return &val; | |
| 213 | } | ||
| 214 | ✗ | return nullptr; | |
| 215 | } | ||
| 216 | |||
| 217 | /** | ||
| 218 | * Check if an anonymous symbol exists in the current scope and return it if possible | ||
| 219 | * | ||
| 220 | * @param declNode AST node where the anonymous symbol is declared | ||
| 221 | * @param numericSuffix Numeric suffix of the anonymous symbol | ||
| 222 | * @return Anonymous symbol | ||
| 223 | */ | ||
| 224 | 6989 | SymbolTableEntry *SymbolTable::lookupAnonymous(const ASTNode *declNode, size_t numericSuffix) { | |
| 225 |
1/2✓ Branch 2 → 3 taken 6989 times.
✗ Branch 2 → 27 not taken.
|
6989 | std::stringstream name; |
| 226 |
5/10✓ Branch 3 → 4 taken 6989 times.
✗ Branch 3 → 25 not taken.
✓ Branch 4 → 5 taken 6989 times.
✗ Branch 4 → 21 not taken.
✓ Branch 5 → 6 taken 6989 times.
✗ Branch 5 → 19 not taken.
✓ Branch 6 → 7 taken 6989 times.
✗ Branch 6 → 19 not taken.
✓ Branch 7 → 8 taken 6989 times.
✗ Branch 7 → 19 not taken.
|
6989 | name << "anon." << declNode->codeLoc.toString() << "." << reinterpret_cast<size_t>(declNode); |
| 227 |
2/2✓ Branch 9 → 10 taken 100 times.
✓ Branch 9 → 12 taken 6889 times.
|
6989 | if (numericSuffix > 0) |
| 228 |
2/4✓ Branch 10 → 11 taken 100 times.
✗ Branch 10 → 25 not taken.
✓ Branch 11 → 12 taken 100 times.
✗ Branch 11 → 25 not taken.
|
100 | name << "." << numericSuffix; |
| 229 |
2/4✓ Branch 12 → 13 taken 6989 times.
✗ Branch 12 → 24 not taken.
✓ Branch 13 → 14 taken 6989 times.
✗ Branch 13 → 22 not taken.
|
13978 | return lookup(name.str()); |
| 230 | 6989 | } | |
| 231 | |||
| 232 | /** | ||
| 233 | * Check if a capture exists in the current or any parent scope and return it if possible | ||
| 234 | * | ||
| 235 | * @param name Name of the desired captured symbol | ||
| 236 | * @return Capture / nullptr if the capture was not found | ||
| 237 | */ | ||
| 238 | 261063 | Capture *SymbolTable::lookupCapture(const std::string &name) { // NOLINT(misc-no-recursion) | |
| 239 | // Check if the capture exists in the current scope. If yes, take it | ||
| 240 |
2/2✓ Branch 3 → 4 taken 33 times.
✓ Branch 3 → 5 taken 261030 times.
|
261063 | if (Capture *capture = lookupCaptureStrict(name)) |
| 241 | 33 | return capture; | |
| 242 | |||
| 243 | // We reached the root scope, the symbol does not exist at all | ||
| 244 |
2/2✓ Branch 5 → 6 taken 75162 times.
✓ Branch 5 → 7 taken 185868 times.
|
261030 | if (parent == nullptr) |
| 245 | 75162 | return nullptr; | |
| 246 | |||
| 247 | 185868 | return parent->lookupCapture(name); | |
| 248 | } | ||
| 249 | |||
| 250 | /** | ||
| 251 | * Check if a capture exists in the current scope and return it if possible | ||
| 252 | * | ||
| 253 | * @param name Name of the desired captured symbol | ||
| 254 | * @return Capture / nullptr if the capture was not found | ||
| 255 | */ | ||
| 256 | 261063 | Capture *SymbolTable::lookupCaptureStrict(const std::string &name) { | |
| 257 | // If available in the current scope, return it | ||
| 258 |
1/2✓ Branch 2 → 3 taken 261063 times.
✗ Branch 2 → 11 not taken.
|
261063 | const auto it = captures.find(name); |
| 259 |
2/2✓ Branch 5 → 6 taken 33 times.
✓ Branch 5 → 8 taken 261030 times.
|
261063 | if (it != captures.end()) |
| 260 | 33 | return &it->second; | |
| 261 | // Otherwise, return nullptr | ||
| 262 | 261030 | return nullptr; | |
| 263 | } | ||
| 264 | |||
| 265 | /** | ||
| 266 | * Set capturing for this scope required. | ||
| 267 | */ | ||
| 268 | 37 | void SymbolTable::setCapturingRequired() { capturingRequired = true; } | |
| 269 | |||
| 270 | /** | ||
| 271 | * Deletes an existing anonymous symbol | ||
| 272 | * | ||
| 273 | * @param name Anonymous symbol name | ||
| 274 | */ | ||
| 275 | 3978 | void SymbolTable::deleteAnonymous(const std::string &name) { symbols.erase(name); } | |
| 276 | |||
| 277 | /** | ||
| 278 | * Stringify a symbol table to a human-readable form. This is used to realize dumps of symbol tables | ||
| 279 | * | ||
| 280 | * Example: | ||
| 281 | * { | ||
| 282 | * "name": "<SymbolTableName>" | ||
| 283 | * "symbols": [ | ||
| 284 | * ... (SymbolTableEntry) | ||
| 285 | * ], | ||
| 286 | * "children": [ | ||
| 287 | * ... (SymbolTable) | ||
| 288 | * ] | ||
| 289 | * } | ||
| 290 | * | ||
| 291 | * @return Symbol table if form of a string | ||
| 292 | */ | ||
| 293 | 93451 | nlohmann::json SymbolTable::toJSON() const { | |
| 294 | // Collect all symbols | ||
| 295 | 93451 | std::vector<nlohmann::json> jsonSymbols; | |
| 296 |
1/2✓ Branch 3 → 4 taken 93451 times.
✗ Branch 3 → 59 not taken.
|
93451 | jsonSymbols.reserve(symbols.size()); |
| 297 |
5/8✓ Branch 4 → 5 taken 93451 times.
✗ Branch 4 → 44 not taken.
✓ Branch 5 → 6 taken 93451 times.
✗ Branch 5 → 44 not taken.
✓ Branch 6 → 7 taken 93451 times.
✗ Branch 6 → 44 not taken.
✓ Branch 14 → 8 taken 213720 times.
✓ Branch 14 → 15 taken 93451 times.
|
307171 | for (const SymbolTableEntry &symbol : symbols | std::views::values) |
| 298 |
2/4✓ Branch 9 → 10 taken 213720 times.
✗ Branch 9 → 43 not taken.
✓ Branch 10 → 11 taken 213720 times.
✗ Branch 10 → 41 not taken.
|
213720 | jsonSymbols.emplace_back(symbol.toJSON()); |
| 299 | |||
| 300 | // Collect all captures | ||
| 301 | 93451 | std::vector<nlohmann::json> jsonCaptures; | |
| 302 |
1/2✓ Branch 16 → 17 taken 93451 times.
✗ Branch 16 → 57 not taken.
|
93451 | jsonCaptures.reserve(captures.size()); |
| 303 |
5/8✓ Branch 17 → 18 taken 93451 times.
✗ Branch 17 → 48 not taken.
✓ Branch 18 → 19 taken 93451 times.
✗ Branch 18 → 48 not taken.
✓ Branch 19 → 20 taken 93451 times.
✗ Branch 19 → 48 not taken.
✓ Branch 27 → 21 taken 25 times.
✓ Branch 27 → 28 taken 93451 times.
|
93476 | for (const Capture &capture : captures | std::views::values) |
| 304 |
2/4✓ Branch 22 → 23 taken 25 times.
✗ Branch 22 → 47 not taken.
✓ Branch 23 → 24 taken 25 times.
✗ Branch 23 → 45 not taken.
|
25 | jsonCaptures.emplace_back(capture.toJSON()); |
| 305 | |||
| 306 | // Generate json | ||
| 307 | 93451 | nlohmann::json result; | |
| 308 |
2/4✓ Branch 29 → 30 taken 93451 times.
✗ Branch 29 → 51 not taken.
✓ Branch 30 → 31 taken 93451 times.
✗ Branch 30 → 49 not taken.
|
93451 | result["symbols"] = jsonSymbols; |
| 309 |
2/4✓ Branch 33 → 34 taken 93451 times.
✗ Branch 33 → 54 not taken.
✓ Branch 34 → 35 taken 93451 times.
✗ Branch 34 → 52 not taken.
|
93451 | result["captures"] = jsonCaptures; |
| 310 | 93451 | return result; | |
| 311 | 93451 | } | |
| 312 | |||
| 313 | } // namespace spice::compiler | ||
| 314 |