global/runtime-module-manager.spice
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | // Std imports | ||
| 4 | import "std/data/unordered-map"; | ||
| 5 | |||
| 6 | // Own imports | ||
| 7 | import "@/source-file"; | ||
| 8 | import "@/util/system-util"; | ||
| 9 | import "@/global/global-resource-manager"; | ||
| 10 | import "@/symboltablebuilder/qual-type"; | ||
| 11 | |||
| 12 | // Constants | ||
| 13 | const string STRING_RT_IMPORT_NAME = "__rt_string"; | ||
| 14 | const string RESULT_RT_IMPORT_NAME = "__rt_result"; | ||
| 15 | const string ERROR_RT_IMPORT_NAME = "__rt_error"; | ||
| 16 | const string ERROR_TRACE_RT_IMPORT_NAME = "__rt_error_trace"; | ||
| 17 | const string MEMORY_RT_IMPORT_NAME = "__rt_memory"; | ||
| 18 | const string RTTI_RT_IMPORT_NAME = "__rt_rtti"; | ||
| 19 | const string STACK_TRACE_RT_IMPORT_NAME = "__rt_stack_trace"; | ||
| 20 | |||
| 21 | public type RuntimeModule enum { | ||
| 22 | STRING_RT = 1, | ||
| 23 | RESULT_RT = 2, | ||
| 24 | ERROR_RT = 4, | ||
| 25 | ERROR_TRACE_RT = 8, | ||
| 26 | MEMORY_RT = 16, | ||
| 27 | RTTI_RT = 32, | ||
| 28 | STACK_TRACE_RT = 64 | ||
| 29 | } | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Get the runtime module, that is required when using the type with the given name | ||
| 33 | * | ||
| 34 | * @param typeName Type name | ||
| 35 | * @param runtimeModule Receives the runtime module, if found | ||
| 36 | * @return True if the type requires a runtime module | ||
| 37 | */ | ||
| 38 | 140855 | public f<bool> getRuntimeModuleForTypeName(const String& typeName, RuntimeModule& runtimeModule) { | |
| 39 | 140855 | if typeName == STROBJ_NAME { | |
| 40 | 21494 | runtimeModule = RuntimeModule::STRING_RT; | |
| 41 | 140855 | } else if typeName == RESULTOBJ_NAME { | |
| 42 | 3660 | runtimeModule = RuntimeModule::RESULT_RT; | |
| 43 | 119361 | } else if typeName == ERROBJ_NAME { | |
| 44 | 4627 | runtimeModule = RuntimeModule::ERROR_RT; | |
| 45 | 4627 | } else { | |
| 46 | 111074 | return false; | |
| 47 | 8287 | } | |
| 48 | 29781 | return true; | |
| 49 | } | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Get the runtime module, that is required when calling the function with the given name | ||
| 53 | * | ||
| 54 | * @param functionName Function name | ||
| 55 | * @param runtimeModule Receives the runtime module, if found | ||
| 56 | * @return True if the function requires a runtime module | ||
| 57 | */ | ||
| 58 | 40741 | public f<bool> getRuntimeModuleForFunctionName(const String& functionName, RuntimeModule& runtimeModule) { | |
| 59 | // Memory RT | ||
| 60 | 40741 | if functionName == "sAlloc" || functionName == "sAllocUnsafe" || functionName == "sRealloc" || functionName == "sReallocUnsafe" | |
| 61 | 39906 | || functionName == "sCopy" || functionName == "sCopyUnsafe" || functionName == "sMove" || functionName == "sDestruct" | |
| 62 | 40741 | || functionName == "sDealloc" || functionName == "sDelete" || functionName == "sCompare" { | |
| 63 | 2399 | runtimeModule = RuntimeModule::MEMORY_RT; | |
| 64 | 40741 | } else if functionName == "ok" || functionName == "err" { // Result RT | |
| 65 | 1563 | runtimeModule = RuntimeModule::RESULT_RT; | |
| 66 | 38342 | } else if functionName == "sErrTraceReset" || functionName == "sErrTracePush" || functionName == "sErrTraceDump" { // Error Trace RT | |
| 67 | 332 | runtimeModule = RuntimeModule::ERROR_TRACE_RT; | |
| 68 | 36779 | } else if functionName == "sDumpStacktrace" || functionName == "sGetStacktrace" { // Stack Trace RT | |
| 69 | 4 | runtimeModule = RuntimeModule::STACK_TRACE_RT; | |
| 70 | 4 | } else { | |
| 71 | 36443 | return false; | |
| 72 | 1899 | } | |
| 73 | 4298 | return true; | |
| 74 | } | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Get the name of a top level definition, that identifies a source file as the given runtime module | ||
| 78 | * | ||
| 79 | * @param runtimeModule Runtime module | ||
| 80 | * @return Identifying top level name | ||
| 81 | */ | ||
| 82 | 45267 | public f<string> getIdentifyingTopLevelName(RuntimeModule runtimeModule) { | |
| 83 | 45267 | switch runtimeModule { | |
| 84 | 26222 | case RuntimeModule::STRING_RT: { return STROBJ_NAME; } // String struct | |
| 85 | 5228 | case RuntimeModule::RESULT_RT: { return RESULTOBJ_NAME; } // Result struct | |
| 86 | 4627 | case RuntimeModule::ERROR_RT: { return ERROBJ_NAME; } // Error struct | |
| 87 | 332 | case RuntimeModule::ERROR_TRACE_RT: { return "sErrTracePush"; } // sErrTracePush function | |
| 88 | 6350 | case RuntimeModule::MEMORY_RT: { return "sAlloc"; } // sAlloc function | |
| 89 | 2489 | case RuntimeModule::RTTI_RT: { return TIOBJ_NAME; } // TypeInfo struct | |
| 90 | 19 | case RuntimeModule::STACK_TRACE_RT: { return "sDumpStacktrace"; } // sDumpStacktrace function | |
| 91 | − | default: { panic(Error("Requested unknown runtime module")); } // LCOV_EXCL_LINE | |
| 92 | } | ||
| 93 | ✗ | } | |
| 94 | |||
| 95 | type ModuleNamePair struct { | ||
| 96 | string importName | ||
| 97 | string fileName | ||
| 98 | } | ||
| 99 | |||
| 100 | 766 | public type RuntimeModuleManager struct { | |
| 101 | GlobalResourceManager &resourceManager | ||
| 102 | UnorderedMap<RuntimeModule, SourceFile *> modules | ||
| 103 | } | ||
| 104 | |||
| 105 | 1055 | public p RuntimeModuleManager.ctor(GlobalResourceManager &resourceManager) { | |
| 106 | 1055 | this.resourceManager = resourceManager; | |
| 107 | 1055 | } | |
| 108 | |||
| 109 | 3522 | public f<SourceFile *> RuntimeModuleManager.requestModule(SourceFile* parentSourceFile, RuntimeModule requestedModule) { | |
| 110 | 3522 | const String importName = String(this.resolveNamePair(requestedModule).importName); | |
| 111 | |||
| 112 | // Check if the requested module is available already, if not load it | ||
| 113 | 3522 | dyn rtFile = this.isModuleAvailable(requestedModule) ? this.getModule(requestedModule) : this.loadModule(parentSourceFile, requestedModule); | |
| 114 | |||
| 115 | // Add the dependency to the parent source file | ||
| 116 | 3522 | parentSourceFile.addDependency(rtFile, importName); | |
| 117 | 3522 | assert parentSourceFile.dependencies.contains(importName); | |
| 118 | 3522 | SourceFile* runtimeFile = parentSourceFile.dependencies.get(importName); | |
| 119 | 3522 | this.modules.upsert(requestedModule, runtimeFile); | |
| 120 | |||
| 121 | // Merge the module name registry with the one of the source file | ||
| 122 | 3522 | parentSourceFile.mergeNameRegistries(*rtFile, importName); | |
| 123 | |||
| 124 | // Tell the source file, that the requested runtime has been imported | ||
| 125 | 3522 | parentSourceFile.importedRuntimeModules |= requestedModule; | |
| 126 | |||
| 127 | 7044 | return runtimeFile; | |
| 128 | 3522 | } | |
| 129 | |||
| 130 | 20040 | public f<SourceFile *> RuntimeModuleManager.getModule(RuntimeModule requestedModule) { | |
| 131 | 20040 | assert this.modules.contains(requestedModule); | |
| 132 | 20040 | return this.modules.get(requestedModule); | |
| 133 | } | ||
| 134 | |||
| 135 | 3522 | public f<bool> RuntimeModuleManager.isModuleAvailable(RuntimeModule requestedModule) { | |
| 136 | 3522 | return this.modules.contains(requestedModule); | |
| 137 | } | ||
| 138 | |||
| 139 | 1490 | public f<SourceFile *> RuntimeModuleManager.loadModule(SourceFile* parentSourceFile, RuntimeModule requestedModule) { | |
| 140 | 1490 | const ModuleNamePair namePair = this.resolveNamePair(requestedModule); | |
| 141 | 1490 | const FilePath filePath = getStdDir() / "runtime" / (String(namePair.fileName) + ".spice"); | |
| 142 | 1490 | assert filePath != parentSourceFile.filePath; | |
| 143 | |||
| 144 | // Instruct the global resource manager to create a new source file | ||
| 145 | 1490 | SourceFile* moduleSourceFile = this.resourceManager.createSourceFile(parentSourceFile, String(namePair.importName), filePath, true); | |
| 146 | 1490 | moduleSourceFile.isMainFile = false; | |
| 147 | |||
| 148 | // Run frontend and first type checker run for the loaded source file | ||
| 149 | 1490 | moduleSourceFile.runFrontEnd(); | |
| 150 | // Merge the runtime module's own dependency registries (deferred tail of the front-end, see SourceFile.runMiddleEnd) | ||
| 151 | 1490 | moduleSourceFile.mergeNameRegistriesRecursive(); | |
| 152 | 1490 | moduleSourceFile.runTypeCheckerPre(); | |
| 153 | |||
| 154 | 2980 | return moduleSourceFile; | |
| 155 | 1490 | } | |
| 156 | |||
| 157 | 5012 | public f<ModuleNamePair> RuntimeModuleManager.resolveNamePair(RuntimeModule requestedModule) { | |
| 158 | 5012 | switch requestedModule { | |
| 159 | case RuntimeModule::STRING_RT: { | ||
| 160 | 1038 | return ModuleNamePair{STRING_RT_IMPORT_NAME, "string_rt"}; | |
| 161 | } | ||
| 162 | case RuntimeModule::RESULT_RT: { | ||
| 163 | 683 | return ModuleNamePair{RESULT_RT_IMPORT_NAME, "result_rt"}; | |
| 164 | } | ||
| 165 | case RuntimeModule::ERROR_RT: { | ||
| 166 | 1291 | return ModuleNamePair{ERROR_RT_IMPORT_NAME, "error_rt"}; | |
| 167 | } | ||
| 168 | case RuntimeModule::ERROR_TRACE_RT: { | ||
| 169 | 664 | return ModuleNamePair{ERROR_TRACE_RT_IMPORT_NAME, "error_trace_rt"}; | |
| 170 | } | ||
| 171 | case RuntimeModule::MEMORY_RT: { | ||
| 172 | 610 | return ModuleNamePair{MEMORY_RT_IMPORT_NAME, "memory_rt"}; | |
| 173 | } | ||
| 174 | case RuntimeModule::RTTI_RT: { | ||
| 175 | 712 | return ModuleNamePair{RTTI_RT_IMPORT_NAME, "rtti_rt"}; | |
| 176 | } | ||
| 177 | case RuntimeModule::STACK_TRACE_RT: { | ||
| 178 | 14 | return ModuleNamePair{STACK_TRACE_RT_IMPORT_NAME, "stack_trace_rt"}; | |
| 179 | } | ||
| 180 | default: { // LCOV_EXCL_LINE | ||
| 181 | − | panic(Error("Requested unknown runtime module")); // LCOV_EXCL_LINE | |
| 182 | } // LCOV_EXCL_LINE | ||
| 183 | } | ||
| 184 | ✗ | } | |
| 185 |