symboltablebuilder/type-chain.spice
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | // Std imports | ||
| 4 | import "std/data/vector"; | ||
| 5 | import "std/text/stringstream"; | ||
| 6 | import "std/type/type-conversion"; | ||
| 7 | |||
| 8 | // Own imports | ||
| 9 | import "@/symboltablebuilder/super-type"; | ||
| 10 | import "@/symboltablebuilder/qual-type"; | ||
| 11 | import "@/symboltablebuilder/scope"; | ||
| 12 | import "@/global/type-name-disambiguator"; | ||
| 13 | |||
| 14 | // Constants | ||
| 15 | public const unsigned long ARRAY_SIZE_UNKNOWN = 0ul; | ||
| 16 | |||
| 17 | 14306594 | public type TypeChainElementData struct { | |
| 18 | 14306594 | public unsigned int arraySize = 0 // TY_ARRAY | |
| 19 | 14306594 | public Scope* bodyScope = nil<Scope*> // TY_STRUCT, TY_INTERFACE, TY_ENUM | |
| 20 | 14306594 | public bool hasCaptures = false // TY_FUNCTION, TY_PROCEDURE (lambdas) | |
| 21 | } | ||
| 22 | |||
| 23 | 14289039 | public type TypeChainElement struct { | |
| 24 | 14301512 | public SuperType superType = SuperType::TY_INVALID | |
| 25 | public String subType | ||
| 26 | 14301512 | public unsigned long typeId = cast<unsigned long>(SuperType::TY_INVALID) | |
| 27 | public TypeChainElementData data | ||
| 28 | public QualTypeList templateTypes | ||
| 29 | public QualTypeList paramTypes // First type is the return type | ||
| 30 | } | ||
| 31 | |||
| 32 | 4331782 | public p TypeChainElement.ctor(SuperType superType) { | |
| 33 | 4331782 | this.superType = superType; | |
| 34 | 4331782 | this.typeId = cast<unsigned long>(superType); | |
| 35 | 4331782 | } | |
| 36 | |||
| 37 | 6445 | public p TypeChainElement.ctor(SuperType superType, const String& subType) { | |
| 38 | 6445 | this.ctor(superType); | |
| 39 | 6445 | this.subType = subType; | |
| 40 | 6445 | } | |
| 41 | |||
| 42 | 1031 | public p TypeChainElement.ctor(SuperType superType, const TypeChainElementData& data) { | |
| 43 | 1031 | this.ctor(superType); | |
| 44 | 1031 | this.data = data; | |
| 45 | 1031 | } | |
| 46 | |||
| 47 | 5079 | public p TypeChainElement.ctor(SuperType superType, const String& subType, unsigned long typeId, const TypeChainElementData& data, const QualTypeList& templateTypes) { | |
| 48 | 5079 | this.superType = superType; | |
| 49 | 5079 | this.subType = subType; | |
| 50 | 5079 | this.typeId = typeId; | |
| 51 | 5079 | this.data = data; | |
| 52 | 5079 | this.templateTypes = templateTypes; | |
| 53 | 5079 | } | |
| 54 | |||
| 55 | // Explicit copy ctor: a user-defined ctor suppresses the auto-generated copy ctor, but elements are copied | ||
| 56 | // when type chains are duplicated (e.g. in Type.toPtr) and stored in vectors, so a deep copy is required. | ||
| 57 | 9957175 | public p TypeChainElement.ctor(const TypeChainElement& other) { | |
| 58 | 9957175 | this.superType = other.superType; | |
| 59 | 9957175 | this.subType = other.subType; | |
| 60 | 9957175 | this.typeId = other.typeId; | |
| 61 | 9957175 | this.data = other.data; | |
| 62 | 9957175 | this.templateTypes = other.templateTypes; | |
| 63 | 9957175 | this.paramTypes = other.paramTypes; | |
| 64 | 9957175 | } | |
| 65 | |||
| 66 | /** | ||
| 67 | * Compare two lists of qualified types element-wise. The equality operator of Vector compares the raw memory, which also | ||
| 68 | * compares the (uninitialized) padding bytes of the QualType elements. | ||
| 69 | * | ||
| 70 | * @param lhs Left list | ||
| 71 | * @param rhs Right list | ||
| 72 | * @return Equal or not | ||
| 73 | */ | ||
| 74 | 1595840 | f<bool> areQualTypeListsEqual(const QualTypeList& lhs, const QualTypeList& rhs) { | |
| 75 | 1595840 | if lhs.getSize() != rhs.getSize() { | |
| 76 | ✗ | return false; | |
| 77 | } | ||
| 78 | 2377712 | for unsigned long i = 0ul; i < lhs.getSize(); i++ { | |
| 79 | 781932 | if lhs[i] != rhs[i] { | |
| 80 | 60 | return false; | |
| 81 | } | ||
| 82 | 781872 | } | |
| 83 | 1595780 | return true; | |
| 84 | } | ||
| 85 | |||
| 86 | 7119570 | public f<bool> operator==(const TypeChainElement& lhs, const TypeChainElement& rhs) { | |
| 87 | // Check super type | ||
| 88 | 7119570 | if lhs.superType != rhs.superType { return false; } | |
| 89 | |||
| 90 | // Check the super-type-specific data payload | ||
| 91 | 7032121 | switch lhs.superType { | |
| 92 | case SuperType::TY_ARRAY: { | ||
| 93 | 1464 | return lhs.data.arraySize == rhs.data.arraySize; | |
| 94 | } | ||
| 95 | case SuperType::TY_STRUCT: { | ||
| 96 | 1624506 | assert lhs.data.bodyScope != nil<Scope*> && rhs.data.bodyScope != nil<Scope*>; | |
| 97 | 1624506 | return lhs.typeId == rhs.typeId && areQualTypeListsEqual(lhs.templateTypes, rhs.templateTypes); | |
| 98 | } | ||
| 99 | case SuperType::TY_INTERFACE: { | ||
| 100 | 7893 | return lhs.typeId == rhs.typeId; | |
| 101 | } | ||
| 102 | case SuperType::TY_UNION: { | ||
| 103 | 108 | assert lhs.data.bodyScope != nil<Scope*> && rhs.data.bodyScope != nil<Scope*>; | |
| 104 | 108 | return lhs.typeId == rhs.typeId && areQualTypeListsEqual(lhs.templateTypes, rhs.templateTypes); | |
| 105 | } | ||
| 106 | case SuperType::TY_ENUM: { | ||
| 107 | 1 | assert lhs.data.bodyScope != nil<Scope*> && rhs.data.bodyScope != nil<Scope*>; | |
| 108 | 1 | return lhs.typeId == rhs.typeId && lhs.data.bodyScope == rhs.data.bodyScope; | |
| 109 | } | ||
| 110 | case SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE: { | ||
| 111 | 81723 | if lhs.paramTypes.getSize() != rhs.paramTypes.getSize() { | |
| 112 | ✗ | return false; | |
| 113 | } | ||
| 114 | 133182 | for unsigned long i = 0ul; i < lhs.paramTypes.getSize(); i++ { | |
| 115 | 51470 | if lhs.paramTypes[i] != rhs.paramTypes[i] { | |
| 116 | 11 | return false; | |
| 117 | } | ||
| 118 | 51459 | } | |
| 119 | 81712 | return true; | |
| 120 | } | ||
| 121 | case SuperType::TY_GENERIC: { | ||
| 122 | 164185 | return lhs.subType == rhs.subType; | |
| 123 | } | ||
| 124 | default: { | ||
| 125 | 5152241 | return true; | |
| 126 | } | ||
| 127 | } | ||
| 128 | ✗ | } | |
| 129 | |||
| 130 | 7119570 | public f<bool> operator!=(const TypeChainElement& lhs, const TypeChainElement& rhs) { | |
| 131 | 7119570 | return !(lhs == rhs); | |
| 132 | } | ||
| 133 | |||
| 134 | 1949865 | public p TypeChainElement.getName(StringStream& name, bool withSize, bool ignorePublic, bool withAliases) { | |
| 135 | 1949865 | switch this.superType { | |
| 136 | case SuperType::TY_PTR: { | ||
| 137 | 190466 | name << "*"; | |
| 138 | 190466 | } | |
| 139 | case SuperType::TY_REF: { | ||
| 140 | 222758 | name << "&"; | |
| 141 | 222758 | } | |
| 142 | case SuperType::TY_ARRAY: { | ||
| 143 | 2168 | name << "["; | |
| 144 | 2168 | if withSize && this.data.arraySize != ARRAY_SIZE_UNKNOWN { | |
| 145 | 813 | name << toString(this.data.arraySize); | |
| 146 | 813 | } | |
| 147 | 2168 | name << "]"; | |
| 148 | 2168 | } | |
| 149 | case SuperType::TY_DOUBLE: { | ||
| 150 | 10727 | name << "double"; | |
| 151 | 10727 | } | |
| 152 | case SuperType::TY_INT: { | ||
| 153 | 167079 | name << "int"; | |
| 154 | 167079 | } | |
| 155 | case SuperType::TY_SHORT: { | ||
| 156 | 12415 | name << "short"; | |
| 157 | 12415 | } | |
| 158 | case SuperType::TY_LONG: { | ||
| 159 | 155137 | name << "long"; | |
| 160 | 155137 | } | |
| 161 | case SuperType::TY_BYTE: { | ||
| 162 | 81114 | name << "byte"; | |
| 163 | 81114 | } | |
| 164 | case SuperType::TY_CHAR: { | ||
| 165 | 76005 | name << "char"; | |
| 166 | 76005 | } | |
| 167 | case SuperType::TY_STRING: { | ||
| 168 | 116487 | name << (withAliases ? "string" : "const char*"); | |
| 169 | 116487 | } | |
| 170 | case SuperType::TY_BOOL: { | ||
| 171 | 103992 | name << "bool"; | |
| 172 | 103992 | } | |
| 173 | case SuperType::TY_STRUCT, SuperType::TY_INTERFACE, SuperType::TY_UNION: { | ||
| 174 | 373697 | name << this.subType << getDisambiguationSuffix(this.subType, this.typeId); | |
| 175 | 373697 | if !this.templateTypes.isEmpty() { | |
| 176 | 167437 | name << "<"; | |
| 177 | 376909 | foreach unsigned long i, const QualType& templateType : this.templateTypes { | |
| 178 | 209472 | if i > 0 { name << ","; } | |
| 179 | 209472 | templateType.getName(name, withSize, ignorePublic); | |
| 180 | 209472 | } | |
| 181 | 167437 | name << ">"; | |
| 182 | 167437 | } | |
| 183 | 373697 | } | |
| 184 | case SuperType::TY_ENUM: { | ||
| 185 | 879 | name << "enum(" << this.subType << ")"; | |
| 186 | 879 | } | |
| 187 | case SuperType::TY_GENERIC, SuperType::TY_ALIAS: { | ||
| 188 | 254982 | name << this.subType; | |
| 189 | 254982 | } | |
| 190 | case SuperType::TY_DYN: { | ||
| 191 | 760 | name << "dyn"; | |
| 192 | 760 | } | |
| 193 | case SuperType::TY_FUNCTION: { | ||
| 194 | 78317 | name << "f"; | |
| 195 | 78317 | if this.data.hasCaptures { name << "[]"; } | |
| 196 | 78317 | if !this.paramTypes.isEmpty() { | |
| 197 | 77557 | const QualType& returnType = this.paramTypes.front(); | |
| 198 | 77557 | name << "<"; | |
| 199 | 77557 | returnType.getName(name, true, ignorePublic); | |
| 200 | 77557 | name << ">"; | |
| 201 | 77557 | } | |
| 202 | 78317 | name << "("; | |
| 203 | 163662 | for unsigned long i = 1ul; i < this.paramTypes.getSize(); i++ { | |
| 204 | 85345 | if i > 1ul { name << ","; } | |
| 205 | 85345 | const QualType& paramType = this.paramTypes.get(i); | |
| 206 | 85345 | paramType.getName(name, true, ignorePublic); | |
| 207 | 85345 | } | |
| 208 | 78317 | name << ")"; | |
| 209 | 78317 | } | |
| 210 | case SuperType::TY_PROCEDURE: { | ||
| 211 | 59311 | name << "p"; | |
| 212 | 59311 | if this.data.hasCaptures { name << "[]"; } | |
| 213 | 59311 | name << "("; | |
| 214 | 119274 | for unsigned long i = 1ul; i < this.paramTypes.getSize(); i++ { | |
| 215 | 59963 | if i > 1ul { name << ","; } | |
| 216 | 59963 | const QualType& paramType = this.paramTypes.get(i); | |
| 217 | 59963 | paramType.getName(name, true, ignorePublic); | |
| 218 | 59963 | } | |
| 219 | 59311 | name << ")"; | |
| 220 | 59311 | } | |
| 221 | case SuperType::TY_IMPORT: { | ||
| 222 | 4141 | name << "import"; | |
| 223 | 4141 | } | |
| 224 | case SuperType::TY_UNRESOLVED: { | ||
| 225 | ✗ | name << "unresolved"; | |
| 226 | ✗ | } | |
| 227 | case SuperType::TY_INVALID: { | ||
| 228 | 39430 | name << "invalid"; | |
| 229 | 39430 | } | |
| 230 | default: { | ||
| 231 | ✗ | panic(Error("Could not get name of this type chain element")); | |
| 232 | } | ||
| 233 | } | ||
| 234 | 1949865 | } | |
| 235 | |||
| 236 | /** | ||
| 237 | * Return the type name as string | ||
| 238 | * | ||
| 239 | * @param withSize Also encode array sizes | ||
| 240 | * @param ignorePublic Ignore public qualifier | ||
| 241 | * @param withAliases Print aliases as is and not decompose them | ||
| 242 | * @return Name as string | ||
| 243 | */ | ||
| 244 | ✗ | public const f<String> TypeChainElement.getName(bool withSize, bool ignorePublic, bool withAliases) { | |
| 245 | ✗ | StringStream name; | |
| 246 | ✗ | this.getName(name, withSize, ignorePublic, withAliases); | |
| 247 | ✗ | return name.str(); | |
| 248 | ✗ | } | |
| 249 | |||
| 250 | public type TypeChain alias Vector<TypeChainElement>; | ||
| 251 |