symboltablebuilder/symbol-table-entry.spice
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | // Std imports | ||
| 4 | import "std/text/json/json-value"; | ||
| 5 | |||
| 6 | // Own imports | ||
| 7 | import "@/ast/ast-nodes"; | ||
| 8 | import "@/symboltablebuilder/scope"; | ||
| 9 | import "@/symboltablebuilder/super-type"; | ||
| 10 | import "@/symboltablebuilder/qual-type"; | ||
| 11 | import "@/symboltablebuilder/lifecycle"; | ||
| 12 | import "@/reader/code-loc"; | ||
| 13 | import "@/util/common-util"; | ||
| 14 | import "@/exception/compiler-error"; | ||
| 15 | |||
| 16 | // Reserved function names for implicitly generated struct constructors/destructors | ||
| 17 | public const string CTOR_FUNCTION_NAME = "ctor"; | ||
| 18 | public const string DTOR_FUNCTION_NAME = "dtor"; | ||
| 19 | |||
| 20 | // Reserved variable names | ||
| 21 | public const string THIS_VARIABLE_NAME = "this"; | ||
| 22 | public const string RETURN_VARIABLE_NAME = "result"; | ||
| 23 | |||
| 24 | 959959 | public type SymbolTableEntry struct { | |
| 25 | // Public fields | ||
| 26 | public String name | ||
| 27 | public Scope* scope | ||
| 28 | public ASTNode* declNode | ||
| 29 | public unsigned long orderIndex | ||
| 30 | public bool global | ||
| 31 | 228906 | public bool isVolatile = false | |
| 32 | 228906 | public bool isParam = false | |
| 33 | 228906 | public bool anonymous = false | |
| 34 | 228906 | public bool used = false | |
| 35 | 228906 | public bool isImplicitField = false | |
| 36 | // Private fields | ||
| 37 | QualType qualType | ||
| 38 | Lifecycle lifecycle | ||
| 39 | } | ||
| 40 | |||
| 41 | 228906 | public p SymbolTableEntry.ctor(const String& name, const QualType& qualType, Scope* scope, ASTNode* declNode, unsigned long orderIndex, bool global) { | |
| 42 | 228906 | this.name = name; | |
| 43 | 228906 | this.qualType = qualType; | |
| 44 | 228906 | this.scope = scope; | |
| 45 | 228906 | this.declNode = declNode; | |
| 46 | 228906 | this.orderIndex = orderIndex; | |
| 47 | 228906 | this.global = global; | |
| 48 | 228906 | } | |
| 49 | |||
| 50 | /** | ||
| 51 | * Retrieve the qualified type of this symbol | ||
| 52 | * | ||
| 53 | * @return Qualified type of this symbol | ||
| 54 | */ | ||
| 55 | 8473650 | public f<const QualType&> SymbolTableEntry.getQualType() { | |
| 56 | 8473650 | return this.qualType; | |
| 57 | } | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Update the type of this symbol. | ||
| 61 | * | ||
| 62 | * @param newType New type of the current symbol | ||
| 63 | * @param overwriteExistingType Overwrites the existing type without throwing an error | ||
| 64 | */ | ||
| 65 | 306452 | public p SymbolTableEntry.updateType(const QualType& newType, bool overwriteExistingType) { | |
| 66 | 306452 | const dyn options = [SuperType::TY_INVALID, SuperType::TY_DYN]; | |
| 67 | 306452 | assert overwriteExistingType || this.qualType.isOneOf(options, len(options)); | |
| 68 | 306452 | this.qualType = newType; | |
| 69 | 306452 | } | |
| 70 | |||
| 71 | /** | ||
| 72 | * Update the state of the current symbol | ||
| 73 | * | ||
| 74 | * @throws CompilerError When the state change is not valid | ||
| 75 | * | ||
| 76 | * @param newState New state of the current symbol | ||
| 77 | */ | ||
| 78 | 473348 | public p SymbolTableEntry.updateState(const LifecycleState& newState) { | |
| 79 | 473348 | const LifecycleState oldState = this.lifecycle.getCurrentState(); | |
| 80 | 473348 | if newState == LifecycleState::DEAD && oldState == LifecycleState::DECLARED { | |
| 81 | ✗ | const String message = "Cannot destroy uninitialized variable '" + this.name + "'"; | |
| 82 | ✗ | const CompilerError error = CompilerError(CompilerErrorType::INTERNAL_ERROR, message.getRaw()); | |
| 83 | ✗ | const String& errorMessage = error.getMessage(); | |
| 84 | ✗ | panic(Error(errorMessage.getRaw())); | |
| 85 | ✗ | } | |
| 86 | 473348 | if newState == LifecycleState::DEAD && oldState == LifecycleState::DEAD { | |
| 87 | ✗ | const String message = "Cannot destroy already destroyed variable '" + this.name + "'"; | |
| 88 | ✗ | const CompilerError error = CompilerError(CompilerErrorType::INTERNAL_ERROR, message.getRaw()); | |
| 89 | ✗ | const String& errorMessage = error.getMessage(); | |
| 90 | ✗ | panic(Error(errorMessage.getRaw())); | |
| 91 | ✗ | } | |
| 92 | 473348 | this.lifecycle.addEvent(LifecycleEvent{newState}); | |
| 93 | 473348 | } | |
| 94 | |||
| 95 | /** | ||
| 96 | * Retrieve the code location where the symbol was declared | ||
| 97 | * | ||
| 98 | * @return Declaration code location | ||
| 99 | */ | ||
| 100 | 212 | public f<const CodeLoc &> SymbolTableEntry.getDeclCodeLoc() { | |
| 101 | 212 | return this.declNode.codeLoc; | |
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Retrieve the lifecycle of this symbol | ||
| 106 | * | ||
| 107 | * @return Lifecycle | ||
| 108 | */ | ||
| 109 | 4397 | public f<const Lifecycle&> SymbolTableEntry.getLifecycle() { | |
| 110 | 4397 | return this.lifecycle; | |
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Check if this symbol is initialized | ||
| 115 | * | ||
| 116 | * @return Initialized or not | ||
| 117 | */ | ||
| 118 | 88208 | public f<bool> SymbolTableEntry.isInitialized() { | |
| 119 | 88208 | return this.lifecycle.isInitialized(); | |
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 123 | * Check if this symbol is a struct field | ||
| 124 | * | ||
| 125 | * @return Struct field or not | ||
| 126 | */ | ||
| 127 | 112402 | public f<bool> SymbolTableEntry.isField() { | |
| 128 | 112402 | const ScopeType scopeType = this.scope.getScopeType(); | |
| 129 | 112402 | return (scopeType == ScopeType::STRUCT || scopeType == ScopeType::UNION) && this.orderIndex < this.scope.getFieldCount() && !this.anonymous; | |
| 130 | } | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Stringify the current symbol to a human-readable form. Used to dump whole symbol tables with their contents. | ||
| 134 | * The returned heap-allocated JSON value is owned by the caller. | ||
| 135 | * | ||
| 136 | * Example: | ||
| 137 | * { | ||
| 138 | * "name": "testIden", | ||
| 139 | * "type": "int[]*", | ||
| 140 | * "orderIndex": 4, | ||
| 141 | * "state": "initialized", | ||
| 142 | * "qualifiers: [ | ||
| 143 | * "const": true, | ||
| 144 | * "signed": false | ||
| 145 | * ], | ||
| 146 | * "isGlobal": false, | ||
| 147 | * "isVolatile": false | ||
| 148 | * } | ||
| 149 | * | ||
| 150 | * @return Symbol table entry as a JSON object | ||
| 151 | */ | ||
| 152 | 375876 | public f<JsonValue*> SymbolTableEntry.toJSON() { | |
| 153 | 375876 | result = __new<JsonValue>(JsonValueKind::JSON_OBJECT); | |
| 154 | 375876 | setJsonField(result, String("name"), __new<JsonValue>(this.name)); | |
| 155 | 375876 | setJsonField(result, String("type"), __new<JsonValue>(this.qualType.getName(true))); | |
| 156 | 375876 | setJsonField(result, String("codeLoc"), __new<JsonValue>(this.declNode.codeLoc.toString())); | |
| 157 | 375876 | setJsonField(result, String("orderIndex"), __new<JsonValue>(this.orderIndex)); | |
| 158 | 375876 | setJsonField(result, String("state"), __new<JsonValue>(String(this.lifecycle.getCurrentStateName()))); | |
| 159 | 375876 | setJsonField(result, String("isGlobal"), __new<JsonValue>(this.global)); | |
| 160 | 375876 | setJsonField(result, String("isVolatile"), __new<JsonValue>(this.isVolatile)); | |
| 161 | 375876 | } | |
| 162 |