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 | 1599237 | 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 | 60004 | void SymbolTableEntry::updateType(const QualType &newType, [[maybe_unused]] bool overwriteExistingType) { | |
26 |
4/6✓ Branch 0 (2→3) taken 28914 times.
✓ Branch 1 (2→6) taken 31090 times.
✓ Branch 2 (3→4) taken 28914 times.
✗ Branch 3 (3→7) not taken.
✗ Branch 4 (4→5) not taken.
✓ Branch 5 (4→6) taken 28914 times.
|
60004 | assert(overwriteExistingType || qualType.isOneOf({TY_INVALID, TY_DYN})); |
27 | 60004 | qualType = newType; | |
28 | 60004 | } | |
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 | 87484 | void SymbolTableEntry::updateState(const LifecycleState &newState, const ASTNode *node) { | |
39 | 87484 | 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 0 (21→22) taken 87484 times.
✗ Branch 1 (21→41) not taken.
|
87484 | lifecycle.addEvent({newState, node}); |
45 | 87484 | } | |
46 | |||
47 | /** | ||
48 | * Retrieve the code location where the symbol was declared | ||
49 | * | ||
50 | * @return Declaration code location | ||
51 | */ | ||
52 | 152 | 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 0 (3→4) taken 6 times.
✓ Branch 1 (3→5) taken 55918 times.
|
55924 | 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 | 42330 | void SymbolTableEntry::updateAddress(llvm::Value *address) { | |
67 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 42330 times.
|
42330 | assert(address != nullptr); |
68 |
1/2✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 42330 times.
|
42330 | 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 0 (8→9) taken 37253 times.
✓ Branch 1 (8→11) taken 5077 times.
✓ Branch 2 (9→10) taken 37253 times.
✗ Branch 3 (9→11) not taken.
✓ Branch 4 (11→12) taken 5077 times.
✗ Branch 5 (11→20) not taken.
✗ Branch 6 (12→13) not taken.
✓ Branch 7 (12→14) taken 5077 times.
|
42330 | assert((scope->type != ScopeType::STRUCT && scope->type != ScopeType::INTERFACE) || |
71 | qualType.isOneOf({TY_FUNCTION, TY_PROCEDURE})); | ||
72 |
2/2✓ Branch 0 (15→16) taken 34754 times.
✓ Branch 1 (15→17) taken 7576 times.
|
42330 | if (memAddress.empty()) |
73 | 34754 | memAddress.push(address); | |
74 | else | ||
75 | 7576 | memAddress.top() = address; | |
76 | 42330 | } | |
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 0 (2→3) not taken.
✓ Branch 1 (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 0 (3→4) not taken.
✓ Branch 1 (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 | 14736 | bool SymbolTableEntry::isField() const { | |
102 |
4/6✓ Branch 0 (2→3) taken 12771 times.
✓ Branch 1 (2→7) taken 1965 times.
✓ Branch 2 (4→5) taken 12771 times.
✗ Branch 3 (4→7) not taken.
✓ Branch 4 (5→6) taken 12771 times.
✗ Branch 5 (5→7) not taken.
|
14736 | return scope->type == ScopeType::STRUCT && orderIndex < scope->getFieldCount() && !anonymous; |
103 | } | ||
104 | |||
105 | /** | ||
106 | * Stringify the current symbol to a human-readable form. Used to dump whole symbol tables with their contents. | ||
107 | * | ||
108 | * Example: | ||
109 | * { | ||
110 | * "name": "testIden", | ||
111 | * "type": "int[]*", | ||
112 | * "orderIndex": 4, | ||
113 | * "state": "initialized", | ||
114 | * "qualifiers: [ | ||
115 | * "const": true, | ||
116 | * "signed": false | ||
117 | * ], | ||
118 | * "isGlobal": false, | ||
119 | * "isVolatile": false | ||
120 | * } | ||
121 | * | ||
122 | * @return Symbol table entry as a JSON object | ||
123 | */ | ||
124 | 121961 | nlohmann::ordered_json SymbolTableEntry::toJSON() const { | |
125 | 121961 | nlohmann::json result; | |
126 |
2/4✓ Branch 0 (3→4) taken 121961 times.
✗ Branch 1 (3→43) not taken.
✓ Branch 2 (4→5) taken 121961 times.
✗ Branch 3 (4→41) not taken.
|
121961 | result["name"] = name; |
127 |
3/6✓ Branch 0 (7→8) taken 121961 times.
✗ Branch 1 (7→48) not taken.
✓ Branch 2 (8→9) taken 121961 times.
✗ Branch 3 (8→46) not taken.
✓ Branch 4 (9→10) taken 121961 times.
✗ Branch 5 (9→44) not taken.
|
121961 | result["type"] = qualType.getName(true); |
128 |
3/6✓ Branch 0 (13→14) taken 121961 times.
✗ Branch 1 (13→54) not taken.
✓ Branch 2 (14→15) taken 121961 times.
✗ Branch 3 (14→52) not taken.
✓ Branch 4 (15→16) taken 121961 times.
✗ Branch 5 (15→50) not taken.
|
121961 | result["codeLoc"] = declNode->codeLoc.toString(); |
129 |
1/2✓ Branch 0 (20→21) taken 121961 times.
✗ Branch 1 (20→56) not taken.
|
121961 | result["orderIndex"] = orderIndex; |
130 |
3/6✓ Branch 0 (23→24) taken 121961 times.
✗ Branch 1 (23→61) not taken.
✓ Branch 2 (24→25) taken 121961 times.
✗ Branch 3 (24→61) not taken.
✓ Branch 4 (25→26) taken 121961 times.
✗ Branch 5 (25→59) not taken.
|
121961 | result["state"] = lifecycle.getCurrentStateName(); |
131 |
1/2✓ Branch 0 (29→30) taken 121961 times.
✗ Branch 1 (29→63) not taken.
|
121961 | result["isGlobal"] = global; |
132 |
1/2✓ Branch 0 (33→34) taken 121961 times.
✗ Branch 1 (33→66) not taken.
|
121961 | result["isVolatile"] = isVolatile; |
133 |
1/2✓ Branch 0 (36→37) taken 121961 times.
✗ Branch 1 (36→69) not taken.
|
243922 | return result; |
134 | 121961 | } | |
135 | |||
136 | } // namespace spice::compiler | ||
137 |