GCC Code Coverage Report


Directory: ../
File: src/symboltablebuilder/SymbolTableEntry.cpp
Date: 2025-10-27 22:48:14
Coverage Exec Excl Total
Lines: 90.9% 40 4 48
Functions: 83.3% 10 0 12
Branches: 47.5% 38 20 100

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "SymbolTableEntry.h"
4
5 #include <ast/ASTNodes.h>
6 #include <exception/SemanticError.h>
7 #include <symboltablebuilder/Scope.h>
8 #include <util/CodeLoc.h>
9
10 namespace spice::compiler {
11
12 /**
13 * Retrieve the qualified type of this symbol
14 *
15 * @return Qualified type of this symbol
16 */
17 1653393 const QualType &SymbolTableEntry::getQualType() const { return qualType; }
18
19 /**
20 * Update the type of this symbol.
21 *
22 * @param newType New type of the current symbol
23 * @param overwriteExistingType Overwrites the existing type without throwing an error
24 */
25 71590 void SymbolTableEntry::updateType(const QualType &newType, [[maybe_unused]] bool overwriteExistingType) {
26
4/6
✓ Branch 2 → 3 taken 34123 times.
✓ Branch 2 → 6 taken 37467 times.
✓ Branch 3 → 4 taken 34123 times.
✗ Branch 3 → 7 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 34123 times.
71590 assert(overwriteExistingType || qualType.isOneOf({TY_INVALID, TY_DYN}));
27 71590 qualType = newType;
28 71590 }
29
30 /**
31 * Update the state of the current symbol
32 *
33 * @throws CompilerError When the state of the symbol is set to initialized before a concrete type was set
34 *
35 * @param newState New state of the current symbol
36 * @param node AST node where the update takes place
37 */
38 101595 void SymbolTableEntry::updateState(const LifecycleState &newState, const ASTNode *node) {
39 101595 const LifecycleState oldState = lifecycle.getCurrentState();
40 if (newState == DEAD && oldState == DECLARED) // GCOV_EXCL_LINE
41 throw CompilerError(INTERNAL_ERROR, "Cannot destroy uninitialized variable '" + name + "'"); // GCOV_EXCL_LINE
42 if (newState == DEAD && oldState == DEAD) // GCOV_EXCL_LINE
43 throw CompilerError(INTERNAL_ERROR, "Cannot destroy already destroyed variable '" + name + "'"); // GCOV_EXCL_LINE
44
1/2
✓ Branch 21 → 22 taken 101595 times.
✗ Branch 21 → 41 not taken.
101595 lifecycle.addEvent({newState, node});
45 101595 }
46
47 /**
48 * Retrieve the code location where the symbol was declared
49 *
50 * @return Declaration code location
51 */
52 157 const CodeLoc &SymbolTableEntry::getDeclCodeLoc() const { return declNode->codeLoc; }
53
54 /**
55 * Retrieve the address of the assigned value
56 *
57 * @return Address of the value in memory
58 */
59
2/2
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 5 taken 63637 times.
63643 llvm::Value *SymbolTableEntry::getAddress() const { return memAddress.empty() ? nullptr : memAddress.top(); }
60
61 /**
62 * Update the address of a symbol. This is used to save the allocated address where the symbol lives.
63 *
64 * @param address Address of the symbol in memory
65 */
66 49462 void SymbolTableEntry::updateAddress(llvm::Value *address) {
67
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 49462 times.
49462 assert(address != nullptr);
68
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 49462 times.
49462 assert(address->getType()->isPointerTy());
69 // Ensure that structs fields get no addresses assigned, as the addresses are meant for the struct instances
70
5/8
✓ Branch 8 → 9 taken 43746 times.
✓ Branch 8 → 11 taken 5716 times.
✓ Branch 9 → 10 taken 43746 times.
✗ Branch 9 → 11 not taken.
✓ Branch 11 → 12 taken 5716 times.
✗ Branch 11 → 20 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 5716 times.
49462 assert((scope->type != ScopeType::STRUCT && scope->type != ScopeType::INTERFACE) ||
71 qualType.isOneOf({TY_FUNCTION, TY_PROCEDURE}));
72
2/2
✓ Branch 15 → 16 taken 40899 times.
✓ Branch 15 → 17 taken 8563 times.
49462 if (memAddress.empty())
73 40899 memAddress.push(address);
74 else
75 8563 memAddress.top() = address;
76 49462 }
77
78 /**
79 * Push a new address to the stack
80 *
81 * @param address Address to push
82 */
83 24 void SymbolTableEntry::pushAddress(llvm::Value *address) {
84
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 24 times.
24 assert(address != nullptr);
85 24 memAddress.push(address);
86 24 }
87
88 /**
89 * Remove the last address from the stack
90 */
91 24 void SymbolTableEntry::popAddress() {
92
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 24 times.
24 assert(!memAddress.empty());
93 24 memAddress.pop();
94 24 }
95
96 /**
97 * Check if this symbol is a struct field
98 *
99 * @return Struct field or not
100 */
101 16387 bool SymbolTableEntry::isField() const {
102
5/6
✓ Branch 2 → 3 taken 14097 times.
✓ Branch 2 → 7 taken 2290 times.
✓ Branch 4 → 5 taken 14056 times.
✓ Branch 4 → 7 taken 41 times.
✓ Branch 5 → 6 taken 14056 times.
✗ Branch 5 → 7 not taken.
16387 return scope->type == ScopeType::STRUCT && orderIndex < scope->getFieldCount() && !anonymous;
103 }
104
105 /**
106 * Check if this symbol is a function/procedure definition
107 *
108 * @return Function/procedure or not
109 */
110 bool SymbolTableEntry::isFunctionOrProcedure() const {
111 return scope->type == ScopeType::GLOBAL && qualType.isOneOf({TY_FUNCTION, TY_PROCEDURE});
112 }
113
114 /**
115 * Check if this symbol is a method definition
116 *
117 * @return Method or not
118 */
119 bool SymbolTableEntry::isMethod() const {
120 return scope->type == ScopeType::STRUCT && !isField() && qualType.isOneOf({TY_FUNCTION, TY_PROCEDURE});
121 }
122
123 /**
124 * Stringify the current symbol to a human-readable form. Used to dump whole symbol tables with their contents.
125 *
126 * Example:
127 * {
128 * "name": "testIden",
129 * "type": "int[]*",
130 * "orderIndex": 4,
131 * "state": "initialized",
132 * "qualifiers: [
133 * "const": true,
134 * "signed": false
135 * ],
136 * "isGlobal": false,
137 * "isVolatile": false
138 * }
139 *
140 * @return Symbol table entry as a JSON object
141 */
142 168182 nlohmann::ordered_json SymbolTableEntry::toJSON() const {
143 168182 nlohmann::json result;
144
2/4
✓ Branch 3 → 4 taken 168182 times.
✗ Branch 3 → 43 not taken.
✓ Branch 4 → 5 taken 168182 times.
✗ Branch 4 → 41 not taken.
168182 result["name"] = name;
145
3/6
✓ Branch 7 → 8 taken 168182 times.
✗ Branch 7 → 48 not taken.
✓ Branch 8 → 9 taken 168182 times.
✗ Branch 8 → 46 not taken.
✓ Branch 9 → 10 taken 168182 times.
✗ Branch 9 → 44 not taken.
168182 result["type"] = qualType.getName(true);
146
3/6
✓ Branch 13 → 14 taken 168182 times.
✗ Branch 13 → 54 not taken.
✓ Branch 14 → 15 taken 168182 times.
✗ Branch 14 → 52 not taken.
✓ Branch 15 → 16 taken 168182 times.
✗ Branch 15 → 50 not taken.
168182 result["codeLoc"] = declNode->codeLoc.toString();
147
1/2
✓ Branch 20 → 21 taken 168182 times.
✗ Branch 20 → 56 not taken.
168182 result["orderIndex"] = orderIndex;
148
3/6
✓ Branch 23 → 24 taken 168182 times.
✗ Branch 23 → 61 not taken.
✓ Branch 24 → 25 taken 168182 times.
✗ Branch 24 → 61 not taken.
✓ Branch 25 → 26 taken 168182 times.
✗ Branch 25 → 59 not taken.
168182 result["state"] = lifecycle.getCurrentStateName();
149
1/2
✓ Branch 29 → 30 taken 168182 times.
✗ Branch 29 → 63 not taken.
168182 result["isGlobal"] = global;
150
1/2
✓ Branch 33 → 34 taken 168182 times.
✗ Branch 33 → 66 not taken.
168182 result["isVolatile"] = isVolatile;
151
1/2
✓ Branch 36 → 37 taken 168182 times.
✗ Branch 36 → 69 not taken.
336364 return result;
152 168182 }
153
154 } // namespace spice::compiler
155