Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 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 | 1510156 | 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 | 47564 | void SymbolTableEntry::updateType(const QualType &newType, [[maybe_unused]] bool overwriteExistingType) { | |
26 |
4/6✓ Branch 0 taken 22998 times.
✓ Branch 1 taken 24566 times.
✓ Branch 3 taken 22998 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 22998 times.
|
47564 | assert(overwriteExistingType || qualType.isOneOf({TY_INVALID, TY_DYN})); |
27 | 47564 | qualType = newType; | |
28 | 47564 | } | |
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 | * @param force Force update. This can only be used compiler-internal | ||
38 | */ | ||
39 | 69316 | void SymbolTableEntry::updateState(const LifecycleState &newState, const ASTNode *node, bool force) { | |
40 | 69316 | const LifecycleState oldState = lifecycle.getCurrentState(); | |
41 | // Check if this is a constant variable and is already initialized | ||
42 | − | if (newState != DEAD && oldState != DECLARED && qualType.isConst() && !force) // GCOV_EXCL_LINE | |
43 | − | throw CompilerError(INTERNAL_ERROR, "Not re-assignable variable '" + name + "'"); // GCOV_EXCL_LINE | |
44 | − | if (newState == DEAD && oldState == DECLARED) // GCOV_EXCL_LINE | |
45 | − | throw CompilerError(INTERNAL_ERROR, "Cannot destroy uninitialized variable '" + name + "'"); // GCOV_EXCL_LINE | |
46 | − | if (newState == DEAD && oldState == DEAD) // GCOV_EXCL_LINE | |
47 | − | throw CompilerError(INTERNAL_ERROR, "Cannot destroy already destroyed variable '" + name + "'"); // GCOV_EXCL_LINE | |
48 |
1/2✓ Branch 1 taken 69316 times.
✗ Branch 2 not taken.
|
69316 | lifecycle.addEvent({newState, node}); |
49 | 69316 | } | |
50 | |||
51 | /** | ||
52 | * Retrieve the code location where the symbol was declared | ||
53 | * | ||
54 | * @return Declaration code location | ||
55 | */ | ||
56 | 95 | const CodeLoc &SymbolTableEntry::getDeclCodeLoc() const { return declNode->codeLoc; } | |
57 | |||
58 | /** | ||
59 | * Retrieve the address of the assigned value | ||
60 | * | ||
61 | * @return Address of the value in memory | ||
62 | */ | ||
63 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 45441 times.
|
45442 | llvm::Value *SymbolTableEntry::getAddress() const { return memAddress.empty() ? nullptr : memAddress.top(); } |
64 | |||
65 | /** | ||
66 | * Update the address of a symbol. This is used to save the allocated address where the symbol lives. | ||
67 | * | ||
68 | * @param address Address of the symbol in memory | ||
69 | */ | ||
70 | 33355 | void SymbolTableEntry::updateAddress(llvm::Value *address) { | |
71 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33355 times.
|
33355 | assert(address != nullptr); |
72 | // Ensure that structs fields get no addresses assigned, as the addresses are meant for the struct instances | ||
73 |
5/8✓ Branch 0 taken 28935 times.
✓ Branch 1 taken 4420 times.
✓ Branch 2 taken 28935 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4420 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4420 times.
|
33355 | assert((scope->type != ScopeType::STRUCT && scope->type != ScopeType::INTERFACE) || |
74 | qualType.isOneOf({TY_FUNCTION, TY_PROCEDURE})); | ||
75 |
2/2✓ Branch 1 taken 26694 times.
✓ Branch 2 taken 6661 times.
|
33355 | if (memAddress.empty()) |
76 | 26694 | memAddress.push(address); | |
77 | else | ||
78 | 6661 | memAddress.top() = address; | |
79 | 33355 | } | |
80 | |||
81 | /** | ||
82 | * Push a new address to the stack | ||
83 | * | ||
84 | * @param address Address to push | ||
85 | */ | ||
86 | 22 | void SymbolTableEntry::pushAddress(llvm::Value *address) { | |
87 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | assert(address != nullptr); |
88 | 22 | memAddress.push(address); | |
89 | 22 | } | |
90 | |||
91 | /** | ||
92 | * Remove the last address from the stack | ||
93 | */ | ||
94 | 22 | void SymbolTableEntry::popAddress() { | |
95 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
|
22 | assert(!memAddress.empty()); |
96 | 22 | memAddress.pop(); | |
97 | 22 | } | |
98 | |||
99 | /** | ||
100 | * Check if this symbol is a struct field | ||
101 | * | ||
102 | * @return Struct field or not | ||
103 | */ | ||
104 | 14721 | bool SymbolTableEntry::isField() const { | |
105 |
4/6✓ Branch 0 taken 13249 times.
✓ Branch 1 taken 1472 times.
✓ Branch 3 taken 13249 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 13249 times.
✗ Branch 6 not taken.
|
14721 | return scope->type == ScopeType::STRUCT && orderIndex < scope->getFieldCount() && !anonymous; |
106 | } | ||
107 | |||
108 | /** | ||
109 | * Stringify the current symbol to a human-readable form. Used to dump whole symbol tables with their contents. | ||
110 | * | ||
111 | * Example: | ||
112 | * { | ||
113 | * "name": "testIden", | ||
114 | * "type": "int[]*", | ||
115 | * "orderIndex": 4, | ||
116 | * "state": "initialized", | ||
117 | * "specifiers: [ | ||
118 | * "const": true, | ||
119 | * "signed": false | ||
120 | * ], | ||
121 | * "isGlobal": false, | ||
122 | * "isVolatile": false | ||
123 | * } | ||
124 | * | ||
125 | * @return Symbol table entry as a JSON object | ||
126 | */ | ||
127 | 323095 | nlohmann::ordered_json SymbolTableEntry::toJSON() const { | |
128 | 323095 | nlohmann::json result; | |
129 |
2/4✓ Branch 1 taken 323095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 323095 times.
✗ Branch 5 not taken.
|
323095 | result["name"] = name; |
130 |
3/6✓ Branch 1 taken 323095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 323095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 323095 times.
✗ Branch 8 not taken.
|
323095 | result["type"] = qualType.getName(true); |
131 |
3/6✓ Branch 1 taken 323095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 323095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 323095 times.
✗ Branch 8 not taken.
|
323095 | result["codeLoc"] = declNode->codeLoc.toString(); |
132 |
1/2✓ Branch 2 taken 323095 times.
✗ Branch 3 not taken.
|
323095 | result["orderIndex"] = orderIndex; |
133 |
3/6✓ Branch 1 taken 323095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 323095 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 323095 times.
✗ Branch 8 not taken.
|
323095 | result["state"] = lifecycle.getCurrentStateName(); |
134 |
1/2✓ Branch 2 taken 323095 times.
✗ Branch 3 not taken.
|
323095 | result["isGlobal"] = global; |
135 |
1/2✓ Branch 2 taken 323095 times.
✗ Branch 3 not taken.
|
323095 | result["isVolatile"] = isVolatile; |
136 |
1/2✓ Branch 1 taken 323095 times.
✗ Branch 2 not taken.
|
646190 | return result; |
137 | 323095 | } | |
138 | |||
139 | } // namespace spice::compiler | ||
140 |