From e7eaf3e9a1c145ece454dd7fe214618d6a8ef802 Mon Sep 17 00:00:00 2001 From: Viper Date: Sun, 19 Jul 2026 13:18:46 +0800 Subject: [PATCH] Initial import of TransPyV --- .gitignore | 25 + App/lib/Projectrans/Config.py | 299 ++ App/lib/Projectrans/Utils.py | 117 + App/lib/Projectrans/__init__.py | 12 + App/lib/__init__.py | 27 + App/lib/core/BuildPipeline.py | 502 +++ App/lib/core/Handles/HandlesAnnAssign.py | 281 ++ App/lib/core/Handles/HandlesAssign.py | 231 ++ App/lib/core/Handles/HandlesAugAssign.py | 254 ++ App/lib/core/Handles/HandlesBase.py | 262 ++ App/lib/core/Handles/HandlesBody.py | 230 ++ App/lib/core/Handles/HandlesClassDef.py | 2327 ++++++++++++ App/lib/core/Handles/HandlesEnum.py | 230 ++ App/lib/core/Handles/HandlesExpr.py | 1525 ++++++++ App/lib/core/Handles/HandlesExprCall.py | 3972 +++++++++++++++++++++ App/lib/core/Handles/HandlesExprOps.py | 287 ++ App/lib/core/Handles/HandlesFor.py | 384 ++ App/lib/core/Handles/HandlesFunctions.py | 936 +++++ App/lib/core/Handles/HandlesIf.py | 141 + App/lib/core/Handles/HandlesImports.py | 404 +++ App/lib/core/Handles/HandlesMain.py | 314 ++ App/lib/core/Handles/HandlesNonlocal.py | 127 + App/lib/core/Handles/HandlesReturn.py | 101 + App/lib/core/Handles/HandlesStruct.py | 975 +++++ App/lib/core/Handles/HandlesTranslator.py | 417 +++ App/lib/core/Handles/HandlesType.py | 1185 ++++++ App/lib/core/Handles/HandlesVar.py | 365 ++ App/lib/core/Handles/HandlesWhile.py | 130 + App/lib/core/Handles/__init__.py | 23 + App/lib/core/IncludesScanner.py | 364 ++ App/lib/core/Phase1.py | 540 +++ App/lib/core/Phase2.py | 680 ++++ App/lib/core/StubMerger.py | 1477 ++++++++ App/lib/core/VLogger.py | 171 + App/lib/core/__init__.py | 9 + App/main.py | 510 +++ Test/App/asm_test.py | 47 + Test/App/attr_test.py | 234 ++ Test/App/augassign_test.py | 58 + Test/App/closure_test.py | 45 + Test/App/deco_test.py | 183 + Test/App/deref_min_test.py | 9 + Test/App/deref_test.py | 13 + Test/App/eq_test.py | 144 + Test/App/float_test.py | 84 + Test/App/flow_test.py | 23 + Test/App/for_test.py | 8 + Test/App/func_test.py | 68 + Test/App/func_vtable_test.py | 116 + Test/App/generic_test.py | 102 + Test/App/inherit_test.py | 121 + Test/App/llvmir_test.py | 247 ++ Test/App/namespace_defs.py | 60 + Test/App/namespace_test.py | 111 + Test/App/new_test.py | 119 + Test/App/oop_test.py | 129 + Test/App/opovl_test.py | 253 ++ Test/App/ptr_only_test.py | 26 + Test/App/ptr_test.py | 111 + Test/App/simple_test.py | 6 + Test/App/string_min_test.py | 9 + Test/App/string_test.py | 106 + Test/App/struct_test.py | 235 ++ Test/App/test_main.py | 109 + Test/App/testcheck_test.py | 37 + Test/App/type_bit_test.py | 26 + Test/App/virtual_dispatch_test.py | 83 + Test/App/vtable_test.py | 63 + Test/NegativeTest/App/defs.py | 20 + Test/NegativeTest/App/main.py | 21 + Test/NegativeTest/project.vpj | 29 + Test/Sha1Test/App/main.py | 62 + Test/Sha1Test/project.vpj | 28 + Test/project.vpj | 29 + project.json | 29 + 75 files changed, 23037 insertions(+) create mode 100644 .gitignore create mode 100644 App/lib/Projectrans/Config.py create mode 100644 App/lib/Projectrans/Utils.py create mode 100644 App/lib/Projectrans/__init__.py create mode 100644 App/lib/__init__.py create mode 100644 App/lib/core/BuildPipeline.py create mode 100644 App/lib/core/Handles/HandlesAnnAssign.py create mode 100644 App/lib/core/Handles/HandlesAssign.py create mode 100644 App/lib/core/Handles/HandlesAugAssign.py create mode 100644 App/lib/core/Handles/HandlesBase.py create mode 100644 App/lib/core/Handles/HandlesBody.py create mode 100644 App/lib/core/Handles/HandlesClassDef.py create mode 100644 App/lib/core/Handles/HandlesEnum.py create mode 100644 App/lib/core/Handles/HandlesExpr.py create mode 100644 App/lib/core/Handles/HandlesExprCall.py create mode 100644 App/lib/core/Handles/HandlesExprOps.py create mode 100644 App/lib/core/Handles/HandlesFor.py create mode 100644 App/lib/core/Handles/HandlesFunctions.py create mode 100644 App/lib/core/Handles/HandlesIf.py create mode 100644 App/lib/core/Handles/HandlesImports.py create mode 100644 App/lib/core/Handles/HandlesMain.py create mode 100644 App/lib/core/Handles/HandlesNonlocal.py create mode 100644 App/lib/core/Handles/HandlesReturn.py create mode 100644 App/lib/core/Handles/HandlesStruct.py create mode 100644 App/lib/core/Handles/HandlesTranslator.py create mode 100644 App/lib/core/Handles/HandlesType.py create mode 100644 App/lib/core/Handles/HandlesVar.py create mode 100644 App/lib/core/Handles/HandlesWhile.py create mode 100644 App/lib/core/Handles/__init__.py create mode 100644 App/lib/core/IncludesScanner.py create mode 100644 App/lib/core/Phase1.py create mode 100644 App/lib/core/Phase2.py create mode 100644 App/lib/core/StubMerger.py create mode 100644 App/lib/core/VLogger.py create mode 100644 App/lib/core/__init__.py create mode 100644 App/main.py create mode 100644 Test/App/asm_test.py create mode 100644 Test/App/attr_test.py create mode 100644 Test/App/augassign_test.py create mode 100644 Test/App/closure_test.py create mode 100644 Test/App/deco_test.py create mode 100644 Test/App/deref_min_test.py create mode 100644 Test/App/deref_test.py create mode 100644 Test/App/eq_test.py create mode 100644 Test/App/float_test.py create mode 100644 Test/App/flow_test.py create mode 100644 Test/App/for_test.py create mode 100644 Test/App/func_test.py create mode 100644 Test/App/func_vtable_test.py create mode 100644 Test/App/generic_test.py create mode 100644 Test/App/inherit_test.py create mode 100644 Test/App/llvmir_test.py create mode 100644 Test/App/namespace_defs.py create mode 100644 Test/App/namespace_test.py create mode 100644 Test/App/new_test.py create mode 100644 Test/App/oop_test.py create mode 100644 Test/App/opovl_test.py create mode 100644 Test/App/ptr_only_test.py create mode 100644 Test/App/ptr_test.py create mode 100644 Test/App/simple_test.py create mode 100644 Test/App/string_min_test.py create mode 100644 Test/App/string_test.py create mode 100644 Test/App/struct_test.py create mode 100644 Test/App/test_main.py create mode 100644 Test/App/testcheck_test.py create mode 100644 Test/App/type_bit_test.py create mode 100644 Test/App/virtual_dispatch_test.py create mode 100644 Test/App/vtable_test.py create mode 100644 Test/NegativeTest/App/defs.py create mode 100644 Test/NegativeTest/App/main.py create mode 100644 Test/NegativeTest/project.vpj create mode 100644 Test/Sha1Test/App/main.py create mode 100644 Test/Sha1Test/project.vpj create mode 100644 Test/project.vpj create mode 100644 project.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..16c5449 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so + +# 备份 +*.bak + +# 构建产物(防御性) +**/output/ +**/temp/ +**/*.deps.json +**/*.doc.json +**/*.pyi +**/*.elf +**/*.o +**/*.obj + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ diff --git a/App/lib/Projectrans/Config.py b/App/lib/Projectrans/Config.py new file mode 100644 index 0000000..962aebe --- /dev/null +++ b/App/lib/Projectrans/Config.py @@ -0,0 +1,299 @@ +import t, c +from stdint import * +import memhub +import string +import stdio +import viperlib +from json.__parser import parse as json_parse +from json import JsonValue, JSON_OBJECT, JSON_INT +import w32.fileio as fileio + + +# ============================================================ +# Config - 工程配置 +# ============================================================ + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemManager | t.CPtr + +# 配置值(从 project.vpj 加载) +SourceDir: str +TempDir: str +OutputDir: str +ProjectName: str +ProjectVersion: str +CompilerCmd: str +CompilerFlags: str # 编译器参数(空格分隔,从 compiler.flags 数组拼接) +LinkerCmd: str +LinkerFlags: str # 链接器参数(空格分隔,从 linker.flags 数组拼接) +LinkerOutput: str +TargetTriple: str +TargetDataLayout: str +SliceLevel: t.CInt +StrictMode: t.CInt +IncludesDir: str # includes 目录路径(从 includes 数组首元素) + + +def Load_project_config(path: str) -> int: + """加载工程配置文件(project.vpj) + + Args: + path: 配置文件路径 + + Returns: + 0 表示成功,非 0 表示失败 + """ + global SourceDir, TempDir, OutputDir, ProjectName, ProjectVersion + global CompilerCmd, CompilerFlags, LinkerCmd, LinkerFlags, LinkerOutput + global TargetTriple, TargetDataLayout, SliceLevel, StrictMode + global IncludesDir + + if path is None: + return 1 + if _mbuddy is None: + return 1 + + # 打开文件 + f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.R) + if f.closed: + return 1 + + # 分配读取缓冲区 + CFG_BUF_SIZE: t.CSizeT = 8192 + buf: bytes = _mbuddy.alloc(CFG_BUF_SIZE) + if buf is None: + f.close() + return 1 + + bytes_read: t.CInt64T = f.read_all(buf, CFG_BUF_SIZE) + f.close() + if bytes_read <= 0: + return 1 + + # 解析 JSON + root: JsonValue | t.CPtr = json_parse(_mbuddy, buf) + if root is None: + return 1 + if not root.is_object(): + return 1 + + # 读取顶层字段 + SourceDir = root["source_dir"].as_string() if root["source_dir"] is not None else None + TempDir = root["temp_dir"].as_string() if root["temp_dir"] is not None else None + OutputDir = root["output_dir"].as_string() if root["output_dir"] is not None else None + ProjectName = root["name"].as_string() if root["name"] is not None else None + ProjectVersion = root["version"].as_string() if root["version"] is not None else None + + # 读取 compiler 子对象 + compiler: JsonValue | t.CPtr = root["compiler"] + if compiler is not None and compiler.is_object(): + CompilerCmd = compiler["cmd"].as_string() if compiler["cmd"] is not None else None + # 读取 compiler.flags 数组,拼接成空格分隔的字符串 + cc_flags_val: JsonValue | t.CPtr = compiler["flags"] + CompilerFlags = _join_flags_array(cc_flags_val) + + # 读取 linker 子对象 + linker: JsonValue | t.CPtr = root["linker"] + if linker is not None and linker.is_object(): + LinkerCmd = linker["cmd"].as_string() if linker["cmd"] is not None else None + LinkerOutput = linker["output"].as_string() if linker["output"] is not None else None + # 读取 linker.flags 数组,拼接成空格分隔的字符串 + ld_flags_val: JsonValue | t.CPtr = linker["flags"] + LinkerFlags = _join_flags_array(ld_flags_val) + + # 读取 target 子对象 + target: JsonValue | t.CPtr = root["target"] + if target is not None and target.is_object(): + TargetTriple = target["triple"].as_string() if target["triple"] is not None else None + TargetDataLayout = target["datalayout"].as_string() if target["datalayout"] is not None else None + + # 读取 options 子对象 + options: JsonValue | t.CPtr = root["options"] + if options is not None and options.is_object(): + sl: JsonValue | t.CPtr = options["slice_level"] + if sl is not None and sl.is_int(): + SliceLevel = sl.as_int() + sm: JsonValue | t.CPtr = options["strict_mode"] + if sm is not None and sm.is_bool(): + StrictMode = 1 if sm.as_bool() else 0 + + # 读取 includes 数组(取首个元素作为 includes 目录) + includes_val: JsonValue | t.CPtr = root["includes"] + if includes_val is not None and includes_val.is_array(): + arr_len: t.CSizeT = includes_val.__len__() + if arr_len > 0: + first_inc: JsonValue | t.CPtr = includes_val.get_item(0) + if first_inc is not None and first_inc.is_string(): + IncludesDir = first_inc.as_string() + + return 0 + + +def _join_flags_array(flags_val: JsonValue | t.CPtr) -> str: + """将 JSON 字符串数组拼接成空格分隔的字符串 + + 用于 linker.flags 和 compiler.flags 数组。 + 用 while + 索引遍历,避免 list 迭代器 bug。 + + Args: + flags_val: JsonValue,应为字符串数组 + + Returns: + 空格分隔的字符串,或 None 如果 flags_val 为 None 或非数组或空数组 + """ + if flags_val is None: + return None + if not flags_val.is_array(): + return None + + arr_len: t.CSizeT = flags_val.__len__() + if arr_len == 0: + return None + + # 第一遍:计算总长度(所有 flag 长度 + 空格分隔符) + total_len: t.CSizeT = 0 + i: t.CSizeT = 0 + while i < arr_len: + item: JsonValue | t.CPtr = flags_val.get_item(i) + if item is not None and item.is_string(): + s: str = item.as_string() + if s is not None: + total_len += string.strlen(s) + 1 # +1 for space + i += 1 + + if total_len == 0: + return None + + # 分配缓冲区(total_len 已含每个 flag 后的空格,最后一个是 '\0') + buf: str = _mbuddy.alloc(total_len + 1) + if buf is None: + return None + + # 第二遍:拼接(flag 之间用空格分隔) + pos: t.CSizeT = 0 + i = 0 + while i < arr_len: + item = flags_val.get_item(i) + if item is not None and item.is_string(): + s = item.as_string() + if s is not None: + slen: t.CSizeT = string.strlen(s) + if pos > 0: + buf[pos] = ' ' + pos += 1 + string.strcpy(buf + pos, s) + pos += slen + i += 1 + buf[pos] = '\0' + return buf + + +def _join_path(rel: str, project_dir: str) -> str: + """将相对路径与 project_dir 拼接为绝对路径 + + - ./App + Test → Test/App + - ./temp + Test → Test/temp + - ../includes + Test → Test/../includes(OS 解析为 includes) + - 绝对路径保持不变 + - None 返回 None + """ + if rel is None: + return None + # 绝对路径(以 / 或 \ 开头)保持不变 + if rel[0] == '/' or rel[0] == '\\': + return rel + + rel_len: t.CSizeT = string.strlen(rel) + dir_len: t.CSizeT = string.strlen(project_dir) + + # 处理 ../ 或 ..\\ 前缀:拼接 project_dir/../... + if rel_len >= 3 and rel[0] == '.' and rel[1] == '.': + if rel[2] == '/' or rel[2] == '\\': + if dir_len == 0: + return rel + total_len: t.CSizeT = dir_len + 1 + rel_len + 1 + buf: str = _mbuddy.alloc(total_len) + if buf is None: + return rel + viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel) + return buf + + # 处理 ./ 或 .\\ 前缀:拼接 project_dir + rel[2:] + rel_off: t.CSizeT = 0 + if rel_len >= 2 and rel[0] == '.': + if rel[1] == '/' or rel[1] == '\\': + rel_off = 2 + else: + return rel # 不是 ./ 开头,保持不变 + else: + return rel # 不是 . 开头,保持不变 + + if dir_len == 0: + # project_dir 为空(当前目录),去掉 ./ 前缀即可 + return rel + rel_off + # 拼接: project_dir + "/" + rel[rel_off:] + total_len = dir_len + 1 + (rel_len - rel_off) + 1 + buf = _mbuddy.alloc(total_len) + if buf is None: + return rel # 分配失败,返回原路径 + viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel + rel_off) + return buf + + +def resolve_paths(project_dir: str) -> int: + """解析并规范化工程路径(src/temp/output/includes) + + 将 project.vpj 中的相对路径(以 ./ 开头)转换为基于 project_dir 的路径。 + + Args: + project_dir: 工程根目录(project.vpj 所在目录) + + Returns: + 0 表示成功,非 0 表示失败 + """ + global SourceDir, TempDir, OutputDir, IncludesDir + if project_dir is None: + return 1 + if _mbuddy is None: + return 1 + + SourceDir = _join_path(SourceDir, project_dir) + TempDir = _join_path(TempDir, project_dir) + OutputDir = _join_path(OutputDir, project_dir) + # includes 路径可能是 ../includes 形式,需要基于 project_dir 解析 + if IncludesDir is not None: + IncludesDir = _join_path(IncludesDir, project_dir) + return 0 + + +def get_includes_binary_dir() -> str: + """获取 includes.binary 目录路径(includes 目录 + .binary 后缀) + + includes 目录如 ../includes,则 includes.binary 为 ../includes.binary + """ + if IncludesDir is None: + return None + inc_len: t.CSizeT = string.strlen(IncludesDir) + buf: str = _mbuddy.alloc(inc_len + 8) + if buf is None: + return None + viperlib.snprintf(buf, inc_len + 8, "%s.binary", IncludesDir) + return buf + + +def print_config(): + """打印当前配置(调试用)""" + if ProjectName is not None: + stdio.printf(" project: %s v%s\n", ProjectName, ProjectVersion if ProjectVersion is not None else "?") + if SourceDir is not None: + stdio.printf(" source_dir: %s\n", SourceDir) + if TempDir is not None: + stdio.printf(" temp_dir: %s\n", TempDir) + if OutputDir is not None: + stdio.printf(" output_dir: %s\n", OutputDir) + if CompilerCmd is not None: + stdio.printf(" compiler: %s\n", CompilerCmd) + if LinkerCmd is not None: + stdio.printf(" linker: %s -> %s\n", LinkerCmd, LinkerOutput if LinkerOutput is not None else "?") + if IncludesDir is not None: + stdio.printf(" includes: %s\n", IncludesDir) \ No newline at end of file diff --git a/App/lib/Projectrans/Utils.py b/App/lib/Projectrans/Utils.py new file mode 100644 index 0000000..e0e25a1 --- /dev/null +++ b/App/lib/Projectrans/Utils.py @@ -0,0 +1,117 @@ +import t, c +from stdint import * +import memhub +import string +import stdlib +import viperlib +import hashlib +import w32.win32file +import w32.win32base + + +# ============================================================ +# Utils - 工程工具函数 +# +# 提供 SHA1 计算和目录清理等通用工具函数。 +# ============================================================ + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemManager | t.CPtr + + +# ============================================================ +# compute_sha1 - 计算字符串的 SHA1,返回前 16 个十六进制字符 +# +# 使用 includes/hashlib 库的 sha1 类计算摘要,转为十六进制字符串。 +# 参考 Projectrans.py 的 compute_sha1(hashlib.sha1().hexdigest()[:16])。 +# ============================================================ +def compute_sha1(pool: memhub.MemBuddy | t.CPtr, content: str) -> str: + """计算字符串的 SHA1,返回前 16 个十六进制字符(用于文件命名)""" + if content is None or pool is None: + return None + + # 构造 sha1 对象(__init__ 会初始化 state/count/buf) + # ctx 在栈上分配(alloca),函数内使用完即丢弃,无需堆分配 + ctx: hashlib.sha1 | t.CPtr = hashlib.sha1() + if ctx is None: + return None + + # 计算摘要 + ctx.update(content) + digest: bytes = pool.alloc(hashlib.SHA1_DIGEST_LEN) + if digest is None: + return None + ctx.final(digest) + + # 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符) + hex_buf: str = pool.alloc(17) + if hex_buf is None: + return None + for i in range(8): + hi: int = (digest[i] >> 4) & 0xF + lo: int = digest[i] & 0xF + if hi < 10: + hex_buf[i * 2] = '0' + hi + else: + hex_buf[i * 2] = 'a' + (hi - 10) + if lo < 10: + hex_buf[i * 2 + 1] = '0' + lo + else: + hex_buf[i * 2 + 1] = 'a' + (lo - 10) + hex_buf[16] = '\0' + return hex_buf + + +# ============================================================ +# CleanDir - 删除目录中所有文件(非递归,保留目录本身) +# +# 用于 --clean 选项:清理 temp_dir 和 output_dir 中的旧文件。 +# ============================================================ +def CleanDir(dir_path: str) -> int: + """删除目录中所有文件(非递归),返回删除的文件数,-1 表示错误""" + if dir_path is None: + return -1 + dir_len: t.CSizeT = string.strlen(dir_path) + pattern: bytes = stdlib.malloc(dir_len + 8) + if pattern is None: + return -1 + viperlib.snprintf(pattern, dir_len + 8, "%s/*", dir_path) + + find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + if find_data is None: + stdlib.free(pattern) + return -1 + string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + stdlib.free(pattern) + stdlib.free(find_data) + return 0 + + deleted: int = 0 + while 1: + fname: str = find_data.cFileName + if fname is not None: + # 跳过 . 和 .. + if fname[0] == '.': + if fname[1] == '\0': + fname = None + elif fname[1] == '.' and fname[2] == '\0': + fname = None + if fname is not None: + fname_len: t.CSizeT = string.strlen(fname) + full_path: bytes = stdlib.malloc(dir_len + fname_len + 2) + if full_path is not None: + viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", dir_path, fname) + if w32.win32file.DeleteFileA(full_path) != 0: + deleted += 1 + stdlib.free(full_path) + + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + + w32.win32file.FindClose(handle) + stdlib.free(pattern) + stdlib.free(find_data) + return deleted diff --git a/App/lib/Projectrans/__init__.py b/App/lib/Projectrans/__init__.py new file mode 100644 index 0000000..64656ea --- /dev/null +++ b/App/lib/Projectrans/__init__.py @@ -0,0 +1,12 @@ +import t, c +from stdint import * + +from .Config import Load_project_config, resolve_paths +from .Utils import compute_sha1, CleanDir + +__all__ = [ + 'Load_project_config', + 'resolve_paths', + 'compute_sha1', + 'CleanDir', +] diff --git a/App/lib/__init__.py b/App/lib/__init__.py new file mode 100644 index 0000000..5294ca9 --- /dev/null +++ b/App/lib/__init__.py @@ -0,0 +1,27 @@ +import t, c +from stdint import * +import memhub +import lib.core.VLogger as VLogger + + +# ============================================================ +# lib 包入口 - 声明全局 _mbuddy 内存池指针 +# ============================================================ + +# 全局 mbuddy 内存池指针(由 App/main.py 初始化后注入) +_mbuddy: memhub.MemManager | t.CPtr + + +def InitLib(mb: memhub.MemManager | t.CPtr) -> int: + """初始化 lib 包的全局 _mbuddy 指针,并级联注入到所有子模块。 + + Args: + mb: memhub.MemManager 实例指针(MemBuddy 等子类通过多态传入) + + Returns: + 0 表示成功,非 0 表示失败 + """ + if mb is None: + return 1 + VLogger._mbuddy = mb + return 0 diff --git a/App/lib/core/BuildPipeline.py b/App/lib/core/BuildPipeline.py new file mode 100644 index 0000000..64f1183 --- /dev/null +++ b/App/lib/core/BuildPipeline.py @@ -0,0 +1,502 @@ +import t, c +from stdint import * +import stdio +import string +import stdlib +import memhub +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import subprocess +import viperlib +import ast +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesImports as HandlesImports + +# ============================================================ +# BuildPipeline - 编译管线 +# +# 负责将 LLVM IR 编译为可执行文件: +# 1. 写 .ll 文件到 temp 目录 +# 2. 调用 llc 编译 .ll → .obj +# 3. 调用 clang++ 链接 .obj → .exe +# ============================================================ + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemManager | t.CPtr + +# 源代码缓冲区大小(1MB) +SRC_BUF_SIZE: t.CDefine = 1048576 + + +# ============================================================ +# TranslateFileGetTrans - 翻译单个文件,返回 Translator 对象 +# +# 读取文件 → AST 解析 → LLVM IR 翻译,返回 Translator 对象供 +# 调用者 dump_ir。命名空间隔离:includes 文件宽松模式(全部可见), +# 用户文件严格模式(仅本地+import)。 +# +# Args: +# mb: 内存池 +# file_path: 源文件路径 +# sha1_val: 文件内容的 SHA1 前16字符(用于函数名混淆) +# +# Returns: +# Translator 对象(None 失败) +# ============================================================ +def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, + sha1_val: str, + current_package: str = None) -> HandlesTranslator.Translator | t.CPtr: + """翻译文件,返回 Translator 对象(调用者负责 dump_ir),None 失败 + + current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块 + """ + if file_path is None: + return None + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f.closed: + return None + src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf is None: + f.close() + return None + bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE) + f.close() + if bytes_read <= 0: + return None + if bytes_read < SRC_BUF_SIZE: + src_buf[bytes_read] = 0 + else: + src_buf[SRC_BUF_SIZE - 1] = 0 + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + ast._lexer_init(lx, src_buf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + if tree is None: + return None + tr: HandlesTranslator.Translator | t.CPtr = mb.alloc(HandlesTranslator.Translator.__sizeof__()) + tr.__before_init__() + tr.__init__() + tr.ModuleSha1 = sha1_val + tr.CurrentPackage = current_package + # 设置当前文件名(供报错使用) + HandlesType.set_current_file(file_path) + # 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离 + HandlesType.clear_cdefine_constants() + # 命名空间隔离:includes 文件宽松模式(全部可见),用户文件严格模式(仅本地+import) + strict_mode: int = 1 + if string.strstr(file_path, "includes") is not None: + strict_mode = 0 + HandlesStruct.reset_visible_structs(mb, strict_mode) + ret: int = tr.translate(tree) + if ret != 0: + return None + return tr + + +class BuildResult: + Success: t.CInt + OutputPath: str + ErrorMsg: str + + def __new__(self) -> t.CPtr: + return t.CPtr(_mbuddy.alloc(BuildResult.__sizeof__())) + + def __init__(self): + self.Success = 0 + self.OutputPath = None + self.ErrorMsg = None + + +def ensure_dir(path: str) -> int: + """递归创建目录(类似 mkdir -p),目录已存在视为成功 + + Args: + path: 目录路径(支持 / 或 \\ 分隔符) + + Returns: + 0 成功(包括目录已存在),非 0 失败 + """ + if path is None: + return 1 + + path_len: t.CSizeT = string.strlen(path) + if path_len == 0: + return 0 + + # 复制路径到可写缓冲区(逐级截断用) + buf: bytes = _mbuddy.alloc(path_len + 1) + if buf is None: + return 1 + string.strcpy(buf, path) + + # 遇到分隔符时临时截断,创建每一层目录 + # CreateDirectoryA 在目录已存在时返回 0(失败),忽略即可 + for i in range(path_len): + ch: int = c.Deref(buf + i) + if ch == ord('/') or ch == ord('\\'): + saved: int = ch + buf[i] = '\0' + w32.win32file.CreateDirectoryA(buf, None) + buf[i] = saved + + # 创建最终目录 + w32.win32file.CreateDirectoryA(buf, None) + return 0 + + +def write_ir_to_file(ir_buf: bytes, ir_len: t.CSizeT, output_dir: str, module_name: str) -> int: + """将 IR 缓冲区写入 .ll 文件 + + Args: + ir_buf: IR 文本缓冲区 + ir_len: IR 文本长度 + output_dir: 输出目录(temp 或 output) + module_name: 模块名(如 "main") + + Returns: + 0 成功,非 0 失败 + """ + if ir_buf is None or output_dir is None: + return 1 + + # 构造文件路径: output_dir/module_name.ll + dir_len: t.CSizeT = string.strlen(output_dir) + name_len: t.CSizeT = string.strlen(module_name) + path_len: t.CSizeT = dir_len + 1 + name_len + 4 # dir/module.ll\0 + path: bytes = _mbuddy.alloc(path_len) + if path is None: + return 1 + viperlib.snprintf(path, path_len, "%s/%s.ll", output_dir, module_name) + + # 打开文件写入 + f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.W) + if f.closed: + return 1 + + written: t.CInt64T = f.write(ir_buf, ir_len) + f.close() + if written < 0: + return 1 + return 0 + + +def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: str, cc_flags: str) -> int: + """调用 llc 将 .ll 编译为 .obj + + Args: + ir_path: .ll 文件路径 + output_dir: 输出目录 + module_name: 模块名(用于生成 .obj 文件名) + cc_cmd: 编译器命令(如 "llc") + cc_flags: 编译器参数(如 "-filetype=obj -relocation-model=pic") + + Returns: + 0 成功,非 0 失败 + """ + if ir_path is None or cc_cmd is None: + return 1 + + # 构造命令: llc -filetype=obj -o output_dir/module_name.obj ir_path + cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(output_dir) + string.strlen(module_name) + string.strlen(ir_path) + 64 + cmd: bytes = _mbuddy.alloc(cmd_len) + if cmd is None: + return 1 + viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s.obj %s", cc_cmd, cc_flags, output_dir, module_name, ir_path) + + result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) + if result is None: + stdio.printf("[FATAL][LLC] subprocess.run 返回 None: %s\n", module_name) + return 1 + if result.returncode != 0: + stdio.printf("[FATAL][LLC] 编译失败 (module=%s, cmd=%s)\n", module_name, cmd) + if result.stdout is not None: + stdio.printf("[LLC] 输出:\n%s\n", result.stdout) + return 1 + return 0 + + +def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT: + """扫描 includes_binary_dir 目录,收集所有 .obj 文件路径到 out_buf + + Args: + includes_binary_dir: includes.binary 目录路径 + out_buf: 输出缓冲区(用于存放空格分隔的 .obj 文件路径) + out_size: 输出缓冲区大小 + + Returns: + 写入的字节数(不含 null 终止符),0 表示无文件或错误 + """ + if includes_binary_dir is None or out_buf is None or out_size == 0: + return 0 + + out_buf[0] = '\0' + out_pos: t.CSizeT = 0 + + # 构造搜索模式: dir/*.obj + dir_len: t.CSizeT = string.strlen(includes_binary_dir) + pattern: bytes = _mbuddy.alloc(dir_len + 8) + if pattern is None: + return 0 + viperlib.snprintf(pattern, dir_len + 8, "%s/*.obj", includes_binary_dir) + + # FindFirstFileA + find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + if find_data is None: + return 0 + string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + return 0 + + # 需要 win32base 的 INVALID_HANDLE_VALUE + while True: + fname: str = find_data.cFileName + if fname is not None: + fname_len: t.CSizeT = string.strlen(fname) + # 构造完整路径并追加到 out_buf + # 路径格式: "dir/fname " + need: t.CSizeT = dir_len + 1 + fname_len + 2 + if out_pos + need < out_size: + if out_pos > 0: + out_buf[out_pos] = ' ' + out_pos += 1 + viperlib.snprintf(out_buf + out_pos, need, "%s/%s", includes_binary_dir, fname) + out_pos += dir_len + 1 + fname_len + else: + # 缓冲区不足,停止 + break + + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + + w32.win32file.FindClose(handle) + out_buf[out_pos] = '\0' + return out_pos + + +def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_flags: str, linker_output: str, + includes_binary_dir: str) -> int: + """调用 clang++ 链接 .obj 为 .exe + + Args: + output_dir: 输出目录(包含 .obj 文件) + module_name: 模块名 + linker_cmd: 链接器命令(如 "clang++") + linker_flags: 链接器参数 + linker_output: 输出文件名(如 "test.exe") + includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) + + Returns: + 0 成功,非 0 失败 + """ + if output_dir is None or linker_cmd is None: + return 1 + + # 收集 includes.binary 的 .obj 文件路径 + EXTRA_BUF_SIZE: t.CSizeT = 32768 + extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE) + if extra_objs is None: + return 1 + extra_len: t.CSizeT = 0 + if includes_binary_dir is not None: + extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE) + if extra_len > 0: + stdio.printf("[link] 附加 %d 字节的 includes.binary .obj 文件\n", extra_len) + else: + stdio.printf("[link] 警告: includes.binary 无 .obj 文件: %s\n", includes_binary_dir) + + # 构造命令: clang++ main.obj extra_objs -o output linker_flags + # 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖 + cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(output_dir) + string.strlen(module_name) + string.strlen(linker_flags) + string.strlen(linker_output) + extra_len + 128 + cmd: bytes = _mbuddy.alloc(cmd_len) + if cmd is None: + return 1 + if extra_len > 0: + viperlib.snprintf(cmd, cmd_len, "%s %s/%s.obj %s -o %s/%s %s", + linker_cmd, output_dir, module_name, extra_objs, + output_dir, linker_output, linker_flags) + else: + viperlib.snprintf(cmd, cmd_len, "%s %s/%s.obj -o %s/%s %s", + linker_cmd, output_dir, module_name, output_dir, linker_output, + linker_flags) + + result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) + if result is None: + stdio.printf("[link] subprocess.run 返回 None\n") + return 1 + if result.returncode != 0: + stdio.printf("[link] 链接失败,返回码: %d\n", result.returncode) + stdio.printf("[link] 命令: %s\n", cmd) + # 显示链接器错误输出(subprocess 将 stderr 合并到 stdout) + if result.stdout is not None: + stdio.printf("[link] 链接器输出:\n%s\n", result.stdout) + else: + stdio.printf("[link] 无输出捕获\n") + return 1 + return 0 + + +def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT, + temp_dir: str, output_dir: str, module_name: str, + cc_cmd: str, cc_flags: str) -> int: + """编译 IR 到 .obj(不链接) + + Args: + ir_buf: LLVM IR 文本缓冲区 + ir_len: IR 文本长度 + temp_dir: 临时目录 + output_dir: 输出目录 + module_name: 模块名(SHA1) + cc_cmd: 编译器命令 + cc_flags: 编译器参数 + + Returns: + 0 成功,非 0 失败 + """ + if ir_buf is None or temp_dir is None or output_dir is None: + return 1 + + # Step 1: 写 .ll 文件 + ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name) + if ret != 0: + stdio.printf("[compile] 写 .ll 失败: %s\n", module_name) + return 1 + + # Step 2: 构造 .ll 路径并编译 → .obj + name_len: t.CSizeT = string.strlen(module_name) + dir_len: t.CSizeT = string.strlen(temp_dir) + ir_path: bytes = _mbuddy.alloc(dir_len + name_len + 5) + if ir_path is None: + return 1 + viperlib.snprintf(ir_path, dir_len + name_len + 5, "%s/%s.ll", temp_dir, module_name) + + ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags) + if ret != 0: + stdio.printf("[compile] llc 编译失败: %s\n", module_name) + return 1 + return 0 + + +def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT, + linker_cmd: str, linker_flags: str, linker_output: str, + includes_binary_dir: str) -> int: + """链接多个 .obj 文件为 .exe + + Args: + obj_paths: 空格分隔的 .obj 文件完整路径字符串 + obj_paths_len: obj_paths 长度 + linker_cmd: 链接器命令(如 "clang++") + linker_flags: 链接器参数 + linker_output: 输出文件完整路径 + includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) + + Returns: + 0 成功,非 0 失败 + """ + if obj_paths is None or obj_paths_len == 0 or linker_cmd is None: + return 1 + + # 收集 includes.binary 的 .obj 文件路径 + EXTRA_BUF_SIZE: t.CSizeT = 32768 + extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE) + if extra_objs is None: + return 1 + extra_len: t.CSizeT = 0 + if includes_binary_dir is not None: + extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE) + + # 构造命令: clang++ obj_paths extra_objs -o linker_output linker_flags + cmd_len: t.CSizeT = string.strlen(linker_cmd) + obj_paths_len + string.strlen(linker_flags) + string.strlen(linker_output) + extra_len + 128 + cmd: bytes = _mbuddy.alloc(cmd_len) + if cmd is None: + return 1 + if extra_len > 0: + viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s %s", + linker_cmd, obj_paths, extra_objs, + linker_output, linker_flags) + else: + viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", + linker_cmd, obj_paths, linker_output, linker_flags) + + result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True) + if result is None: + stdio.printf("[link] subprocess.run 返回 None\n") + return 1 + if result.returncode != 0: + stdio.printf("[link] 链接失败,返回码: %d\n", result.returncode) + stdio.printf("[link] 命令: %s\n", cmd) + if result.stdout is not None: + stdio.printf("[link] 链接器输出:\n%s\n", result.stdout) + return 1 + return 0 + + +def run_pipeline(ir_buf: bytes, ir_len: t.CSizeT, + temp_dir: str, output_dir: str, module_name: str, + cc_cmd: str, cc_flags: str, + linker_cmd: str, linker_flags: str, linker_output: str, + includes_binary_dir: str) -> BuildResult | t.CPtr: + """执行完整编译管线 + + Args: + ir_buf: LLVM IR 文本缓冲区 + ir_len: IR 文本长度 + temp_dir: 临时目录 + output_dir: 输出目录 + module_name: 模块名 + cc_cmd: 编译器命令 + cc_flags: 编译器参数 + linker_cmd: 链接器命令 + linker_flags: 链接器参数 + linker_output: 输出文件名 + includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj) + + Returns: + BuildResult 对象 + """ + result: BuildResult | t.CPtr = BuildResult() + if result is None: + return None + + # Step 0: 确保 temp/output 目录存在(自动创建,避免写文件失败) + ensure_dir(temp_dir) + ensure_dir(output_dir) + + # Step 1: 写 .ll 文件 + ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name) + if ret != 0: + result.Success = 0 + result.ErrorMsg = "写 .ll 文件失败" + return result + + # Step 2: llc 编译 .ll → .obj + # 构造 .ll 文件路径 + name_len: t.CSizeT = string.strlen(module_name) + dir_len: t.CSizeT = string.strlen(temp_dir) + ir_path: bytes = _mbuddy.alloc(dir_len + name_len + 5) + if ir_path is None: + result.Success = 0 + result.ErrorMsg = "内存分配失败" + return result + viperlib.snprintf(ir_path, dir_len + name_len + 5, "%s/%s.ll", temp_dir, module_name) + + ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags) + if ret != 0: + result.Success = 0 + result.ErrorMsg = "llc 编译失败" + return result + + # Step 3: clang++ 链接 .obj → .exe(附加 includes.binary 预编译 .obj) + ret = link_obj_to_exe(output_dir, module_name, linker_cmd, linker_flags, linker_output, + includes_binary_dir) + if ret != 0: + result.Success = 0 + result.ErrorMsg = "链接失败" + return result + + result.Success = 1 + return result \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesAnnAssign.py b/App/lib/core/Handles/HandlesAnnAssign.py new file mode 100644 index 0000000..a7a13a2 --- /dev/null +++ b/App/lib/core/Handles/HandlesAnnAssign.py @@ -0,0 +1,281 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesExprCall as HandlesExprCall + + +# ============================================================ +# HandlesAnnAssign - AnnAssign 语句处理(Mixin 继承模式) +# ============================================================ + + +# ============================================================ +# is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数) +# +# 支持两种形式: +# 1. Attribute(Name('t'), 'CDefine') +# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解) +# ============================================================ +def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int: + """检测注解是否为 t.CDefine,返回 1 表示是,0 表示否""" + if annot is None: + return 0 + k: int = annot.kind() + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot) + if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0: + return 1 + return 0 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) + if is_cdefine_annotation(bop.left) != 0: + return 1 + if is_cdefine_annotation(bop.right) != 0: + return 1 + return 0 + + +# ============================================================ +# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数) +# +# 仅支持 ast.Constant(INT),其他形式返回 0 +# ============================================================ +def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int: + """从值节点提取整数常量(仅支持 Constant INT)""" + if val_node is None: + return 0 + if val_node.kind() != ast.ASTKind.Constant: + return 0 + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node) + if cn.const_kind != ast.CONST_INT: + return 0 + return cn.int_val + + +@t.NoVTable +class AnnAssignHandle(HandlesBase.Mixin): + """AnnAssign 语句处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # PreScan - 预扫描 AnnAssign,为有类型注解的变量提前创建 alloca + # + # 返回新增的变量数 + # ============================================================ + def PreScan(self, node: ast.AST | t.CPtr) -> int: + """预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部""" + if node is None: + return 0 + k: int = node.kind() + if k != ast.ASTKind.AnnAssign: + return 0 + + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa is None or aa.target is None: + return 0 + target: ast.AST | t.CPtr = aa.target + if target.kind() != ast.ASTKind.Name: + return 0 + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm.id is None: + return 0 + + # CDefine 注解: 不创建 alloca,但注册常量到全局表 + # 供后续 t.CArray[elem_ty, NAME] 编译期解析使用 + if is_cdefine_annotation(aa.annotation) != 0: + pool_ps: memhub.MemBuddy | t.CPtr = self.Trans.Pool + val_ps: int = extract_cdefine_int_value(aa.value) + HandlesType.register_cdefine_constant(pool_ps, nm.id, val_ps) + return 0 + + # global/nonlocal 变量不需要局部 alloca + if HT.is_global_name(self.Trans, nm.id) != 0: + return 0 + if HT.is_nonlocal_name(self.Trans, nm.id) != 0: + return 0 + + # 检查是否已存在 + existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + self.Trans.SymTab, nm.id) + if existing is not None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder + + # 从 annotation 推断类型(修复:原硬编码 i32 导致 str 等类型错误) + var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + annot: ast.AST | t.CPtr = aa.annotation + if annot is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, annot, self.Trans._imported_modules, self.Trans._from_imports) + if resolved is None: + # 尝试特化泛型类注解(如 list[str]) + # resolve_annotation_type 返回 None 可能是因为泛型类未特化 + if annot.kind() == ast.ASTKind.Subscript: + sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name: + sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value) + if sub_nm.id is not None: + template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(sub_nm.id) + if template_cd is not None: + type_args_ps: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(pool, sub_annot.slice) + if type_args_ps is not None and type_args_ps.__len__() > 0: + spec_name_ps: str = HandlesClassDef._specialize_generic_class( + self.Trans, sub_nm.id, type_args_ps) + if spec_name_ps is not None: + resolved = HandlesType.resolve_annotation_type( + pool, annot, self.Trans._imported_modules, self.Trans._from_imports) + if resolved is not None: + var_ty = resolved + + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, var_ty) + if alloca is not None: + if HandlesVar.define_var( + self.Trans.SymTab, nm.id, alloca) == 0: + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + if annot is not None: + cls_nm_ps: str = HandlesType.extract_class_name_from_annotation( + annot, self.Trans._imported_modules) + if cls_nm_ps is not None: + HandlesVar.set_var_annot_class_name( + self.Trans.SymTab, nm.id, cls_nm_ps) + return 0 + return 0 + + # ============================================================ + # Handle - 翻译 AnnAssign 语句 + # + # 返回新增的变量数 + # ============================================================ + def Handle(self, node: ast.AST | t.CPtr) -> int: + """翻译 AnnAssign(target=Name, annotation=..., value=expr)""" + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa is None: + return 0 + + target: ast.AST | t.CPtr = aa.target + if target is None or target.kind() != ast.ASTKind.Name: + return 0 + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm.id is None: + return 0 + + # CDefine 注解: 编译期常量,不生成运行时代码 + # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 + # 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册 + if is_cdefine_annotation(aa.annotation) != 0: + pool_cd: memhub.MemBuddy | t.CPtr = self.Trans.Pool + val_cd: int = extract_cdefine_int_value(aa.value) + HandlesType.register_cdefine_constant(pool_cd, nm.id, val_cd) + return 0 + + pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module + + # 确定类型(从 annotation 推断) + var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + annot: ast.AST | t.CPtr = aa.annotation + if annot is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, annot, self.Trans._imported_modules, self.Trans._from_imports) + if resolved is not None: + var_ty = resolved + + # global 变量:写入模块作用域中的全局变量 + if HT.is_global_name(self.Trans, nm.id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + self.Trans.SymTab, nm.id) + if mod_alloca is not None and aa.value is not None: + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aa.value, + None, 0, self.Trans) + if rhs_val is not None: + target_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + target_ty = mod_alloca.Ty.Pointee + if target_ty is not None: + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty) + llvmlite.build_store(builder, rhs_val, mod_alloca) + return 0 + + # nonlocal 变量:通过闭包 env 写入 + if HT.is_nonlocal_name(self.Trans, nm.id) != 0: + if aa.value is not None: + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aa.value, + None, 0, self.Trans) + if rhs_val is not None: + nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( + self.Trans, nm.id) + if nl_ptr is not None: + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, rhs_val, i32_ty) + llvmlite.build_store(builder, rhs_coerced, nl_ptr) + return 0 + + # 普通局部变量 + # 创建 alloca + alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( + self.Trans.SymTab, pool, builder, nm.id, var_ty) + if alloca is None: + return 0 + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + if annot is not None: + cls_nm_hd: str = HandlesType.extract_class_name_from_annotation( + annot, self.Trans._imported_modules) + if cls_nm_hd is not None: + HandlesVar.set_var_annot_class_name( + self.Trans.SymTab, nm.id, cls_nm_hd) + + new_vars: int = 0 + existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + self.Trans.SymTab, nm.id) + if existing is None: + new_vars = 1 + + # 如果有初始值,store + if aa.value is not None: + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aa.value, + None, 0, self.Trans) + if rhs_val is not None: + # 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型 + # 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext + target_ty: llvmlite.LLVMType | t.CPtr = None + if alloca.Ty is not None: + target_ty = alloca.Ty.Pointee + if target_ty is not None: + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty) + llvmlite.build_store(builder, rhs_val, alloca) + + return 0 + + +# ============================================================ +# NewAnnAssignHandle - 工厂函数 +# ============================================================ +def NewAnnAssignHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> AnnAssignHandle | t.CPtr: + h: AnnAssignHandle | t.CPtr = pool.alloc(AnnAssignHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, AnnAssignHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesAssign.py b/App/lib/core/Handles/HandlesAssign.py new file mode 100644 index 0000000..f5d825e --- /dev/null +++ b/App/lib/core/Handles/HandlesAssign.py @@ -0,0 +1,231 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import viperlib +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct + + +# ============================================================ +# HandlesAssign - Assign 语句处理(Mixin 继承模式) +# +# 对应 TransPyC 的 class AssignHandle(BaseHandle): +# @t.NoVTable 继承 Mixin 获得 Trans 字段(展平嵌入,无 vtable) +# 通过 self.Trans 访问共享状态(Pool/Module/_cur_builder/SymTab/...) +# 通过 self.Trans.ExprH / self.Trans.IfH 等访问其他 Handle +# ============================================================ + + +@t.NoVTable +class AssignHandle(HandlesBase.Mixin): + """Assign 语句处理器:继承 Mixin 获得 Trans 回指针 + 共享方法""" + _CurrentClass: str # 模块私有状态 + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + self._CurrentClass = None + + # ============================================================ + # Handle - 处理 Assign 语句,返回新增变量数(0 或 1) + # + # 对应 TransPyC AssignHandle._HandleAssignLlvm + # 共享状态从 self.Trans 获取,无需 11 个参数 + # ============================================================ + def Handle(self, node: ast.AST | t.CPtr) -> int: + asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) + if asgn is None: + stdio.printf("[ASGN] cast failed\n") + return 0 + + targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets + if targets is None: + stdio.printf("[ASGN] targets is None\n") + return 0 + + # 从 self.Trans 取共享状态(替代 11 个参数) + pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module + + # 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, asgn.value, None, 0, self.Trans) + if rhs_val is None: + stdio.printf("[ASGN] rhs_val is None\n") + return 0 + + new_vars: int = 0 + tn: t.CSizeT = targets.__len__() + for ti in range(tn): + target: ast.AST | t.CPtr = targets.get(ti) + if target is None: + continue + + tk: int = target.kind() + + # Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val + if tk == ast.ASTKind.Subscript: + # 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct) + # list 的 subscript 赋值走 __setitem__ 内联路径 + list_obj: llvmlite.Value | t.CPtr = HandlesExpr.is_list_subscript( + target, self.Trans) + if list_obj is not None: + # list[T] 类型: 内联生成 __setitem__ 逻辑 + sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) + if sub_node is not None and sub_node.slice is not None: + list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_node.slice, None, 0, self.Trans) + if list_idx_val is not None: + HandlesExpr.list_setitem_inline( + builder, pool, list_obj, list_idx_val, rhs_val) + continue + # 普通 Subscript 赋值 + elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( + builder, pool, mod, target, self.Trans) + if elem_ptr is not None: + store_val: llvmlite.Value | t.CPtr = rhs_val + if elem_ptr.Ty is not None: + elem_ty: llvmlite.LLVMType | t.CPtr = elem_ptr.Ty.Pointee + if elem_ty is not None: + store_val = HandlesExpr.coerce_to_type( + builder, rhs_val, elem_ty) + llvmlite.build_store(builder, store_val, elem_ptr) + else: + # get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载 + # 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val)) + sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) + setitem_done: int = 0 + if sub_asgn is not None and sub_asgn.value is not None: + if sub_asgn.value.kind() == ast.ASTKind.Name: + sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value) + if sub_nm.id is not None: + sub_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + self.Trans.SymTab, sub_nm.id) + if sub_alloca is not None and sub_alloca.Ty is not None: + if HandlesExpr.is_ptr_type(sub_alloca.Ty) != 0: + sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee + if sub_pointee is not None: + cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee) + if cls_nm_set is not None: + obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, sub_pointee, sub_alloca) + if obj_val_set is not None: + key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_asgn.slice, None, 0, self.Trans) + if key_val_set is not None: + arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16) + if arg_vals_set is not None: + arg_vals_set[0] = t.CSizeT(key_val_set) + arg_vals_set[1] = t.CSizeT(rhs_val) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, cls_nm_set, "__setitem__", + obj_val_set, arg_vals_set, 2, self.Trans) + setitem_done = 1 + if setitem_done == 0: + HandlesType.fatal_error(target, "subscript ptr is None") + continue + + # Attribute 赋值: obj.field = val + if tk == ast.ASTKind.Attribute: + field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( + builder, pool, mod, target, self.Trans) + if field_ptr is not None: + # 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64) + store_val: llvmlite.Value | t.CPtr = rhs_val + if field_ptr.Ty is not None: + field_ty: llvmlite.LLVMType | t.CPtr = field_ptr.Ty.Pointee + if field_ty is not None: + store_val = HandlesExpr.coerce_to_type( + builder, rhs_val, field_ty) + llvmlite.build_store(builder, store_val, field_ptr) + else: + # 构造详细错误信息 + attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) + attr_name: str = "(unknown)" + obj_name: str = "(unknown)" + if attr_node is not None: + attr_name = attr_node.attr + if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name: + obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value) + obj_name = obj_nm.id + err_buf: t.CChar | t.CPtr = pool.alloc(256) + if err_buf is not None: + viperlib.snprintf(err_buf, 256, + "attribute ptr is None: %s.%s", + obj_name, attr_name) + HandlesType.fatal_error(target, err_buf) + else: + HandlesType.fatal_error(target, "attribute ptr is None") + continue + + # Name 赋值: var = val + if tk == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm.id is not None: + # global 变量:写入模块作用域中的全局变量 + if HT.is_global_name(self.Trans, nm.id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + self.Trans.SymTab, nm.id) + if mod_alloca is not None: + target_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + target_ty = mod_alloca.Ty.Pointee + if target_ty is not None: + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty) + llvmlite.build_store(builder, rhs_val, mod_alloca) + continue + + # nonlocal 变量:通过闭包 env 写入 + if HT.is_nonlocal_name(self.Trans, nm.id) != 0: + nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( + self.Trans, nm.id) + if nl_ptr is not None: + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, rhs_val, i32_ty) + llvmlite.build_store(builder, rhs_coerced, nl_ptr) + continue + + # 普通局部变量 + alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( + self.Trans.SymTab, pool, builder, nm.id, rhs_val.Ty) + if alloca is not None: + # 按 alloca 类型对值进行转换(如 double → float) + store_val: llvmlite.Value | t.CPtr = rhs_val + if alloca.Ty is not None: + alloca_ty: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if alloca_ty is not None: + store_val = HandlesExpr.coerce_to_type( + builder, rhs_val, alloca_ty) + llvmlite.build_store(builder, store_val, alloca) + existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + self.Trans.SymTab, nm.id) + if existing is None: + new_vars += 1 + else: + stdio.printf("[ASGN] alloca failed for %s\n", nm.id) + + return new_vars + + +# ============================================================ +# NewAssignHandle - 工厂函数:分配并初始化 AssignHandle +# ============================================================ +def NewAssignHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> AssignHandle | t.CPtr: + h: AssignHandle | t.CPtr = pool.alloc(AssignHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, AssignHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesAugAssign.py b/App/lib/core/Handles/HandlesAugAssign.py new file mode 100644 index 0000000..3db6e2e --- /dev/null +++ b/App/lib/core/Handles/HandlesAugAssign.py @@ -0,0 +1,254 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import stdio +import string +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal + + +# ============================================================ +# HandlesAugAssign - 增强赋值语句处理(Mixin 继承模式) +# +# 处理 += -= *= /= %= &= |= ^= <<= >>= +# 流程: load target → apply binop → store result +# +# 支持 local/global/nonlocal 三种变量作用域 +# ============================================================ + + +@t.NoVTable +class AugAssignHandle(HandlesBase.Mixin): + """增强赋值处理器 (+=, -=, *=, etc.):继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # Handle - 处理 AugAssign 语句,返回新增变量数(始终为 0) + # ============================================================ + def Handle(self, node: ast.AST | t.CPtr) -> int: + """翻译增强赋值语句 (x += 1, y -= 2, etc.)""" + if node is None: + return 0 + + aug: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node) + if aug is None: + return 0 + + target: ast.AST | t.CPtr = aug.target + if target is None: + return 0 + + tk: int = target.kind() + + # Attribute 目标: self.field += 1 + # 流程: get_attribute_ptr → load → binop → store + if tk == ast.ASTKind.Attribute: + pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module + + # 1. 获取字段指针 + field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( + builder, pool, mod, target, self.Trans) + if field_ptr is None: + stdio.printf("[AUGASGN] attribute ptr is None\n") + return 0 + + # 2. 确定字段类型并加载当前值 + target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if field_ptr.Ty is not None: + target_ty = field_ptr.Ty.Pointee + cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, target_ty, field_ptr) + if cur_val is None: + stdio.printf("[AUGASGN] cannot load attribute\n") + return 0 + + # 3. 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aug.value, None, 0, self.Trans) + if rhs_val is None: + stdio.printf("[AUGASGN] rhs is None\n") + return 0 + + # 4. 应用二元运算 + result: llvmlite.Value | t.CPtr = _apply_aug_op( + pool, builder, aug.op, cur_val, rhs_val) + if result is None: + stdio.printf("[AUGASGN] binop failed for attr op=%d\n", aug.op) + return 0 + + # 5. 类型对齐并存储 + result = HandlesExpr.coerce_to_type(builder, result, target_ty) + if result is None: + return 0 + llvmlite.build_store(builder, result, field_ptr) + return 0 + + if tk != ast.ASTKind.Name: + stdio.printf("[AUGASGN] only Name/Attribute target supported\n") + return 0 + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm is None or nm.id is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal + scope_type: int = 0 + if HT.is_global_name(self.Trans, nm.id) != 0: + scope_type = 1 + elif HT.is_nonlocal_name(self.Trans, nm.id) != 0: + scope_type = 2 + + # 2. 加载当前值 + cur_val: llvmlite.Value | t.CPtr = None + target_alloca: llvmlite.Value | t.CPtr = None + target_ty: llvmlite.LLVMType | t.CPtr = i32_ty + + if scope_type == 1: + # global 变量 + target_alloca = HandlesVar.lookup_module_var( + self.Trans.SymTab, nm.id) + if target_alloca is not None: + if target_alloca.Ty is not None: + target_ty = target_alloca.Ty.Pointee + cur_val = llvmlite.build_load(builder, target_ty, target_alloca) + elif scope_type == 2: + # nonlocal 变量(通过闭包 env) + cur_val = HandlesNonlocal.load_nonlocal_var(self.Trans, nm.id) + if cur_val is not None: + target_ty = cur_val.Ty + else: + # 普通局部变量 + target_alloca = HandlesVar.lookup_var(self.Trans.SymTab, nm.id) + if target_alloca is not None: + if target_alloca.Ty is not None: + target_ty = target_alloca.Ty.Pointee + cur_val = llvmlite.build_load(builder, target_ty, target_alloca) + + if cur_val is None: + stdio.printf("[AUGASGN] cannot load target %s\n", nm.id) + return 0 + + # 3. 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aug.value, None, 0, self.Trans) + if rhs_val is None: + stdio.printf("[AUGASGN] rhs is None\n") + return 0 + + # 4. 类型对齐 + 应用二元运算 + # 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__) + result: llvmlite.Value | t.CPtr = _apply_aug_op( + pool, builder, aug.op, cur_val, rhs_val) + if result is None: + stdio.printf("[AUGASGN] binop failed for op=%d\n", aug.op) + return 0 + + # 5. 存储结果 + result = HandlesExpr.coerce_to_type(builder, result, target_ty) + if result is None: + return 0 + + if scope_type == 1: + # global 变量 + if target_alloca is not None: + llvmlite.build_store(builder, result, target_alloca) + elif scope_type == 2: + # nonlocal 变量 + nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( + self.Trans, nm.id) + if nl_ptr is not None: + llvmlite.build_store(builder, result, nl_ptr) + else: + # 普通局部变量 + if target_alloca is not None: + llvmlite.build_store(builder, result, target_alloca) + + return 0 + + +# ============================================================ +# _apply_aug_op - 应用增强赋值的二元运算 +# +# 支持指针算术: ptr += int / ptr -= int +# 整数运算自动类型提升 +# ============================================================ +def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + op: int, + lhs: llvmlite.Value | t.CPtr, + rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """应用增强赋值的二元运算(指针算术 + 整数运算)""" + lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty) + rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty) + + # 指针算术: ptr += int / ptr -= int + if lhs_bits == 0 and rhs_bits != 0: + if op == ast.OpKind.Add or op == ast.OpKind.Sub: + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + ptr_as_int: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint(builder, lhs, i64_ty) + int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty) + if ptr_as_int is None or int_val is None: + return None + if op == ast.OpKind.Add: + result: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, ptr_as_int, int_val) + else: + result = llvmlite.build_sub(builder, ptr_as_int, int_val) + if result is None: + return None + return llvmlite.build_inttoptr(builder, result, lhs.Ty) + return None + + # 整数运算:类型提升 + if lhs_bits > rhs_bits and rhs_bits > 0: + rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty) + elif rhs_bits > lhs_bits and lhs_bits > 0: + lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty) + + if op == ast.OpKind.Add: + return llvmlite.build_add(builder, lhs, rhs) + elif op == ast.OpKind.Sub: + return llvmlite.build_sub(builder, lhs, rhs) + elif op == ast.OpKind.Mult: + return llvmlite.build_mul(builder, lhs, rhs) + elif op == ast.OpKind.Div: + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.Mod: + return llvmlite.build_srem(builder, lhs, rhs) + elif op == ast.OpKind.BitAnd: + return llvmlite.build_and(builder, lhs, rhs) + elif op == ast.OpKind.BitOr: + return llvmlite.build_or(builder, lhs, rhs) + elif op == ast.OpKind.BitXor: + return llvmlite.build_xor(builder, lhs, rhs) + elif op == ast.OpKind.LShift: + return llvmlite.build_shl(builder, lhs, rhs) + elif op == ast.OpKind.RShift: + return llvmlite.build_ashr(builder, lhs, rhs) + return None + + +# ============================================================ +# NewAugAssignHandle - 工厂函数 +# ============================================================ +def NewAugAssignHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> AugAssignHandle | t.CPtr: + h: AugAssignHandle | t.CPtr = pool.alloc(AugAssignHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, AugAssignHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesBase.py b/App/lib/core/Handles/HandlesBase.py new file mode 100644 index 0000000..764974d --- /dev/null +++ b/App/lib/core/Handles/HandlesBase.py @@ -0,0 +1,262 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +import hashtable +import lib.core.Handles.HandlesTranslator as HT + + +# ============================================================ +# TypeKind - 类型种类枚举 +# +# 替代 TransPyC 中 CType.position frozenset 的元属性系统。 +# 每个 TypeInfo 通过 Kind 字段标记其种类,避免 Python ClassVar 反射。 +# ============================================================ +class TypeKind(t.CEnum): + Basic: t.State # 基本类型(int/char/float/double/bool 等) + Pointer: t.State # 指针(T*)— 指针层数由 TypeInfo.PtrCount 表达 + Struct: t.State # 结构体/类 + Union: t.State # 联合体 + Enum: t.State # 枚举 + Typedef: t.State # 类型别名 + Function: t.State # 函数指针 + Array: t.State # 数组 T[N] + Void: t.State # void + + +# ============================================================ +# TypeInfo - 类型信息结构 +# +# 设计原则(相对 TransPyC CTypeInfo 的简化): +# - POD 数据结构,无虚函数,无 Python 元特性(ClassVar/Generic/frozenset) +# - 通过 mbuddy 分配,调用方管理生命周期(参考 llvmlite Module 模式) +# - 通过 Kind 枚举代替 position frozenset +# - PtrCount 表达指针层数(0=非指针, 1=T*, 2=T**) +# - IsSigned 三态:-1=不适用(void/float), 0=unsigned, 1=signed +# +# 字段布局(8 字段): +# Kind : i32 类型种类(TypeKind 枚举值) +# Name : i8* 类型名(如 'int', 'CInt', 'MyStruct'),可能为 None +# Size : i32 位宽(0=void/未知;int=32, char=8, double=64, long long=64) +# Align : i32 对齐字节数(0=默认) +# IsSigned : i32 -1=N/A, 0=unsigned, 1=signed +# PtrCount : i32 指针层数 +# IsConst : i32 const 限定符(0/1) +# IsVolatile : i32 volatile 限定符(0/1) +# +# 注意:Size 使用位宽(bit width)而非字节数,与 LLVM IR 的 i{N} 和 +# TransPyC CType.Size 约定一致(CInt.Size=32, CChar.Size=8)。 +# ============================================================ +@t.NoVTable +class TypeInfo: + Kind: int + Name: str + Size: int + Align: int + IsSigned: int + PtrCount: int + IsConst: int + IsVolatile: int + + +# ============================================================ +# TypeRegistry - 类型注册表 +# +# 维护 name(str) → TypeInfo* 映射,基于 HashTable 实现 O(1) 查找。 +# 替代 TransPyC CTypeRegistry 的 _name_to_class dict。 +# 内置基本类型(int/char/void/...)由 InitBasicTypes 注册。 +# ============================================================ +class TypeRegistry: + _ht: hashtable.HashTable | t.CPtr + __mbuddy__: memhub.MemManager | t.CPtr + + def Register(self, ti: TypeInfo | t.CPtr) -> int: + """注册一个 TypeInfo。ti.Name 字段必须已设置。 + + Returns: + 1 表示成功,0 表示失败(ti 为 None 或 Name 为 None) + """ + if ti is None: + return 0 + if ti.Name is None: + return 0 + self._ht[ti.Name] = ti + return 1 + + def Lookup(self, name: str) -> TypeInfo | t.CPtr: + """按名称查找 TypeInfo。 + + Returns: + 找到返回 TypeInfo*,找不到返回 None + """ + if name is None: + return None + return self._ht[name] + + def Has(self, name: str) -> int: + """检查类型是否已注册。""" + if name is None: + return 0 + return name in self._ht + + +# ============================================================ +# NewTypeInfo - 工厂函数:分配并初始化一个 TypeInfo +# +# 默认值:Kind=Basic, IsSigned=-1, 其余=0/None +# ============================================================ +def NewTypeInfo(pool: memhub.MemManager | t.CPtr) -> TypeInfo | t.CPtr: + ptr: TypeInfo | t.CPtr = pool.alloc(TypeInfo.__sizeof__()) + if ptr is None: + return None + string.memset(ptr, 0, TypeInfo.__sizeof__()) + ptr.Kind = TypeKind.Basic + ptr.IsSigned = -1 + return ptr + + +# ============================================================ +# NewTypeRegistry - 工厂函数:创建类型注册表 +# ============================================================ +def NewTypeRegistry(pool: memhub.MemManager | t.CPtr) -> TypeRegistry | t.CPtr: + ptr: TypeRegistry | t.CPtr = pool.alloc(TypeRegistry.__sizeof__()) + if ptr is None: + return None + string.memset(ptr, 0, TypeRegistry.__sizeof__()) + ptr.__mbuddy__ = pool + ptr._ht = hashtable.HashTable(pool) + return ptr + + +# ============================================================ +# TypeToLLVM - 将 TypeInfo 转换为 LLVM IR 类型字符串 +# +# 规则: +# - Kind == Void 或 (Size==0 且 IsSigned==-1 且 PtrCount==0) → "void" +# - void 有 PtrCount > 0 → "i8" + PtrCount 个 "*" +# - IsSigned == -1 且 Size > 0 → 浮点: half/float/double/fp128 +# - IsSigned != -1 且 Size > 0 → 整数: i{Size} +# - 未知 → "i8*" +# +# Args: +# buf: 输出缓冲区(i8*) +# buf_size: 缓冲区容量 +# ti: TypeInfo 指针 +# +# Returns: +# 写入的字符数(不含 NUL),失败返回 -1 +# ============================================================ +def TypeToLLVM(buf: t.CChar | t.CPtr, buf_size: t.CSizeT, + ti: TypeInfo | t.CPtr) -> int: + if buf is None: + return -1 + if ti is None: + return -1 + if buf_size == 0: + return -1 + + # 判定 void + is_void: int = 0 + if ti.Kind == TypeKind.Void: + is_void = 1 + elif ti.Size == 0 and ti.IsSigned == -1 and ti.PtrCount == 0: + is_void = 1 + + # 写入 base 类型字符串到 buf + base_len: int = 0 + if is_void == 1: + if ti.PtrCount == 0: + # "void" + if buf_size < 5: + return -1 + string.strcpy(buf, "void") + base_len = 4 + else: + # void* → i8*(LLVM 中 void* 表示为 i8*) + if buf_size < 4: + return -1 + string.strcpy(buf, "i8") + base_len = 2 + elif ti.IsSigned == -1: + # 浮点 + if ti.Size == 16: + if buf_size < 5: + return -1 + string.strcpy(buf, "half") + base_len = 4 + elif ti.Size == 32: + if buf_size < 6: + return -1 + string.strcpy(buf, "float") + base_len = 5 + elif ti.Size == 64: + if buf_size < 7: + return -1 + string.strcpy(buf, "double") + base_len = 6 + elif ti.Size == 128: + if buf_size < 6: + return -1 + string.strcpy(buf, "fp128") + base_len = 5 + else: + # 未知浮点尺寸 → double 兜底 + if buf_size < 7: + return -1 + string.strcpy(buf, "double") + base_len = 6 + else: + # 整数: i{Size},用 snprintf 安全写入 + if ti.Size <= 0: + # 无效尺寸 → i8 兜底 + if buf_size < 4: + return -1 + string.strcpy(buf, "i8") + base_len = 2 + else: + viperlib.snprintf(buf, buf_size, "i%d", ti.Size) + base_len = string.strlen(buf) + + # 追加 PtrCount 个 "*" + if base_len + ti.PtrCount + 1 > buf_size: + return -1 + pos: int = base_len + for i in range(ti.PtrCount): + buf[pos] = '*' + pos += 1 + buf[pos] = 0 + return pos + + +# ============================================================ +# Mixin - 所有 Handle 的非多态基类(对应 TransPyC 的 BaseHandle) +# +# @t.NoVTable 继承:字段展平嵌入子类,无 vtable 开销(对应 C++ 非多态继承)。 +# 子类继承 Trans 字段 + 共享工具方法,编译器自动生成子类方法包装 +# (self bitcast 为父类指针后调用),子类可直接调用继承的方法。 +# +# 用法: +# @t.NoVTable +# class AssignHandle(Mixin): +# _CurrentClass: str +# def __init__(self, trans): +# self.InitMixin(trans) +# self._CurrentClass = None +# def Handle(self, node) -> int: +# rhs = self.Trans.ExprH.HandleValue(node.value) +# ... +# ============================================================ +@t.NoVTable +class Mixin: + """所有 Handle 的非多态基类:持有 Translator 回指针 + 共享委托方法""" + Trans: HT.Translator | t.CPtr + + def InitMixin(self, trans: HT.Translator | t.CPtr) -> int: + """初始化 Mixin 字段(子类 __init__ 中调用)""" + self.Trans = trans + return 0 + + +# 全局 mbuddy 指针 +_mbuddy: t.CVoid | t.CPtr diff --git a/App/lib/core/Handles/HandlesBody.py b/App/lib/core/Handles/HandlesBody.py new file mode 100644 index 0000000..714cadb --- /dev/null +++ b/App/lib/core/Handles/HandlesBody.py @@ -0,0 +1,230 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import viperlib +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.Handles.HandlesClassDef as HandlesClassDef + + +# ============================================================ +# HandlesBody - 语句分派(trans 单参模式,全方法调用) +# +# 所有语句类型通过 trans.XxxH.Handle(node) 分派到对应 Handle。 +# 对应 TransPyC BodyHandle.HandleBodyLlvm 的 isinstance 分派。 +# ============================================================ + + +# ============================================================ +# 语句翻译分派 +# ============================================================ +def translate_stmt(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译单条语句,返回新增的变量数""" + if node is None: + return 0 + k: int = node.kind() + + if k == ast.ASTKind.Expr: + return translate_expr_stmt(trans, node) + elif k == ast.ASTKind.Assign: + return trans.AssignH.Handle(node) + elif k == ast.ASTKind.AnnAssign: + return trans.AnnAssignH.Handle(node) + elif k == ast.ASTKind.FunctionDef: + # 嵌套函数定义:提升为顶层函数 + 创建闭包 + return HandlesFunctions.translate_nested_function_def(trans, node) + elif k == ast.ASTKind.Return: + return trans.ReturnH.Handle(node) + elif k == ast.ASTKind.If: + return trans.IfH.Handle(node) + elif k == ast.ASTKind.While: + return trans.WhileH.Handle(node) + elif k == ast.ASTKind.AugAssign: + return trans.AugAssignH.Handle(node) + elif k == ast.ASTKind.For: + return trans.ForH.Handle(node) + elif k == ast.ASTKind.ClassDef: + return HandlesClassDef.translate_class_def(trans, node) + elif k == ast.ASTKind.Import: + return trans.ImportsH.HandleImport(node) + elif k == ast.ASTKind.ImportFrom: + trans.ImportsH.HandleImportFromModule(node) + return trans.ImportsH.HandleImportFromNames(node) + elif k == ast.ASTKind.Global: + return translate_global(trans, node) + elif k == ast.ASTKind.Nonlocal: + return translate_nonlocal(trans, node) + elif k == ast.ASTKind.Pass: + return 0 + elif k == ast.ASTKind.Break: + return translate_break(trans) + elif k == ast.ASTKind.Continue: + return translate_continue(trans) + return 0 + + +# ============================================================ +# 翻译 Global 语句: global x, y +# +# 将 names 中的变量名加入 _global_names 集合 +# ============================================================ +def translate_global(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 global 语句:记录 global 变量名""" + gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node) + if gn is None: + return 0 + names: list[ast.AST | t.CPtr] | t.CPtr = gn.names + if names is None: + return 0 + n: t.CSizeT = names.__len__() + for i in range(n): + nm_node: ast.AST | t.CPtr = names.get(i) + if nm_node is not None and nm_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) + if nm.id is not None: + HT.add_global_name(trans, nm.id) + return 0 + + +# ============================================================ +# 翻译 Nonlocal 语句: nonlocal x, y +# +# 将 names 中的变量名加入 _nonlocal_names 集合 +# ============================================================ +def translate_nonlocal(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 nonlocal 语句:记录 nonlocal 变量名""" + nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node) + if nl is None: + return 0 + names: list[ast.AST | t.CPtr] | t.CPtr = nl.names + if names is None: + return 0 + n: t.CSizeT = names.__len__() + for i in range(n): + nm_node: ast.AST | t.CPtr = names.get(i) + if nm_node is not None and nm_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node) + if nm.id is not None: + HT.add_nonlocal_name(trans, nm.id) + return 0 + + +# ============================================================ +# 翻译表达式语句 Expr(value=Call(...)) +# ============================================================ +def translate_expr_stmt(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译表达式语句(printf 调用等)""" + ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node) + if ex is None: + return 0 + call_node: ast.AST | t.CPtr = ex.value + if call_node is None: + return 0 + ck: int = call_node.kind() + if ck != ast.ASTKind.Call: + return 0 + + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node) + func_node: ast.AST | t.CPtr = cl.func + if func_node is None: + return 0 + + func_name: str = HandlesExpr.get_func_name(func_node) + if func_name is None: + return 0 + + # printf / print 走特殊路径(print 映射到 printf) + if string.strcmp(func_name, "printf") == 0 or string.strcmp(func_name, "print") == 0: + trans.ExprCallH.HandlePrintfCall(cl) + else: + # 通用函数调用(返回值丢弃) + trans.ExprCallH.HandleCall(call_node) + return 0 + + +# ============================================================ +# 预扫描:为局部变量提前创建 alloca +# ============================================================ +def pre_scan_allocas(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预扫描语句中的 AnnAssign,提前创建 alloca + + 返回新增的变量数 + """ + if node is None: + return 0 + return trans.AnnAssignH.PreScan(node) + + +# ============================================================ +# 翻译 break 语句 +# ============================================================ +def translate_break(trans: HT.Translator | t.CPtr) -> int: + """翻译 break 语句:跳转到循环 end 块""" + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + pool: memhub.MemBuddy | t.CPtr = trans.Pool + + if builder is None or func is None: + return 0 + + # 发射 br 到 break 目标 + if trans._break_bb is not None: + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, trans._break_bb) + + # 创建死代码 BB,用于后续语句(break 后面的代码不可达) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: t.CChar | t.CPtr = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "dead.%d", cnt) + dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + llvmlite.position_at_end(builder, dead_bb) + return 0 + + +# ============================================================ +# 翻译 continue 语句 +# ============================================================ +def translate_continue(trans: HT.Translator | t.CPtr) -> int: + """翻译 continue 语句:跳转到循环 cond/incr 块""" + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + pool: memhub.MemBuddy | t.CPtr = trans.Pool + + if builder is None or func is None: + return 0 + + # 发射 br 到 continue 目标 + if trans._continue_bb is not None: + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, trans._continue_bb) + + # 创建死代码 BB,用于后续语句 + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: t.CChar | t.CPtr = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "dead.%d", cnt) + dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + llvmlite.position_at_end(builder, dead_bb) + return 0 + + +# ============================================================ +# 获取语句类型名(调试用) +# ============================================================ +def get_stmt_kind_name(node: ast.AST | t.CPtr) -> str: + """获取语句类型名""" + if node is None: + return None + return node.type_name() diff --git a/App/lib/core/Handles/HandlesClassDef.py b/App/lib/core/Handles/HandlesClassDef.py new file mode 100644 index 0000000..d7c665e --- /dev/null +++ b/App/lib/core/Handles/HandlesClassDef.py @@ -0,0 +1,2327 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import viperlib +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesEnum as HandlesEnum + + +# 枚举成员临时数组最大数量(本地常量) +ENUM_MEMBER_MAX_LOCAL: t.CDefine = 64 + + +# ============================================================ +# HandlesClassDef - class 定义处理 +# +# 解析 class 定义,创建 LLVM StructType 并注册字段信息 +# +# 纯内存结构体(无方法)的 class 定义: +# class Point: +# x: t.CInt +# y: t.CInt +# +# 生成 LLVM 类型: { i32, i32 } +# 注册字段: x→index 0, y→index 1 +# ============================================================ + + +# ============================================================ +# _is_cenum_base — 检查 base 节点是否为 t.CEnum +# +# 支持 Name(id='CEnum') 和 Attribute(value=Name('t'), attr='CEnum') +# ============================================================ +def _is_cenum_base(base_node: ast.AST | t.CPtr) -> int: + """检查 base 节点是否为 t.CEnum,返回 1=是 / 0=否""" + if base_node is None: + return 0 + k: int = base_node.kind() + # Name('CEnum') 形式(from t import CEnum) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) + if nm.id is not None and string.strcmp(nm.id, "CEnum") == 0: + return 1 + return 0 + # Attribute(t.CEnum) 形式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) + if at.attr is not None and string.strcmp(at.attr, "CEnum") == 0: + return 1 + return 0 + return 0 + + +# ============================================================ +# _is_enum_class — 检查 ClassDef 是否继承自 t.CEnum +# ============================================================ +def _is_enum_class(cd: ast.ClassDef | t.CPtr) -> int: + """检查 ClassDef 是否继承自 t.CEnum,返回 1=是 / 0=否""" + if cd is None or cd.bases is None: + return 0 + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = bases.__len__() + if bn == 0: + return 0 + for bi in range(bn): + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + if _is_cenum_base(base_node) == 1: + return 1 + return 0 + + +# ============================================================ +# _is_cunion_base — 检查 base 节点是否为 t.CUnion +# +# 支持 Name(id='CUnion') 和 Attribute(value=Name('t'), attr='CUnion') +# ============================================================ +def _is_cunion_base(base_node: ast.AST | t.CPtr) -> int: + """检查 base 节点是否为 t.CUnion,返回 1=是 / 0=否""" + if base_node is None: + return 0 + k: int = base_node.kind() + # Name('CUnion') 形式(from t import CUnion) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) + if nm.id is not None and string.strcmp(nm.id, "CUnion") == 0: + return 1 + return 0 + # Attribute(t.CUnion) 形式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) + if at.attr is not None and string.strcmp(at.attr, "CUnion") == 0: + return 1 + return 0 + return 0 + + +# ============================================================ +# _is_union_class — 检查 ClassDef 是否继承自 t.CUnion +# ============================================================ +def _is_union_class(cd: ast.ClassDef | t.CPtr) -> int: + """检查 ClassDef 是否继承自 t.CUnion,返回 1=是 / 0=否""" + if cd is None or cd.bases is None: + return 0 + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = bases.__len__() + if bn == 0: + return 0 + for bi in range(bn): + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + if _is_cunion_base(base_node) == 1: + return 1 + return 0 + + +# ============================================================ +# VTable 装饰器检测和继承关系判断 +# ============================================================ + +# 标记基类集合(非真实父类,仅作为类型标记) +_MARKER_BASES: t.CDefine = 8 +# 使用字符串比较代替集合,标记基类列表 +# Object, CVTable, Exception, CEnum, Enum, CStruct, CUnion, REnum + + +# ============================================================ +# _has_decorator — 检查 ClassDef/FunctionDef 的 decorator_list 中是否有指定装饰器 +# +# 支持 @t.Name 和 @Name 两种形式 +# 返回 1=有 / 0=无 +# ============================================================ +def _has_decorator(decorator_list: list[ast.AST | t.CPtr] | t.CPtr, + deco_name: str) -> int: + """检查 decorator_list 中是否有指定装饰器名""" + if decorator_list is None: + return 0 + dn: t.CSizeT = decorator_list.__len__() + if dn == 0: + return 0 + for di in range(dn): + deco: ast.AST | t.CPtr = decorator_list.get(di) + if deco is None: + continue + k: int = deco.kind() + # @t.NoVTable 形式(Attribute) + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco) + if at.attr is not None and string.strcmp(at.attr, deco_name) == 0: + # 检查 value 是 Name('t') + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if vn.id is not None and string.strcmp(vn.id, "t") == 0: + return 1 + return 0 + # @NoVTable 形式(Name,from t import NoVTable) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco) + if nm.id is not None and string.strcmp(nm.id, deco_name) == 0: + return 1 + return 0 + + +# ============================================================ +# _is_marker_base — 检查基类名是否为标记基类(非真实父类) +# +# 标记基类: Object, CVTable, Exception, CEnum, Enum, CStruct, CUnion, REnum +# ============================================================ +def _is_marker_base(base_name: str) -> int: + """检查基类名是否为标记基类,返回 1=是 / 0=否""" + if base_name is None: + return 0 + if string.strcmp(base_name, "Object") == 0: + return 1 + if string.strcmp(base_name, "CVTable") == 0: + return 1 + if string.strcmp(base_name, "Exception") == 0: + return 1 + if string.strcmp(base_name, "CEnum") == 0: + return 1 + if string.strcmp(base_name, "Enum") == 0: + return 1 + if string.strcmp(base_name, "CStruct") == 0: + return 1 + if string.strcmp(base_name, "CUnion") == 0: + return 1 + if string.strcmp(base_name, "REnum") == 0: + return 1 + return 0 + + +# ============================================================ +# _get_base_name — 从 base AST 节点提取基类名 +# +# 支持 Name(id), Attribute(attr), Subscript +# ============================================================ +def _get_base_name(base_node: ast.AST | t.CPtr) -> str: + """从 base AST 节点提取基类名,返回 None=失败""" + if base_node is None: + return None + k: int = base_node.kind() + # Name(id) 形式 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) + return nm.id + # Attribute(attr) 形式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node) + return at.attr + return None + + +# ============================================================ +# _get_parent_class — 获取 ClassDef 的真实父类名(非标记基类) +# +# 遍历 bases,返回第一个非标记基类的名字,None=无真实父类 +# ============================================================ +def _get_parent_class(cd: ast.ClassDef | t.CPtr) -> str: + """获取 ClassDef 的真实父类名,返回 None=无真实父类""" + if cd is None or cd.bases is None: + return None + bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases + bn: t.CSizeT = bases.__len__() + if bn == 0: + return None + for bi in range(bn): + base_node: ast.AST | t.CPtr = bases.get(bi) + if base_node is None: + continue + bname: str = _get_base_name(base_node) + if bname is not None and _is_marker_base(bname) == 0: + return bname + return None + + +# ============================================================ +# _has_any_func_cvtable — 检查类中是否有任何函数标记了 @t.CVTable +# +# 用于类级别未启用虚表时,检查函数级 @t.CVTable 是否触发虚表。 +# 跳过 __init__ 和 __before_init__(构造函数不进入虚表)。 +# ============================================================ +def _has_any_func_cvtable(cd: ast.ClassDef | t.CPtr) -> int: + """检查类中是否有任何函数标记了 @t.CVTable,返回 1=有 / 0=无""" + if cd is None or cd.children is None: + return 0 + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + cn: t.CSizeT = children.__len__() + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() != ast.ASTKind.FunctionDef: + continue + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd is None or fd.name is None: + continue + # 跳过构造函数 + if string.strcmp(fd.name, "__init__") == 0: + continue + if string.strcmp(fd.name, "__before_init__") == 0: + continue + if string.strcmp(fd.name, "__new__") == 0: + continue + if fd.decorator_list is not None: + if _has_decorator(fd.decorator_list, "CVTable") == 1: + return 1 + return 0 + + +# ============================================================ +# _should_method_be_virtual — 判断方法是否应该进入虚表 +# +# 规则(优先级从高到低): +# 1. 函数有 @t.NoVTable → 排除(返回 0) +# 2. 函数有 @t.CVTable → 包含(返回 1) +# 3. 类有 @t.CVTable → 包含(返回 1) +# 4. 有继承关系(父类非 NoVTable)→ 包含(返回 1) +# 5. 默认 → 排除(返回 0) +# ============================================================ +def _should_method_be_virtual(cd: ast.ClassDef | t.CPtr, + fd: ast.FunctionDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """判断方法是否应该进入虚表,返回 1=包含 / 0=排除""" + if fd is None: + return 0 + # 1. 检查函数级 @t.NoVTable(最高优先级,排除) + if fd.decorator_list is not None: + if _has_decorator(fd.decorator_list, "NoVTable") == 1: + return 0 + # 2. 检查函数级 @t.CVTable(明确包含) + if _has_decorator(fd.decorator_list, "CVTable") == 1: + return 1 + + # 3. 检查类级别 @t.CVTable + if cd is not None and cd.decorator_list is not None: + if _has_decorator(cd.decorator_list, "CVTable") == 1: + return 1 + + # 4. 检查继承关系 + parent_name: str = _get_parent_class(cd) + if parent_name is not None: + # 用 SHA1 感知查找父类,规避跨模块同名找错 + is_nvt: int = 0 + if trans is not None: + p_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + parent_name, trans.ModuleSha1) + if p_entry is not None: + is_nvt = p_entry.IsNoVTable + else: + is_nvt = HandlesStruct.is_novtable_by_name(parent_name) + if is_nvt != 1: + return 1 # 有继承且父类非 NoVTable + + # 5. 默认排除 + return 0 + + +# ============================================================ +# _detect_vtable_status — 检测类是否应该启用虚表 +# +# 规则: +# 1. @t.CVTable → 有虚表 +# 2. 有真实父类且非 NoVTable → 有虚表(自动启用) +# 3. @t.NoVTable → 检查函数级 @t.CVTable,有则启用 +# 4. 默认 → 检查函数级 @t.CVTable,有则启用 +# +# 返回: 1=有虚表 / 0=无虚表 +# ============================================================ +def _detect_vtable_status(cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """检测类是否应该启用虚表""" + if cd is None: + return 0 + + # 检查类装饰器 + if cd.decorator_list is not None: + # @t.CVTable 优先级最高,直接启用 + if _has_decorator(cd.decorator_list, "CVTable") == 1: + return 1 + # @t.NoVTable:类级别禁用,但检查函数级 @t.CVTable + if _has_decorator(cd.decorator_list, "NoVTable") == 1: + return _has_any_func_cvtable(cd) + + # 检查是否有真实父类(继承自动启用 CVTable) + parent_name: str = _get_parent_class(cd) + if parent_name is not None: + # 用 SHA1 感知查找父类,规避跨模块同名找错 + is_nvt: int = 0 + if trans is not None: + p_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + parent_name, trans.ModuleSha1) + if p_entry is not None: + is_nvt = p_entry.IsNoVTable + else: + is_nvt = HandlesStruct.is_novtable_by_name(parent_name) + if is_nvt == 1: + # 父类是 NoVTable,检查函数级 @t.CVTable + return _has_any_func_cvtable(cd) + return 1 # 有父类且非 NoVTable,自动启用虚表 + + # 默认(无装饰器无继承),检查函数级 @t.CVTable + return _has_any_func_cvtable(cd) + + +# ============================================================ +# _resolve_enum_member_type — 解析枚举成员的类型 +# +# - t.State → 默认 i32 +# - int / t.CInt8T / t.CInt16T / t.CInt32T / t.CInt64T 等 → 对应整数类型 +# - 联合注解(t.State | t.CInt8T)递归查找实际类型 +# ============================================================ +def _resolve_enum_member_type(pool: memhub.MemBuddy | t.CPtr, + ann_node: ast.AST | t.CPtr, + imported_modules: str, + from_imports: str) -> llvmlite.LLVMType | t.CPtr: + """解析枚举成员的类型注解为 LLVM 整数类型""" + if ann_node is None: + return llvmlite.Int32(pool) + + k: int = ann_node.kind() + + # Attribute 节点: t.State / int / t.CInt8T 等 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(ann_node) + if at.attr is None: + return llvmlite.Int32(pool) + # t.State → 默认 i32 + if string.strcmp(at.attr, "State") == 0: + return llvmlite.Int32(pool) + # 其他 t.CXxx 类型 + ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, at.attr) + if ty is not None: + return ty + return llvmlite.Int32(pool) + + # Name 节点: from-import 形式(State / CInt) + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_node) + if nm.id is None: + return llvmlite.Int32(pool) + if string.strcmp(nm.id, "State") == 0: + return llvmlite.Int32(pool) + ty2: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, nm.id) + if ty2 is not None: + return ty2 + return llvmlite.Int32(pool) + + # BinOp 节点: t.State | t.CInt8T(递归查找实际类型) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(ann_node) + if bop.op == ast.OpKind.BitOr: + left_ty: llvmlite.LLVMType | t.CPtr = _resolve_enum_member_type( + pool, bop.left, imported_modules, from_imports) + # 跳过 t.State(i32 默认),优先返回具体类型 + left_bits: int = HandlesType.get_llvm_type_bits(left_ty) + if left_bits != 0 and not _is_state_annotation(bop.left): + return left_ty + right_ty: llvmlite.LLVMType | t.CPtr = _resolve_enum_member_type( + pool, bop.right, imported_modules, from_imports) + if right_ty is not None and not _is_state_annotation(bop.right): + return right_ty + # 两边都是 State 或无法确定,返回较宽的 + right_bits: int = HandlesType.get_llvm_type_bits(right_ty) + if left_bits >= right_bits: + return left_ty + return right_ty + return llvmlite.Int32(pool) + + return llvmlite.Int32(pool) + + +# ============================================================ +# _is_state_annotation — 检查注解节点是否为 t.State +# ============================================================ +def _is_state_annotation(node: ast.AST | t.CPtr) -> int: + """检查注解节点是否为 t.State,返回 1=是 / 0=否""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is not None and string.strcmp(at.attr, "State") == 0: + return 1 + return 0 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and string.strcmp(nm.id, "State") == 0: + return 1 + return 0 + return 0 + + +# ============================================================ +# _extract_int_value — 从 AST 节点提取整数值 +# +# 支持 Constant(int) 和 UnaryOp(USub, Constant(int)) +# ============================================================ +def _extract_int_value(node: ast.AST | t.CPtr) -> t.CInt64T: + """从 AST 节点提取整数值,失败返回 0""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_INT: + return cn.int_val + return 0 + if k == ast.ASTKind.UnaryOp: + uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uo.op == ast.OpKind.USub: + inner: t.CInt64T = _extract_int_value(uo.operand) + return -inner + return 0 + return 0 + + +# ============================================================ +# _translate_enum_def — 翻译枚举类定义 +# +# 遍历 class body 中的 AnnAssign,收集成员名、类型、值 +# 自动赋值:无值时从上一值+1递增(首值默认 0) +# 基准类型:所有成员类型中 Bits 最大的(t.State 视为 i32) +# ============================================================ +def _translate_enum_def(trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """翻译枚举类定义,返回 0""" + if cd is None or cd.name is None or trans is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 已注册则跳过 + if HandlesEnum.is_enum_class(class_name) == 1: + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + stdio.printf("[ENUM] %s has no body\n", class_name) + return 0 + + cn: t.CSizeT = children.__len__() + + # 临时数组存储成员信息 + member_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + member_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + member_values_buf: t.CInt64T | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL) + if member_names_buf is None or member_types_buf is None or member_values_buf is None: + return 0 + string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + string.memset(member_types_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + string.memset(member_values_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL) + + member_count: int = 0 + next_val: t.CInt64T = 0 + + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa is None or aa.target is None: + continue + + # 获取成员名 + if aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + + # 解析成员类型 + member_ty: llvmlite.LLVMType | t.CPtr = _resolve_enum_member_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports) + + # 解析成员值 + has_value: int = 0 + cur_val: t.CInt64T = 0 + if aa.value is not None: + cur_val = _extract_int_value(aa.value) + has_value = 1 + else: + cur_val = next_val + + # 下一个自动值 + next_val = cur_val + 1 + + # 存储 + if member_count < ENUM_MEMBER_MAX_LOCAL: + member_names_buf[member_count] = t.CSizeT(tgt.id) + member_types_buf[member_count] = t.CSizeT(member_ty) + member_values_buf[member_count] = cur_val + member_count += 1 + + if member_count == 0: + stdio.printf("[ENUM] %s has no members\n", class_name) + return 0 + + # 确定基准类型:所有成员类型中 Bits 最大的 + base_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + max_bits: int = 0 + for mi in range(member_count): + ty_addr: t.CSizeT = member_types_buf[mi] + if ty_addr == 0: + continue + mty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(ty_addr, t.CPtr)) + bits: int = HandlesType.get_llvm_type_bits(mty) + if bits > max_bits: + max_bits = bits + base_ty = mty + + # 注册枚举 + entry: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.register_enum( + pool, class_name, base_ty) + if entry is None: + stdio.printf("[ENUM] failed to register %s\n", class_name) + return 0 + + # 添加成员 + for mi in range(member_count): + fname_addr: t.CSizeT = member_names_buf[mi] + if fname_addr == 0: + continue + mname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) + fty_addr2: t.CSizeT = member_types_buf[mi] + if fty_addr2 == 0: + continue + mty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(fty_addr2, t.CPtr)) + mval: t.CInt64T = member_values_buf[mi] + if mname is not None and mty2 is not None: + HandlesEnum.add_enum_member(pool, entry, mname, mval, mty2) + + stdio.printf("[ENUM] registered %s with %d members, base_bits=%d\n", + class_name, member_count, max_bits) + return 0 + + +# ============================================================ +# _get_type_size — 计算 LLVM 类型的字节大小 +# +# 用于联合体确定最大字段大小 +# ============================================================ +def _get_type_size(ty: llvmlite.LLVMType | t.CPtr) -> int: + """计算 LLVM 类型的字节大小""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Int(bits): + return (bits + 7) // 8 + case llvmlite.LLVMType.Float(bits): + return bits // 8 + case llvmlite.LLVMType.Ptr(pointee): + return 8 + case llvmlite.LLVMType.Array(elem_ty, count): + return _get_type_size(elem_ty) * count + case llvmlite.LLVMType.Struct(fields, fcount, name): + total: int = 0 + cur: llvmlite.ParamNode | t.CPtr = fields + i: int = 0 + while cur is not None and i < fcount: + if cur.Ty is not None: + fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) + total += _get_type_size(fty) + cur = cur.Next + i += 1 + return total + case _: + return 8 + + +# ============================================================ +# _translate_union_def — 翻译联合体定义 +# +# 联合体语法: +# class MyUnion(t.CUnion): +# a: t.CInt +# b: t.CFloat +# c: t.CInt64T +# +# 实现方式: +# - 收集所有字段类型 +# - 计算最大字段字节大小 max_size +# - LLVM 类型 = Struct([Array(Int8, max_size)]) # { [N x i8] } +# - 注册到 HandlesStruct 并标记 IsUnion=1 +# - 字段访问通过 bitcast 实现(HandlesExpr 中处理) +# ============================================================ +def _translate_union_def(trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr) -> int: + """翻译联合体定义,返回 0""" + if cd is None or cd.name is None or trans is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前) + HandlesStruct.add_visible_struct(pool, class_name) + + # 检查是否已注册(用 SHA1 区分跨模块同名类) + existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + class_name, trans.ModuleSha1) + if existing is not None: + # Phase B: 将已存在的命名结构体注册到当前模块 + if existing.Ty is not None: + llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) + # SHA1 已在 register_struct 时设置,无需再补 + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + stdio.printf("[UNION] %s has no body\n", class_name) + return 0 + + cn: t.CSizeT = children.__len__() + + # 临时数组存储字段信息 + field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if field_names_buf is None or field_types_buf is None: + return 0 + string.memset(field_names_buf, 0, 8 * 32) + string.memset(field_types_buf, 0, 8 * 32) + + field_count: int = 0 + max_size: int = 0 + + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa is None or aa.target is None: + continue + + # 获取字段名 + if aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + + # 解析字段类型 + field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports) + if field_ty is None: + field_ty = llvmlite.Int32(pool) + + # 计算字段大小,更新 max_size + fsize: int = _get_type_size(field_ty) + if fsize > max_size: + max_size = fsize + + # 存储到数组 + if field_count < 32: + field_names_buf[field_count] = t.CSizeT(tgt.id) + field_types_buf[field_count] = t.CSizeT(field_ty) + field_count += 1 + + if field_count == 0: + stdio.printf("[UNION] %s has no fields\n", class_name) + return 0 + + if max_size < 1: + max_size = 1 + + # 创建联合体的 LLVM 类型: Struct([Array(Int8, max_size)]) + # 即 { [max_size x i8] } + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + array_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, max_size) + + # 构建 ParamNode 链表(单字段:字节数组) + pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) + if pnode is None: + return 0 + string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) + pnode.Ty = array_ty + + # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" + union_type_name: str = class_name + if trans.ModuleSha1 is not None: + union_name_buf: t.CChar | t.CPtr = pool.alloc(64) + if union_name_buf is not None: + viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) + union_type_name = union_name_buf + + union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name) + if union_ty is None: + stdio.printf("[UNION] failed to create type for %s\n", class_name) + return 0 + + # 注册命名结构体到模块 + llvmlite.module_add_named_type(trans.Module, pool, union_ty) + + # 注册到 HandlesStruct(传递 SHA1 在注册时直接设置,避免跨模块同名找错 entry) + entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( + pool, class_name, union_ty, trans.ModuleSha1) + if entry is None: + stdio.printf("[UNION] failed to register %s\n", class_name) + return 0 + + # 标记为当前文件可见(命名空间隔离) + HandlesStruct.add_visible_struct(pool, class_name) + + # 标记为联合体(直接用 entry,规避跨模块同名 find_struct 找错) + entry.IsUnion = 1 + + # 添加字段信息(所有字段 Index=0,因为共享偏移 0) + for fi in range(field_count): + fname_addr: t.CSizeT = field_names_buf[fi] + if fname_addr == 0: + continue + fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) + fty_addr2: t.CSizeT = field_types_buf[fi] + if fty_addr2 == 0: + continue + fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(fty_addr2, t.CPtr)) + if fname is not None and fty2 is not None: + HandlesStruct.add_field(pool, entry, fname, fty2, None, None) + + stdio.printf("[UNION] registered %s with %d fields, max_size=%d\n", + class_name, field_count, max_size) + return 0 + + +# ============================================================ +# translate_class_def — 翻译 class 定义 +# +# 遍历 class body 中的 AnnAssign 语句,收集字段类型 +# 创建 LLVM StructType 并注册到 HandlesStruct +# ============================================================ +# ============================================================ +# 泛型类模板存储(模块级) +# +# 泛型类 class list[T]: 不直接发射 IR,而是存储为模板, +# 等遇到 list[int](pool) 实例化时触发 _specialize_generic_class +# ============================================================ + +_generic_class_names: list[str] | t.CPtr = None +_generic_class_nodes: list[ast.ClassDef | t.CPtr] | t.CPtr = None + + +def _is_generic_class(cd: ast.ClassDef | t.CPtr) -> int: + """检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否""" + if cd is None: + return 0 + tp: list[str] | t.CPtr = cd.type_params + if tp is None: + return 0 + if tp.__len__() == 0: + return 0 + return 1 + + +def _register_generic_template(pool: memhub.MemBuddy | t.CPtr, + cd: ast.ClassDef | t.CPtr): + """注册泛型类模板(类名 + ClassDef 节点)""" + global _generic_class_names, _generic_class_nodes + if _generic_class_names is None: + _generic_class_names = list[str](pool, 8) + _generic_class_nodes = list[ast.ClassDef | t.CPtr](pool, 8) + # 检查是否已注册 + cn: t.CSizeT = _generic_class_names.__len__() + i: t.CSizeT + for i in range(cn): + nm: str = _generic_class_names.get(i) + if nm is not None and string.strcmp(nm, cd.name) == 0: + return + _generic_class_names.append(cd.name) + _generic_class_nodes.append(cd) + + +def _find_generic_template(class_name: str) -> ast.ClassDef | t.CPtr: + """查找泛型类模板,返回 ClassDef 节点或 None""" + if _generic_class_names is None or class_name is None: + return None + cn: t.CSizeT = _generic_class_names.__len__() + i: t.CSizeT + for i in range(cn): + nm: str = _generic_class_names.get(i) + if nm is not None and string.strcmp(nm, class_name) == 0: + return _generic_class_nodes.get(i) + return None + + +def _mangle_generic_class_name(pool: memhub.MemBuddy | t.CPtr, + class_name: str, + type_args: list[str] | t.CPtr) -> str: + """生成特化类名: list + [int] -> list[int] + + 分配新缓冲区拼接,避免原地 strcat 导致缓冲区溢出 + """ + if class_name is None or type_args is None or pool is None: + return class_name + n: t.CSizeT = type_args.__len__() + if n == 0: + return class_name + # 计算总长度: class_name + "[" + arg0 + "," + arg1 + ... + "]" + NUL + total_len: t.CSizeT = string.strlen(class_name) + 2 # "[" 和 "]" + i: t.CSizeT + for i in range(n): + if i > 0: + total_len += 1 # "," + ta: str = type_args.get(i) + if ta is not None: + total_len += string.strlen(ta) + total_len += 1 # NUL + # 分配新缓冲区 + mangled: str = pool.alloc(total_len) + if mangled is None: + return class_name + mangled[0] = '\0' + string.strcat(mangled, class_name) + string.strcat(mangled, "[") + for i in range(n): + if i > 0: + string.strcat(mangled, ",") + ta: str = type_args.get(i) + if ta is not None: + string.strcat(mangled, ta) + string.strcat(mangled, "]") + return mangled + + +# ============================================================ +# 类型注解拷贝(用于泛型特化) +# +# _clone_annotation: 拷贝类型注解表达式,替换类型参数 T 为具体类型 +# _clone_arguments: 拷贝 Arguments 节点,替换 arg annotation 中的 T +# _clone_classdef_for_spec: 拷贝 ClassDef 用于泛型特化 +# ============================================================ + +def _clone_annotation(pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + tp_names: list[str] | t.CPtr, + type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr: + """拷贝类型注解表达式,替换类型参数 T 为具体类型名 + + tp_names: 类型参数名列表 ['T'] + type_args: 类型实参名列表 ['int'] + """ + if node is None: + return None + k: int = node.kind() + + # Name: 可能是类型参数 T + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None: + n: t.CSizeT = tp_names.__len__() if tp_names is not None else 0 + i: t.CSizeT + for i in range(n): + tpn: str = tp_names.get(i) + if tpn is not None and string.strcmp(nm.id, tpn) == 0: + ta: str = type_args.get(i) + # 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析 + return HandlesType._parse_type_string(pool, ta, nm.ctx) + return ast.Name(pool, nm.id, nm.ctx) + return None + + # Attribute: t.CPtr 等 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + new_value: ast.AST | t.CPtr = _clone_annotation(pool, at.value, tp_names, type_args) + return ast.Attribute(pool, new_value, at.attr, at.ctx) + + # BinOp: T | t.CPtr 等 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + new_left: ast.AST | t.CPtr = _clone_annotation(pool, bop.left, tp_names, type_args) + new_right: ast.AST | t.CPtr = _clone_annotation(pool, bop.right, tp_names, type_args) + return ast.BinOp(pool, new_left, bop.op, new_right) + + # Subscript: list[int] 等 + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + new_value2: ast.AST | t.CPtr = _clone_annotation(pool, sub.value, tp_names, type_args) + new_slice: ast.AST | t.CPtr = _clone_annotation(pool, sub.slice, tp_names, type_args) + return ast.Subscript(pool, new_value2, new_slice, sub.ctx) + + # Tuple: (T, int) 等 + if k == ast.ASTKind.Tuple: + tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node) + new_elts: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8) + if tup.elts is not None: + en: t.CSizeT = tup.elts.__len__() + ei: t.CSizeT + for ei in range(en): + el: ast.AST | t.CPtr = tup.elts.get(ei) + new_el: ast.AST | t.CPtr = _clone_annotation(pool, el, tp_names, type_args) + if new_el is not None: + new_elts.append(new_el) + return ast.Tuple(pool, new_elts, tup.ctx) + + # Constant: 默认值等 + if k == ast.ASTKind.Constant: + cnst: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + return ast.Constant(pool, cnst.const_kind, cnst.int_val, cnst.float_val, + cnst.str_val, cnst.lineno, cnst.col_offset) + + # 其他: 直接引用(不拷贝) + return node + + +def _clone_arguments(pool: memhub.MemBuddy | t.CPtr, + args: ast.AST | t.CPtr, + tp_names: list[str] | t.CPtr, + type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr: + """拷贝 Arguments 节点,替换 arg annotation 中的 T""" + if args is None: + return None + if args.kind() != ast.ASTKind.Arguments: + return args + old_args: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args) + # 拷贝 args 列表,替换每个 Arg 的 annotation + new_arg_list: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8) + if old_args.args is not None: + an: t.CSizeT = old_args.args.__len__() + ai: t.CSizeT + for ai in range(an): + arg_node: ast.AST | t.CPtr = old_args.args.get(ai) + if arg_node is None: + continue + if arg_node.kind() == ast.ASTKind.Arg: + ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(arg_node) + new_anno: ast.AST | t.CPtr = _clone_annotation(pool, ag.annotation, tp_names, type_args) + new_arg: ast.Arg | t.CPtr = ast.Arg(pool, ag.arg, new_anno) + new_arg_list.append(new_arg) + else: + new_arg_list.append(arg_node) + return ast.Arguments(pool, new_arg_list, old_args.vararg, old_args.kwarg, + old_args.defaults, old_args.kw_defaults) + + +def _clone_classdef_for_spec(pool: memhub.MemBuddy | t.CPtr, + cd: ast.ClassDef | t.CPtr, + spec_name: str, + tp_names: list[str] | t.CPtr, + type_args: list[str] | t.CPtr) -> ast.ClassDef | t.CPtr: + """拷贝 ClassDef 节点用于泛型特化 + + - 替换类名为 spec_name + - 清除 type_params(特化后不是泛型类) + - 拷贝 children 中的 AnnAssign 和 FunctionDef,替换类型注解中的 T + - 方法体直接引用原始节点(通过 type_map 上下文处理 T) + """ + # 创建新 ClassDef(type_params=None 表示非泛型) + new_cd: ast.ClassDef | t.CPtr = ast.ClassDef(pool, spec_name, cd.bases, cd.keywords, + cd.decorator_list, None) + # 拷贝 children + if cd.children is not None: + cn: t.CSizeT = cd.children.__len__() + ci: t.CSizeT + for ci in range(cn): + child: ast.AST | t.CPtr = cd.children.get(ci) + if child is None: + continue + ck: int = child.kind() + + if ck == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) + new_target: ast.AST | t.CPtr = aa.target + new_anno2: ast.AST | t.CPtr = _clone_annotation(pool, aa.annotation, tp_names, type_args) + new_value3: ast.AST | t.CPtr = aa.value + new_aa: ast.AnnAssign | t.CPtr = ast.AnnAssign(pool, new_target, new_anno2, new_value3, aa.simple) + new_cd.append(new_aa) + + elif ck == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + new_args2: ast.AST | t.CPtr = _clone_arguments(pool, fd.args, tp_names, type_args) + new_returns2: ast.AST | t.CPtr = _clone_annotation(pool, fd.returns, tp_names, type_args) + new_fd: ast.FunctionDef | t.CPtr = ast.FunctionDef(pool, fd.name, new_args2, + fd.decorator_list, new_returns2, 0) + # 方法体直接引用原始节点 + if fd.children is not None: + bcn: t.CSizeT = fd.children.__len__() + bci: t.CSizeT + for bci in range(bcn): + body_stmt: ast.AST | t.CPtr = fd.children.get(bci) + if body_stmt is not None: + new_fd.append(body_stmt) + new_cd.append(new_fd) + + else: + new_cd.append(child) + + return new_cd + + +# ============================================================ +# 泛型特化缓存(模块级) +# ============================================================ + +_spec_keys: list[str] | t.CPtr = None +_spec_names: list[str] | t.CPtr = None + + +def _find_cached_spec(spec_key: str) -> str: + """查找已缓存的特化名,未找到返回 None""" + if _spec_keys is None or spec_key is None: + return None + n: t.CSizeT = _spec_keys.__len__() + i: t.CSizeT + for i in range(n): + k: str = _spec_keys.get(i) + if k is not None and string.strcmp(k, spec_key) == 0: + return _spec_names.get(i) + return None + + +def _cache_spec(pool: memhub.MemBuddy | t.CPtr, spec_key: str, spec_name: str): + """缓存特化结果""" + global _spec_keys, _spec_names + if _spec_keys is None: + _spec_keys = list[str](pool, 8) + _spec_names = list[str](pool, 8) + _spec_keys.append(spec_key) + _spec_names.append(spec_name) + + +def _specialize_generic_class(trans: HT.Translator | t.CPtr, + class_name: str, + type_args: list[str] | t.CPtr) -> str: + """特化泛型类,返回特化类名 + + 1. 查找泛型模板 + 2. 生成特化名 + 3. 检查缓存 + 4. 拷贝 ClassDef 节点(替换类型注解中的 T) + 5. 设置 type_map 上下文(用于方法体中的 T 替换) + 6. 调用 translate_class_def 翻译特化类 + 7. 返回特化名 + """ + if trans is None or class_name is None or type_args is None: + return None + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + + # 1. 查找泛型模板 + template_cd: ast.ClassDef | t.CPtr = _find_generic_template(class_name) + if template_cd is None: + return None + + # 2. 生成特化名 + spec_name: str = _mangle_generic_class_name(pool, class_name, type_args) + if spec_name is None: + return None + + # 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突) + # 分配新缓冲区避免原地 strcat 溢出 + sk_n: t.CSizeT = type_args.__len__() + sk_total: t.CSizeT = string.strlen(class_name) + 2 # "<" 和 ">" + sk_i: t.CSizeT + for sk_i in range(sk_n): + if sk_i > 0: + sk_total += 1 # "," + sk_ta: str = type_args.get(sk_i) + if sk_ta is not None: + sk_total += string.strlen(sk_ta) + sk_total += 1 # NUL + spec_key: str = pool.alloc(sk_total) + if spec_key is None: + return None + spec_key[0] = '\0' + string.strcat(spec_key, class_name) + string.strcat(spec_key, "<") + for sk_i in range(sk_n): + if sk_i > 0: + string.strcat(spec_key, ",") + sk_ta: str = type_args.get(sk_i) + if sk_ta is not None: + string.strcat(spec_key, sk_ta) + string.strcat(spec_key, ">") + cached: str = _find_cached_spec(spec_key) + if cached is not None: + return cached + + # 4. 检查是否已注册(Phase B 重复特化) + existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) + if existing is not None: + _cache_spec(pool, spec_key, spec_name) + return spec_name + + # 预注册缓存(防止递归) + _cache_spec(pool, spec_key, spec_name) + + # 5. 拷贝 ClassDef 节点 + tp_names: list[str] | t.CPtr = template_cd.type_params + spec_cd: ast.ClassDef | t.CPtr = _clone_classdef_for_spec( + pool, template_cd, spec_name, tp_names, type_args) + if spec_cd is None: + return None + + # 6. 设置 type_map 上下文(用于方法体中的 T 替换) + trans.GenericTypeParamNames = tp_names + trans.GenericTypeArgs = type_args + HandlesType.set_generic_context(tp_names, type_args) + + # 7. 翻译特化类 + translate_class_def(trans, spec_cd) + + # 8. 清除 type_map 上下文 + trans.GenericTypeParamNames = None + trans.GenericTypeArgs = None + HandlesType.clear_generic_context() + + return spec_name + + +def translate_class_def(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 class 定义,返回 0""" + if node is None or trans is None: + return 0 + + cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node) + if cd is None or cd.name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + class_name: str = cd.name + + # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前, + # 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类) + HandlesStruct.add_visible_struct(pool, class_name) + + # 枚举类:交给 HandlesEnum 处理 + if _is_enum_class(cd) == 1: + return _translate_enum_def(trans, cd) + + # 联合体类:交给联合体处理 + if _is_union_class(cd) == 1: + return _translate_union_def(trans, cd) + + # 泛型类:存储为模板,不发射 IR(等实例化时特化) + if _is_generic_class(cd) == 1: + _register_generic_template(pool, cd) + return 0 + + # 检查是否已注册(用 SHA1 区分跨模块同名类) + existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + class_name, trans.ModuleSha1) + if existing is not None: + # 结构体已注册(Phase B 重新翻译),但仍需在当前模块中翻译方法 + if existing.Ty is not None: + # Phase B: 将已存在的命名结构体注册到当前模块(输出类型定义行) + llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) + _translate_oop_methods(trans, cd, existing.Ty, class_name) + # SHA1 已在 register_struct 时设置,无需再补 + return 0 + + # ============================================================ + # VTable 检测:判断是否启用虚表 + # ============================================================ + has_vtable: int = _detect_vtable_status(cd, trans) + parent_name: str = _get_parent_class(cd) + is_novtable_deco: int = 0 + if cd.decorator_list is not None: + if _has_decorator(cd.decorator_list, "NoVTable") == 1: + is_novtable_deco = 1 + + # ============================================================ + # 1. 遍历 class body,收集字段信息 + # ============================================================ + # 用 CSizeT 数组存储指针值(64 位系统上 8 字节) + field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + field_defaults_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + field_annot_buf: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if field_names_buf is None or field_types_buf is None or field_defaults_buf is None: + return 0 + if field_annot_buf is None: + return 0 + string.memset(field_names_buf, 0, 8 * 32) + string.memset(field_types_buf, 0, 8 * 32) + string.memset(field_defaults_buf, 0, 8 * 32) + string.memset(field_annot_buf, 0, 8 * 32) + + field_count: int = 0 + + # ============================================================ + # 1.5 继承父类字段(字段展平) + # + # 父类字段排在子类字段之前,结构体布局: + # [vtable_ptr?, parent_field1, ..., child_field1, ...] + # 跳过父类的 __vtable__ 字段(子类会有自己的 vtable 指针) + # ============================================================ + if parent_name is not None: + # 用 SHA1 感知查找父类,规避跨模块同名找错 + parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + parent_name, trans.ModuleSha1) + if parent_entry is not None: + pfc: int = parent_entry.FieldCount + for pfi in range(pfc): + pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + parent_entry, pfi) + if pfe is None: + continue + pfn: str = HandlesStruct.get_field_name_ptr(pfe) + if pfn is None: + continue + # 跳过父类的 vtable 指针字段 + if string.strcmp(pfn, "__vtable__") == 0: + continue + if field_count < 32: + pft: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_field_type_ptr(pfe) + pfd: ast.AST | t.CPtr = HandlesStruct.get_field_default_ptr(pfe) + pfa: str = HandlesStruct.get_field_annot_class_name(pfe) + field_names_buf[field_count] = t.CSizeT(pfn) + field_types_buf[field_count] = t.CSizeT(pft) + if pfd is not None: + field_defaults_buf[field_count] = t.CSizeT(pfd) + else: + field_defaults_buf[field_count] = 0 + if pfa is not None: + stored_val: t.CSizeT = t.CSizeT(pfa) + field_annot_buf[field_count] = stored_val + else: + field_annot_buf[field_count] = 0 + field_count += 1 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return 0 + + cn: t.CSizeT = children.__len__() + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + sk: int = stmt.kind() + + if sk != ast.ASTKind.AnnAssign: continue + + # AnnAssign(target=Name(id), annotation=type, value=...) + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) + if aa is None or aa.target is None: + continue + + # 获取字段名 + if aa.target.kind() != ast.ASTKind.Name: + continue + tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if tgt.id is None: + continue + + # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) + # 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码 + # 避免类体中 list 字面量翻译失败(类体无 pool 变量上下文) + if string.strcmp(tgt.id, "__provides__") == 0: + continue + if string.strcmp(tgt.id, "__requires__") == 0: + continue + if string.strcmp(tgt.id, "__require_must__") == 0: + continue + + # 解析字段类型 + field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports) + if field_ty is None: + field_ty = llvmlite.Int32(pool) + + # 存储到数组(指针转 CSizeT) + if field_count < 32: + diag_name_val: t.CSizeT = t.CSizeT(tgt.id) + field_names_buf[field_count] = diag_name_val + field_types_buf[field_count] = t.CSizeT(field_ty) + # 存储默认值 AST 指针(None=无默认值) + if aa.value is not None: + field_defaults_buf[field_count] = t.CSizeT(aa.value) + else: + field_defaults_buf[field_count] = 0 + # 提取原始类型注解的类名(联合类型简化为 Ptr(i8) 时回退查找结构体) + if aa.annotation is not None: + annot_cn: str = HandlesType.extract_class_name_from_annotation( + aa.annotation, trans._imported_modules) + if annot_cn is not None: + diag_cn_val: t.CSizeT = t.CSizeT(annot_cn) + field_annot_buf[field_count] = diag_cn_val + else: + field_annot_buf[field_count] = 0 + else: + field_annot_buf[field_count] = 0 + field_count += 1 + + if field_count == 0: + stdio.printf("[CLASS] %s has no fields\n", class_name) + return 0 + + # ============================================================ + # 2. 创建 LLVM StructType + # ============================================================ + # 构建 ParamNode 链表 + first_node: llvmlite.ParamNode | t.CPtr = None + prev_node: llvmlite.ParamNode | t.CPtr = None + total_field_count: int = field_count + + # 如果有虚表,首字段添加 i8* vtable 指针 + if has_vtable == 1: + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + vtable_node: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) + if vtable_node is None: + stdio.printf("[CLASS] failed to alloc vtable node for %s\n", class_name) + return 0 + string.memset(vtable_node, 0, llvmlite.ParamNode.__sizeof__()) + vtable_node.Ty = i8_ptr_ty + first_node = vtable_node + prev_node = vtable_node + total_field_count = field_count + 1 + + for fi in range(field_count): + fty_addr: t.CSizeT = field_types_buf[fi] + if fty_addr == 0: + continue + fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr, t.CPtr)) + + # 创建 ParamNode + pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) + if pnode is None: + continue + string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) + pnode.Ty = fty + + if first_node is None: + first_node = pnode + if prev_node is not None: + prev_node.Next = pnode + prev_node = pnode + + # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" + type_name: str = class_name + if trans.ModuleSha1 is not None: + name_buf: t.CChar | t.CPtr = pool.alloc(64) + if name_buf is not None: + viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) + type_name = name_buf + + # 创建 StructType(命名结构体) + struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name) + if struct_ty is None: + stdio.printf("[CLASS] failed to create StructType for %s\n", class_name) + return 0 + + # 注册命名结构体到模块(输出 %"name" = type { ... } 定义行) + llvmlite.module_add_named_type(trans.Module, pool, struct_ty) + + # 扫描字段类型,为跨模块结构体引用添加 opaque 声明 + # 例如 list[int].__pool__ 引用 memhub.MemManager,需要在当前模块添加 %"sha1.MemManager" = type opaque + for fi in range(field_count): + fty_addr_op: t.CSizeT = field_types_buf[fi] + if fty_addr_op == 0: + continue + fty_op: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr_op, t.CPtr)) + llvmlite.module_ensure_opaque_for_type(trans.Module, pool, fty_op) + + # ============================================================ + # 3. 注册到 HandlesStruct + # ============================================================ + entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct( + pool, class_name, struct_ty, trans.ModuleSha1) + if entry is None: + stdio.printf("[CLASS] failed to register %s\n", class_name) + return 0 + + # 标记 VTable 状态(直接用 entry,规避跨模块同名 find_struct 找错) + if has_vtable == 1: + entry.HasVTable = 1 + if is_novtable_deco == 1: + entry.IsNoVTable = 1 + if parent_name is not None: + entry.ParentName = parent_name + + # 添加字段信息 + # 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始 + if has_vtable == 1: + i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + HandlesStruct.add_field(pool, entry, "__vtable__", i8_ptr_ty2, None, None) + + for fi in range(field_count): + fname_addr: t.CSizeT = field_names_buf[fi] + if fname_addr == 0: + continue + fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) + fty_addr2: t.CSizeT = field_types_buf[fi] + if fty_addr2 == 0: + continue + fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr2, t.CPtr)) + # 恢复默认值 AST 指针 + fdef_addr: t.CSizeT = field_defaults_buf[fi] + fdef: ast.AST | t.CPtr = None + if fdef_addr != 0: + fdef = (ast.AST | t.CPtr)(t.CVoid(fdef_addr, t.CPtr)) + # 恢复注解类名指针 + fannot_addr: t.CSizeT = field_annot_buf[fi] + fannot: t.CChar | t.CPtr = None + if fannot_addr != 0: + fannot = (t.CChar | t.CPtr)(t.CVoid(fannot_addr, t.CPtr)) + if fname is not None and fty2 is not None: + HandlesStruct.add_field(pool, entry, fname, fty2, fdef, fannot) + + stdio.printf("[CLASS] registered %s with %d fields (vtable=%d)\n", + class_name, field_count, has_vtable) + + # Phase 1a 声明模式:只注册 struct,不翻译方法体 + if trans._declare_only == 1: + return 0 + + # ============================================================ + # 4. OOP 方法处理:扫描 FunctionDef,标记 OOP,翻译方法,生成 __before_init__ + # ============================================================ + _translate_oop_methods(trans, cd, struct_ty, class_name) + + return 0 + + +# ============================================================ +# VTable 生成 +# +# 生成 VTable 全局变量: +# @"SHA1.ClassName.vtable" = internal constant { i8*, i8*, ... } { +# i8* bitcast (ret (params)* @"SHA1.ClassName.method1" to i8*), +# ... +# } +# +# VTable 槽位顺序: class body 中 FunctionDef 的出现顺序 +# ============================================================ + +VTBL_METHOD_MAX: t.CDefine = 32 + + +# _vtable_strcat — 将 src 追加到 dst 末尾 +def _vtable_strcat(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, + src: t.CChar | t.CPtr): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: + return + dlen: t.CSizeT = string.strlen(dst) + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: + return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# _vtable_name_needs_quote — 检查 LLVM 标识符是否需要引号 +def _vtable_name_needs_quote(name: str) -> int: + """检查 LLVM 标识符是否需要引号(以数字开头或含 '.')""" + if name is None: + return 0 + if '0' <= name[0] <= '9': + return 1 + for i in name: + if i == '.': + return 1 + return 0 + + +# _format_func_type_str — 从 Function 对象生成函数类型字符串 +# +# 格式: ret_ty (param1_ty, param2_ty, ...) +# 例如: void ({i32, i32}*, i32) +def _format_func_type_str(pool: memhub.MemBuddy | t.CPtr, + buf: t.CChar | t.CPtr, buf_size: t.CSizeT, + func: llvmlite.Function | t.CPtr) -> int: + """从 Function 对象生成函数类型字符串""" + if buf is None or func is None or buf_size == 0: + return 0 + buf[0] = '\0' + + # 打印返回类型(使用访问器函数避免跨模块直接字段访问) + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func) + ret_buf: t.CChar | t.CPtr = pool.alloc(128) + if ret_buf is not None and ret_ty is not None: + ret_buf[0] = '\0' + llvmlite.TypePrint(ret_buf, 128, ret_ty, pool) + _vtable_strcat(buf, buf_size, ret_buf) + _vtable_strcat(buf, buf_size, " (") + + # 遍历参数(使用访问器函数避免跨模块直接字段访问) + cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + first: int = 1 + param_buf: t.CChar | t.CPtr = pool.alloc(128) + while cur is not None: + if first == 0: + _vtable_strcat(buf, buf_size, ", ") + if param_buf is not None: + param_buf[0] = '\0' + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur) + if param_ty is not None: + llvmlite.TypePrint(param_buf, 128, param_ty, pool) + _vtable_strcat(buf, buf_size, param_buf) + cur = llvmlite.param_get_next(cur) + first = 0 + _vtable_strcat(buf, buf_size, ")") + return 1 + + +# _generate_vtable — 生成 VTable 全局变量 +# +# 1. 收集 class body 中所有 FunctionDef 作为虚方法 +# 2. 构造 VTable 类型 { i8*, i8*, ... } +# 3. 构造初始化字符串 { i8* bitcast (...), ... } +# 4. 创建全局变量 @"SHA1.ClassName.vtable" +# 5. 存储虚方法名列表到 StructEntry +def _generate_vtable(trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + class_name: str) -> int: + """生成 VTable 全局变量""" + if trans is None or cd is None or class_name is None: + return 0 + + # 懒导入 + import lib.core.Handles.HandlesFunctions as HandlesFunctions + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return 0 + cn: t.CSizeT = children.__len__() + + # 1. 收集虚方法信息 + full_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * VTBL_METHOD_MAX) + method_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * VTBL_METHOD_MAX) + # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) + method_parent_sha1s: t.CSizeT | t.CPtr = pool.alloc(8 * VTBL_METHOD_MAX) + if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None: + return 0 + string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX) + string.memset(method_names_buf, 0, 8 * VTBL_METHOD_MAX) + string.memset(method_parent_sha1s, 0, 8 * VTBL_METHOD_MAX) + + method_count: int = 0 + + # ============================================================ + # 1.5 继承父类虚方法 + # + # 父类虚方法排在子类虚方法之前,保持 vtable 槽位顺序一致。 + # 如果子类覆盖了方法,full_name 用子类的;否则用父类的。 + # 用 SHA1 感知查找,规避跨模块同名 find_struct 找错 + # ============================================================ + vt_self_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + class_name, trans.ModuleSha1) + parent_name: str = None + if vt_self_entry is not None: + parent_name = vt_self_entry.ParentName + if parent_name is not None: + # 查找父类 entry(优先同模块 SHA1 匹配) + vt_parent_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module( + parent_name, trans.ModuleSha1) + if vt_parent_entry is None: + # 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找 + vt_parent_entry = HandlesStruct.find_struct(parent_name) + parent_vt_count: int = 0 + if vt_parent_entry is not None: + parent_vt_count = vt_parent_entry.VTableMethodCount + if parent_vt_count > 0: + for pvi in range(parent_vt_count): + if method_count >= VTBL_METHOD_MAX: + break + pmethod_name: str = None + if vt_parent_entry is not None: + pmethod_name = HandlesStruct.get_vtable_method_name(parent_name, pvi) + if pmethod_name is None: + continue + # 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable + child_overrides: int = 0 + child_nvt: int = 0 + for ci2 in range(cn): + stmt2: ast.AST | t.CPtr = children.get(ci2) + if stmt2 is None: + continue + if stmt2.kind() != ast.ASTKind.FunctionDef: + continue + fd2: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt2) + if fd2 is not None and fd2.name is not None: + if string.strcmp(fd2.name, pmethod_name) == 0: + child_overrides = 1 + # 检查子类覆盖方法是否标记 @t.NoVTable + if fd2.decorator_list is not None: + if _has_decorator(fd2.decorator_list, "NoVTable") == 1: + child_nvt = 1 + break + # 构造 full_name + # 子类覆盖且未标记 NoVTable → 用子类实现 + # 子类未覆盖 或 子类覆盖但标记 NoVTable → 用父类实现(保持 vtable 槽位) + pfname_buf: t.CChar | t.CPtr = pool.alloc(128) + if pfname_buf is not None: + if child_overrides == 1 and child_nvt == 0: + viperlib.snprintf(pfname_buf, 128, "%s.%s", class_name, pmethod_name) + else: + viperlib.snprintf(pfname_buf, 128, "%s.%s", parent_name, pmethod_name) + full_names_buf[method_count] = t.CSizeT(pfname_buf) + # 复制方法名(短名) + pmname_len: t.CSizeT = string.strlen(pmethod_name) + pmname_buf: t.CChar | t.CPtr = pool.alloc(pmname_len + 1) + if pmname_buf is not None: + string.strcpy(pmname_buf, pmethod_name) + method_names_buf[method_count] = t.CSizeT(pmname_buf) + # 记录 mangling 用的 SHA1(继承未覆盖的方法用父模块 SHA1) + if child_overrides == 1 and child_nvt == 0: + # 子类覆盖: 用当前模块 SHA1(保持 0) + method_parent_sha1s[method_count] = 0 + else: + # 继承未覆盖: 用父类模块 SHA1 + if vt_parent_entry is not None and vt_parent_entry.ModuleSha1 is not None: + method_parent_sha1s[method_count] = t.CSizeT(vt_parent_entry.ModuleSha1) + method_count += 1 + + # 2. 收集当前类的虚方法(跳过已从父类继承的) + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() != ast.ASTKind.FunctionDef: + continue + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd is None or fd.name is None: + continue + if method_count >= VTBL_METHOD_MAX: + break + + mname: str = fd.name + # 跳过构造函数和特殊方法(不应放入虚表) + if string.strcmp(mname, "__init__") == 0: + continue + if string.strcmp(mname, "__before_init__") == 0: + continue + if string.strcmp(mname, "__new__") == 0: + continue + # 函数级装饰器过滤:判断方法是否应该进入虚表 + if _should_method_be_virtual(cd, fd, trans) == 0: + continue + # 检查是否已从父类继承(避免重复) + already_in_vt: int = 0 + for mi in range(method_count): + exist_addr: t.CSizeT = method_names_buf[mi] + if exist_addr != 0: + exist_name: str = (str | t.CPtr)(t.CVoid(exist_addr, t.CPtr)) + if exist_name is not None and string.strcmp(exist_name, mname) == 0: + already_in_vt = 1 + break + if already_in_vt == 1: + continue + # 构造 full_name = "ClassName.method_name" + fname_buf: t.CChar | t.CPtr = pool.alloc(128) + if fname_buf is not None: + viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname) + full_names_buf[method_count] = t.CSizeT(fname_buf) + + # 复制方法名 + mname_len: t.CSizeT = string.strlen(mname) + mname_buf: t.CChar | t.CPtr = pool.alloc(mname_len + 1) + if mname_buf is not None: + string.strcpy(mname_buf, mname) + method_names_buf[method_count] = t.CSizeT(mname_buf) + + method_count += 1 + + if method_count == 0: + return 0 + + # 2. 构造 VTable 类型: { i8*, i8*, ..., i8* } + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + first_node: llvmlite.ParamNode | t.CPtr = None + tail_node: llvmlite.ParamNode | t.CPtr = None + for i in range(method_count): + pnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + if pnode is None: + continue + tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) + if first_node is None: + first_node = tail_node + + vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, method_count, None) + if vtable_ty is None: + return 0 + + # 3. 构造初始化字符串 + init_buf: t.CChar | t.CPtr = pool.alloc(4096) + if init_buf is None: + return 0 + init_buf[0] = '\0' + _vtable_strcat(init_buf, 4096, "{ ") + + for i in range(method_count): + if i > 0: + _vtable_strcat(init_buf, 4096, ", ") + + full_name_addr: t.CSizeT = full_names_buf[i] + if full_name_addr == 0: + _vtable_strcat(init_buf, 4096, "i8* null") + continue + + full_name: str = (str | t.CPtr)(t.CVoid(full_name_addr, t.CPtr)) + + # 检查是否是继承方法(method_parent_sha1s 非 0 表示用父模块 SHA1 mangling) + parent_sha1_addr: t.CSizeT = method_parent_sha1s[i] + if parent_sha1_addr != 0: + # 继承方法: 用父类模块 SHA1 做 mangling + parent_sha1: str = (str | t.CPtr)(t.CVoid(parent_sha1_addr, t.CPtr)) + mangled_name: str = HandlesFunctions._mangle_name_with_sha1(parent_sha1, full_name) + # 从全局函数表查找(跨模块函数不在当前模块表中) + func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_global(full_name) + else: + # 当前类方法: 用当前模块 SHA1 + mangled_name: str = HandlesFunctions._mangle_name(trans, full_name) + func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_table( + trans._funcs, trans._func_count, full_name) + # 当前模块表找不到时,回退到全局表 + if func is None: + func = HandlesExprCall.find_func_global(full_name) + + if func is None: + _vtable_strcat(init_buf, 4096, "i8* null") + continue + + # 构造函数类型字符串 + func_ty_buf: t.CChar | t.CPtr = pool.alloc(512) + if func_ty_buf is None: + _vtable_strcat(init_buf, 4096, "i8* null") + continue + _format_func_type_str(pool, func_ty_buf, 512, func) + + # 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*) + _vtable_strcat(init_buf, 4096, "i8* bitcast (") + _vtable_strcat(init_buf, 4096, func_ty_buf) + _vtable_strcat(init_buf, 4096, "* @") + + if _vtable_name_needs_quote(mangled_name) != 0: + _vtable_strcat(init_buf, 4096, "\"") + _vtable_strcat(init_buf, 4096, mangled_name) + _vtable_strcat(init_buf, 4096, "\"") + else: + _vtable_strcat(init_buf, 4096, mangled_name) + _vtable_strcat(init_buf, 4096, " to i8*)") + + _vtable_strcat(init_buf, 4096, " }") + + # 4. 构造 VTable 全局变量名 + vtable_name_buf: t.CChar | t.CPtr = pool.alloc(128) + if vtable_name_buf is None: + return 0 + viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) + vtable_mangled: str = HandlesFunctions._mangle_name(trans, vtable_name_buf) + + # 5. 创建全局变量 + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( + pool, vtable_mangled, vtable_ty) + if gv is None: + return 0 + gv.Initializer = init_buf + gv.IsConstant = 1 + gv.Linkage = "internal" + + # 添加到模块 + llvmlite.module_add_global(mod, gv) + + # 6. 存储虚方法名列表到 StructEntry(直接用 entry,规避跨模块同名 find_struct 找错) + if vt_self_entry is not None: + vt_self_entry.VTableMethods = method_names_buf + vt_self_entry.VTableMethodCount = method_count + + stdio.printf("[VTABLE] generated vtable for %s with %d methods\n", + class_name, method_count) + return 0 + + +# ============================================================ +# OOP 方法翻译 +# +# 存在任意 FunctionDef 的 class 自动升级为 OOP 结构体。 +# 方法翻译为 SHA1.ClassName.method_name(self: Ptr(StructTy), ...) 函数。 +# self 参数直接注册为 SSA 值(不创建 alloca),使 self.field 能通过 GEP 直接访问。 +# ============================================================ + + +# ============================================================ +# _translate_oop_methods — 扫描 class body 中的方法并翻译 +# +# 遍历 ClassDef.children,对每个 FunctionDef: +# - 标记 OOP(mark_as_oop) +# - 如果是 __init__,标记 has_init +# - 翻译方法(生成 SHA1.ClassName.method_name 函数) +# 翻译完所有方法后,生成 __before_init__ 函数 +# ============================================================ +def _translate_oop_methods(trans: HT.Translator | t.CPtr, + cd: ast.ClassDef | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str) -> int: + """扫描 class body 中的方法并翻译,生成 __before_init__""" + if trans is None or cd is None or struct_ty is None or class_name is None: + return 0 + + children: list[ast.AST | t.CPtr] | t.CPtr = cd.children + if children is None: + return 0 + + cn: t.CSizeT = children.__len__() + has_method: int = 0 + has_init: int = 0 + has_new: int = 0 + + # 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错) + oop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + + # 第一遍:检测是否有方法,标记 OOP + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() == ast.ASTKind.FunctionDef: + has_method = 1 + fd_check: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd_check is not None and fd_check.name is not None: + if string.strcmp(fd_check.name, "__init__") == 0: + has_init = 1 + if string.strcmp(fd_check.name, "__new__") == 0: + has_new = 1 + + if has_method == 0: + # 子类没有自己的方法,但可能继承了父类的虚方法 + # 用 oop_entry 直接获取 ParentName,规避 find_struct 按名查找找错 + parent_name: str = None + if oop_entry is not None: + parent_name = oop_entry.ParentName + if parent_name is not None: + parent_vt_count: int = HandlesStruct.get_vtable_method_count(parent_name) + if parent_vt_count > 0: + has_method = 1 # 标记为有方法(继承的虚方法) + if has_method == 0: + return 0 + + # 标记为 OOP 结构体 + if oop_entry is not None: + oop_entry.IsOOP = 1 + if has_init != 0: + oop_entry.HasInit = 1 + if has_new != 0: + oop_entry.HasNew = 1 + + # 第二遍:翻译每个方法 + for ci in range(cn): + stmt: ast.AST | t.CPtr = children.get(ci) + if stmt is None: + continue + if stmt.kind() == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt) + if fd is not None and fd.name is not None: + _translate_method(trans, fd, struct_ty, class_name) + + # 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount) + # 必须在 __before_init__ 之前,否则 __before_init__ 读不到 VTableMethodCount + # 用 oop_entry 直接检查,规避跨模块同名 find_struct 找错 + has_vt_flag: int = 0 + if oop_entry is not None: + has_vt_flag = oop_entry.HasVTable + if has_vt_flag == 1: + _generate_vtable(trans, cd, class_name) + + # 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置) + _generate_before_init(trans, struct_ty, class_name) + + return 0 + + +# ============================================================ +# _translate_method — 翻译单个方法 +# +# 生成: define @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...) +# +# self 参数处理: +# - 类型 Ptr(struct_ty),直接注册为 SSA 值(不创建 alloca) +# - 使 self.field 能通过 GEP 直接访问原始结构体 +# ============================================================ +def _translate_method(trans: HT.Translator | t.CPtr, + fd: ast.FunctionDef | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str) -> int: + """翻译单个方法,返回 0""" + if trans is None or fd is None or struct_ty is None or class_name is None: + return 0 + + # 懒导入 + import lib.core.Handles.HandlesFunctions as HandlesFunctions + import lib.core.Handles.HandlesVar as HandlesVar + import lib.core.Handles.HandlesBody as HandlesBody + import lib.core.Handles.HandlesType as HandlesType + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs + func_count: int = trans._func_count + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + + method_name: str = fd.name + + # 构建方法全名: ClassName.method_name + full_name_buf: t.CChar | t.CPtr = pool.alloc(128) + if full_name_buf is None: + return 0 + viperlib.snprintf(full_name_buf, 128, "%s.%s", class_name, method_name) + full_name: str = full_name_buf + + # SHA1 命名空间混淆 + mangled_name: str = HandlesFunctions._mangle_name(trans, full_name) + + # 推断返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = HandlesType.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports) + if ret_ty is None and fd.returns is not None: + if HandlesType.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + if ret_ty is None: + # __init__ 和 __before_init__ 返回 void + if string.strcmp(method_name, "__init__") == 0: + ret_ty = llvmlite.Void(pool) + # __new__ 返回 Ptr(struct_ty)(结构体指针作为存储空间) + elif string.strcmp(method_name, "__new__") == 0: + ret_ty = llvmlite.Ptr(pool, struct_ty) + else: + param_types_str: str = HandlesType.build_param_types_str(pool, fd.args) + ret_ty = HandlesType.infer_return_type( + pool, fd.children, param_types_str) + + # 创建 LLVM 函数 + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_name, ret_ty) + if func is None: + return 0 + + # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) + max_funcs: int = 256 + if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs) == 0: + trans._func_count = func_count + 1 + + # 添加 self 参数(Ptr(struct_ty)) + llvmlite.add_param(pool, func, self_ptr_ty, "%self") + + # 添加其他参数(支持类型注解,跳过索引 0 的 self 参数) + args_node: ast.Arguments | t.CPtr = fd.args + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = alist.__len__() + for ai in range(1, an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports) + if resolved is not None: + param_ty = resolved + pname: t.CChar | t.CPtr = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # 创建 entry 块 + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + + # 创建方法专属 builder + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 进入函数作用域 + HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION) + + # 注册 self 为 SSA 值(不创建 alloca,不 store) + # 这样 self.field 通过 lookup_var 获取 Ptr(struct_ty) 后直接 GEP + self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") + HandlesVar.define_var(trans.SymTab, "self", self_val) + # 设置 self 的类型注解类名(属性访问 lookup_field 回退查找用) + HandlesVar.set_var_annot_class_name(trans.SymTab, "self", class_name) + + # 为其他参数创建 alloca 并 store(与普通函数一致,跳过索引 0 的 self 参数) + if args_node is not None: + ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags2.args is not None: + alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args + an2: t.CSizeT = alist2.__len__() + for ai2 in range(1, an2): + arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) + if arg2 is not None and arg2.arg is not None: + param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty + if arg2.annotation is not None: + resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg2.annotation, imported_modules, from_imports) + if resolved2 is not None: + param_ty2 = resolved2 + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) + if alloca is not None: + HandlesVar.define_var(trans.SymTab, arg2.arg, alloca) + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + if arg2.annotation is not None: + cls_nm_oc: str = HandlesType.extract_class_name_from_annotation( + arg2.annotation, imported_modules) + if cls_nm_oc is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, arg2.arg, cls_nm_oc) + pname2: t.CChar | t.CPtr = pool.alloc(32) + if pname2 is not None: + viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) + param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, param_ty2, pname2) + llvmlite.build_store(func_builder, param_val, alloca) + + # 保存模块级作用域状态 + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + + trans._cur_func = func + trans._cur_builder = func_builder + HT.clear_scope_names(trans) + + # 预扫描方法体:为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = body.__len__() + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.pre_scan_allocas(trans, stmt) + + # 翻译方法体 + if body is not None: + bn2: t.CSizeT = body.__len__() + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + HandlesBody.translate_stmt(trans, stmt2) + + # 如果返回类型为 void,添加 ret void;否则添加隐式 ret 0 + is_void: int = 0 + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + is_void = 1 + + if is_void != 0: + if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: + llvmlite.build_ret_void(func_builder) + else: + last_is_return: int = 0 + if body is not None: + bn3: t.CSizeT = body.__len__() + if bn3 > 0: + last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: + # __new__ 返回指针类型,隐式返回 null 指针 + if string.strcmp(method_name, "__new__") == 0: + null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") + llvmlite.build_ret(func_builder, null_val) + else: + zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(func_builder, zero_val) + + # 恢复模块级作用域 + HandlesVar.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + + return 0 + + +# ============================================================ +# _generate_before_init — 生成 __before_init__ 函数 +# +# 生成: define void @SHA1.ClassName.__before_init__(Ptr(StructTy) %self) +# +# 执行: +# 1. store zeroinitializer 到 %self(零值填充) +# 2. 逐字段 store 默认值(如有) +# 3. ret void +# ============================================================ +def _generate_before_init(trans: HT.Translator | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str) -> int: + """生成 __before_init__ 函数,返回 0""" + if trans is None or struct_ty is None or class_name is None: + return 0 + + import lib.core.Handles.HandlesFunctions as HandlesFunctions + import lib.core.Handles.HandlesVar as HandlesVar + import lib.core.Handles.HandlesExpr as HandlesExpr + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs + func_count: int = trans._func_count + + self_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + + # 构建函数名: ClassName.__before_init__ + full_name_buf: t.CChar | t.CPtr = pool.alloc(128) + if full_name_buf is None: + return 0 + viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) + full_name: str = full_name_buf + + mangled_name: str = HandlesFunctions._mangle_name(trans, full_name) + + # 创建函数 + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_name, void_ty) + if func is None: + return 0 + + # 注册到函数表 + max_funcs: int = 256 + if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs) == 0: + trans._func_count = func_count + 1 + + # 添加 self 参数 + llvmlite.add_param(pool, func, self_ptr_ty, "%self") + + # 创建 entry 块 + builder + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 注册 self 为 SSA 值 + self_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, self_ptr_ty, "%self") + + # 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + if zero is not None: + llvmlite.build_store(func_builder, zero, self_val) + + # 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0) + # 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错 + bi_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + bi_has_vt: int = 0 + if bi_entry is not None: + bi_has_vt = bi_entry.HasVTable + if bi_has_vt == 1: + vt_method_count: int = 0 + if bi_entry is not None: + vt_method_count = bi_entry.VTableMethodCount + if vt_method_count > 0: + # 构造 vtable 类型 { i8*, i8*, ..., i8* } + vt_i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + vt_i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_i8_ty) + + vt_first_node: llvmlite.ParamNode | t.CPtr = None + vt_prev_node: llvmlite.ParamNode | t.CPtr = None + for vti in range(vt_method_count): + vtnode: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, vt_i8_ptr_ty) + if vtnode is None: + continue + if vt_first_node is None: + vt_first_node = vtnode + if vt_prev_node is not None: + llvmlite.paramnode_set_next(vt_prev_node, vtnode) + vt_prev_node = vtnode + + vt_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first_node, vt_method_count, None) + vt_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_ty) + + # 构造 vtable 全局变量名 + vt_name_buf: t.CChar | t.CPtr = pool.alloc(128) + if vt_name_buf is not None: + viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name) + vt_full_name: str = vt_name_buf + vt_mangled: str = HandlesFunctions._mangle_name(trans, vt_full_name) + + # GEP 到 __vtable__ 字段(索引 0) + vt_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, vt_i8_ptr_ty, self_val, 0) + if vt_slot is not None: + # 创建全局变量引用 Value + vt_ref: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if vt_ref is not None: + llvmlite.value_set_ty(vt_ref, vt_ptr_ty) + llvmlite.value_set_isconst(vt_ref, 1) + # Name 格式: @"mangled" 或 @mangled + vt_ref_name: t.CChar | t.CPtr = pool.alloc(256) + if vt_ref_name is not None: + vt_ref_name[0] = '\0' + if _vtable_name_needs_quote(vt_mangled) != 0: + viperlib.snprintf(vt_ref_name, 256, "@\"%s\"", vt_mangled) + else: + viperlib.snprintf(vt_ref_name, 256, "@%s", vt_mangled) + llvmlite.value_set_name(vt_ref, vt_ref_name) + + # bitcast 到 i8* + vt_as_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + func_builder, vt_ref, vt_i8_ptr_ty) + if vt_as_i8 is not None: + llvmlite.build_store(func_builder, vt_as_i8, vt_slot) + + # 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错) + if bi_entry is not None: + for fi in range(bi_entry.FieldCount): + fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + bi_entry, fi) + if fe is None or fe.DefaultVal is None: + continue + # 翻译默认值表达式 + default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + func_builder, pool, mod, fe.DefaultVal, None, 0, trans) + if default_val is None: + continue + # GEP 到字段 + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + func_builder, struct_ty, fe.Ty, self_val, fe.Index) + if field_ptr is None: + continue + # 类型转换并 store + default_val = HandlesExpr.coerce_to_type(func_builder, default_val, fe.Ty) + llvmlite.build_store(func_builder, default_val, field_ptr) + + # 3. ret void + llvmlite.build_ret_void(func_builder) + + return 0 diff --git a/App/lib/core/Handles/HandlesEnum.py b/App/lib/core/Handles/HandlesEnum.py new file mode 100644 index 0000000..cdae79f --- /dev/null +++ b/App/lib/core/Handles/HandlesEnum.py @@ -0,0 +1,230 @@ +import t, c +from stdint import * +import memhub +import string +import llvmlite +import stdio + + +# ============================================================ +# HandlesEnum - 枚举类型注册和成员查找 +# +# 管理 t.CEnum 派生类的成员信息: +# - 枚举名 → EnumEntry(基准类型 + 成员表) +# - 成员名 → EnumMember(值、类型) +# +# 使用全局数组存储,线性查找(枚举数量通常很少) +# ============================================================ + +ENUM_MAX: t.CDefine = 64 +ENUM_MEMBER_MAX: t.CDefine = 64 + + +# ============================================================ +# EnumMember - 枚举成员条目 +# ============================================================ +@t.NoVTable +class EnumMember: + Name: t.CChar | t.CPtr # 成员名(字符串) + Value: t.CInt64T # 成员的整数值 + Ty: llvmlite.LLVMType | t.CPtr # 成员的 LLVM 类型(用于混用类型场景) + + +# ============================================================ +# EnumEntry - 枚举类型条目 +# ============================================================ +@t.NoVTable +class EnumEntry: + Name: t.CChar | t.CPtr # 枚举类名 + BaseTy: llvmlite.LLVMType | t.CPtr # 基准类型(所有成员类型中最大的) + MemberCount: int # 成员数量 + Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位) + + +# ============================================================ +# 全局注册表(静态分配) +# ============================================================ +_enum_table: EnumEntry | t.CPtr = None +_enum_count: int = 0 + + +# ============================================================ +# init_enum_table — 初始化枚举注册表 +# ============================================================ +def init_enum_table(pool: memhub.MemBuddy | t.CPtr) -> int: + """初始化枚举注册表,返回 1 成功""" + global _enum_table + global _enum_count + + if _enum_table is not None: + return 1 + + entry_size: t.CSizeT = EnumEntry.__sizeof__() + _enum_table = pool.alloc(entry_size * ENUM_MAX) + if _enum_table is None: + return 0 + string.memset(_enum_table, 0, entry_size * ENUM_MAX) + _enum_count = 0 + return 1 + + +# ============================================================ +# _get_enum_entry — 获取第 i 个 EnumEntry 槽位 +# ============================================================ +def _get_enum_entry(i: int) -> EnumEntry | t.CPtr: + """获取第 i 个枚举条目""" + if _enum_table is None or i < 0 or i >= ENUM_MAX: + return None + entry_size: t.CSizeT = EnumEntry.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(_enum_table) + i * entry_size + return (EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) + + +# ============================================================ +# _get_enum_member — 获取枚举中第 i 个 EnumMember 槽位 +# ============================================================ +def _get_enum_member(enum_entry: EnumEntry | t.CPtr, i: int) -> EnumMember | t.CPtr: + """获取枚举中第 i 个成员条目""" + if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX: + return None + member_size: t.CSizeT = EnumMember.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size + return (EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr)) + + +# ============================================================ +# register_enum — 注册枚举类型 +# +# 返回 EnumEntry 指针,可用于添加成员 +# ============================================================ +def register_enum(pool: memhub.MemBuddy | t.CPtr, + name: str, + base_ty: llvmlite.LLVMType | t.CPtr) -> EnumEntry | t.CPtr: + """注册枚举类型,返回 EnumEntry 指针""" + if init_enum_table(pool) == 0: + return None + + # 检查是否已注册 + existing: EnumEntry | t.CPtr = find_enum(name) + if existing is not None: + return existing + + if _enum_count >= ENUM_MAX: + stdio.printf("[ENUM] table full, cannot register %s\n", name) + return None + + entry: EnumEntry | t.CPtr = _get_enum_entry(_enum_count) + if entry is None: + return None + + # 分配成员数组 + member_size: t.CSizeT = EnumMember.__sizeof__() + entry.Members = pool.alloc(member_size * ENUM_MEMBER_MAX) + if entry.Members is None: + return None + string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX) + + # 复制类名 + name_len: t.CSizeT = string.strlen(name) + name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) + if name_buf is not None: + string.strcpy(name_buf, name) + entry.Name = name_buf + + entry.BaseTy = base_ty + entry.MemberCount = 0 + + _enum_count += 1 + return entry + + +# ============================================================ +# add_enum_member — 向枚举添加成员 +# ============================================================ +def add_enum_member(pool: memhub.MemBuddy | t.CPtr, + enum_entry: EnumEntry | t.CPtr, + member_name: str, + member_val: t.CInt64T, + member_ty: llvmlite.LLVMType | t.CPtr) -> int: + """向枚举添加成员,返回成员索引(-1 失败)""" + if enum_entry is None or member_name is None or member_ty is None: + return -1 + + if enum_entry.MemberCount >= ENUM_MEMBER_MAX: + stdio.printf("[ENUM] member table full for %s\n", enum_entry.Name) + return -1 + + idx: int = enum_entry.MemberCount + me: EnumMember | t.CPtr = _get_enum_member(enum_entry, idx) + if me is None: + return -1 + + # 复制成员名 + name_len: t.CSizeT = string.strlen(member_name) + name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) + if name_buf is not None: + string.strcpy(name_buf, member_name) + me.Name = name_buf + + me.Value = member_val + me.Ty = member_ty + + enum_entry.MemberCount = idx + 1 + return idx + + +# ============================================================ +# find_enum — 按枚举类名查找 +# ============================================================ +def find_enum(name: str) -> EnumEntry | t.CPtr: + """按枚举类名查找,返回 EnumEntry 或 None""" + if name is None or _enum_table is None: + return None + for i in range(_enum_count): + entry: EnumEntry | t.CPtr = _get_enum_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + return None + + +# ============================================================ +# lookup_enum_member — 按枚举类名和成员名查找 +# ============================================================ +def lookup_enum_member(enum_name: str, + member_name: str) -> EnumMember | t.CPtr: + """按枚举类名和成员名查找,返回 EnumMember 或 None""" + if enum_name is None or member_name is None: + return None + entry: EnumEntry | t.CPtr = find_enum(enum_name) + if entry is None: + return None + for mi in range(entry.MemberCount): + me: EnumMember | t.CPtr = _get_enum_member(entry, mi) + if me is not None and me.Name is not None: + if string.strcmp(me.Name, member_name) == 0: + return me + return None + + +# ============================================================ +# is_enum_class — 检查类名是否为已注册枚举 +# ============================================================ +def is_enum_class(name: str) -> int: + """检查类名是否为已注册枚举,返回 1=是 / 0=否""" + if name is None: + return 0 + if find_enum(name) is not None: + return 1 + return 0 + + +# ============================================================ +# get_enum_base_type — 按枚举类名获取基准类型 +# ============================================================ +def get_enum_base_type(enum_name: str) -> llvmlite.LLVMType | t.CPtr: + """按枚举类名获取基准类型""" + entry: EnumEntry | t.CPtr = find_enum(enum_name) + if entry is not None: + return entry.BaseTy + return None diff --git a/App/lib/core/Handles/HandlesExpr.py b/App/lib/core/Handles/HandlesExpr.py new file mode 100644 index 0000000..e2429b6 --- /dev/null +++ b/App/lib/core/Handles/HandlesExpr.py @@ -0,0 +1,1525 @@ +import t, c +from stdint import * +import ast +import memhub +import string +import llvmlite +import viperlib +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExprOps as HandlesExprOps +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesImports as HandlesImports + + +# ============================================================ +# HandlesExpr - 表达式处理(Mixin 继承模式) +# +# 工具函数保留为模块级(供外部调用),ExprHandle.HandleValue 提供 trans 接口 +# ============================================================ + + +# ============================================================ +# 从 AST 节点提取函数名 +# ============================================================ +def get_func_name(func_node: ast.AST | t.CPtr) -> str: + """从函数节点提取函数名""" + if func_node is None: + return None + k: int = func_node.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node) + return nm.id + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node) + return at.attr + return None + + +# ============================================================ +# 转义 LLVM IR 字符串字面量 +# ============================================================ +def escape_llvm_string(pool: memhub.MemBuddy | t.CPtr, + src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """ + if src is None: + return None + slen: t.CSizeT = string.strlen(src) + alloc_size: t.CSizeT = 4 * slen + 8 + buf: t.CChar | t.CPtr = pool.alloc(alloc_size) + if buf is None: + return None + pos: t.CSizeT = 0 + buf[pos] = 'c' + pos += 1 + buf[pos] = '"' + pos += 1 + for i in range(slen): + ch: t.CChar = src[i] + if ch == '\0': + break + if ch == '\"' or ch == '\\' or ch < 0x20: + buf[pos] = '\\' + pos += 1 + hi: int = (ch >> 4) & 0xF + lo: int = ch & 0xF + if hi < 10: + buf[pos] = '0' + hi + else: + buf[pos] = 'A' + (hi - 10) + pos += 1 + if lo < 10: + buf[pos] = '0' + lo + else: + buf[pos] = 'A' + (lo - 10) + pos += 1 + else: + buf[pos] = ch + pos += 1 + buf[pos] = '\\' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = '"' + pos += 1 + buf[pos] = '\0' + return buf + + +# ============================================================ +# 获取 LLVM 整数类型的位宽 +# ============================================================ +def get_llvm_type_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 整数类型的位宽,非整数类型返回 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Int(bits): + return bits + case _: + return 0 + + +# ============================================================ +# 获取 LLVM 浮点类型的位宽 +# ============================================================ +def get_llvm_float_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 浮点类型的位宽,非浮点类型返回 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Float(bits): + return bits + case _: + return 0 + + +# ============================================================ +# 检查类型是否为 Ptr(独立函数,避免嵌套 match 的编译器 BUG) +# +# 嵌套 match 的 REnum 检测在宿主编译器中有 BUG:当 match 嵌套在 +# 另一个 match 的 case 块中时,内层 match 走非 REnum 路径, +# 导致 case 列表为空。提取为独立函数可规避此问题。 +# ============================================================ +def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Ptr(pointee): + return 1 + case _: + return 0 + + +# ============================================================ +# _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用 +# +# 用于支持 X|t.CPtr 类型变量的属性访问: +# - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用 +# - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用 +# +# 用 is_ptr_type 避免嵌套 match 的编译器 BUG +# ============================================================ +def _deref_if_ptr_ptr(builder: llvmlite.IRBuilder | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针""" + if obj_ptr is None or obj_ptr.Ty is None: + return obj_ptr + if is_ptr_type(obj_ptr.Ty) == 0: + return obj_ptr + pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee + if pointee is None: + return obj_ptr + if is_ptr_type(pointee) == 0: + return obj_ptr + # obj_ptr 是 Ptr(Ptr(...)),load 解引用 + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr) + if loaded is None: + return obj_ptr + return loaded + + +# ============================================================ +# 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si +# ============================================================ +def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """将 val 强制转换为 target_ty + + 整数: sext(扩展)/ trunc(截断) + 浮点: fpext(扩展)/ fptrunc(截断) + int→float: sitofp + float→int: fptosi + """ + if val is None or target_ty is None: + return val + # 整数转换 + val_bits: int = get_llvm_type_bits(val.Ty) + target_bits: int = get_llvm_type_bits(target_ty) + if val_bits != 0 and target_bits != 0: + if val_bits == target_bits: + return val + if val_bits < target_bits: + return llvmlite.build_sext(builder, val, target_ty) + return llvmlite.build_trunc(builder, val, target_ty) + # 浮点转换 + val_fbits: int = get_llvm_float_bits(val.Ty) + target_fbits: int = get_llvm_float_bits(target_ty) + if val_fbits != 0 and target_fbits != 0: + if val_fbits == target_fbits: + return val + if val_fbits < target_fbits: + return llvmlite.build_fpext(builder, val, target_ty) + return llvmlite.build_fptrunc(builder, val, target_ty) + # int → float + if val_bits != 0 and target_fbits != 0: + return llvmlite.build_si2fp(builder, val, target_ty) + # float → int + if val_fbits != 0 and target_bits != 0: + return llvmlite.build_fp2si(builder, val, target_ty) + # 指针 → 非指针值: build_load 解引用 + # 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值 + # 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load + # 注意:使用独立函数 is_ptr_type 检查,避免嵌套 match 的编译器 BUG + if is_ptr_type(val.Ty) != 0 and is_ptr_type(target_ty) == 0: + return llvmlite.build_load(builder, target_ty, val) + # 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针) + if is_ptr_type(val.Ty) != 0 and is_ptr_type(target_ty) != 0: + return llvmlite.build_bitcast(builder, val, target_ty) + return val + + +# ============================================================ +# 创建全局字符串常量 +# ============================================================ +def create_global_string(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + str_val: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """创建全局字符串常量并返回 i8* bitcast""" + escaped: t.CChar | t.CPtr = escape_llvm_string(pool, str_val) + if escaped is None: + return None + + slen: t.CSizeT = string.strlen(str_val) + count: int = slen + 1 + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count) + + # 使用模块级计数器(trans._label_counter)避免跨函数命名冲突 + str_idx: int = trans._label_counter + trans._label_counter += 1 + + # 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名 + gv_name: t.CChar | t.CPtr = pool.alloc(48) + if gv_name is None: + return None + if trans.ModuleSha1 is not None: + viperlib.snprintf(gv_name, 48, ".str.%s.%d", trans.ModuleSha1, str_idx) + else: + viperlib.snprintf(gv_name, 48, ".str.%d", str_idx) + + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty) + if gv is None: + return None + llvmlite.module_add_global(mod, gv) + + # 去掉 private 链接,和函数一致:stub 中 declare,text 中 define + llvmlite.global_set_unnamed_addr(gv, 1) + llvmlite.global_set_constant(gv, 1) + gv.Initializer = escaped + + arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty) + gv_ref_name: t.CChar | t.CPtr = pool.alloc(64) + if gv_ref_name is None: + return None + viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name) + gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name) + + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + return llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty) + + +# ============================================================ +# 翻译常量表达式 +# ============================================================ +def translate_constant(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译常量(int/str/bool)""" + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn is None: + return None + if cn.const_kind == ast.CONST_INT: + # 超出 i32 范围则用 i64(避免常量创建时被截断) + iv: t.CInt64T = cn.int_val + if iv > 2147483647 or iv < -2147483648: + return llvmlite.const_int64(pool, iv) + return llvmlite.const_int32(pool, iv) + elif cn.const_kind == ast.CONST_FLOAT: + # 浮点常量默认创建为 double(64 位),赋值时由 coerce_to_type 自动 fptrunc + double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + return llvmlite.ConstFloat(pool, double_ty, cn.float_val) + elif cn.const_kind == ast.CONST_STR: + return create_global_string(builder, pool, mod, cn.str_val, trans) + elif cn.const_kind == ast.CONST_BOOL: + if cn.int_val != 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + elif cn.const_kind == ast.CONST_NONE: + # None → i8* null(空指针常量),用于 `p is None` / `p is not None` 比较 + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + return llvmlite.ConstNull(pool, i8_ptr_ty, "null") + return None + + +# ============================================================ +# _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名 +# +# 用于 list 字面量 [a, b, c] 的元素类型推断 +# ============================================================ +def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr, + value: llvmlite.Value | t.CPtr) -> str: + """从 LLVM Value 的类型推断 list 元素类型名""" + if value is None or value.Ty is None: + return "str" + ty: llvmlite.LLVMType | t.CPtr = value.Ty + bits: int = get_llvm_type_bits(ty) + if bits != 0: + if bits == 32: + return "int" + if bits == 64: + return "CSizeT" + if bits == 8: + return "CInt8T" + if bits == 16: + return "CInt16T" + return "int" + if is_ptr_type(ty) != 0: + return "str" + fbits: int = get_llvm_float_bits(ty) + if fbits != 0: + if fbits == 64: + return "CDouble" + if fbits == 32: + return "CFloat" + return "str" + + +# ============================================================ +# _find_pool_var — 查找上下文中的 pool 变量 +# +# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb" +# ============================================================ +def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """查找上下文中的 pool 变量,返回 alloca 或 None""" + if trans is None: + return None + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool") + if alloca is not None: + return alloca + alloca = HandlesVar.lookup_var(trans.SymTab, "_mbuddy") + if alloca is not None: + return alloca + alloca = HandlesVar.lookup_var(trans.SymTab, "mbuddy") + if alloca is not None: + return alloca + alloca = HandlesVar.lookup_var(trans.SymTab, "mb") + if alloca is not None: + return alloca + return None + + +# ============================================================ +# translate_list_literal — 翻译 list 字面量 [a, b, c] +# +# 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列 +# +# Args: +# builder: IRBuilder +# pool: 编译器内存池(MemBuddy) +# mod: LLVMModule +# node: ast.List 节点 +# elem_type_name: 元素类型名(如 "str", "int"),None 表示从元素推断 +# trans: Translator 对象 +# +# Returns: +# list 对象指针(Ptr(list[T] struct)),None 失败 +# ============================================================ +def translate_list_literal(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + elem_type_name: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列""" + if node is None or trans is None: + return None + + list_node: ast.List | t.CPtr = (ast.List | t.CPtr)(node) + if list_node is None: + return None + + elts: list[ast.AST | t.CPtr] | t.CPtr = list_node.elts + elts_count: t.CSizeT = 0 + if elts is not None: + elts_count = elts.__len__() + + # 推断元素类型 + inferred_type_name: str = elem_type_name + first_elem_val: llvmlite.Value | t.CPtr = None + if inferred_type_name is None: + inferred_type_name = "str" + if elts_count > 0: + first_elem_node: ast.AST | t.CPtr = elts.get(0) + first_elem_val = translate_value(builder, pool, mod, first_elem_node, None, 0, trans) + if first_elem_val is not None: + inferred_type_name = _infer_elem_type_from_value(pool, first_elem_val) + + # 查找 pool 变量 + pool_alloca: llvmlite.Value | t.CPtr = _find_pool_var(trans) + if pool_alloca is None: + HandlesType.fatal_error(node, "list literal requires pool variable in context") + return None + + # load pool 变量值(i8*) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + pool_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca) + if pool_val is None: + return None + + # 特化 list[T] 类 + type_args: list[str] | t.CPtr = list[str](pool, 4) + type_args.append(inferred_type_name) + spec_name: str = HandlesClassDef._specialize_generic_class(trans, "list", type_args) + if spec_name is None: + HandlesType.fatal_error(node, "list literal generic specialization failed") + return None + + # 查找 struct entry + struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) + if struct_entry is None: + HandlesType.fatal_error(node, "list literal specialized class not registered") + return None + struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty + if struct_ty is None: + return None + + # alloca 临时 list 空间 + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return None + + # 调用 __new__(tmp, pool_val) → storage_ptr + new_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_args is None: + return None + string.memset(new_args, 0, 8 * 32) + new_args[0] = t.CSizeT(pool_val) + storage_ptr: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans) + if storage_ptr is None: + storage_ptr = tmp + + # 调用 __before_init__(storage_ptr) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) + + # 调用 __init__(storage_ptr, pool_val, elem_size=0) + init_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if init_args is None: + return None + string.memset(init_args, 0, 8 * 32) + init_args[0] = t.CSizeT(pool_val) + elem_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + init_args[1] = t.CSizeT(elem_size_val) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans) + + # 对每个元素调用 append(storage_ptr, elem_val) + if elts_count > 0: + # 第一个元素可能已经翻译过 + if first_elem_val is not None: + append_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if append_args is not None: + string.memset(append_args, 0, 8 * 32) + append_args[0] = t.CSizeT(first_elem_val) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans) + + # 翻译剩余元素 + i: t.CSizeT = 1 + while i < elts_count: + elem_node_i: ast.AST | t.CPtr = elts.get(i) + elem_val_i: llvmlite.Value | t.CPtr = translate_value(builder, pool, mod, elem_node_i, None, 0, trans) + if elem_val_i is not None: + ap_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if ap_args is not None: + string.memset(ap_args, 0, 8 * 32) + ap_args[0] = t.CSizeT(elem_val_i) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans) + i += 1 + + return storage_ptr + + +# ============================================================ +# 翻译值表达式(RHS 分派)— 模块级版本 +# ============================================================ +def translate_value(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr = None, + func_count: int = 0, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译值表达式为 LLVM Value""" + if node is None: + return None + k: int = node.kind() + if k == ast.ASTKind.Constant: + return translate_constant(builder, pool, mod, node, trans) + elif k == ast.ASTKind.Name: + return translate_name_value(builder, pool, node, trans) + elif k == ast.ASTKind.BinOp: + return HandlesExprOps.translate_binop(pool, builder, mod, node, trans) + elif k == ast.ASTKind.Call: + return HandlesExprCall.translate_call(pool, builder, mod, node, + funcs_ptr, func_count, trans) + elif k == ast.ASTKind.Compare: + return translate_compare(builder, pool, mod, node, trans) + elif k == ast.ASTKind.UnaryOp: + return translate_unaryop(builder, pool, mod, node, trans) + elif k == ast.ASTKind.BoolOp: + return translate_boolop(builder, pool, mod, node, + funcs_ptr, func_count, trans) + elif k == ast.ASTKind.Subscript: + return translate_subscript(builder, pool, mod, node, trans) + elif k == ast.ASTKind.Attribute: + return translate_attribute(builder, pool, mod, node, trans) + elif k == ast.ASTKind.List: + return translate_list_literal(builder, pool, mod, node, None, trans) + return None + + +# ============================================================ +# 翻译比较表达式 Compare(left, ops, comparators) +# ============================================================ +def translate_compare(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译比较表达式,返回 i1 结果""" + cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + if cmp is None: + return None + + ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops) + if ops_list is None or ops_list.__len__() == 0: + return None + op: int = ops_list.get(0) + + comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators + if comparators is None or comparators.__len__() == 0: + return None + rhs: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, comparators.get(0), None, 0, trans) + if rhs is None: + return None + + # === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 === + # 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载 + lhs_node: ast.AST | t.CPtr = cmp.left + if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) + if nm is not None and nm.id is not None: + lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm.id) + if lhs_alloca is not None: + ovl_result: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload( + pool, builder, mod, lhs_alloca, rhs, op, trans, 1) + if ovl_result is not None: + return ovl_result + + # 正常翻译 lhs + lhs: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, cmp.left, None, 0, trans) + if lhs is None: + return None + + # === 比较运算符重载路径 2: lhs 是 Ptr(Struct) === + # Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较 + ovl_result2: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload( + pool, builder, mod, lhs, rhs, op, trans, 1) + if ovl_result2 is not None: + return ovl_result2 + + predicate: int = llvmlite.ICMP_SLT + if op == ast.OpKind.Lt: + predicate = llvmlite.ICMP_SLT + elif op == ast.OpKind.Le: + predicate = llvmlite.ICMP_SLE + elif op == ast.OpKind.Gt: + predicate = llvmlite.ICMP_SGT + elif op == ast.OpKind.Ge: + predicate = llvmlite.ICMP_SGE + elif op == ast.OpKind.Eq: + predicate = llvmlite.ICMP_EQ + elif op == ast.OpKind.Ne: + predicate = llvmlite.ICMP_NE + elif op == ast.OpKind.Is: + # `x is y` → 指针/值相等比较 + predicate = llvmlite.ICMP_EQ + elif op == ast.OpKind.IsNot: + # `x is not y` → 指针/值不等比较 + predicate = llvmlite.ICMP_NE + + # 隐式类型转换:当一侧是指针(i8*),另一侧是整数时, + # 从指针加载第一个字节,使两侧类型一致 + lhs_is_ptr: int = is_ptr_type(lhs.Ty) + rhs_is_ptr: int = is_ptr_type(rhs.Ty) + if lhs_is_ptr != 0 and rhs_is_ptr == 0: + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + lhs = llvmlite.build_load(builder, i8_ty, lhs) + elif rhs_is_ptr != 0 and lhs_is_ptr == 0: + i8_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + rhs = llvmlite.build_load(builder, i8_ty2, rhs) + + # 类型对齐:icmp 要求两边类型相同,将较窄的整数 sext 到较宽的类型 + lhs_bits: int = get_llvm_type_bits(lhs.Ty) + rhs_bits: int = get_llvm_type_bits(rhs.Ty) + if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits: + if lhs_bits < rhs_bits: + lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) + else: + rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) + + return llvmlite.build_icmp(builder, predicate, lhs, rhs) + + +# ============================================================ +# 翻译一元运算表达式 UnaryOp(op, operand) +# ============================================================ +def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译一元运算(-x, +x, not x, ~x)""" + uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uo is None: + return None + + operand: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, uo.operand, None, 0, trans) + if operand is None: + return None + + if uo.op == ast.OpKind.USub: + # -x = 0 - x + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + return llvmlite.build_sub(builder, zero, operand) + elif uo.op == ast.OpKind.UAdd: + # +x = x + return operand + elif uo.op == ast.OpKind.Not: + # not x = (x == 0),返回 i1 + zero = llvmlite.const_int32(pool, 0) + return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero) + elif uo.op == ast.OpKind.Invert: + # ~x = x ^ -1 + neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1) + return llvmlite.build_xor(builder, operand, neg1) + return operand + + +# ============================================================ +# 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1 +# +# and: a and b and c → 若 a 为假短路到 merge(返回 a 的 i1),否则求 b, +# 最后一个值直接求值并跳 merge +# or: a or b or c → 若 a 为真短路到 merge(返回 a 的 i1),否则求 b, +# 最后一个值直接求值并跳 merge +# merge 块用 phi 合并所有入边的 i1 +# ============================================================ +def translate_boolop(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr = None, + func_count: int = 0, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译布尔运算(and/or)的短路求值,返回 i1""" + bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + if bo is None: + return None + + op: int = bo.op + values: list[ast.AST | t.CPtr] | t.CPtr = bo.values + if values is None: + return None + count: t.CSizeT = values.__len__() + if count == 0: + return None + if count == 1: + return translate_value(builder, pool, mod, values.get(0), + funcs_ptr, func_count, trans) + + func: llvmlite.Function | t.CPtr = builder.Func + if func is None: + return None + + # 创建 merge BB(用 builder.Counter 生成唯一标签名,position_at_end 的 + # move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全) + cnt: int = builder.Counter + builder.Counter = cnt + 1 + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is None: + return None + viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt) + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # phi 入边链表头/尾 + phi_head: llvmlite.PhiIncoming | t.CPtr = None + phi_tail: llvmlite.PhiIncoming | t.CPtr = None + phi_count: int = count - 1 # 循环次数 + + # 对每个值(除最后一个)求值并短路 + for i in range(count - 1): + val_node: ast.AST | t.CPtr = values.get(i) + val: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, val_node, + funcs_ptr, func_count, trans) + if val is None: + return None + + # 转为 i1(已经是 i1 的直接用,否则与 0 比较) + val_bits: int = get_llvm_type_bits(val.Ty) + val_i1: llvmlite.Value | t.CPtr = val + if val_bits != 1: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero) + + # 创建 next BB(求值下一个值) + cnt = builder.Counter + builder.Counter = cnt + 1 + viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt) + next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # and: 短路假→merge,真→next;or: 短路真→merge,假→next + if op == ast.OpKind.And: + llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb) + else: + llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb) + + # 添加 phi 入边:(val_i1, cond_br 所在 BB) + cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock + inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb) + if phi_head is None: + phi_head = inc + phi_tail = inc + else: + phi_tail.Next = inc + phi_tail = inc + + # 定位到 next BB,求值下一个值 + llvmlite.position_at_end(builder, next_bb) + + # 最后一个值:求值后直接跳 merge + last_node: ast.AST | t.CPtr = values.get(count - 1) + last_val: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, last_node, + funcs_ptr, func_count, trans) + if last_val is None: + return None + last_bits: int = get_llvm_type_bits(last_val.Ty) + last_i1: llvmlite.Value | t.CPtr = last_val + if last_bits != 1: + zero = llvmlite.const_int32(pool, 0) + last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero) + + llvmlite.build_br(builder, merge_bb) + + cur_bb = builder.CurBlock + inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb) + if phi_head is None: + phi_head = inc + else: + phi_tail.Next = inc + phi_count += 1 + + # 定位到 merge,创建 phi 合并所有入边 + llvmlite.position_at_end(builder, merge_bb) + i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count) + + +# ============================================================ +# 翻译变量引用(Name 节点)→ load +# ============================================================ +def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译变量引用(Name 节点)→ load""" + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm is None: + return None + nm_id: str = nm.id + if nm_id is None: + return None + + # CDefine 编译期常量: 直接返回整数常量值(不生成运行时代码) + # NAME: t.CDefine = value 形式定义的常量在编译期已注册到全局表 + cdef_val: int = HandlesType.lookup_cdefine_constant(nm_id) + if cdef_val >= 0: + return llvmlite.const_int32(pool, cdef_val) + + # global 变量:从模块作用域查找 + if trans is not None: + if HT.is_global_name(trans, nm_id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + trans.SymTab, nm_id) + if mod_alloca is not None: + load_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + load_ty = mod_alloca.Ty.Pointee + if load_ty is None: + load_ty = llvmlite.Int32(pool) + return llvmlite.build_load(builder, load_ty, mod_alloca) + + # nonlocal 变量:通过闭包 env 访问 + if HT.is_nonlocal_name(trans, nm_id) != 0: + return HandlesNonlocal.load_nonlocal_var(trans, nm_id) + + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id) + if alloca is None: + return None + + load_ty: llvmlite.LLVMType | t.CPtr = None + if alloca.Ty is not None: + load_ty = alloca.Ty.Pointee + if load_ty is None: + load_ty = llvmlite.Int32(pool) + return llvmlite.build_load(builder, load_ty, alloca) + + +# ============================================================ +# ExprHandle - 表达式处理器(Mixin 继承模式) +# +# HandleValue 提供 trans 接口,委托到模块级 translate_value +# ============================================================ +@t.NoVTable +class ExprHandle(HandlesBase.Mixin): + """表达式处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # HandleValue - 翻译值表达式为 LLVM Value + # ============================================================ + def HandleValue(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译值表达式,从 self.Trans 获取共享状态""" + return translate_value( + self.Trans._cur_builder, self.Trans.Pool, self.Trans.Module, + node, + self.Trans._funcs, self.Trans._func_count, self.Trans) + + +# ============================================================ +# NewExprHandle - 工厂函数 +# ============================================================ +def NewExprHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> ExprHandle | t.CPtr: + h: ExprHandle | t.CPtr = pool.alloc(ExprHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, ExprHandle.__sizeof__()) + h.Trans = trans + return h + + +# ============================================================ +# list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑 +# +# list 结构布局 (6 字段 × 8 字节): +# __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) +# 返回元素地址 (i8*),调用方根据元素类型 load 正确的值 +# ============================================================ +def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + lm_obj: llvmlite.Value | t.CPtr, + idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)""" + if builder is None or pool is None or lm_obj is None or idx_val is None: + return None + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + # 加载 __data__ (偏移 0, index 0) + g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) + if g_dpp is None: + return None + g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) + if g_epp is None: + return None + g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) + if g_data is None or g_esize is None: + return None + g_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty) + if g_idx_i64 is None: + return None + g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) + if g_offset is None: + return None + # 返回元素地址 (i8*),不 load + return llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + + +# ============================================================ +# _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 +# +# 类型名格式: .list[] +# 用 strstr 检查完整模式,避免子串提取 +# 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等 +# 默认: i32 +# ============================================================ +def _list_elem_type_from_name(pool: memhub.MemBuddy | t.CPtr, + struct_name: str) -> llvmlite.LLVMType | t.CPtr: + """从 list 类型名提取元素 LLVM 类型""" + if pool is None or struct_name is None: + return None + # 用 strstr 检查完整模式 + if string.strstr(struct_name, "list[int]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt8T]") is not None: + return llvmlite.Int8(pool) + if string.strstr(struct_name, "list[CInt16T]") is not None: + return llvmlite.Int16(pool) + if string.strstr(struct_name, "list[CInt32T]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt64T]") is not None: + return llvmlite.Int64(pool) + if string.strstr(struct_name, "list[CSizeT]") is not None: + return llvmlite.Int64(pool) + if string.strstr(struct_name, "list[CDouble]") is not None: + return llvmlite.Double(pool) + if string.strstr(struct_name, "list[CFloat]") is not None: + return llvmlite.Float(pool) + if string.strstr(struct_name, "list[CChar]") is not None: + return llvmlite.Int8(pool) + # str/bytes/CPtr/其他指针类型 → i8* + i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + return llvmlite.Ptr(pool, i8_ty_d) + + +# ============================================================ +# list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 +# +# 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store) +# ============================================================ +def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + lm_obj: llvmlite.Value | t.CPtr, + idx_val: llvmlite.Value | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr) -> int: + """内联生成 list __setitem__ 逻辑,返回 0""" + if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None: + return 0 + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + # 加载 __data__ (偏移 0, index 0) + s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) + if s_dpp is None: + return 0 + s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) + if s_epp is None: + return 0 + s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) + if s_data is None or s_esize is None: + return 0 + s_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty) + if s_idx_i64 is None: + return 0 + s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) + if s_offset is None: + return 0 + s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) + if s_addr is None: + return 0 + s_val_ptr: llvmlite.Value | t.CPtr = coerce_to_type(builder, rhs_val, i8_ptr_ty) + if s_val_ptr is None: + return 0 + llvmlite.build_store(builder, s_val_ptr, s_addr) + return 0 + + +# ============================================================ +# is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型 +# +# 返回 list 对象指针 (Ptr(list[T])) 或 None +# ============================================================ +def is_list_subscript(node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None""" + if node is None or trans is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None or sub.value is None: + return None + if sub.value.kind() != ast.ASTKind.Name: + return None + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm is None or nm.id is None: + return None + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return None + if is_ptr_type(alloca.Ty) == 0: + return None + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return None + # 检查 pointee 是否是 Ptr(Struct) + inner_ty: llvmlite.LLVMType | t.CPtr = None + match pointee: + case llvmlite.LLVMType.Ptr(it): + inner_ty = it + case _: + return None + if inner_ty is None: + return None + # 检查 inner_ty 是否是 Struct 且名称包含 "list[" + struct_name: str = None + match inner_ty: + case llvmlite.LLVMType.Struct(_, _, sname): + struct_name = sname + case _: + return None + if struct_name is None: + return None + if string.strstr(struct_name, "list[") is None: + return None + # 是 list 类型: load 出 list 对象指针 + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + return llvmlite.build_load(builder, pointee, alloca) + + +# ============================================================ +# 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] +# +# 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load +# 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load +# list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径 +# ============================================================ +def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译下标表达式,返回加载的元素值""" + if node is None or builder is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None: + return None + + # 翻译索引 + idx_val: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, sub.slice, None, 0, trans) + if idx_val is None: + return None + + # 如果 value 是 Name,尝试从 alloca 类型推断 + if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is not None and trans is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is not None and alloca.Ty is not None: + if is_ptr_type(alloca.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is not None: + # 单层 match(避免嵌套 match 的编译器 bug) + match pointee: + case llvmlite.LLVMType.Array(elem_ty, count): + # 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, pointee, elem_ty, alloca, idx_val) + if elem_ptr is not None: + return llvmlite.build_load(builder, elem_ty, elem_ptr) + return None + case llvmlite.LLVMType.Ptr(inner_ty): + # 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct) + # list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历 + list_struct_name: str = None + match inner_ty: + case llvmlite.LLVMType.Struct(_, _, lsn): + list_struct_name = lsn + case _: + pass + if list_struct_name is not None: + if string.strstr(list_struct_name, "list[") is not None: + # list[T] 类型: 内联生成 __getitem__ 逻辑 + ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_list is not None: + elem_addr_list: llvmlite.Value | t.CPtr = list_getitem_inline( + builder, pool, ptr_val_list, idx_val) + if elem_addr_list is not None: + # 根据类型名提取元素类型,bitcast 后 load + elem_ty_list: llvmlite.LLVMType | t.CPtr = _list_elem_type_from_name( + pool, list_struct_name) + if elem_ty_list is not None: + elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, elem_ty_list) + casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, elem_addr_list, elem_ptr_ty_list) + if casted_addr_list is not None: + return llvmlite.build_load( + builder, elem_ty_list, casted_addr_list) + return None + # 普通指针遍历: 先 load 指针值,再 GEP + ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val is not None: + elem_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val, idx_val) + if elem_ptr2 is not None: + return llvmlite.build_load(builder, inner_ty, elem_ptr2) + return None + case _: + # 自定义类(结构体类型): 转发到 __getitem__ 方法调用 + # 如 hashtable[key] → hashtable.__getitem__(key) + cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee) + if cls_nm_sub is not None: + obj_val_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if obj_val_sub is not None: + arg_vals_sub: t.CSizeT | t.CPtr = pool.alloc(8) + if arg_vals_sub is not None: + arg_vals_sub[0] = t.CSizeT(idx_val) + ret_sub: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, cls_nm_sub, "__getitem__", + obj_val_sub, arg_vals_sub, 1, trans) + if ret_sub is not None: + return ret_sub + pass + + # 通用路径:翻译 value 获取指针 + ptr_val: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, sub.value, None, 0, trans) + if ptr_val is None or ptr_val.Ty is None: + return None + + # 检查是否是指针类型 + if is_ptr_type(ptr_val.Ty) != 0: + elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty2 is not None: + elem_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, elem_ty2, ptr_val, idx_val) + if elem_ptr3 is not None: + return llvmlite.build_load(builder, elem_ty2, elem_ptr3) + return None + + +# ============================================================ +# find_global_in_module - 在模块全局变量链表中按名称查找 +# +# 查找策略: +# 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy) +# 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy") +# ============================================================ +def find_global_in_module(mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.GlobalVariable | t.CPtr: + """在模块全局变量链表中按名称查找全局变量""" + if mod is None or name is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead + # 第一遍: 精确匹配 + while cur is not None: + if cur.Name is not None: + if string.strcmp(cur.Name, name) == 0: + return cur + cur = cur.Next + # 第二遍: 后缀匹配 (.name) + cur = mod.GlobalHead + while cur is not None: + if cur.Name is not None: + cur_len: t.CSizeT = string.strlen(cur.Name) + if cur_len > name_len + 1: + suffix_start: t.CSizeT = cur_len - name_len + if cur.Name[suffix_start - 1] == '.': + match: int = 1 + for i in range(name_len): + if cur.Name[suffix_start + i] != name[i]: + match = 0 + break + if match == 1: + return cur + cur = cur.Next + return None + + +# ============================================================ +# make_global_ref - 创建全局变量引用 (@name,类型为 ty*) +# +# 用于跨模块全局变量访问: stub 未注入时,翻译阶段生成 @name 引用, +# 链接时由 stub 提供 external global 声明。 +# ============================================================ +def make_global_ref(pool: memhub.MemBuddy | t.CPtr, + name: str, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """创建全局变量引用 (类型为 ty*,名称为 @name)""" + if name is None or ty is None: + return None + ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty) + ref_name: t.CChar | t.CPtr = pool.alloc(64) + if ref_name is None: + return None + viperlib.snprintf(ref_name, 64, "@%s", name) + return llvmlite.SSAValue(pool, ptr_ty, ref_name) + + +# ============================================================ +# _resolve_module_attribute_global - 解析模块属性访问的全局变量引用 +# +# 当 obj 是已导入模块名 (如 sys._mbuddy) 时: +# 1. 在当前模块全局变量链表中查找 (stub 已注入的情况) +# 2. 未找到则创建前向引用 (@attr_name, 类型为 ty 参数) +# +# 参数: +# ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退) +# 返回: Value 指针 (类型为 ty*),未识别为模块属性返回 None +# ============================================================ +def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + at: ast.Attribute | t.CPtr, + ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)""" + if at is None or at.value is None or at.attr is None: + return None + if at.value.kind() != ast.ASTKind.Name: + return None + if trans is None or trans._imported_modules is None: + return None + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is None: + return None + # 检查是否是已导入模块 + if HandlesImports.is_module_imported(trans._imported_modules, mod_nm.id) == 0: + return None + # 在当前模块查找全局变量 (stub 可能已注入) + gv: llvmlite.GlobalVariable | t.CPtr = find_global_in_module(mod, at.attr) + if gv is not None and gv.Ty is not None: + return make_global_ref(pool, at.attr, gv.Ty) + # 未找到: 创建前向引用 (stub 后续注入时提供声明) + use_ty: llvmlite.LLVMType | t.CPtr = ty_hint + if use_ty is None: + use_ty = llvmlite.Int8(pool) + return make_global_ref(pool, at.attr, use_ty) + + +# ============================================================ +# 翻译属性访问 Attribute(value, attr, ctx) — obj.field +# +# 优先级: +# 1. 枚举成员访问 (State.Idle → 常量值) +# 2. 模块属性访问 (sys._mbuddy → 加载全局变量) +# 3. 结构体字段访问 (obj.field → GEP + load) +# +# 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) +# ============================================================ +def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译属性访问,返回加载的字段值""" + if node is None or builder is None: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at is None or at.value is None or at.attr is None: + return None + + # 枚举成员访问: EnumName.MemberName → 常量值 + # 当 value 是 Name 且 Name.id 是已注册枚举时,查找成员并返回常量 + if at.value.kind() == ast.ASTKind.Name: + enum_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if enum_nm.id is not None: + if HandlesEnum.is_enum_class(enum_nm.id) == 1: + member: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( + enum_nm.id, at.attr) + if member is not None: + base_ty: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( + enum_nm.id) + if base_ty is not None: + # 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值) + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is not None: + viperlib.snprintf(name_buf, 32, "%lld", member.Value) + return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf) + return llvmlite.const_int32(pool, member.Value) + return None + + # 模块属性访问 (读路径): sys._mbuddy → 加载全局变量 @_mbuddy + # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用并加载 + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_ma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_ma.id is not None: + # 先检查是否是普通变量 (优先级高于模块属性) + ma_is_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm_ma.id) + if ma_is_var is None: + # 使用 i8* 作为类型提示 (模块级变量通常存储指针) + i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + mod_gv_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global( + pool, mod, trans, at, i8_ptr_hint) + if mod_gv_ref is not None and mod_gv_ref.Ty is not None: + load_ty_mod: llvmlite.LLVMType | t.CPtr = mod_gv_ref.Ty.Pointee + if load_ty_mod is not None: + return llvmlite.build_load(builder, load_ty_mod, mod_gv_ref) + + # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体) + obj_ptr: llvmlite.Value | t.CPtr = None + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm.id is not None: + obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) + + # 非 Name 路径:翻译对象值(会 load) + if obj_ptr is None: + obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans) + + if obj_ptr is None or obj_ptr.Ty is None: + return None + + # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), + # load 解引用获取 Ptr(Struct) + obj_ptr = _deref_if_ptr_ptr(builder, obj_ptr) + + # 查找结构体类型信息 + # obj_ptr 类型应该是 Ptr(Struct(...)) + match obj_ptr.Ty: + case llvmlite.LLVMType.Ptr(struct_ty): + # 查找字段索引和类型 + field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + struct_ty, at.attr) + # 回退: 类型指针比较失败时,通过 AnnotClassName 按类名查找 + # 传递 SHA1 以区分跨模块同名类 + if field_info is None: + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_fb.id is not None: + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm_fb.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + cur_sha1: str = trans.ModuleSha1 + field_info = HandlesStruct.lookup_field_by_class( + var_entry.AnnotClassName, at.attr, cur_sha1) + if field_info is not None: + field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty + # 联合体:bitcast obj_ptr 到 field_ty* 后 load + if HandlesStruct.is_union_by_type(struct_ty) == 1: + field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_ty) + casted: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, field_ptr_ty) + if casted is not None: + return llvmlite.build_load(builder, field_ty, casted) + return None + # 普通结构体:GEP + load + field_idx: int = field_info.Index + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, field_ty, obj_ptr, field_idx) + if field_ptr is not None: + return llvmlite.build_load(builder, field_ty, field_ptr) + return None + case _: + return None + +# ============================================================ +# 获取下标表达式的元素指针(不加载值,用于赋值) +# ============================================================ +def get_subscript_ptr(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """获取下标表达式的元素指针(用于赋值 lhs)""" + if node is None or builder is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None: + return None + + # 翻译索引 + idx_val: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, sub.slice, None, 0, trans) + if idx_val is None: + return None + + # 如果 value 是 Name,尝试从 alloca 类型推断 + if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is not None and trans is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is not None and alloca.Ty is not None: + if is_ptr_type(alloca.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is not None: + # 单层 match(避免嵌套 match 的编译器 bug) + match pointee: + case llvmlite.LLVMType.Array(elem_ty, count): + # 数组遍历 + return llvmlite.build_gep_array( + builder, pointee, elem_ty, alloca, idx_val) + case llvmlite.LLVMType.Ptr(inner_ty): + # 指针遍历 + ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val is not None: + return llvmlite.build_gep( + builder, inner_ty, ptr_val, idx_val) + return None + case _: + pass + + # 通用路径 + ptr_val: llvmlite.Value | t.CPtr = translate_value( + builder, pool, mod, sub.value, None, 0, trans) + if ptr_val is None or ptr_val.Ty is None: + return None + if is_ptr_type(ptr_val.Ty) != 0: + elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty2 is not None: + return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) + return None + + +# ============================================================ +# 获取属性访问的字段指针(不加载值,用于赋值) +# 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) +# ============================================================ +def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """获取属性访问的字段指针(用于赋值 lhs)""" + if node is None or builder is None: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at is None or at.value is None or at.attr is None: + return None + + # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体) + obj_ptr: llvmlite.Value | t.CPtr = None + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm.id is not None: + obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) + + # 模块属性访问 (写路径): sys._mbuddy = mb → store 到全局变量 @_mbuddy + # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用 + if obj_ptr is None and at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_wma.id is not None: + # 使用 i8* 作为类型提示 (模块级变量通常存储指针) + i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + wma_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global( + pool, mod, trans, at, i8_ptr_w) + if wma_ref is not None: + return wma_ref + + # 非 Name 路径:翻译对象值(会 load) + if obj_ptr is None: + obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans) + + if obj_ptr is None or obj_ptr.Ty is None: + return None + + # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), + # load 解引用获取 Ptr(Struct) + obj_ptr = _deref_if_ptr_ptr(builder, obj_ptr) + + match obj_ptr.Ty: + case llvmlite.LLVMType.Ptr(struct_ty): + field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + struct_ty, at.attr) + # 回退: 类型指针比较失败时,通过 AnnotClassName 按类名查找 + # 传递 SHA1 以区分跨模块同名类 + if field_info is None: + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_fb.id is not None: + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm_fb.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + cur_sha1: str = None + if trans is not None: + cur_sha1 = trans.ModuleSha1 + field_info = HandlesStruct.lookup_field_by_class( + var_entry.AnnotClassName, at.attr, cur_sha1) + if field_info is not None: + # 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store) + if HandlesStruct.is_union_by_type(struct_ty) == 1: + field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty) + return llvmlite.build_bitcast(builder, obj_ptr, field_ptr_ty) + # 普通结构体:GEP 获取字段指针 + return llvmlite.build_gep_struct( + builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index) + return None + case _: + return None diff --git a/App/lib/core/Handles/HandlesExprCall.py b/App/lib/core/Handles/HandlesExprCall.py new file mode 100644 index 0000000..3e2ec2e --- /dev/null +++ b/App/lib/core/Handles/HandlesExprCall.py @@ -0,0 +1,3972 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import sys +import viperlib +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef + + +# ============================================================ +# 全局模块 SHA1 映射(module_name → SHA1) +# +# 翻译时用于跨模块函数调用名混淆: +# string.strchr(...) → call @{sha1_of_string}.strchr(...) +# +# 通过 set_module_sha1_map 设置,_lookup_module_sha1 查询 +# ============================================================ +_g_sha1_arr: bytes = None +_g_mod_arr: bytes = None +_g_sha1_count: int = 0 + + +def set_module_sha1_map(sha1_arr: bytes, mod_arr: bytes, count: int) -> int: + """设置全局模块 SHA1 映射""" + global _g_sha1_arr + global _g_mod_arr + global _g_sha1_count + _g_sha1_arr = sha1_arr + _g_mod_arr = mod_arr + _g_sha1_count = count + return 0 + + +def _lookup_module_sha1(mod_name: str) -> str: + """查找模块名对应的 SHA1,找不到返回 None""" + if mod_name is None: + return None + if _g_sha1_arr is None or _g_mod_arr is None: + return None + if _g_sha1_count <= 0: + return None + for i in range(_g_sha1_count): + idx: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(_g_mod_arr + idx, mod_name) == 0: + sidx: t.CSizeT = t.CSizeT(i) * 17 + return _g_sha1_arr + sidx + return None + + +def _lookup_module_sha1_suffix(mod_suffix: str) -> str: + """后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types" + + 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点), + 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。 + """ + if mod_suffix is None: + return None + if _g_sha1_arr is None or _g_mod_arr is None: + return None + if _g_sha1_count <= 0: + return None + suffix_len: t.CSizeT = string.strlen(mod_suffix) + if suffix_len == 0: + return None + for i in range(_g_sha1_count): + idx: t.CSizeT = t.CSizeT(i) * 64 + mod_name: str = _g_mod_arr + idx + mod_len: t.CSizeT = string.strlen(mod_name) + if mod_len < suffix_len: + continue + # 精确匹配 + if mod_len == suffix_len: + if string.strcmp(mod_name, mod_suffix) == 0: + sidx: t.CSizeT = t.CSizeT(i) * 17 + return _g_sha1_arr + sidx + # 后缀匹配:mod_name 以 "." + mod_suffix 结尾 + if mod_len > suffix_len: + if mod_name[mod_len - suffix_len - 1] == '.': + cmp_start: str = mod_name + mod_len - suffix_len + if string.strcmp(cmp_start, mod_suffix) == 0: + sidx2: t.CSizeT = t.CSizeT(i) * 17 + return _g_sha1_arr + sidx2 + return None + + +# ============================================================ +# 全局 CExport 函数表(module_sha1 + func_name) +# +# t.CExport 函数定义时不加 SHA1 前缀(如 @strlen), +# 跨模块调用时需要查表确认目标函数是否是 CExport 函数。 +# 若是,使用裸名调用(@strlen);否则使用 @{sha1}.func。 +# 必须包含模块 SHA1 记录,避免同名跨模块函数冲突 +# (一个模块有 CExport 的 strlen→@strlen,另一个没有→@{sha1}.strlen)。 +# ============================================================ +_g_cexport_sha1_arr: bytes = None +_g_cexport_func_arr: bytes = None +_g_cexport_count: int = 0 +_CEXPORT_MAX: t.CDefine = 256 + + +def register_cexport_func(sha1: str, func_name: str) -> int: + """注册 CExport 函数到全局表(sha1+func_name 二元组)""" + global _g_cexport_sha1_arr + global _g_cexport_func_arr + global _g_cexport_count + if sha1 is None or func_name is None: + return 0 + if _g_cexport_sha1_arr is None: + _g_cexport_sha1_arr = stdlib.malloc(_CEXPORT_MAX * 17) + _g_cexport_func_arr = stdlib.malloc(_CEXPORT_MAX * 64) + if _g_cexport_sha1_arr is None or _g_cexport_func_arr is None: + return 0 + string.memset(_g_cexport_sha1_arr, 0, _CEXPORT_MAX * 17) + string.memset(_g_cexport_func_arr, 0, _CEXPORT_MAX * 64) + if _g_cexport_count < _CEXPORT_MAX: + idx: t.CSizeT = t.CSizeT(_g_cexport_count) * 17 + string.strcpy(_g_cexport_sha1_arr + idx, sha1) + idx2: t.CSizeT = t.CSizeT(_g_cexport_count) * 64 + string.strcpy(_g_cexport_func_arr + idx2, func_name) + _g_cexport_count += 1 + return 1 + return 0 + + +def is_cexport_func(sha1: str, func_name: str) -> int: + """检查 (sha1, func_name) 是否是 CExport 函数""" + if sha1 is None or func_name is None: + return 0 + if _g_cexport_sha1_arr is None: + return 0 + for i in range(_g_cexport_count): + idx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(_g_cexport_sha1_arr + idx, sha1) == 0: + idx2: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(_g_cexport_func_arr + idx2, func_name) == 0: + return 1 + return 0 + + +# ============================================================ +# _lookup_mod_sha1 - 从 from_imports 查找类所属模块的 SHA1 +# +# lookup_from_import 返回指向 from_imports 内部的指针,不是 null 终止 +# (如 "namespace_defs Gadget:namespace_defs ...")。此函数手动截断 +# 模块名,复制到新缓冲区,再查找 SHA1(精确+后缀匹配)。 +# ============================================================ +def _lookup_mod_sha1(pool: memhub.MemBuddy | t.CPtr, + from_imports: str, class_name: str, + allow_star_fallback: int = 1) -> str: + """从 from_imports 查找类所属模块的 SHA1,返回 None=未找到 + + allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找) + """ + mod_name_raw: str = HandlesImports.lookup_from_import( + from_imports, class_name, allow_star_fallback) + if mod_name_raw is None: + return None + # 手动找到模块名结束位置(空格或 null),复制到新缓冲区 + mod_len: t.CSizeT = 0 + while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0': + mod_len += 1 + mod_name_buf: str = pool.alloc(mod_len + 1) + if mod_name_buf is None: + return None + for mi in range(mod_len): + mod_name_buf[mi] = mod_name_raw[mi] + mod_name_buf[mod_len] = '\0' + # 去掉相对导入的前导点 + base_mod: str = mod_name_buf + while base_mod[0] == '.': + base_mod = base_mod + 1 + sha1: str = _lookup_module_sha1(base_mod) + if sha1 is None: + sha1 = _lookup_module_sha1_suffix(base_mod) + return sha1 + + +# ============================================================ +# HandlesExprCall - 函数调用表达式处理(Mixin 继承模式) +# +# 工具函数和 FuncEntry 保留为模块级,ExprCallHandle 提供 trans 接口 +# ============================================================ + + +# ============================================================ +# 在模块函数链表中按名称查找函数 +# ============================================================ +def find_func_in_module(mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.Function | t.CPtr: + """在模块的函数链表中按名称查找函数 + + 查找策略: + 1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数) + 2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数) + + 使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制 + (stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。 + """ + if mod is None or name is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: llvmlite.Function | t.CPtr = mod.FuncHead + # 第一遍:精确匹配 + while cur is not None: + cur_name: t.CChar | t.CPtr = llvmlite.function_get_name(cur) + if cur_name is not None: + if string.strcmp(cur_name, name) == 0: + return cur + cur = llvmlite.function_get_next(cur) + # 第二遍:后缀匹配(.name) + # 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到 + # 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名 + cur = mod.FuncHead + while cur is not None: + cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur) + if cur_name2 is not None: + cur_len: t.CSizeT = string.strlen(cur_name2) + if cur_len > name_len + 1: + suffix_start: t.CSizeT = cur_len - name_len + if cur_name2[suffix_start - 1] == '.': + match: int = 1 + for i in range(name_len): + if cur_name2[suffix_start + i] != name[i]: + match = 0 + break + if match == 1: + return cur + cur = llvmlite.function_get_next(cur) + return None + + +# ============================================================ +# _infer_external_func_ret_ty - 根据函数名推断外部函数返回类型 +# +# stubs 在翻译后才注入 IR,翻译时模块中无 stub 函数声明, +# 因此对 includes 库函数(如 string.strchr 返回 i8*)需根据 +# 函数名推断返回类型,避免指针被截断为 i32。 +# +# 覆盖 includes/string.py 所有导出函数: +# i8*: strcpy, strncpy, strchr, strrchr, strstr, memset, memset32, memcpy, memmove +# i64: strlen, atoll +# double: atof +# i8: samestr +# i32(默认): strcmp, strncmp, memcmp, strspn, atoi, split +# ============================================================ +def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr, + func_name: str) -> llvmlite.LLVMType | t.CPtr: + """根据函数名推断外部 includes 函数的返回类型""" + if pool is None or func_name is None: + return llvmlite.Int32(pool) + + # 返回 i8* 的函数(指针返回值,截断会导致错误) + if func_name == "strchr": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "strrchr": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "strstr": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "strcpy": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "strncpy": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "memset": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "memset32": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "memcpy": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "memmove": + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i64 的函数 + if func_name == "strlen": + return llvmlite.Int64(pool) + if func_name == "atoll": + return llvmlite.Int64(pool) + + # 返回 double 的函数 + if func_name == "atof": + return llvmlite.Double(pool) + + # 返回 i8 的函数 + if func_name == "samestr": + return llvmlite.Int8(pool) + + # Win32 API 返回指针(VOIDPTR/HANDLE)的函数 + # stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if func_name == "VirtualAlloc": + return i8_ptr_ty + if func_name == "HeapAlloc": + return i8_ptr_ty + if func_name == "HeapReAlloc": + return i8_ptr_ty + if func_name == "HeapCreate": + return i8_ptr_ty + if func_name == "GetProcessHeap": + return i8_ptr_ty + if func_name == "GlobalAlloc": + return i8_ptr_ty + if func_name == "GlobalFree": + return i8_ptr_ty + if func_name == "GlobalLock": + return i8_ptr_ty + if func_name == "LocalAlloc": + return i8_ptr_ty + if func_name == "LocalFree": + return i8_ptr_ty + if func_name == "GetProcAddress": + return i8_ptr_ty + if func_name == "GetModuleHandleA": + return i8_ptr_ty + if func_name == "GetModuleHandleW": + return i8_ptr_ty + if func_name == "LoadLibraryA": + return i8_ptr_ty + if func_name == "LoadLibraryW": + return i8_ptr_ty + + # Win32 API 返回 i64 (SIZE_T) 的函数 + if func_name == "VirtualQuery": + return llvmlite.Int64(pool) + if func_name == "HeapSize": + return llvmlite.Int64(pool) + if func_name == "HeapCompact": + return llvmlite.Int64(pool) + if func_name == "GlobalSize": + return llvmlite.Int64(pool) + + # 默认 i32 + return llvmlite.Int32(pool) + + +# ============================================================ +# _get_external_func_param_ty - 获取外部函数第 idx 个参数的期望类型 +# +# stubs 翻译时未注入,需推断参数类型以提升字面量(如 i32→i64), +# 避免 declare(i64) 与 call(i32) 类型不匹配。 +# +# 注意:stubs 翻译时 ULONG(t.CUnsignedLong) 在 LLVM IR 中被翻译为 i64 +# (因为 LLVM 中 long 是 64 位),因此 Win32 API 中所有 ULONG/DWORD/SIZE_T +# 参数在 declare 中都是 i64。call 时必须匹配,否则类型不匹配。 +# +# 策略:对 Win32 API 函数的所有非指针参数(字面量)都提升为 i64, +# 以匹配 declare 中 ULONG 被翻译为 i64 的情况。 +# +# 指针参数(VOIDPTR/HANDLE)不在此处理,由调用点的 inttoptr 处理。 +# ============================================================ +def _get_external_func_param_ty(pool: memhub.MemBuddy | t.CPtr, + func_name: str, + param_idx: int) -> llvmlite.LLVMType | t.CPtr: + """获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型 + + 对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中 + ULONG/SIZE_T 被统一翻译为 i64 的情况。 + """ + if pool is None or func_name is None: + return None + + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + # Win32 API 函数列表:所有非指针参数在 declare 中都是 i64 + # (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64) + win32_apis: list[str] | t.CPtr = [ + "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", + "VirtualLock", "VirtualUnlock", + "HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc", + "HeapFree", "HeapSize", "HeapValidate", "HeapCompact", + "GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize", + "LocalAlloc", "LocalFree", + "GetLastError", "SetLastError", + "Sleep", "SleepEx", + "GetTickCount", "GetProcessHeap" + ] + + for api_name in win32_apis: + if api_name == func_name: + return i64_ty + + return None + + +# ============================================================ +# _emit_llvm_memcpy_intrinsic — 将 memcpy 调用映射到 @llvm.memcpy 内联函数 +# +# 背景: string.memcpy 是 t.CExport 函数,跨模块调用生成 @memcpy 裸名调用。 +# 但在 monomorphization 场景下,目标模块的 deps.txt 可能不含 string, +# 导致 @memcpy 声明缺失,链接器报 undefined value。 +# +# 解决: 将 memcpy 调用映射到 LLVM 内联函数 @llvm.memcpy, +# 该内联函数在当前模块内声明,无需跨模块依赖。 +# +# @llvm.memcpy 签名: void (i8* dst, i8* src, i64 len, i1 isvolatile) +# C memcpy 签名: i8* (i8* dst, i8* src, i64 len) — 返回 dst +# +# Args: +# args_head: 参数链表头(dst, src, num),通过 Value.Next 链接 +# arg_count: 参数数量(应为 3) +# +# Returns: +# dst 值(匹配 C memcpy 语义: 返回 dest 指针) +# ============================================================ +def _emit_llvm_memcpy_intrinsic(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + dst_val: llvmlite.Value | t.CPtr, + src_val: llvmlite.Value | t.CPtr, + num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """将 memcpy 调用映射到 @llvm.memcpy 内联函数 + + 直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的 + Next 字段可能被其他操作污染,导致链表断裂)。 + """ + if pool is None or builder is None or mod is None: + return None + if dst_val is None or src_val is None or num_val is None: + return None + + # 在函数顶部声明 void_ty,避免后续遮蔽 + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + + # 声明 @llvm.memcpy(如未声明) + memcpy_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, "llvm.memcpy") + if memcpy_func is None: + memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty) + if memcpy_func is not None: + i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst") + llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src") + llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len") + llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile") + + # 类型转换: dst, src → i8*; num → i64 + # 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + # dst → i8* + dst_coerced: llvmlite.Value | t.CPtr = dst_val + dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val) + if HandlesExpr.is_ptr_type(dst_ty) != 0: + dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty) + else: + dst_bits: int = HandlesExpr.get_llvm_type_bits(dst_ty) + if dst_bits != 0: + if dst_bits < 64: + dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty) + dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty) + + # src → i8* + src_coerced: llvmlite.Value | t.CPtr = src_val + src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val) + if HandlesExpr.is_ptr_type(src_ty) != 0: + src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty) + else: + src_bits: int = HandlesExpr.get_llvm_type_bits(src_ty) + if src_bits != 0: + if src_bits < 64: + src_coerced = llvmlite.build_zext(builder, src_val, i64_ty) + src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty) + + # num → i64 + num_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, num_val, i64_ty) + + if dst_coerced is None or src_coerced is None or num_coerced is None: + return None + + # 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数 + false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false") + + # 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移 + # (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty) + llvmlite.value_set_next(dst_coerced, src_coerced) + llvmlite.value_set_next(src_coerced, num_coerced) + if false_val is not None: + llvmlite.value_set_next(num_coerced, false_val) + llvmlite.value_set_next(false_val, None) + else: + llvmlite.value_set_next(num_coerced, None) + + # 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确) + # _ll_name_needs_quote 已对 llvm. 前缀豁免引号 + result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0) + + # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) + return dst_coerced + + +# ============================================================ +# c.Deref(ptr) — 解引用指针,load i8(字符遍历用例) +# +# 生成: %N = load i8, i8* %ptr +# 返回 i8 值 +# ============================================================ +def translate_c_deref(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Deref(ptr) → load i8 from ptr""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 1: + return None + + ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + if ptr_val is None: + return None + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + return llvmlite.build_load(builder, i8_ty, ptr_val) + + +# ============================================================ +# c.DerefAs(ptr, val) — 解引用写入,*ptr = val +# +# 生成: %pc = bitcast i8* %ptr to * +# store %val, * %pc +# ============================================================ +def translate_c_derefas(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 2: + return None + + ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if ptr_val is None or val is None: + return None + + # bitcast ptr 到 val.Ty* 再 store + val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty) + if casted_ptr is None: + return None + llvmlite.build_store(builder, val, casted_ptr) + return val + + +# ============================================================ +# c.Addr(var) — 取变量地址,返回 alloca 指针(不 load) +# +# 用于获取栈变量的可写地址,配合 c.DerefAs 使用 +# ============================================================ +def translate_c_addr(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Addr(var) → 返回变量的 alloca 指针(不 load)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 1: + return None + + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None or arg0.kind() != ast.ASTKind.Name: + return None + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0) + if nm.id is None: + return None + + return HandlesVar.lookup_var(trans.SymTab, nm.id) + + +# ============================================================ +# c.Load(a, b) — 指针间复制: *a = *b +# +# 加载 b 指向的值,存储到 a 指向的地址。 +# 生成: %pc_src = bitcast i8* %src to * +# %loaded = load , * %pc_src +# %pc_dst = bitcast i8* %dst to * +# store %loaded, * %pc_dst +# ============================================================ +def translate_c_load(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)""" + if cl is None: + return None + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 2: + return None + + dst_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + src_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(1), None, 0, trans) + if dst_ptr is None or src_ptr is None: + return None + + # 确定 pointee 类型(优先用 src 的 pointee,回退到 dst 的 pointee) + pointee: llvmlite.LLVMType | t.CPtr = None + if src_ptr.Ty is not None: + pointee = src_ptr.Ty.Pointee + if pointee is None and dst_ptr.Ty is not None: + pointee = dst_ptr.Ty.Pointee + if pointee is None: + return None + + # bitcast src 到 pointee* 并 load + target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee) + src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty) + if src_cast is None: + return None + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast) + if loaded is None: + return None + + # bitcast dst 到 pointee* 并 store + dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty) + if dst_cast is None: + return None + llvmlite.build_store(builder, loaded, dst_cast) + return loaded + + +# ============================================================ +# c.Asm — 内联汇编支持 +# +# 生成: %N = call asm sideeffect "", ""() +# 或: call void asm sideeffect "", ""() +# +# 操作数按出现顺序编号 $0, $1, ...(用户需按输出在前写 f-string) +# ============================================================ + +ASM_MAX_OPERANDS: t.CDefine = 16 +ASM_TEXT_BUF_SIZE: t.CDefine = 2048 +ASM_CONST_BUF_SIZE: t.CDefine = 512 +ASM_ARGS_BUF_SIZE: t.CDefine = 512 +ASM_LINE_BUF_SIZE: t.CDefine = 4096 + + +# ============================================================ +# AsmOperand - 内联汇编操作数条目 +# ============================================================ +@t.NoVTable +class AsmOperand: + """内联汇编操作数条目""" + Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca + Constraint: str # 约束字符串 (如 "r", "=r") + IsOutput: int # 1=输出, 0=输入 + + +# ============================================================ +# _asm_append_cstr — 将 C 字符串 src 追加到 dst 末尾 +# ============================================================ +def _asm_append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, + src: t.CChar | t.CPtr): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: + return + dlen: t.CSizeT = string.strlen(dst) + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: + return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# ============================================================ +# _asm_escape_for_ir — 将汇编文本转义为 LLVM IR 字符串内容 +# +# \n → \0A, " → \22, \ → \5C +# ============================================================ +def _asm_escape_for_ir(pool: memhub.MemBuddy | t.CPtr, + src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """转义汇编文本用于 LLVM IR 字符串字面量""" + if src is None: + return None + slen: t.CSizeT = string.strlen(src) + buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8) + if buf is None: + return None + pos: t.CSizeT = 0 + for ch in src: + if ch == '\n': + buf[pos] = '\\' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = 'A' + pos += 1 + elif ch == '"': + buf[pos] = '\\' + pos += 1 + buf[pos] = '2' + pos += 1 + buf[pos] = '2' + pos += 1 + elif ch == '\\': + buf[pos] = '\\' + pos += 1 + buf[pos] = '5' + pos += 1 + buf[pos] = 'C' + pos += 1 + else: + buf[pos] = ch + pos += 1 + buf[pos] = '\0' + return buf + + +# ============================================================ +# _resolve_register — 将 ASM_DESCR 属性名映射到约束字符串 +# ============================================================ +def _resolve_register(attr_name: str) -> str: + """将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值""" + if attr_name is None: + return "" + + # Clobber 破坏描述符 + if attr_name == "CLOBBER_MEMORY": return "memory" + if attr_name == "CLOBBER_CC": return "cc" + if attr_name == "CLOBBER_RAX": return "rax" + if attr_name == "CLOBBER_RBX": return "rbx" + if attr_name == "CLOBBER_RCX": return "rcx" + if attr_name == "CLOBBER_RDX": return "rdx" + if attr_name == "CLOBBER_RSI": return "rsi" + if attr_name == "CLOBBER_RDI": return "rdi" + if attr_name == "CLOBBER_RBP": return "rbp" + if attr_name == "CLOBBER_RSP": return "rsp" + if attr_name == "CLOBBER_R8": return "r8" + if attr_name == "CLOBBER_R9": return "r9" + if attr_name == "CLOBBER_R10": return "r10" + if attr_name == "CLOBBER_R11": return "r11" + if attr_name == "CLOBBER_R12": return "r12" + if attr_name == "CLOBBER_R13": return "r13" + if attr_name == "CLOBBER_R14": return "r14" + if attr_name == "CLOBBER_R15": return "r15" + if attr_name == "CLOBBER_EAX": return "eax" + if attr_name == "CLOBBER_EBX": return "ebx" + if attr_name == "CLOBBER_ECX": return "ecx" + if attr_name == "CLOBBER_EDX": return "edx" + if attr_name == "CLOBBER_ESI": return "esi" + if attr_name == "CLOBBER_EDI": return "edi" + if attr_name == "CLOBBER_DX": return "dx" + if attr_name == "CLOBBER_AX": return "ax" + if attr_name == "CLOBBER_CX": return "cx" + if attr_name == "CLOBBER_SI": return "si" + if attr_name == "CLOBBER_DI": return "di" + + # Output 输出约束 + if attr_name == "OUTPUT_REG": return "=r" + if attr_name == "OUTPUT_MEM": return "=m" + if attr_name == "OUTPUT_EAX": return "=a" + if attr_name == "OUTPUT_EBX": return "=b" + if attr_name == "OUTPUT_ECX": return "=c" + if attr_name == "OUTPUT_EDX": return "=d" + if attr_name == "OUTPUT_ESI": return "=S" + if attr_name == "OUTPUT_EDI": return "=D" + if attr_name == "OUTPUT_RAX": return "=a" + if attr_name == "OUTPUT_RBX": return "=b" + if attr_name == "OUTPUT_RCX": return "=c" + if attr_name == "OUTPUT_RDX": return "=d" + if attr_name == "OUTPUT_RSI": return "=S" + if attr_name == "OUTPUT_RDI": return "=D" + + # Input/Register 输入约束 + if attr_name == "REG_ANY": return "r" + if attr_name == "REG_EAX": return "a" + if attr_name == "REG_EBX": return "b" + if attr_name == "REG_ECX": return "c" + if attr_name == "REG_EDX": return "d" + if attr_name == "REG_ESI": return "S" + if attr_name == "REG_EDI": return "D" + if attr_name == "REG_RAX": return "a" + if attr_name == "REG_RBX": return "b" + if attr_name == "REG_RCX": return "c" + if attr_name == "REG_RDX": return "d" + if attr_name == "REG_RSI": return "S" + if attr_name == "REG_RDI": return "D" + + if attr_name == "INPUT_REG": return "r" + if attr_name == "INPUT_MEM": return "m" + if attr_name == "INPUT_EAX": return "a" + if attr_name == "INPUT_EBX": return "b" + if attr_name == "INPUT_ECX": return "c" + if attr_name == "INPUT_EDX": return "d" + if attr_name == "INPUT_ESI": return "S" + if attr_name == "INPUT_EDI": return "D" + if attr_name == "INPUT_RAX": return "a" + if attr_name == "INPUT_RBX": return "b" + if attr_name == "INPUT_RCX": return "c" + if attr_name == "INPUT_RDX": return "d" + if attr_name == "INPUT_RSI": return "S" + if attr_name == "INPUT_RDI": return "D" + + return "" + + +# ============================================================ +# _resolve_asm_descr — 递归解析约束表达式 +# +# 支持: +# t.ASM_DESCR.XXX → _resolve_register(XXX) +# expr | expr (BinOp BitOr) → 拼接 +# "string" (Constant) → 直接返回 +# ============================================================ +def _resolve_asm_descr(pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> str: + """递归解析约束表达式,返回约束字符串""" + if node is None: + return "" + + k: int = node.kind() + + # BinOp with BitOr: 拼接左右 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + left_str: str = _resolve_asm_descr(pool, bop.left) + right_str: str = _resolve_asm_descr(pool, bop.right) + llen: t.CSizeT = string.strlen(left_str) + rlen: t.CSizeT = string.strlen(right_str) + buf: str = pool.alloc(llen + rlen + 1) + if buf is None: + return "" + string.strcpy(buf, left_str) + for i in range(rlen): + buf[llen + i] = right_str[i] + buf[llen + rlen] = '\0' + return buf + return "" + + # Attribute: t.ASM_DESCR.XXX 或 t.XXX + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + # t.ASM_DESCR.XXX + if at.value is not None and at.value.kind() == ast.ASTKind.Attribute: + inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) + if inner.value is not None and inner.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0: + if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0: + return _resolve_register(at.attr) + # t.XXX 简化形式 + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0: + return _resolve_register(at.attr) + return "" + + # Constant: 字符串常量 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR: + return cn.str_val + return "" + + return "" + + +# ============================================================ +# _asm_get_operand — 获取操作数数组中第 idx 个元素的指针 +# ============================================================ +def _asm_get_operand(base: AsmOperand | t.CPtr, + idx: int) -> AsmOperand | t.CPtr: + """获取操作数数组中第 idx 个元素的指针""" + entry_size: t.CSizeT = AsmOperand.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size + return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + + +# ============================================================ +# _asm_is_c_call — 检查 Call 节点是否是 c.XXX 调用 +# +# 返回 attr_name(如 "AsmInp"/"AsmOut"),不是则返回 None +# ============================================================ +def _asm_is_c_call(node: ast.Call | t.CPtr) -> str: + """检查 Call 节点是否是 c.XXX 调用,返回属性名或 None""" + if node is None or node.func is None: + return None + if node.func.kind() != ast.ASTKind.Attribute: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func) + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return None + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0: + return None + return at.attr + + +# ============================================================ +# _asm_add_operand — 添加操作数到数组 +# +# 返回 1 成功, 0 失败(数组已满) +# ============================================================ +def _asm_add_operand(operands: AsmOperand | t.CPtr, + count: int, + val: llvmlite.Value | t.CPtr, + constraint: str, + is_output: int) -> int: + """添加操作数到数组,返回新计数(失败返回原计数)""" + if count >= ASM_MAX_OPERANDS: + return count + op: AsmOperand | t.CPtr = _asm_get_operand(operands, count) + op.Value = val + op.Constraint = constraint + op.IsOutput = is_output + return count + 1 + + +# ============================================================ +# translate_c_asm — 翻译 c.Asm 内联汇编 +# +# 语法: +# c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY]) +# c.Asm(f"mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}", op=[...]) +# c.Asm(f"...", out=[c.AsmOut(var, t.ASM_DESCR.OUTPUT_REG)], op=[...]) +# ============================================================ +def translate_c_asm(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)""" + if cl is None: + return None + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 1: + return None + + # 分配操作数数组 + operand_size: t.CSizeT = AsmOperand.__sizeof__() + operands: AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS) + if operands is None: + return None + string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS) + + # 分配 clobber 名数组 + clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS) + if clobbers is None: + return None + string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS) + + # 分配 asm 文本缓冲区 + asm_text: t.CChar | t.CPtr = pool.alloc(ASM_TEXT_BUF_SIZE) + if asm_text is None: + return None + asm_text[0] = '\0' + + operand_count: int = 0 + clobber_count: int = 0 + fv_count: int = 0 + + # 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引) + fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS) + if fv_orig_indices is None: + return None + string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS) + + # ============================================================ + # 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数 + # 不生成 asm 文本(占位符 $N 需在重排后才能确定编号) + # ============================================================ + tmpl_node: ast.AST | t.CPtr = cargs.get(0) + if tmpl_node is not None: + tk: int = tmpl_node.kind() + + if tk == ast.ASTKind.JoinedStr: + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) + jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values + if jvalues is not None: + jvlen: t.CSizeT = jvalues.__len__() + for vi in range(jvlen): + part: ast.AST | t.CPtr = jvalues.get(vi) + if part is None: + continue + pk: int = part.kind() + + if pk == ast.ASTKind.FormattedValue: + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + fexpr: ast.AST | t.CPtr = fv.value + if fexpr is None or fexpr.kind() != ast.ASTKind.Call: + continue + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = _asm_is_c_call(fcall) + if attr_nm is None: + continue + + is_out: int = 0 + if string.strcmp(attr_nm, "AsmOut") == 0: + is_out = 1 + elif string.strcmp(attr_nm, "AsmInp") == 0: + is_out = 0 + else: + continue + + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or fargs.__len__() < 1: + continue + + val_node: ast.AST | t.CPtr = fargs.get(0) + cons_str: str = "" + if fargs.__len__() >= 2: + cons_str = _resolve_asm_descr(pool, fargs.get(1)) + + if is_out != 0: + # 输出:获取变量 alloca + if val_node is None or val_node.kind() != ast.ASTKind.Name: + continue + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is None: + continue + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is None: + continue + operand_count = _asm_add_operand( + operands, operand_count, alloca, cons_str, 1) + else: + # 输入:翻译值 + ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if ival is None: + continue + operand_count = _asm_add_operand( + operands, operand_count, ival, cons_str, 0) + + # 记录 fv 的原始操作数索引 + if fv_count < ASM_MAX_OPERANDS: + fv_orig_indices[fv_count] = operand_count - 1 + fv_count += 1 + + # ============================================================ + # 2. 解析关键字参数 out=/inp=/op=/clobber= + # ============================================================ + keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + if keywords is not None: + kwlen: t.CSizeT = keywords.__len__() + for ki in range(kwlen): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + kwk: int = kw.value.kind() + + if string.strcmp(kw.arg, "out") == 0: + # 输出操作数列表 + if kwk != ast.ASTKind.List: + continue + out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts + if out_elts is None: + continue + oelen: t.CSizeT = out_elts.__len__() + for oi in range(oelen): + oelt: ast.AST | t.CPtr = out_elts.get(oi) + if oelt is None or oelt.kind() != ast.ASTKind.Call: + continue + ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt) + oattr: str = _asm_is_c_call(ocall) + if oattr is None or string.strcmp(oattr, "AsmOut") != 0: + continue + oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args + if oargs is None or oargs.__len__() < 1: + continue + oval_node: ast.AST | t.CPtr = oargs.get(0) + ocons: str = "" + if oargs.__len__() >= 2: + ocons = _resolve_asm_descr(pool, oargs.get(1)) + if oval_node is None or oval_node.kind() != ast.ASTKind.Name: + continue + onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node) + if onm.id is None: + continue + oalloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, onm.id) + if oalloca is None: + continue + operand_count = _asm_add_operand( + operands, operand_count, oalloca, ocons, 1) + + elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0: + # 输入操作数列表 + if kwk != ast.ASTKind.List: + continue + in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts + if in_elts is None: + continue + ielen: t.CSizeT = in_elts.__len__() + for ii in range(ielen): + ielt: ast.AST | t.CPtr = in_elts.get(ii) + if ielt is None or ielt.kind() != ast.ASTKind.Call: + continue + icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt) + iattr: str = _asm_is_c_call(icall) + if iattr is None or string.strcmp(iattr, "AsmInp") != 0: + continue + iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args + if iargs is None or iargs.__len__() < 1: + continue + ival_node: ast.AST | t.CPtr = iargs.get(0) + icons: str = "" + if iargs.__len__() >= 2: + icons = _resolve_asm_descr(pool, iargs.get(1)) + ival2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, ival_node, None, 0, trans) + if ival2 is None: + continue + operand_count = _asm_add_operand( + operands, operand_count, ival2, icons, 0) + + elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0: + # 破坏列表 + if kwk != ast.ASTKind.List: + continue + cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value) + cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts + if cl_elts is None: + continue + clen: t.CSizeT = cl_elts.__len__() + for ci in range(clen): + celt: ast.AST | t.CPtr = cl_elts.get(ci) + if celt is None: + continue + cstr: str = _resolve_asm_descr(pool, celt) + if cstr is None or cstr[0] == '\0': + continue + if clobber_count < ASM_MAX_OPERANDS: + cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 + cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr)) + cl_ptr[0] = cstr + clobber_count += 1 + + # ============================================================ + # 3. 解析第二个位置参数作为破坏列表 + # ============================================================ + if cargs.__len__() >= 2: + pos_node: ast.AST | t.CPtr = cargs.get(1) + if pos_node is not None and pos_node.kind() == ast.ASTKind.List: + pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node) + pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts + if pos_elts is not None: + plen: t.CSizeT = pos_elts.__len__() + for pi in range(plen): + pelt: ast.AST | t.CPtr = pos_elts.get(pi) + if pelt is None: + continue + pstr: str = _resolve_asm_descr(pool, pelt) + if pstr is None or pstr[0] == '\0': + continue + if clobber_count < ASM_MAX_OPERANDS: + pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8 + pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr)) + pcl_ptr[0] = pstr + clobber_count += 1 + + # ============================================================ + # 4. 统计输出/输入数量,确定返回类型 + # ============================================================ + output_count: int = 0 + input_count: int = 0 + first_output_idx: int = -1 + for oi2 in range(operand_count): + op2: AsmOperand | t.CPtr = _asm_get_operand(operands, oi2) + if op2.IsOutput != 0: + if first_output_idx < 0: + first_output_idx = oi2 + output_count += 1 + else: + input_count += 1 + + # 确定返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + if output_count > 0 and first_output_idx >= 0: + out_op: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx) + if out_op.Value is not None and out_op.Value.Ty is not None: + # alloca 的类型是指针,Pointee 是目标类型 + if out_op.Value.Ty.Pointee is not None: + ret_ty = out_op.Value.Ty.Pointee + else: + ret_ty = llvmlite.Int32(pool) + + # 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题 + is_void: int = 1 + if output_count > 0: + is_void = 0 + + # ============================================================ + # 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求) + # + # new_order[new_idx] = orig_idx — 新位置对应原索引 + # orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号) + # ============================================================ + new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) + orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1)) + if new_order is None or orig_to_new is None: + return None + + new_idx: int = 0 + # 先放输出 + for oi3 in range(operand_count): + op3: AsmOperand | t.CPtr = _asm_get_operand(operands, oi3) + if op3.IsOutput != 0: + new_order[new_idx] = oi3 + new_idx += 1 + # 再放输入 + for oi4 in range(operand_count): + op4: AsmOperand | t.CPtr = _asm_get_operand(operands, oi4) + if op4.IsOutput == 0: + new_order[new_idx] = oi4 + new_idx += 1 + # 建立映射 orig -> new + for ni2 in range(operand_count): + orig_to_new[new_order[ni2]] = ni2 + + # ============================================================ + # 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符) + # 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用 + # ============================================================ + if tmpl_node is not None: + tk2: int = tmpl_node.kind() + if tk2 == ast.ASTKind.JoinedStr: + js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node) + jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values + if jvalues2 is not None: + jvlen2: t.CSizeT = jvalues2.__len__() + fv_fi: int = 0 + for vi2 in range(jvlen2): + part2: ast.AST | t.CPtr = jvalues2.get(vi2) + if part2 is None: + continue + pk2: int = part2.kind() + if pk2 == ast.ASTKind.Constant: + cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2) + if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None: + _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val) + elif pk2 == ast.ASTKind.FormattedValue: + if fv_fi < fv_count: + orig_idx2: int = fv_orig_indices[fv_fi] + new_idx2: int = orig_to_new[orig_idx2] + ph_buf2: t.CChar | t.CPtr = pool.alloc(16) + if ph_buf2 is not None: + viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2) + _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2) + fv_fi += 1 + elif tk2 == ast.ASTKind.Constant: + cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node) + if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None: + _asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val) + + # ============================================================ + # 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后) + # ============================================================ + const_buf: t.CChar | t.CPtr = pool.alloc(ASM_CONST_BUF_SIZE) + if const_buf is None: + return None + const_buf[0] = '\0' + + first_const: int = 1 + for ci2 in range(operand_count): + orig_i: int = new_order[ci2] + cop: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i) + cons_val: str = cop.Constraint + if cons_val is None: + cons_val = "r" + + if first_const == 0: + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") + first_const = 0 + + if cop.IsOutput != 0: + # 输出约束:确保以 = 开头 + if cons_val[0] != '=': + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=") + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) + else: + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val) + + # 追加 clobber 约束 ~{name} + for cidx in range(clobber_count): + cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8 + cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0] + if cname is None or cname[0] == '\0': + continue + if first_const == 0: + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",") + first_const = 0 + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{") + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname) + _asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}") + + # ============================================================ + # 6. 构建参数列表文本(仅输入操作数) + # ============================================================ + args_buf: t.CChar | t.CPtr = pool.alloc(ASM_ARGS_BUF_SIZE) + if args_buf is None: + return None + args_buf[0] = '\0' + + first_arg: int = 1 + for ai3 in range(operand_count): + orig_i2: int = new_order[ai3] + aop: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i2) + if aop.IsOutput != 0: + continue + aval: llvmlite.Value | t.CPtr = aop.Value + if aval is None or aval.Ty is None or aval.Name is None: + continue + + if first_arg == 0: + _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ") + first_arg = 0 + + # 类型文本 + ty_buf: t.CChar | t.CPtr = pool.alloc(64) + if ty_buf is not None: + ty_buf[0] = '\0' + llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool) + _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf) + _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ") + _asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name) + + # ============================================================ + # 7. 转义汇编文本 + # ============================================================ + escaped_asm: t.CChar | t.CPtr = _asm_escape_for_ir(pool, asm_text) + if escaped_asm is None: + return None + + # ============================================================ + # 8. 生成 IR 行并发射 + # ============================================================ + line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE) + if line is None: + return None + line[0] = '\0' + + ssa_name: t.CChar | t.CPtr = None + if is_void == 0: + ssa_name = pool.alloc(16) + if ssa_name is not None: + viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter) + builder.Counter += 1 + + # 获取返回类型文本 + ret_ty_buf: t.CChar | t.CPtr = pool.alloc(64) + if ret_ty_buf is not None: + ret_ty_buf[0] = '\0' + llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool) + + if is_void == 1: + viperlib.snprintf(line, ASM_LINE_BUF_SIZE, + "call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", + ret_ty_buf, escaped_asm, const_buf, args_buf) + else: + viperlib.snprintf(line, ASM_LINE_BUF_SIZE, + "%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)", + ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf) + + # 发射 IR 到当前块 + llvmlite.block_append_text(pool, builder.CurBlock, line) + + # ============================================================ + # 9. 处理输出:存储结果到输出变量 + # ============================================================ + if is_void == 0 and first_output_idx >= 0: + result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name) + out_op2: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx) + if out_op2.Value is not None: + llvmlite.build_store(builder, result_val, out_op2.Value) + return result_val + + return None + + +# ============================================================ +# c.LLVMIR — 内联 LLVM IR 支持 +# +# 语法: +# c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) +# c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) +# +# c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 值 +# c.LOut(expr) - 输出操作数,翻译后结果存储到该变量 +# +# 支持的指令: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr +# fadd/fsub/fmul/fdiv +# icmp eq/ne/sgt/sge/slt/sle/ugt/uge/ult/ule +# fcmp oeq/one/olt/ogt/ole/oge +# zext/sext/trunc/bitcast/ptrtoint/inttoptr +# load/store +# ============================================================ + +LLVMIR_MAX_OPS: t.CDefine = 16 +LLVMIR_TEMPLATE_BUF: t.CDefine = 512 + + +# ============================================================ +# _llvmir_get_op — 获取第 i 个 AsmOperand 槽位 +# ============================================================ +def _llvmir_get_op(buf: AsmOperand | t.CPtr, i: int) -> AsmOperand | t.CPtr: + """获取第 i 个操作数槽位""" + entry_size: t.CSizeT = AsmOperand.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(buf) + i * entry_size + return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + + +# ============================================================ +# _llvmir_find_op_marker — 在字符串中查找 %__OP 并返回编号 +# +# 返回 (位置, 编号),未找到返回 (None, 0) +# ============================================================ +def _llvmir_find_op_marker(s: t.CChar | t.CPtr) -> t.CPtr: + """查找 %__OP 标记,返回标记开始位置或 None""" + if s is None: + return None + return string.strstr(s, "%__OP") + + +# ============================================================ +# _llvmir_parse_op_num — 从 %__OPN__ 中解析编号 N +# +# 输入: 指向 "%__OP" 的指针 +# 返回: 操作数编号 +# ============================================================ +def _llvmir_parse_op_num(marker: t.CChar | t.CPtr) -> int: + """从 %__OPN__ 标记中解析编号 N""" + if marker is None: + return -1 + # 跳过 "%__OP" (5 字符) + num_start: t.CChar | t.CPtr = marker + 5 + if num_start is None: + return -1 + # 解析数字直到 "__" + num: int = 0 + i: t.CSizeT = 0 + ch: t.CChar = num_start[0] + while '0' <= ch <= '9': + num = num * 10 + (ch - '0') + i += 1 + ch = num_start[i] + return num + + +# ============================================================ +# _llvmir_match_icmp_pred — 将预测字符串转为 ICMP 常量 +# ============================================================ +def _llvmir_match_icmp_pred(pred: str) -> int: + """将 icmp 预测字符串转为常量""" + if pred is None: + return 0 + if string.strcmp(pred, "eq") == 0: + return 0 + if string.strcmp(pred, "ne") == 0: + return 1 + if string.strcmp(pred, "sgt") == 0: + return 2 + if string.strcmp(pred, "sge") == 0: + return 3 + if string.strcmp(pred, "slt") == 0: + return 4 + if string.strcmp(pred, "sle") == 0: + return 5 + if string.strcmp(pred, "ugt") == 0: + return 6 + if string.strcmp(pred, "uge") == 0: + return 7 + if string.strcmp(pred, "ult") == 0: + return 8 + if string.strcmp(pred, "ule") == 0: + return 9 + return 0 + + +# ============================================================ +# _llvmir_match_fcmp_pred — 将预测字符串转为 FCMP 常量 +# ============================================================ +def _llvmir_match_fcmp_pred(pred: str) -> int: + """将 fcmp 预测字符串转为常量""" + if pred is None: + return 0 + if string.strcmp(pred, "oeq") == 0: + return 0 + if string.strcmp(pred, "ogt") == 0: + return 1 + if string.strcmp(pred, "oge") == 0: + return 2 + if string.strcmp(pred, "olt") == 0: + return 3 + if string.strcmp(pred, "ole") == 0: + return 4 + if string.strcmp(pred, "one") == 0: + return 5 + if string.strcmp(pred, "ord") == 0: + return 6 + if string.strcmp(pred, "uno") == 0: + return 7 + if string.strcmp(pred, "ueq") == 0: + return 8 + if string.strcmp(pred, "ugt") == 0: + return 9 + if string.strcmp(pred, "uge") == 0: + return 10 + if string.strcmp(pred, "ult") == 0: + return 11 + if string.strcmp(pred, "ule") == 0: + return 12 + if string.strcmp(pred, "une") == 0: + return 13 + return 0 + + +# ============================================================ +# _llvmir_extract_two_ops — 从模板中提取两个操作数编号 +# +# 通过输出参数返回 op1_num 和 op2_num +# ============================================================ +def _llvmir_extract_two_ops(template: t.CChar | t.CPtr, + out_nums: int | t.CPtr) -> int: + """从模板中提取前两个 %__OP 标记的编号 + + 结果写入 out_nums[0] 和 out_nums[1] + 返回 1 成功, 0 失败 + """ + out_nums[0] = -1 + out_nums[1] = -1 + m1: t.CChar | t.CPtr = _llvmir_find_op_marker(template) + if m1 is None: + return 0 + out_nums[0] = _llvmir_parse_op_num(m1) + + # 跳过第一个标记 "%__OPN__" + next_pos: t.CChar | t.CPtr = m1 + 5 # 跳过 "%__OP" + i: t.CSizeT = 0 + while next_pos[i] >= '0' and next_pos[i] <= '9': + i += 1 + next_pos = next_pos + i + 2 + + m2: t.CChar | t.CPtr = _llvmir_find_op_marker(next_pos) + if m2 is None: + return 1 + out_nums[1] = _llvmir_parse_op_num(m2) + return 1 + + +# ============================================================ +# _llvmir_resolve_op — 根据编号解析操作数值 +# ============================================================ +def _llvmir_resolve_op(op_num: int, + all_kinds: int | t.CPtr, + all_indices: int | t.CPtr, + input_ops: AsmOperand | t.CPtr, + output_targets: AsmOperand | t.CPtr) -> llvmlite.Value | t.CPtr: + """根据操作数编号解析实际 Value""" + if op_num < 0 or op_num >= LLVMIR_MAX_OPS: + return None + kind: int = all_kinds[op_num] + idx: int = all_indices[op_num] + if kind == 0: + # 输入操作数 + op: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, idx) + return op.Value + else: + # 输出操作数 + op2: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, idx) + return op2.Value + + +# ============================================================ +# _llvmir_store_outputs — 将结果存储到输出变量 +# ============================================================ +def _llvmir_store_outputs(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + result: llvmlite.Value | t.CPtr, + output_targets: AsmOperand | t.CPtr, + output_count: int) -> llvmlite.Value | t.CPtr: + """将结果存储到所有输出变量""" + if output_count == 0: + return result + for oi in range(output_count): + op: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, oi) + if op.Value is not None and result is not None: + llvmlite.build_store(builder, result, op.Value) + return result + + +# ============================================================ +# translate_c_llvmir — 翻译 c.LLVMIR 内联 LLVM IR +# ============================================================ +def translate_c_llvmir(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译 c.LLVMIR 内联 LLVM IR,返回结果 Value""" + if cl is None: + return None + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None or cargs.__len__() < 1: + return None + + # 分配操作数数组 + op_size: t.CSizeT = AsmOperand.__sizeof__() + input_ops: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) + output_targets: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) + if input_ops is None or output_targets is None: + return None + string.memset(input_ops, 0, op_size * LLVMIR_MAX_OPS) + string.memset(output_targets, 0, op_size * LLVMIR_MAX_OPS) + + # all_ops 映射: kinds[i]=0(inp)/1(out), indices[i]=在对应数组中的索引 + all_kinds: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) + all_indices: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) + if all_kinds is None or all_indices is None: + return None + string.memset(all_kinds, 0, 4 * LLVMIR_MAX_OPS) + string.memset(all_indices, 0, 4 * LLVMIR_MAX_OPS) + + input_count: int = 0 + output_count: int = 0 + op_seq: int = 0 + + # 分配模板缓冲区 + template: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) + if template is None: + return None + template[0] = '\0' + + # 解析返回类型(默认 i32) + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if cargs.__len__() >= 2: + ret_type_node: ast.AST | t.CPtr = cargs.get(1) + if ret_type_node is not None: + resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, ret_type_node, trans._imported_modules, trans._from_imports) + if resolved_ty is not None: + ret_ty = resolved_ty + + # ============================================================ + # 1. 解析 IR 模板(JoinedStr 或 Constant)— 收集操作数 + # ============================================================ + first_arg: ast.AST | t.CPtr = cargs.get(0) + if first_arg is None: + return None + + tk: int = first_arg.kind() + + if tk == ast.ASTKind.JoinedStr: + js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg) + jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values + if jvalues is not None: + jvlen: t.CSizeT = jvalues.__len__() + for vi in range(jvlen): + part: ast.AST | t.CPtr = jvalues.get(vi) + if part is None: + continue + pk: int = part.kind() + + if pk == ast.ASTKind.Constant: + # 字符串字面量片段 + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) + if cn.str_val is not None: + _asm_append_cstr(template, LLVMIR_TEMPLATE_BUF, cn.str_val) + + elif pk == ast.ASTKind.FormattedValue: + fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) + fexpr: ast.AST | t.CPtr = fv.value + if fexpr is None or fexpr.kind() != ast.ASTKind.Call: + continue + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = _asm_is_c_call(fcall) + if attr_nm is None: + # 非 c.LInp/c.LOut 调用,作为普通输入处理 + ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fexpr, None, 0, trans) + if ival is not None and input_count < LLVMIR_MAX_OPS: + op_in: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) + op_in.Value = ival + all_kinds[op_seq] = 0 + all_indices[op_seq] = input_count + input_count += 1 + op_seq += 1 + # 追加占位符 + viperlib.snprintf( + template + string.strlen(template), + LLVMIR_TEMPLATE_BUF - string.strlen(template), + "%%__OP%d__", op_seq - 1) + continue + + # 处理 c.LInp / c.LOut + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or fargs.__len__() < 1: + continue + val_node: ast.AST | t.CPtr = fargs.get(0) + + if string.strcmp(attr_nm, "LInp") == 0: + # 输入操作数:翻译值 + inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if inp_val is not None and input_count < LLVMIR_MAX_OPS: + op_inp: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) + op_inp.Value = inp_val + all_kinds[op_seq] = 0 + all_indices[op_seq] = input_count + input_count += 1 + op_seq += 1 + viperlib.snprintf( + template + string.strlen(template), + LLVMIR_TEMPLATE_BUF - string.strlen(template), + "%%__OP%d__", op_seq - 1) + + elif string.strcmp(attr_nm, "LOut") == 0: + # 输出操作数:获取变量 alloca + if val_node is not None and val_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is not None and output_count < LLVMIR_MAX_OPS: + op_out: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, output_count) + op_out.Value = alloca + all_kinds[op_seq] = 1 + all_indices[op_seq] = output_count + output_count += 1 + op_seq += 1 + viperlib.snprintf( + template + string.strlen(template), + LLVMIR_TEMPLATE_BUF - string.strlen(template), + "%%__OP%d__", op_seq - 1) + + elif tk == ast.ASTKind.Constant: + cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) + if cn2.str_val is not None: + string.strcpy(template, cn2.str_val) + + # ============================================================ + # 2. 解析模板并生成 LLVM 指令 + # ============================================================ + + # 检查是否为赋值形式: %__OPN__ = <指令> + # 如果是,去掉赋值前缀,记录输出操作数编号 + assign_out_num: int = -1 + assign_marker: t.CChar | t.CPtr = _llvmir_find_op_marker(template) + if assign_marker is not None and assign_marker == template: + # 模板以 %__OP 开头 + # 查找 "=" 号 + eq_pos: t.CChar | t.CPtr = string.strchr(template, 61) # '=' = 61 + if eq_pos is not None: + # 确认 "%__OPN__ = " 格式 + assign_out_num = _llvmir_parse_op_num(assign_marker) + # 跳过 "%__OP__ = " 到实际指令开始 + # 找到 "=" 后第一个非空格字符 + instr_start: t.CChar | t.CPtr = eq_pos + 1 + while instr_start[0] == ' ' or instr_start[0] == '\t': + instr_start += 1 + # 将剩余部分复制到新模板 + tmpl2: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) + if tmpl2 is not None: + string.strcpy(tmpl2, instr_start) + template = tmpl2 + + # 去除前导空格 + while template[0] == ' ' or template[0] == '\t': + template += 1 + + # 提取指令关键字(第一个单词) + instr_kw: t.CChar | t.CPtr = pool.alloc(32) + if instr_kw is None: + return None + instr_kw[0] = '\0' + ki: t.CSizeT = 0 + while template[ki] != ' ' and template[ki] != '\t' and template[ki] != '\0' and ki < 31: + instr_kw[ki] = template[ki] + ki += 1 + instr_kw[ki] = '\0' + + # ============================================================ + # 二元运算: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr + # ============================================================ + binop_result: llvmlite.Value | t.CPtr = None + + # 提取两个操作数编号 + op_nums: int | t.CPtr = pool.alloc(8) + if op_nums is not None: + string.memset(op_nums, 0, 8) + _llvmir_extract_two_ops(template, op_nums) + op1_num: int = -1 + op2_num: int = -1 + if op_nums is not None: + op1_num = op_nums[0] + op2_num = op_nums[1] + + lhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( + op1_num, all_kinds, all_indices, input_ops, output_targets) + rhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( + op2_num, all_kinds, all_indices, input_ops, output_targets) + + if lhs is not None and rhs is not None: + if string.strcmp(instr_kw, "add") == 0: + binop_result = llvmlite.build_add(builder, lhs, rhs) + elif string.strcmp(instr_kw, "sub") == 0: + binop_result = llvmlite.build_sub(builder, lhs, rhs) + elif string.strcmp(instr_kw, "mul") == 0: + binop_result = llvmlite.build_mul(builder, lhs, rhs) + elif string.strcmp(instr_kw, "sdiv") == 0: + binop_result = llvmlite.build_sdiv(builder, lhs, rhs) + elif string.strcmp(instr_kw, "udiv") == 0: + binop_result = llvmlite.build_udiv(builder, lhs, rhs) + elif string.strcmp(instr_kw, "srem") == 0: + binop_result = llvmlite.build_srem(builder, lhs, rhs) + elif string.strcmp(instr_kw, "urem") == 0: + binop_result = llvmlite.build_urem(builder, lhs, rhs) + elif string.strcmp(instr_kw, "and") == 0: + binop_result = llvmlite.build_and(builder, lhs, rhs) + elif string.strcmp(instr_kw, "or") == 0: + binop_result = llvmlite.build_or(builder, lhs, rhs) + elif string.strcmp(instr_kw, "xor") == 0: + binop_result = llvmlite.build_xor(builder, lhs, rhs) + elif string.strcmp(instr_kw, "shl") == 0: + binop_result = llvmlite.build_shl(builder, lhs, rhs) + elif string.strcmp(instr_kw, "lshr") == 0: + binop_result = llvmlite.build_lshr(builder, lhs, rhs) + elif string.strcmp(instr_kw, "ashr") == 0: + binop_result = llvmlite.build_ashr(builder, lhs, rhs) + elif string.strcmp(instr_kw, "fadd") == 0: + binop_result = llvmlite.build_fadd(builder, lhs, rhs) + elif string.strcmp(instr_kw, "fsub") == 0: + binop_result = llvmlite.build_fsub(builder, lhs, rhs) + elif string.strcmp(instr_kw, "fmul") == 0: + binop_result = llvmlite.build_fmul(builder, lhs, rhs) + elif string.strcmp(instr_kw, "fdiv") == 0: + binop_result = llvmlite.build_fdiv(builder, lhs, rhs) + + # ============================================================ + # icmp 比较: icmp %__OP0__, %__OP1__ + # ============================================================ + if binop_result is None and string.strcmp(instr_kw, "icmp") == 0: + # 提取预测(第二个单词) + pred_start: t.CChar | t.CPtr = template + ki + 1 + while pred_start[0] == ' ' or pred_start[0] == '\t': + pred_start += 1 + pred_str: t.CChar | t.CPtr = pool.alloc(16) + if pred_str is not None: + pred_str[0] = '\0' + pi: t.CSizeT = 0 + while pred_start[pi] != ' ' and pred_start[pi] != '\t' and pred_start[pi] != '\0' and pi < 15: + pred_str[pi] = pred_start[pi] + pi += 1 + pred_str[pi] = '\0' + pred_val: int = _llvmir_match_icmp_pred(pred_str) + if lhs is not None and rhs is not None: + binop_result = llvmlite.build_icmp(builder, pred_val, lhs, rhs) + + # ============================================================ + # fcmp 比较: fcmp %__OP0__, %__OP1__ + # ============================================================ + if binop_result is None and string.strcmp(instr_kw, "fcmp") == 0: + pred_start2: t.CChar | t.CPtr = template + ki + 1 + while pred_start2[0] == ' ' or pred_start2[0] == '\t': + pred_start2 += 1 + pred_str2: t.CChar | t.CPtr = pool.alloc(16) + if pred_str2 is not None: + pred_str2[0] = '\0' + pi2: t.CSizeT = 0 + while pred_start2[pi2] != ' ' and pred_start2[pi2] != '\t' and pred_start2[pi2] != '\0' and pi2 < 15: + pred_str2[pi2] = pred_start2[pi2] + pi2 += 1 + pred_str2[pi2] = '\0' + pred_val2: int = _llvmir_match_fcmp_pred(pred_str2) + if lhs is not None and rhs is not None: + binop_result = llvmlite.build_fcmp(builder, pred_val2, lhs, rhs) + + # ============================================================ + # store 指令: store %__OP0__, %__OP1__ + # ============================================================ + if binop_result is None and string.strcmp(instr_kw, "store") == 0: + if lhs is not None and rhs is not None: + llvmlite.build_store(builder, lhs, rhs) + return None + + # ============================================================ + # load 指令: load , %__OP0__ + # ============================================================ + if binop_result is None and string.strcmp(instr_kw, "load") == 0: + if lhs is not None: + # 从指针加载,类型由 ret_ty 指定 + binop_result = llvmlite.build_load(builder, ret_ty, lhs) + + # ============================================================ + # 类型转换: zext/sext/trunc/bitcast/ptrtoint/inttoptr + # ============================================================ + if binop_result is None: + if string.strcmp(instr_kw, "zext") == 0: + if lhs is not None: + binop_result = llvmlite.build_zext(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "sext") == 0: + if lhs is not None: + binop_result = llvmlite.build_sext(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "trunc") == 0: + if lhs is not None: + binop_result = llvmlite.build_trunc(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "bitcast") == 0: + if lhs is not None: + binop_result = llvmlite.build_bitcast(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "ptrtoint") == 0: + if lhs is not None: + binop_result = llvmlite.build_ptrtoint(builder, lhs, ret_ty) + elif string.strcmp(instr_kw, "inttoptr") == 0: + if lhs is not None: + binop_result = llvmlite.build_inttoptr(builder, lhs, ret_ty) + + # ============================================================ + # 3. 处理输出 + # ============================================================ + if binop_result is not None: + # 如果有赋值形式(%__OPN__ = ...),存储到对应输出 + if assign_out_num >= 0: + target: llvmlite.Value | t.CPtr = _llvmir_resolve_op( + assign_out_num, all_kinds, all_indices, input_ops, output_targets) + if target is not None: + llvmlite.build_store(builder, binop_result, target) + + # 存储到所有输出操作数 + _llvmir_store_outputs(pool, builder, binop_result, output_targets, output_count) + return binop_result + + # 未识别的指令,返回 0 + stdio.printf("[LLVMIR] unsupported instruction: %s\n", instr_kw) + return None + + +# ============================================================ +# _apply_struct_defaults — 应用结构体字段的默认值 +# +# 在 zeroinitializer 之后、显式参数之前调用 +# 遍历所有字段,对有默认值的字段翻译并 store +# 显式参数(位置/关键字)后续会覆盖默认值 +# ============================================================ +def _apply_struct_defaults(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + tmp: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr): + """应用结构体字段的默认值""" + # 用类型指针定位 entry,规避跨模块同名 find_struct 找错 + entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + if entry is None: + return + for fi in range(entry.FieldCount): + fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + entry, fi) + if fe is None or fe.DefaultVal is None: + continue + default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fe.DefaultVal, None, 0, trans) + if default_val is None: + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty) + llvmlite.build_store(builder, default_val, field_ptr) + + +# ============================================================ +# _translate_struct_ctor — 结构体构造函数 Point(10, 20) +# +# 生成: +# %tmp = alloca {i32, i32} +# store {i32, i32} zeroinitializer, {i32, i32}* %tmp +# %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 +# store i32 10, i32* %f0 +# %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 +# store i32 20, i32* %f1 +# %result = load {i32, i32}, {i32, i32}* %tmp +# ============================================================ +def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """结构体构造函数:按字段顺序 store 参数值,返回结构体值 + + OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load + 普通结构体:alloca → zero + defaults → store 参数 → load + """ + # 创建临时 alloca + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return llvmlite.ConstZero(pool, struct_ty) + + # 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错) + ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + is_oop: int = 0 + if ctor_entry is not None: + is_oop = ctor_entry.IsOOP + + if is_oop != 0: + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + storage_ptr: llvmlite.Value | t.CPtr = tmp + + # 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针 + # __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty) + has_new_flag: int = 0 + if ctor_entry is not None: + has_new_flag = ctor_entry.HasNew + if has_new_flag != 0: + new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_arg_vals is not None: + string.memset(new_arg_vals, 0, 8 * 32) + new_arg_count: int = 0 + for nai in range(can): + new_arg_node: ast.AST | t.CPtr = cargs.get(nai) + if new_arg_node is None: + continue + new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, new_arg_node, None, 0, trans) + if new_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(new_av) + new_arg_count += 1 + + new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr( + pool, builder, mod, class_name, + "__new__", tmp, new_arg_vals, new_arg_count, trans) + if new_ptr is not None: + storage_ptr = new_ptr + + # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 + _call_method_on_ptr(pool, builder, mod, class_name, + "__before_init__", storage_ptr, None, 0, trans) + + # 如果有 __init__,调用 __init__(ptr, args...) + has_init_flag: int = 0 + if ctor_entry is not None: + has_init_flag = ctor_entry.HasInit + if has_init_flag != 0: + # 翻译构造函数参数 + arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if arg_vals is not None: + string.memset(arg_vals, 0, 8 * 32) + real_arg_count: int = 0 + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if av is not None: + if real_arg_count < 32: + arg_vals[real_arg_count] = t.CSizeT(av) + real_arg_count += 1 + + _call_method_on_ptr(pool, builder, mod, class_name, + "__init__", storage_ptr, arg_vals, real_arg_count, trans) + else: + # 无 __init__:逐字段 store 参数值 + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + fe: HandlesStruct.FieldEntry | t.CPtr = None + if ctor_entry is not None: + fe = HandlesStruct._get_field_entry(ctor_entry, ai) + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, storage_ptr, fe.Index) + if field_ptr is None: + continue + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return storage_ptr + + # 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零) + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + llvmlite.build_store(builder, zero, tmp) + + # 应用默认值(显式参数会覆盖默认值) + _apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) + + # 逐字段 store 参数值(覆盖默认值) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + # 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错) + fe: HandlesStruct.FieldEntry | t.CPtr = None + if ctor_entry is not None: + fe = HandlesStruct._get_field_entry(ctor_entry, ai) + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + continue + # GEP 到字段 ai + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + # 类型转换并 store + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return tmp + + +# ============================================================ +# _do_virtual_call — 通过虚表间接调用虚方法 +# +# IR 模式: +# %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8** +# %2 = load i8*, i8** %1 ; i8* (vtable ptr) +# %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr +# %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8** +# %5 = load i8*, i8** %4 ; i8* (func ptr) +# %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr +# call RetTy %6(Params %self, ...) +# +# 参数: +# args_head — 已构建好的参数链表头(self_ptr 为首节点) +# args_count — 参数总数(含 self) +# found_func — 方法对应的 Function 对象(用于推断函数签名) +# ret_ty — 返回类型 +# ============================================================ +def _do_virtual_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + self_ptr: llvmlite.Value | t.CPtr, + args_head: llvmlite.Value | t.CPtr, + args_count: int, + found_func: llvmlite.Function | t.CPtr, + ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """通过虚表间接调用虚方法,返回 call 结果(void 方法返回 None)""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + if self_ptr is None or args_head is None: + return None + + # 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + vc_entry: HandlesStruct.StructEntry | t.CPtr = None + struct_ty: llvmlite.LLVMType | t.CPtr = None + if self_ptr.Ty is not None: + vc_entry = HandlesStruct.get_struct_type_from_value(self_ptr) + if vc_entry is not None: + # vc_entry 是 struct_ty(LLVMType),需要找 StructEntry + vc_entry = HandlesStruct.find_struct_by_type(vc_entry) + if vc_entry is not None: + struct_ty = vc_entry.Ty + if struct_ty is None: + struct_ty = HandlesStruct.get_struct_type(class_name) + if struct_ty is None: + return None + + # 2. 获取方法在虚表中的索引(用 entry 直接查找) + method_index: int = -1 + if vc_entry is not None and vc_entry.VTableMethods is not None: + methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(vc_entry.VTableMethods, t.CPtr)) + for mi in range(vc_entry.VTableMethodCount): + mname_addr: t.CSizeT = methods_arr[mi] + if mname_addr == 0: + continue + mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) + if mname is not None and string.strcmp(mname, method_name) == 0: + method_index = mi + break + else: + method_index = HandlesStruct.get_vtable_method_index(class_name, method_name) + if method_index < 0: + return None + + # 3. 基础类型 + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + + # 4. bitcast 到 i8** 访问 __vtable__ 字段(索引 0) + # vtable 指针总是在对象第一个字段,无需 GEP,直接 bitcast 到 i8** 即可。 + # 这样即使 struct_ty 是 opaque(跨模块未加载完整定义)也能正常工作。 + vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, self_ptr, i8_ptr_ptr_ty) + if vtable_slot is None: + return None + + # 5. load vtable 指针 (i8*) + vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot) + if vtable_ptr is None: + return None + + # 6. 构造 vtable 类型 {i8*, i8*, ...} + method_count: int = 0 + if vc_entry is not None: + method_count = vc_entry.VTableMethodCount + else: + method_count = HandlesStruct.get_vtable_method_count(class_name) + if method_count <= 0: + return None + + vt_first: llvmlite.ParamNode | t.CPtr = None + vt_prev: llvmlite.ParamNode | t.CPtr = None + for vi in range(method_count): + pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + if pn is None: + continue + if vt_first is None: + vt_first = pn + if vt_prev is not None: + llvmlite.paramnode_set_next(vt_prev, pn) + vt_prev = pn + + vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None) + if vtable_ty is None: + return None + vtable_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vtable_ty) + + # 7. bitcast i8* 到 vtable 类型指针 + vtable_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, vtable_ptr, vtable_ptr_ty) + if vtable_typed is None: + return None + + # 8. GEP 到方法槽位 + func_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, vtable_ty, i8_ptr_ty, vtable_typed, method_index) + if func_slot is None: + return None + + # 9. load 函数指针 (i8*) + func_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, func_slot) + if func_i8 is None: + return None + + # 10. 从 args_head 构造函数类型 RetTy(Param1, Param2, ...) + # 直接遍历 Value 链表提取参数类型,避免跨模块访问 found_func(stub 字段偏移问题) + fp_first: llvmlite.ParamNode | t.CPtr = None + fp_prev: llvmlite.ParamNode | t.CPtr = None + fp_count: int = 0 + cur_val: llvmlite.Value | t.CPtr = args_head + for vi in range(args_count): + if cur_val is None: + break + cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_val) + fpn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty) + if fpn is not None: + if fp_first is None: + fp_first = fpn + if fp_prev is not None: + llvmlite.paramnode_set_next(fp_prev, fpn) + fp_prev = fpn + cur_val = llvmlite.value_get_next(cur_val) + fp_count += 1 + + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, fp_count) + if func_ty is None: + return None + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + + # 11. bitcast i8* 到函数指针类型 + func_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, func_i8, func_ptr_ty) + if func_ptr is None: + return None + + # 12. 间接调用 + return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty) + + +# ============================================================ +# _call_method_on_ptr — 在结构体指针上调用方法 +# +# 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数 +# 如果该方法在虚表中,则走虚方法分发路径(间接调用) +# ============================================================ +def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + self_ptr: llvmlite.Value | t.CPtr, + extra_args: t.CSizeT | t.CPtr, + extra_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """在结构体指针上调用方法,返回 call 结果(void 方法返回 None)""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + if self_ptr is None: + return None + + # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + # 用于 SHA1 查找和虚表分派 + cmop_entry: HandlesStruct.StructEntry | t.CPtr = None + cmop_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(self_ptr) + if cmop_struct_ty is not None: + cmop_entry = HandlesStruct.find_struct_by_type(cmop_struct_ty) + if cmop_entry is None: + cmop_entry = HandlesStruct.find_struct(class_name) + + # 构造方法查找名: ClassName.method_name + lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) + + # 查找函数(支持 SHA1 后缀匹配) + found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) + + # 确定调用名 + call_name: str = lookup_name + if found_func is not None: + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 + # 优先从 entry 获取 SHA1(规避跨模块同名 find_struct 找错) + cls_sha1: str = None + if cmop_entry is not None: + cls_sha1 = cmop_entry.ModuleSha1 + else: + cls_sha1 = HandlesStruct.get_struct_sha1(class_name) + if cls_sha1 is None and trans is not None: + # fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理) + cls_sha1 = _lookup_mod_sha1(pool, trans._from_imports, class_name) + if cls_sha1 is None: + err_msg: t.CChar | t.CPtr = pool.alloc(256) + if err_msg is not None: + viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name) + HandlesType.fatal_error(None, err_msg) + HandlesType.fatal_error(None, "找不到模块 SHA1") + mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2 + mangled2: str = pool.alloc(mangled_len2) + if mangled2 is not None: + viperlib.snprintf(mangled2, mangled_len2, "%s.%s", cls_sha1, lookup_name) + call_name = mangled2 + + # 确定返回类型(__before_init__ 和 __init__ 返回 void) + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + call_ret_ty: llvmlite.LLVMType | t.CPtr = void_ty + if found_func is not None: + frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt is not None: + call_ret_ty = frt + + # 构建参数链表: self_ptr → extra_args... + llvmlite.value_set_next(self_ptr, None) + head: llvmlite.Value | t.CPtr = self_ptr + tail: llvmlite.Value | t.CPtr = self_ptr + + if extra_args is not None and extra_count > 0: + for ei in range(extra_count): + arg_addr: t.CSizeT = extra_args[ei] + if arg_addr == 0: + continue + av: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(arg_addr, t.CPtr)) + if av is not None: + llvmlite.value_set_next(av, None) + llvmlite.value_set_next(tail, av) + tail = av + + total_count: int = 1 + extra_count + + # 默认参数填入:如果调用点参数少于函数定义参数,用零值填充缺失参数 + # 这处理 list[int](bd) 中 elem_size=0 默认值缺失的情况 + if found_func is not None: + param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + skip_idx: int = 0 + # 跳过已提供的参数 + while skip_idx < total_count and param_node is not None: + param_node = llvmlite.param_get_next(param_node) + skip_idx += 1 + # 为剩余参数填入零值 + while param_node is not None: + missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node) + zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty) + if zero_val is not None: + llvmlite.value_set_next(zero_val, None) + llvmlite.value_set_next(tail, zero_val) + tail = zero_val + total_count += 1 + param_node = llvmlite.param_get_next(param_node) + + # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 + # 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错) + if found_func is not None: + cmop_has_vt: int = 0 + cmop_method_idx: int = -1 + if cmop_entry is not None: + cmop_has_vt = cmop_entry.HasVTable + if cmop_has_vt == 1 and cmop_entry.VTableMethods is not None: + cmop_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(cmop_entry.VTableMethods, t.CPtr)) + for cmop_mi in range(cmop_entry.VTableMethodCount): + cmop_mname_addr: t.CSizeT = cmop_methods_arr[cmop_mi] + if cmop_mname_addr == 0: + continue + cmop_mname: str = (str | t.CPtr)(t.CVoid(cmop_mname_addr, t.CPtr)) + if cmop_mname is not None and string.strcmp(cmop_mname, method_name) == 0: + cmop_method_idx = cmop_mi + break + if cmop_has_vt == 1 and cmop_method_idx >= 0: + return _do_virtual_call(pool, builder, mod, class_name, method_name, + self_ptr, head, total_count, found_func, call_ret_ty) + + return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) + + +# ============================================================ +# _infer_method_ret_ty - 根据方法名推断返回类型 +# +# stub 未注入时,find_func_in_module 返回 None, +# 需要根据方法名推断返回类型避免指针被截断为 i32。 +# ============================================================ +def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr, + method_name: str) -> llvmlite.LLVMType | t.CPtr: + """根据方法名推断返回类型(stub 未注入时的回退方案)""" + if pool is None or method_name is None: + return llvmlite.Int32(pool) + + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i8* 的方法(分配/返回指针) + if string.strcmp(method_name, "alloc") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "calloc") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "realloc") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "alloc_buf") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "_fl_pop") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "_buddy_of") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "_split_to_order") == 0: + return i8_ptr_ty + if string.strcmp(method_name, "__enter__") == 0: + return i8_ptr_ty + + # 返回 void 的方法 + if string.strcmp(method_name, "__before_init__") == 0: + return llvmlite.Void(pool) + + # 默认 i32(free, reset, __init__, __exit__, _fl_push 等) + return llvmlite.Int32(pool) + + +# ============================================================ +# _translate_method_call - 翻译方法调用 obj.method(args) +# +# 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) +# +# obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 +# ============================================================ +def _translate_method_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + obj_ptr: llvmlite.Value | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译方法调用,返回 call 结果 Value""" + if pool is None or builder is None or class_name is None or method_name is None: + return None + if obj_ptr is None or cl is None: + return None + + # 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错) + # 用于继承链遍历、SHA1 查找和虚表分派 + mc_entry: HandlesStruct.StructEntry | t.CPtr = None + mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr) + if mc_struct_ty is not None: + mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty) + if mc_entry is None: + mc_entry = HandlesStruct.find_struct(class_name) + + # 构造方法查找名: ClassName.method_name + lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name) + + # 查找函数(支持 SHA1 后缀匹配) + found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name) + + # 沿继承链查找父类方法(子类未覆盖时回退到父类) + if found_func is None: + cur_parent: str = None + if mc_entry is not None: + cur_parent = mc_entry.ParentName + else: + cur_parent = HandlesStruct.get_parent_name(class_name) + while cur_parent is not None: + parent_lookup: t.CChar | t.CPtr = pool.alloc(128) + if parent_lookup is not None: + viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, method_name) + parent_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, parent_lookup) + if parent_func is not None: + found_func = parent_func + break + # 后续父类按名查找(无 ParentSha1,只能按名回退) + cur_parent = HandlesStruct.get_parent_name(cur_parent) + + # 确定调用名 + call_name: str = lookup_name + if found_func is not None: + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名 + # 沿继承链查找第一个有 SHA1 的类 + cls_sha1_mc: str = None + if mc_entry is not None: + cls_sha1_mc = mc_entry.ModuleSha1 + else: + cls_sha1_mc = HandlesStruct.get_struct_sha1(class_name) + if cls_sha1_mc is None: + cur_p: str = None + if mc_entry is not None: + cur_p = mc_entry.ParentName + else: + cur_p = HandlesStruct.get_parent_name(class_name) + while cur_p is not None and cls_sha1_mc is None: + cls_sha1_mc = HandlesStruct.get_struct_sha1(cur_p) + cur_p = HandlesStruct.get_parent_name(cur_p) + if cls_sha1_mc is not None: + mangled_len_mc: t.CSizeT = string.strlen(cls_sha1_mc) + string.strlen(lookup_name) + 2 + mangled_mc: str = pool.alloc(mangled_len_mc) + if mangled_mc is not None: + viperlib.snprintf(mangled_mc, mangled_len_mc, "%s.%s", cls_sha1_mc, lookup_name) + call_name = mangled_mc + + # 确定返回类型 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if found_func is not None: + frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if frt is not None: + call_ret_ty = frt + else: + # found_func 为 None(stub 未注入):根据方法名推断返回类型 + call_ret_ty = _infer_method_ret_ty(pool, method_name) + + # 翻译调用参数 + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = cargs.__len__() + + # 构建参数链表: obj_ptr → arg1 → arg2 → ... + llvmlite.value_set_next(obj_ptr, None) + head: llvmlite.Value | t.CPtr = obj_ptr + tail: llvmlite.Value | t.CPtr = obj_ptr + + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is None: + continue + llvmlite.value_set_next(arg_val, None) + llvmlite.value_set_next(tail, arg_val) + tail = arg_val + + total_count: int = 1 + can + + # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 + # (不依赖 found_func — 继承的虚方法可能没有子类实现) + # 复用前面已获取的 mc_entry(find_struct_by_type 规避跨模块同名找错) + mc_has_vt: int = 0 + mc_method_idx: int = -1 + if mc_entry is not None: + mc_has_vt = mc_entry.HasVTable + if mc_has_vt == 1 and mc_entry.VTableMethods is not None: + mc_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(mc_entry.VTableMethods, t.CPtr)) + for mc_mi in range(mc_entry.VTableMethodCount): + mc_mname_addr: t.CSizeT = mc_methods_arr[mc_mi] + if mc_mname_addr == 0: + continue + mc_mname: str = (str | t.CPtr)(t.CVoid(mc_mname_addr, t.CPtr)) + if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0: + mc_method_idx = mc_mi + break + if mc_has_vt == 1 and mc_method_idx >= 0: + return _do_virtual_call(pool, builder, mod, class_name, method_name, + obj_ptr, head, total_count, found_func, call_ret_ty) + + return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) + + +# ============================================================ +# _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名 +# +# 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a") +# 跳过 % 前缀后逐字符比较 +# ============================================================ +def _kwarg_name_matches(kw_arg: str, + param_name: t.CChar | t.CPtr) -> int: + """检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)""" + if kw_arg is None or param_name is None: + return 0 + start: t.CSizeT = 0 + if param_name[0] == '%': + start = 1 + for i, ch in enumerate(kw_arg): + c: t.CChar = param_name[start + i] + if c == '\0' or c != ch: + return 0 + if param_name[start + i + 1] != '\0': + return 0 + return 1 + + +# ============================================================ +# _translate_struct_ctor_kw — 结构体构造函数(关键字参数) +# +# 支持两种语法: +# Point(x=10, y=20) — 全关键字 +# Point(10, y=20) — 混合(位置 + 关键字) +# +# 位置参数按字段索引赋值,关键字参数按字段名查找赋值 +# ============================================================ +def _translate_struct_ctor_kw(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + keywords: list[ast.AST | t.CPtr] | t.CPtr, + kw_count: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """结构体构造函数(关键字参数版本)""" + # 创建临时 alloca + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return llvmlite.ConstZero(pool, struct_ty) + + # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 + # 用 find_struct_by_type 规避跨模块同名 find_struct 找错 + kw_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + is_oop: int = 0 + if kw_entry is not None: + is_oop = kw_entry.IsOOP + if is_oop != 0: + _call_method_on_ptr(pool, builder, mod, class_name, + "__before_init__", tmp, None, 0, trans) + else: + # 普通结构体:store zeroinitializer + 应用默认值 + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + llvmlite.build_store(builder, zero, tmp) + _apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) + + # 先处理位置参数(按字段索引,覆盖默认值) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + fe: HandlesStruct.FieldEntry | t.CPtr = None + if kw_entry is not None: + fe = HandlesStruct._get_field_entry(kw_entry, ai) + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 处理关键字参数(按字段名查找) + # SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错) + kw_sha1: str = None + if kw_entry is not None: + kw_sha1 = kw_entry.ModuleSha1 + for ki in range(kw_count): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( + class_name, kw.arg, kw_sha1) + if fe is None: + continue + kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, kw.value, None, 0, trans) + if kw_val is None: + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + kw_val = HandlesExpr.coerce_to_type(builder, kw_val, fe.Ty) + llvmlite.build_store(builder, kw_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return tmp + + +# ============================================================ +# _translate_call_with_kwargs — 带关键字参数的函数调用 +# +# 支持两种语法: +# add(b=4, a=3) — 全关键字乱序 +# greet("Hello", name="World") — 位置 + 关键字混合 +# +# 策略: 遍历 found_func.Params 链表,对每个参数: +# 1. 若位置参数仍有剩余(param_idx < can),取位置参数 +# 2. 否则按参数名匹配关键字参数 +# 3. 按参数顺序构建调用参数链表 +# ============================================================ +def _translate_call_with_kwargs(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + func_name: str, + found_func: llvmlite.Function | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + keywords: list[ast.AST | t.CPtr] | t.CPtr, + kw_count: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """带关键字参数的函数调用,按参数顺序构建调用链表 + + 使用 llvmlite 访问器函数绕过 stub 类型限制: + found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub + 类型中字段不足,直接访问会被 TransPyC 静默跳过。 + """ + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + actual_count: t.CSizeT = 0 + # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) + mc_dst1: llvmlite.Value | t.CPtr = None + mc_src1: llvmlite.Value | t.CPtr = None + mc_num1: llvmlite.Value | t.CPtr = None + + # 遍历函数参数链表(使用访问器获取 Head) + param_idx: t.CSizeT = 0 + cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + + while cur_param is not None: + arg_val: llvmlite.Value | t.CPtr = None + if param_idx < can: + # 优先使用位置参数 + arg: ast.AST | t.CPtr = cargs.get(param_idx) + if arg is not None: + arg_val = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + else: + # 查找匹配的关键字参数 + param_name: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param) + if param_name is not None: + for ki in range(kw_count): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + if _kwarg_name_matches(kw.arg, param_name) == 1: + arg_val = HandlesExpr.translate_value( + builder, pool, mod, kw.value, None, 0, trans) + break + + if arg_val is not None: + # 类型转换(按参数类型,使用访问器) + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param) + if param_ty is not None: + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, param_ty) + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + # memcpy 专用: 保存前三个参数的独立引用 + if actual_count == 0: + mc_dst1 = arg_val + elif actual_count == 1: + mc_src1 = arg_val + elif actual_count == 2: + mc_num1 = arg_val + actual_count += 1 + + param_idx += 1 + cur_param = llvmlite.param_get_next(cur_param) + + # 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器) + # t.CExtern/t.State/t.CExport 函数(declare)使用裸名,不加 SHA1 前缀 + call_name: str = func_name + if llvmlite.function_is_declared(found_func) == 0: + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + + # 返回类型(使用访问器) + call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if call_ret_ty is None: + call_ret_ty = _infer_external_func_ret_ty(pool, func_name) + + # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) + if func_name == "memcpy" and actual_count >= 3: + return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1) + return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0) + + +# ============================================================ +# _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 +# +# 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, +# 将 value 转换为目标类型: +# - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) +# - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) +# - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) +# - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) +# ============================================================ +def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """类型转换:根据参数类型和目标类型选择转换方式""" + if val is None or target_ty is None: + return None + + val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) + target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty) + + # 整数 → 整数: trunc/zext + if val_bits != 0 and target_bits != 0: + if val_bits == target_bits: + return val + elif val_bits < target_bits: + return llvmlite.build_zext(builder, val, target_ty) + else: + return llvmlite.build_trunc(builder, val, target_ty) + + # 指针 → 整数: ptrtoint + if val_bits == 0 and target_bits != 0: + return llvmlite.build_ptrtoint(builder, val, target_ty) + + # 整数 → 指针: inttoptr + if val_bits != 0 and target_bits == 0: + return llvmlite.build_inttoptr(builder, val, target_ty) + + # 指针 → 指针: bitcast + return llvmlite.build_bitcast(builder, val, target_ty) + + +# ============================================================ +# 泛型实例化辅助:从 Subscript slice 提取类型实参名 +# ============================================================ +# _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) +# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 + + +def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr, + slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: + """从 Subscript.slice 提取类型实参名列表 + + list[int] -> ["int"] + dict[str, int] -> ["str", "int"] + list[AST | t.CPtr] -> ["AST|t.CPtr"] + """ + if slice_node is None or pool is None: + return None + result: list[str] | t.CPtr = list[str](pool, 4) + k: int = slice_node.kind() + if k == ast.ASTKind.Tuple: + tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node) + elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts + if elts is not None: + n: t.CSizeT = elts.__len__() + i: t.CSizeT + for i in range(n): + elt: ast.AST | t.CPtr = elts.get(i) + tn: str = HandlesType._get_type_name_from_annotation(pool, elt) + if tn is not None: + result.append(tn) + else: + tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node) + if tn is not None: + result.append(tn) + return result + + +# ============================================================ +# 翻译函数调用 Call(func, args) — 模块级版本 +# ============================================================ +def translate_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译函数调用,返回 call 结果 Value""" + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None: + return None + + func_name: str = HandlesExpr.get_func_name(cl.func) + if func_name is None: + # 检查是否是 list[int](pool) 形式的泛型实例化调用 + # Subscript 节点作为 Call func: 泛型类构造函数 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None: + sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func) + if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name: + gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value) + gen_class_name: str = gen_nm_node.id + # 检查是否是泛型类模板 + template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_class_name) + if template_cd is not None: + # 提取类型实参 + gen_type_args: list[str] | t.CPtr = _extract_type_args_from_slice(pool, sub_node.slice) + if gen_type_args is not None and gen_type_args.__len__() > 0: + # 特化泛型类,返回特化类名 + spec_name: str = HandlesClassDef._specialize_generic_class( + trans, gen_class_name, gen_type_args) + if spec_name is not None: + func_name = spec_name + else: + # 泛型类模板未找到:可能未 import 定义模块 + gt_err: str = pool.alloc(256) + if gt_err is not None: + viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name) + HandlesType.fatal_error(gen_nm_node, gt_err) + HandlesType.fatal_error(gen_nm_node, "泛型类模板未找到") + if func_name is None: + # 检查是否是 (A | t.CPtr)(value) 形式的类型转换 + # BinOp 节点作为 Call func: 联合类型注解用作类型转换 + if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None: + binop_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, cl.func, trans._imported_modules, trans._from_imports) + if binop_ty is not None: + binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if binop_args is not None and binop_args.__len__() == 1: + binop_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans) + if binop_arg_val is not None: + return _translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) + return None + + # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0: + if string.strcmp(func_name, "Deref") == 0: + return translate_c_deref(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "DerefAs") == 0: + return translate_c_derefas(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Addr") == 0: + return translate_c_addr(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Load") == 0: + return translate_c_load(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Asm") == 0: + return translate_c_asm(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "LLVMIR") == 0: + return translate_c_llvmir(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: + # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) + return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") + + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = cargs.__len__() + + # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 + # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) + # 支持: + # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) + # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) + # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: + tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) + if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: + target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) + if target_ty is not None: + tc_effective_can: t.CSizeT = can + # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) + # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* + if can == 2: + tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) + if tc_arg2_node is not None and tc_arg2_node.kind() == ast.ASTKind.Attribute: + tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) + if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: + if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: + tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) + if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match target_ty: + case llvmlite.LLVMType.Void(): + target_ty = llvmlite.Int8(pool) + case _: + pass + target_ty = llvmlite.Ptr(pool, target_ty) + tc_effective_can = 1 + if tc_effective_can == 1: + tc_arg_node: ast.AST | t.CPtr = cargs.get(0) + if tc_arg_node is not None: + tc_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, tc_arg_node, None, 0, trans) + if tc_arg_val is not None: + return _translate_t_type_cast(pool, builder, tc_arg_val, target_ty) + # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL + return None + + # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) + # __sizeof__ 是内置方法,不走跨模块调用路径 + # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: + if sz_at.value is not None and can == 0: + sz_cls_name: str = None + sz_vk: int = sz_at.value.kind() + if sz_vk == ast.ASTKind.Name: + sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) + sz_cls_name = sz_cls_nm2.id + elif sz_vk == ast.ASTKind.Attribute: + sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) + sz_cls_name = sz_inner_at.attr + if sz_cls_name is not None: + # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() + sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name) + # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) + # 联合类型在 TPV 中表示指针,可以指向多种类型 + # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 + if string.strstr(sz_cls_name, "|") is not None: + return llvmlite.const_int64(pool, 8) + # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) + sz_builtin: int = -1 + if string.strcmp(sz_cls_name, "int") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "str") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "bytes") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CInt") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt8T") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CInt16T") == 0: + sz_builtin = 2 + elif string.strcmp(sz_cls_name, "CInt32T") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt64T") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CChar") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CDouble") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CFloat") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CPtr") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CSizeT") == 0: + sz_builtin = 8 + if sz_builtin >= 0: + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal + # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 + return llvmlite.const_int64(pool, sz_builtin) + sz_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type( + sz_cls_name) + if sz_struct_ty is not None: + sz_val: int = HandlesClassDef._get_type_size(sz_struct_ty) + if sz_val > 0: + return llvmlite.const_int64(pool, sz_val) + # 类型已注册但大小为 0(opaque struct 或字段链表未填充):报错终止 + stdio.printf("[FATAL][__sizeof__] 类型 '%s' 已注册但大小为 0(字段链表未填充),立即终止编译\n", sz_cls_name) + sys.exit(1) + # 类型未注册:报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) + stdio.printf("[FATAL][__sizeof__] 类型 '%s' 未在结构体表中注册,无法计算大小,立即终止编译\n", sz_cls_name) + sys.exit(1) + + # 检测 obj.__len__() — 返回 list 对象的 __count__ 字段(偏移 8,i64) + # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: + if len_at.value is not None and can == 0: + obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_name_value( + builder, pool, len_at.value, trans) + if obj_val is not None: + i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 + # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) + idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty_len, obj_val, idx_one) + if count_ptr is not None: + return llvmlite.build_load(builder, i64_ty_len, count_ptr) + + # 检测方法调用: obj.method(args) + # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if method_at is not None and method_at.value is not None: + if method_at.value.kind() == ast.ASTKind.Name and trans is not None: + method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) + if method_obj_nm.id is not None: + # 查找对象变量 + obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, method_obj_nm.id) + if obj_var is not None and obj_var.Ty is not None: + # 检查是否为 Ptr(Struct(...))(结构体值变量) + # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) + match obj_var.Ty: + case llvmlite.LLVMType.Ptr(obj_struct_ty): + class_nm: str = HandlesStruct.get_class_name_by_type( + pool, obj_struct_ty) + if class_nm is not None: + return _translate_method_call( + pool, builder, mod, class_nm, func_name, + obj_var, cl, trans) + # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) + # load 获取实际指针 Ptr(Struct) 后再查找 + match obj_struct_ty: + case llvmlite.LLVMType.Ptr(inner_struct_ty): + inner_nm: str = HandlesStruct.get_class_name_by_type( + pool, inner_struct_ty) + if inner_nm is not None: + obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, obj_struct_ty, obj_var) + if obj_ptr is not None: + return _translate_method_call( + pool, builder, mod, inner_nm, func_name, + obj_ptr, cl, trans) + # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, + # 通过原始类型注解的类名查找结构体 + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, method_obj_nm.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + annot_val: str = var_entry.AnnotClassName + # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" + dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.') + cls_nm2: str = annot_val + mod_nm2: str = None + if dot_ptr is not None: + cls_nm2 = dot_ptr + 1 + total_len_av: t.CSizeT = string.strlen(annot_val) + cls_len_av: t.CSizeT = string.strlen(cls_nm2) + mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 + mod_nm2 = pool.alloc(mod_len2 + 1) + if mod_nm2 is not None: + string.strncpy(mod_nm2, annot_val, mod_len2) + mod_nm2[mod_len2] = '\0' + # 检查结构体是否已注册 + if HandlesStruct.get_struct_type(cls_nm2) is not None: + # 结构体已注册:load obj_ptr 走方法调用 + i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty2, obj_var) + if obj_ptr2 is not None: + return _translate_method_call( + pool, builder, mod, cls_nm2, func_name, + obj_ptr2, cl, trans) + else: + # 结构体未注册(跨模块依赖未翻译): + # 用模块名查 SHA1 构造方法调用名 + sha1_fc: str = None + if mod_nm2 is not None: + sha1_fc = _lookup_module_sha1(mod_nm2) + if sha1_fc is not None: + # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 + mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 + mangled3: str = pool.alloc(mlen3) + if mangled3 is not None: + viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) + # load obj_ptr (self) + i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty3, obj_var) + if obj_ptr3 is not None: + # 构建参数链表: obj_ptr3 (self) → 其他参数 + llvmlite.value_set_next(obj_ptr3, None) + head3: llvmlite.Value | t.CPtr = obj_ptr3 + tail3: llvmlite.Value | t.CPtr = obj_ptr3 + for ai3 in range(can): + arg3: ast.AST | t.CPtr = cargs.get(ai3) + if arg3 is not None: + arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg3, None, 0, trans) + if arg_val3 is not None: + llvmlite.value_set_next(arg_val3, None) + llvmlite.value_set_next(tail3, arg_val3) + tail3 = arg_val3 + total3: int = 1 + can + ret_ty3: llvmlite.LLVMType | t.CPtr = _infer_method_ret_ty(pool, func_name) + return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) + + # ============================================================ + # 检测 self.field.method() 调用 + # + # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, + # 翻译字段值获取对象指针,然后走方法调用路径。 + # + # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) + # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if attr_method_at is not None and attr_method_at.value is not None: + if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: + inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) + if inner_attr is not None and inner_attr.attr is not None: + # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) + field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) + if field_obj is not None and field_obj.Ty is not None: + field_cls_nm: str = None + # 路径1: 从字段值的 LLVM 类型获取类名 + match field_obj.Ty: + case llvmlite.LLVMType.Ptr(field_struct_ty): + field_cls_nm = HandlesStruct.get_class_name_by_type( + pool, field_struct_ty) + # 路径2: 从字段注解类名回退查找 + if field_cls_nm is None: + if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: + inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) + if inner_name_node is not None and inner_name_node.id is not None: + inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, inner_name_node.id) + if inner_var is not None and inner_var.Ty is not None: + match inner_var.Ty: + case llvmlite.LLVMType.Ptr(field_owner_struct_ty): + field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + field_owner_struct_ty, inner_attr.attr) + if field_info is not None: + field_annot: str = HandlesStruct.get_field_annot_class_name(field_info) + if field_annot is not None: + dot_p: t.CChar | t.CPtr = string.strrchr(field_annot, 46) + if dot_p is not None: + field_cls_nm = dot_p + 1 + else: + field_cls_nm = field_annot + if field_cls_nm is not None: + return _translate_method_call( + pool, builder, mod, field_cls_nm, func_name, + field_obj, cl, trans) + + # ============================================================ + # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() + # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, + # 需要在此特殊处理。 + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: + lm_name: str = lm_at.attr + # 判断是否是 list 方法名 + lm_is_list: int = 0 + if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 + + if lm_is_list == 1 and trans is not None: + # 翻译 list 对象 + lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) + if lm_obj is not None: + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # get / __getitem__: 返回 index 处的元素 + if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: + if can >= 1: + # 加载 __data__ (偏移 0) + g_idx0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 0, "0") + g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) + g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + g_idx4: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 4, "0") + g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) + g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) + # 翻译 index + g_idx_node: ast.AST | t.CPtr = cargs.get(0) + g_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, g_idx_node, None, 0, trans) + if g_data is not None and g_esize is not None and g_idx_val is not None: + g_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, g_idx_val, i64_ty) + g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) + g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + if g_addr is not None: + return llvmlite.build_load(builder, i8_ptr_ty, g_addr) + + # set / __setitem__: 设置 index 处的元素 + elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: + if can >= 2: + s_idx0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 0, "0") + s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) + s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) + s_idx4: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 4, "0") + s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) + s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) + s_idx_node: ast.AST | t.CPtr = cargs.get(0) + s_val_node: ast.AST | t.CPtr = cargs.get(1) + s_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, s_idx_node, None, 0, trans) + s_val_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, s_val_node, None, 0, trans) + if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: + s_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, s_idx_val, i64_ty) + s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) + s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) + if s_addr is not None: + s_val_ptr: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, s_val_val, i8_ptr_ty) + llvmlite.build_store(builder, s_val_ptr, s_addr) + return None + + # pop: 返回最后一个元素,count-- + elif string.strcmp(lm_name, "pop") == 0: + p_idx1: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 1, "0") + p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) + p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) + p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( + builder, p_count, llvmlite.ConstInt(pool, i64_ty, 1, "0")) + llvmlite.build_store(builder, p_nc, p_cpp) + p_idx0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 0, "0") + p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) + p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) + p_idx4: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 4, "0") + p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) + p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) + if p_data is not None and p_esize is not None and p_nc is not None: + p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) + p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) + if p_addr is not None: + return llvmlite.build_load(builder, i8_ptr_ty, p_addr) + + # clear: count = 0 + elif string.strcmp(lm_name, "clear") == 0: + c_idx1: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 1, "0") + c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) + llvmlite.build_store(builder, llvmlite.ConstInt(pool, i64_ty, 0, "0"), c_cpp) + return None + + # __iter__: iter_index = 0, return self + elif string.strcmp(lm_name, "__iter__") == 0: + it_idx5: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 5, "0") + it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) + llvmlite.build_store(builder, llvmlite.ConstInt(pool, i64_ty, 0, "0"), it_ipp) + return lm_obj + + # append: 直接调用 list.append(self, item) + # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 + elif string.strcmp(lm_name, "append") == 0: + if can >= 1: + ap_sha1: str = _lookup_module_sha1("_list") + if ap_sha1 is not None: + ap_mlen: t.CSizeT = string.strlen(ap_sha1) + 13 + ap_mangled: str = pool.alloc(ap_mlen) + if ap_mangled is not None: + viperlib.snprintf(ap_mangled, ap_mlen, "%s.list.append", ap_sha1) + ap_item_node: ast.AST | t.CPtr = cargs.get(0) + ap_item_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, ap_item_node, None, 0, trans) + if ap_item_val is not None: + llvmlite.value_set_next(lm_obj, None) + llvmlite.value_set_next(ap_item_val, None) + llvmlite.value_set_next(lm_obj, ap_item_val) + ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) + + # 获取关键字参数 + keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords + kw_count: t.CSizeT = 0 + if keywords is not None: + kw_count = keywords.__len__() + + # 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20) + # 命名空间隔离:严格模式下检查结构体可见性 + # - 裸名 Class(): 需要 from X import Class 或本地定义 + # - 模块限定 Module.Class(): 需要 import Module + # 用 find_struct_by_module 规避跨模块同名 find_struct 找错 + struct_ty: llvmlite.LLVMType | t.CPtr = None + gen_ctor_entry: HandlesStruct.StructEntry | t.CPtr = None + vis: int = HandlesStruct.is_struct_visible(func_name) + if vis != 0: + if trans is not None: + gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1) + if gen_ctor_entry is None: + gen_ctor_entry = HandlesStruct.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name: + mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value) + imp_ok: int = HandlesImports.is_module_imported(trans._imported_modules, mod_nm_qc.id) + if imp_ok != 0: + if trans is not None: + gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1) + if gen_ctor_entry is None: + gen_ctor_entry = HandlesStruct.find_struct(func_name) + if gen_ctor_entry is not None: + struct_ty = gen_ctor_entry.Ty + if struct_ty is not None: + if can == 0 and kw_count == 0: + # OOP 结构体:即使无参数也调用 __before_init__ + # 用 gen_ctor_entry 规避跨模块同名 find_struct 找错 + ctor_is_oop: int = 0 + if gen_ctor_entry is not None: + ctor_is_oop = gen_ctor_entry.IsOOP + if ctor_is_oop != 0: + return _translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, 0, trans) + # 普通结构体:检查是否有默认值(用 entry 直接访问) + gen_has_defaults: int = 0 + if gen_ctor_entry is not None: + for gdi in range(gen_ctor_entry.FieldCount): + gdf: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + gen_ctor_entry, gdi) + if gdf is not None and gdf.DefaultVal is not None: + gen_has_defaults = 1 + break + else: + gen_has_defaults = HandlesStruct.struct_has_defaults(func_name) + if gen_has_defaults == 1: + # 有默认值:走构造函数路径应用默认值 + return _translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, 0, trans) + # 无默认值:返回 zeroinitializer + ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + return ret + if kw_count > 0: + # 有关键字参数:按字段名赋值 + return _translate_struct_ctor_kw( + pool, builder, mod, struct_ty, func_name, cargs, can, + keywords, kw_count, trans) + # 仅位置参数:按字段顺序构建 + return _translate_struct_ctor( + pool, builder, mod, struct_ty, func_name, cargs, can, trans) + + # 查找函数:优先从函数表按裸名精确匹配(同模块函数), + # 再从模块函数链表按后缀匹配(SHA1 前缀名)。 + # stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None, + # 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*) + # 如果调用方未传 funcs_ptr/func_count(如 AnnAssign 路径),从 trans 获取 + actual_funcs: HandlesExprCall.FuncEntry | t.CPtr = funcs_ptr + actual_func_count: int = func_count + if actual_funcs is None and trans is not None: + actual_funcs = trans._funcs + actual_func_count = trans._func_count + found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, func_name) + # 使用访问器绕过 stub 类型限制 + found_ret_ty: llvmlite.LLVMType | t.CPtr = None + found_params: t.CPtr = None + if found_func is not None: + found_ret_ty = llvmlite.function_get_ret_ty(found_func) + found_params = llvmlite.function_get_params(found_func) + if found_ret_ty is not None: + call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty + else: + call_ret_ty = _infer_external_func_ret_ty(pool, func_name) + + # 如果模块中找不到函数,检查是否是变量(闭包调用) + if found_func is None: + closure_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name) + if closure_ptr is not None: + return translate_closure_call(pool, builder, mod, closure_ptr, + cargs, can) + + # 翻译参数并链接 + # 有关键字参数且找到函数定义时,按参数名匹配 + if kw_count > 0 and found_func is not None and found_params is not None: + return _translate_call_with_kwargs( + pool, builder, mod, func_name, found_func, + cargs, can, keywords, kw_count, trans) + + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) + mc_dst2: llvmlite.Value | t.CPtr = None + mc_src2: llvmlite.Value | t.CPtr = None + mc_num2: llvmlite.Value | t.CPtr = None + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + # 参数类型提升:当 found_func 为 None(stub 未注入)时, + # 根据外部函数签名推断期望类型,提升字面量(如 i32→i64) + # 避免 declare(i64) 与 call(i32) 类型不匹配 + if found_func is None and arg_val.Ty is not None: + ext_param_ty: llvmlite.LLVMType | t.CPtr = _get_external_func_param_ty( + pool, func_name, ai) + if ext_param_ty is not None: + val_bits_ap: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) + tgt_bits_ap: int = HandlesExpr.get_llvm_type_bits(ext_param_ty) + if val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap: + if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap: + arg_val = llvmlite.build_zext(builder, arg_val, ext_param_ty) + else: + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, ext_param_ty) + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + # memcpy 专用: 保存前三个参数的独立引用 + if ai == 0: + mc_dst2 = arg_val + elif ai == 1: + mc_src2 = arg_val + elif ai == 2: + mc_num2 = arg_val + + # 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi") + # t.CExtern/t.State/t.CExport 函数不加 SHA1 前缀,使用裸名 + # declare 函数(IsDeclared=1)使用裸名(func_name),define 函数使用实际名(可能带 SHA1 前缀) + call_name: str = func_name + if found_func is not None: + if llvmlite.function_is_declared(found_func) == 0: + found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + else: + # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 + # 如 string.strchr(...) → @{sha1_of_string}.strchr + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if xmod_at.value is not None and xmod_at.value.kind() == ast.ASTKind.Name: + xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value) + if xmod_nm.id is not None: + mod_sha1: str = _lookup_module_sha1(xmod_nm.id) + if mod_sha1 is not None: + # CExport 函数定义用裸名(@strlen),跨模块调用需用裸名而非 @{sha1}.func + if is_cexport_func(mod_sha1, func_name) != 0: + call_name = func_name + else: + mangled_len: t.CSizeT = string.strlen(mod_sha1) + string.strlen(func_name) + 2 + mangled: str = pool.alloc(mangled_len) + if mangled is not None: + viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name) + call_name = mangled + else: + # t 和 c 是内部库,豁免 SHA1 查找:使用裸名调用 + if string.strcmp(xmod_nm.id, "t") == 0 or string.strcmp(xmod_nm.id, "c") == 0: + call_name = func_name + else: + # Bug 修复: 先检查是否是已导入的模块名(如 BuildPipeline.run_pipeline) + # 如果是已导入模块但 SHA1 未注册,说明该模块未被编译(如 Phase2 未扫描到), + # 应该立即报错,而不是错误地走 from_imports 查找(会被 star import 回退误导) + is_imported_mod: int = 0 + if trans is not None and trans._imported_modules is not None: + is_imported_mod = HandlesImports.is_module_imported( + trans._imported_modules, xmod_nm.id) + if is_imported_mod != 0: + # 已导入模块但 SHA1 未注册:该模块未被编译,立即报错 + err_msg_imp: t.CChar | t.CPtr = pool.alloc(256) + if err_msg_imp is not None: + viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_nm.id) + HandlesType.fatal_error(xmod_nm, err_msg_imp) + HandlesType.fatal_error(xmod_nm, "已导入模块 SHA1 未注册") + else: + # 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType) + # LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名, + # 但 Ptr 是 __types 模块的模块级函数 + # 禁用 star import 回退:xmod_nm.id 是明确名称,不应回退到 star import 模块 + from_sha1: str = None + if trans is not None and trans._from_imports is not None: + from_sha1 = _lookup_mod_sha1(pool, trans._from_imports, xmod_nm.id, 0) + if from_sha1 is not None: + # CExport 函数定义用裸名,跨模块调用需用裸名 + if is_cexport_func(from_sha1, func_name) != 0: + call_name = func_name + else: + fmangled_len: t.CSizeT = string.strlen(from_sha1) + string.strlen(func_name) + 2 + fmangled: str = pool.alloc(fmangled_len) + if fmangled is not None: + viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name) + call_name = fmangled + else: + err_msg2: t.CChar | t.CPtr = pool.alloc(256) + if err_msg2 is not None: + viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_nm.id, func_name) + HandlesType.fatal_error(xmod_nm, err_msg2) + HandlesType.fatal_error(xmod_nm, "跨模块调用找不到模块 SHA1") + else: + # 裸名调用(非 Attribute):检查 from_imports + # 裸名调用允许 star import 回退:from stdint import * 导入的名称(如 BYTEPTR)需要通过 star import 查找 + if trans is not None and trans._from_imports is not None: + bare_sha1: str = _lookup_mod_sha1(pool, trans._from_imports, func_name, 1) + if bare_sha1 is not None: + if is_cexport_func(bare_sha1, func_name) != 0: + call_name = func_name + else: + bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(func_name) + 2 + bare_mangled: str = pool.alloc(bare_mangled_len) + if bare_mangled is not None: + viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, func_name) + call_name = bare_mangled + else: + err_msg3: t.CChar | t.CPtr = pool.alloc(256) + if err_msg3 is not None: + viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name) + HandlesType.fatal_error(node, err_msg3) + HandlesType.fatal_error(node, "裸名调用未定义且未导入") + else: + err_msg4: t.CChar | t.CPtr = pool.alloc(256) + if err_msg4 is not None: + viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name) + HandlesType.fatal_error(node, err_msg4) + HandlesType.fatal_error(node, "裸名调用未定义且未导入") + + # 直接调用 + # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) + if func_name == "memcpy" and can >= 3: + return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) + return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, 0) + + +# ============================================================ +# 翻译闭包调用 — 通过闭包指针间接调用 +# +# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节) +# 调用过程: +# 1. load closure_ptr 从变量 alloca +# 2. load fn_ptr 从 offset 0 +# 3. load env_ptr 从 offset 8 +# 4. bitcast fn_ptr to i32 (i8*)* +# 5. call i32 %fn_typed(i8* %env_ptr) +# ============================================================ +def translate_closure_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + closure_alloca: llvmlite.Value | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """通过闭包指针间接调用""" + if builder is None or closure_alloca is None: + return None + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 1. 加载闭包指针 (i8*) + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca) + if closure_ptr is None: + return None + + # 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8* + fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_ptr_addr is None: + return None + fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr) + if fn_raw is None: + return None + + # 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8* + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val) + if env_addr is None: + return None + env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr) + if env_ptr is None: + return None + + # 4. bitcast fn_raw to i32 (i8*)* + param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, 1) + func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty) + fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty) + if fn_typed is None: + return None + + # 5. 间接调用: call i32 %fn_typed(i8* %env_ptr) + env_ptr.Next = None + return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty) + + +# ============================================================ +# 翻译 printf 调用 — 模块级版本 +# ============================================================ +def translate_printf_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr = None): + """翻译 printf 调用(特殊处理格式字符串)""" + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cargs is None: + return + can: t.CSizeT = cargs.__len__() + if can == 0: + return + + arg0: ast.AST | t.CPtr = cargs.get(0) + if arg0 is None: + return + + fmt_str: str = None + arg0_kind: int = arg0.kind() + if arg0_kind == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0) + if cn.const_kind == ast.CONST_STR: + fmt_str = cn.str_val + + if fmt_str is None: + return + + fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( + builder, pool, mod, fmt_str, trans) + if fmt_ptr is None: + return + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 翻译额外参数并链接 + prev: llvmlite.Value | t.CPtr = fmt_ptr + for ai in range(1, can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is not None: + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is not None: + # C ABI integer promotion: i8/i16 → i32(printf 变参函数要求) + arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) + if arg_bits != 0 and arg_bits < 32: + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, i32_ty) + # C ABI float promotion: float → double(printf 变参函数要求) + arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty) + if arg_fbits != 0 and arg_fbits < 64: + double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, double_ty) + arg_val.Next = None + prev.Next = arg_val + prev = arg_val + prev.Next = None + + # is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf), + # 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器) + llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1) + + +# ============================================================ +# FuncEntry 结构体(用于函数表) +# ============================================================ +@t.NoVTable +class FuncEntry: + """函数表条目""" + Name: str + Func: llvmlite.Function | t.CPtr + + +# ============================================================ +# 初始化函数表 +# ============================================================ +def init_func_table(pool: memhub.MemBuddy | t.CPtr, + max_count: int) -> FuncEntry | t.CPtr: + """分配并清零函数表数组""" + size: t.CSizeT = max_count * FuncEntry.__sizeof__() + funcs_ptr: FuncEntry | t.CPtr = pool.alloc(size) + if funcs_ptr is not None: + string.memset(funcs_ptr, 0, size) + return funcs_ptr + + +# ============================================================ +# 查找函数 +# ============================================================ +def find_func_in_table(funcs: FuncEntry | t.CPtr, + func_count: int, + name: str) -> llvmlite.Function | t.CPtr: + """在函数表中按名称查找,返回 Function 指针或 None""" + if name is None or funcs is None: + return None + entry_size: t.CSizeT = FuncEntry.__sizeof__() + for i in range(func_count): + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size + entry: FuncEntry | t.CPtr = (FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry.Func + return None + + +# ============================================================ +# 添加函数到函数表 +# ============================================================ +def add_func_to_table(funcs: FuncEntry | t.CPtr, + func_count: int, + name: str, + func: llvmlite.Function | t.CPtr, + max_count: int) -> int: + """添加函数到函数表,返回 0 成功""" + if name is None or func is None or funcs is None: + return 1 + if func_count >= max_count: + return 1 + entry_size: t.CSizeT = FuncEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size + entry: FuncEntry | t.CPtr = (FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + entry.Name = name + entry.Func = func + # 同时注册到全局函数表(供跨模块 vtable 初始化查找) + _register_global_func(name, func) + return 0 + + +# ============================================================ +# 全局函数注册表(跨模块函数查找) +# +# 所有模块翻译的函数都会注册到此表(通过 add_func_to_table 自动注册)。 +# 主要用途: vtable 初始化时查找跨模块继承方法的 Function 对象, +# 以获取函数类型信息构造 bitcast 字符串。 +# ============================================================ +GLOBAL_FUNC_MAX: t.CDefine = 8192 +_global_funcs: FuncEntry | t.CPtr = None +_global_func_count: int = 0 + + +def _init_global_func_table() -> int: + """初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)""" + global _global_funcs + global _global_func_count + if _global_funcs is not None: + return 1 + size: t.CSizeT = GLOBAL_FUNC_MAX * FuncEntry.__sizeof__() + _global_funcs = stdlib.malloc(size) + if _global_funcs is None: + return 0 + string.memset(_global_funcs, 0, size) + _global_func_count = 0 + return 1 + + +def _register_global_func(name: str, func: llvmlite.Function | t.CPtr) -> int: + """注册函数到全局表(已存在则跳过),返回 0 成功 + + 直接操作全局表,不调用 add_func_to_table,避免递归。 + """ + global _global_func_count + if name is None or func is None: + return 1 + if _init_global_func_table() == 0: + return 1 + # 已存在则跳过(避免重复) + if find_func_in_table(_global_funcs, _global_func_count, name) is not None: + return 0 + if _global_func_count >= GLOBAL_FUNC_MAX: + return 1 + # 直接写入全局表(不调用 add_func_to_table,避免递归) + entry_size: t.CSizeT = FuncEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(_global_funcs) + _global_func_count * entry_size + entry: FuncEntry | t.CPtr = (FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + entry.Name = name + entry.Func = func + _global_func_count += 1 + return 0 + + +def find_func_global(name: str) -> llvmlite.Function | t.CPtr: + """在全局函数表中按名称查找,返回 Function 指针或 None""" + if name is None or _global_funcs is None: + return None + return find_func_in_table(_global_funcs, _global_func_count, name) + + +# ============================================================ +# ExprCallHandle - 函数调用处理器(Mixin 继承模式) +# +# HandleCall / HandlePrintfCall 提供 trans 接口 +# ============================================================ +@t.NoVTable +class ExprCallHandle(HandlesBase.Mixin): + """函数调用处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # HandleCall - 翻译函数调用,返回 call 结果 Value + # ============================================================ + def HandleCall(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译函数调用,从 self.Trans 获取共享状态""" + return translate_call( + self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, + node, + self.Trans._funcs, self.Trans._func_count, self.Trans) + + # ============================================================ + # HandlePrintfCall - 翻译 printf 调用 + # ============================================================ + def HandlePrintfCall(self, cl: ast.Call | t.CPtr): + """翻译 printf 调用,从 self.Trans 获取共享状态""" + translate_printf_call( + self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, + cl, self.Trans) + + +# ============================================================ +# NewExprCallHandle - 工厂函数 +# ============================================================ +def NewExprCallHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> ExprCallHandle | t.CPtr: + h: ExprCallHandle | t.CPtr = pool.alloc(ExprCallHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, ExprCallHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesExprOps.py b/App/lib/core/Handles/HandlesExprOps.py new file mode 100644 index 0000000..dac726d --- /dev/null +++ b/App/lib/core/Handles/HandlesExprOps.py @@ -0,0 +1,287 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesTranslator as HT + + +# ============================================================ +# HandlesExprOps - 二元运算处理(模块级纯函数) +# ============================================================ + +# ============================================================ +# 运算符重载支持 +# +# 当二元/比较运算的 lhs 是结构体指针时,检查该类是否定义了 +# 对应的 dunder 方法(如 __add__、__eq__),若有则生成方法调用 +# 而非原生算术/比较指令。 +# ============================================================ + +# BinOp 运算符 → dunder 方法名 +def _binop_to_dunder(op: int) -> str: + """将 BinOp 运算符映射到 dunder 方法名,无映射时返回 None""" + if op == ast.OpKind.Add: return "__add__" + if op == ast.OpKind.Sub: return "__sub__" + if op == ast.OpKind.Mult: return "__mul__" + if op == ast.OpKind.Div: return "__div__" + if op == ast.OpKind.Mod: return "__mod__" + if op == ast.OpKind.BitAnd: return "__and__" + if op == ast.OpKind.BitOr: return "__or__" + if op == ast.OpKind.BitXor: return "__xor__" + if op == ast.OpKind.LShift: return "__lshift__" + if op == ast.OpKind.RShift: return "__rshift__" + if op == ast.OpKind.FloorDiv: return "__floordiv__" + return None + +# Compare 运算符 → dunder 方法名 +def _cmpop_to_dunder(op: int) -> str: + """将 Compare 运算符映射到 dunder 方法名,无映射时返回 None""" + if op == ast.OpKind.Eq: return "__eq__" + if op == ast.OpKind.Ne: return "__ne__" + if op == ast.OpKind.Lt: return "__lt__" + if op == ast.OpKind.Le: return "__le__" + if op == ast.OpKind.Gt: return "__gt__" + if op == ast.OpKind.Ge: return "__ge__" + return None + + +# ============================================================ +# try_operator_overload - 尝试运算符重载 +# +# 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的 +# dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回 +# 调用结果;未找到返回 None,调用方回退到原生运算。 +# +# Args: +# pool: 内存池 +# builder: IRBuilder +# mod: LLVM 模块 +# lhs: 左操作数 Value(已求值) +# rhs: 右操作数 Value(已求值) +# op: OpKind 运算符 +# trans: Translator 对象 +# is_compare: 0=BinOp, 1=Compare(决定 dunder 映射表) +# +# Returns: +# 方法调用的 Value(成功),None(未重载) +# ============================================================ +def try_operator_overload(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + lhs: llvmlite.Value | t.CPtr, + rhs: llvmlite.Value | t.CPtr, + op: int, + trans: HT.Translator | t.CPtr, + is_compare: int) -> llvmlite.Value | t.CPtr: + """尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None""" + if lhs is None or rhs is None: + return None + + # 延迟导入避免循环依赖 + import lib.core.Handles.HandlesStruct as HandlesStruct + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + # 映射运算符到 dunder 方法名 + dunder: str = None + if is_compare != 0: + dunder = _cmpop_to_dunder(op) + else: + dunder = _binop_to_dunder(op) + if dunder is None: + return None + + # 检查 lhs 是否为结构体指针 + struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lhs) + if struct_ty is None: + return None + + # 获取类名 + class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) + if class_name is None: + return None + + # 在继承链中查找 dunder 方法 + lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + found_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, lookup_name) + + search_class: str = class_name + if found_func is None: + cur_parent: str = HandlesStruct.get_parent_name(class_name) + while cur_parent is not None: + parent_lookup: t.CChar | t.CPtr = pool.alloc(128) + if parent_lookup is not None: + viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, dunder) + parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) + if parent_func is not None: + found_func = parent_func + search_class = cur_parent + break + cur_parent = HandlesStruct.get_parent_name(cur_parent) + + # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) + # 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错) + cls_sha1: str = None + op_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + if op_entry is not None: + cls_sha1 = op_entry.ModuleSha1 + if cls_sha1 is None: + cls_sha1 = HandlesStruct.get_struct_sha1(search_class) + if cls_sha1 is None: + cur_p: str = HandlesStruct.get_parent_name(search_class) + while cur_p is not None and cls_sha1 is None: + cls_sha1 = HandlesStruct.get_struct_sha1(cur_p) + cur_p = HandlesStruct.get_parent_name(cur_p) + + # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 + if found_func is None and cls_sha1 is None: + return None + + # 构建 extra_args 数组(仅含 rhs 一个参数) + extra_args: t.CSizeT | t.CPtr = pool.alloc(8) + if extra_args is None: + return None + extra_args[0] = t.CSizeT(rhs) + + # 调用方法: lhs.__dunder__(rhs) + return HandlesExprCall._call_method_on_ptr( + pool, builder, mod, search_class, dunder, + lhs, extra_args, 1, trans) + + +# ============================================================ +# 翻译二元运算(自动类型提升) +# ============================================================ +def translate_binop(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译二元运算(自动类型提升)""" + binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if binop is None: + return None + + lhs_node: ast.AST | t.CPtr = binop.left + rhs_node: ast.AST | t.CPtr = binop.right + op: int = binop.op + + # 先翻译 rhs(只翻译一次,避免副作用重复) + rhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, rhs_node, None, 0, trans) + if rhs is None: + return None + + # === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 === + # 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值, + # 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。 + if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) + if nm is not None and nm.id is not None: + lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm.id) + if lhs_alloca is not None: + ovl_result: llvmlite.Value | t.CPtr = try_operator_overload( + pool, builder, mod, lhs_alloca, rhs, op, trans, 0) + if ovl_result is not None: + return ovl_result + + # 正常翻译 lhs + lhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, lhs_node, None, 0, trans) + if lhs is None: + return None + + # === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)=== + ovl_result2: llvmlite.Value | t.CPtr = try_operator_overload( + pool, builder, mod, lhs, rhs, op, trans, 0) + if ovl_result2 is not None: + return ovl_result2 + + # 获取操作数类型信息 + lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty) + rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty) + lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty) + rhs_fbits: int = HandlesExpr.get_llvm_float_bits(rhs.Ty) + + # 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查, + # 因为 float 的 int bits 为 0,会被误认为指针) + if lhs_fbits != 0 or rhs_fbits != 0: + # 确定目标浮点类型(使用较大的位宽) + target_fbits: int = lhs_fbits + if rhs_fbits > target_fbits: + target_fbits = rhs_fbits + target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + if target_fbits == 32: + target_float_ty = llvmlite.Float(pool) + # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) + lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty) + rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty) + if op == ast.OpKind.Add: + return llvmlite.build_fadd(builder, lhs, rhs) + if op == ast.OpKind.Sub: + return llvmlite.build_fsub(builder, lhs, rhs) + if op == ast.OpKind.Mult: + return llvmlite.build_fmul(builder, lhs, rhs) + if op == ast.OpKind.Div: + return llvmlite.build_fdiv(builder, lhs, rhs) + if op == ast.OpKind.Mod: + return llvmlite.build_frem(builder, lhs, rhs) + return None + + # 指针算术: ptr + int 或 ptr - int → ptrtoint + add/sub + inttoptr + if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0): + if op == ast.OpKind.Add or op == ast.OpKind.Sub: + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + if lhs_bits == 0: + # lhs 是指针,rhs 是整数 + ptr_as_int: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint(builder, lhs, i64_ty) + int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty) + if op == ast.OpKind.Add: + result: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, ptr_as_int, int_val) + else: + result = llvmlite.build_sub(builder, ptr_as_int, int_val) + return llvmlite.build_inttoptr(builder, result, lhs.Ty) + else: + # rhs 是指针,lhs 是整数(仅 Add 支持交换) + ptr_as_int = llvmlite.build_ptrtoint(builder, rhs, i64_ty) + int_val = HandlesExpr.coerce_to_type(builder, lhs, i64_ty) + if op == ast.OpKind.Add: + result = llvmlite.build_add(builder, int_val, ptr_as_int) + else: + result = llvmlite.build_sub(builder, int_val, ptr_as_int) + return llvmlite.build_inttoptr(builder, result, rhs.Ty) + + if lhs_bits > rhs_bits: + rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty) + elif rhs_bits > lhs_bits: + lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty) + + if op == ast.OpKind.Add: + return llvmlite.build_add(builder, lhs, rhs) + elif op == ast.OpKind.Sub: + return llvmlite.build_sub(builder, lhs, rhs) + elif op == ast.OpKind.Mult: + return llvmlite.build_mul(builder, lhs, rhs) + elif op == ast.OpKind.Div: + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.Mod: + return llvmlite.build_srem(builder, lhs, rhs) + elif op == ast.OpKind.BitAnd: + return llvmlite.build_and(builder, lhs, rhs) + elif op == ast.OpKind.BitOr: + return llvmlite.build_or(builder, lhs, rhs) + elif op == ast.OpKind.BitXor: + return llvmlite.build_xor(builder, lhs, rhs) + elif op == ast.OpKind.LShift: + return llvmlite.build_shl(builder, lhs, rhs) + elif op == ast.OpKind.RShift: + return llvmlite.build_ashr(builder, lhs, rhs) + return None diff --git a/App/lib/core/Handles/HandlesFor.py b/App/lib/core/Handles/HandlesFor.py new file mode 100644 index 0000000..0ed8f1e --- /dev/null +++ b/App/lib/core/Handles/HandlesFor.py @@ -0,0 +1,384 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import viperlib +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesBody as HandlesBody +import lib.core.Handles.HandlesType as HandlesType + + +# ============================================================ +# HandlesFor - for 循环语句处理(Mixin 继承模式) +# +# 支持 for i in range(start, stop, step) 模式: +# %i = alloca i32 +# store i32 start, i32* %i +# br label %cond +# cond: +# %cur = load i32, i32* %i +# %cmp = icmp slt i32 %cur, stop +# br i1 %cmp, label %body, label %end +# body: +# ... body ... +# br label %incr +# incr: +# %cur2 = load i32, i32* %i +# %next = add i32 %cur2, step +# store i32 %next, i32* %i +# br label %cond +# end: +# ============================================================ + + +@t.NoVTable +class ForHandle(HandlesBase.Mixin): + """for 循环语句处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # Handle - 处理 for 语句,返回新增变量数 + # ============================================================ + def Handle(self, node: ast.AST | t.CPtr) -> int: + """翻译 for i in range(...) 循环语句""" + if node is None: + return 0 + + trans: HT.Translator | t.CPtr = self.Trans + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + if builder is None or func is None: + return 0 + + for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node) + + # 1. 获取循环变量名(仅支持 for i in range(...)) + target: ast.AST | t.CPtr = for_node.target + if target is None: + return 0 + if target.kind() != ast.ASTKind.Name: + return 0 + target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + var_name: str = target_nm.id + if var_name is None: + return 0 + + # 2. 解析迭代器:支持 range() 和指针迭代 + iter_node: ast.AST | t.CPtr = for_node.iter + if iter_node is None: + return 0 + + # 检查是否是 range() 调用 + is_range_iter: int = 0 + if iter_node.kind() == ast.ASTKind.Call: + call_pre: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) + fn_pre: str = HandlesExpr.get_func_name(call_pre.func) + if fn_pre is not None: + if string.strcmp(fn_pre, "range") == 0: + is_range_iter = 1 + else: + err_msg: t.CChar | t.CPtr = pool.alloc(256) + if err_msg is not None: + viperlib.snprintf(err_msg, 256, "仅支持 range() 或指针迭代,got call '%s'", fn_pre) + HandlesType.fatal_error(iter_node, err_msg) + HandlesType.fatal_error(iter_node, "仅支持 range() 或指针迭代") + + # 非范围迭代:走指针迭代路径 + if is_range_iter == 0: + return self._handle_ptr_iter(for_node, var_name) + + call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) + + # 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step) + args: list[ast.AST | t.CPtr] | t.CPtr = call.args + if args is None: + return 0 + arg_count: t.CSizeT = args.__len__() + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + start_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + stop_val: llvmlite.Value | t.CPtr = None + step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + + if arg_count == 1: + stop_val = HandlesExpr.translate_value( + builder, pool, trans.Module, args.get(0), + trans._funcs, trans._func_count, trans) + elif arg_count >= 2: + start_val = HandlesExpr.translate_value( + builder, pool, trans.Module, args.get(0), + trans._funcs, trans._func_count, trans) + stop_val = HandlesExpr.translate_value( + builder, pool, trans.Module, args.get(1), + trans._funcs, trans._func_count, trans) + if arg_count >= 3: + step_val = HandlesExpr.translate_value( + builder, pool, trans.Module, args.get(2), + trans._funcs, trans._func_count, trans) + + if stop_val is None: + stop_val = llvmlite.const_int32(pool, 0) + if start_val is None: + start_val = llvmlite.const_int32(pool, 0) + if step_val is None: + step_val = llvmlite.const_int32(pool, 1) + + # 4. 创建/查找循环变量 alloca + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = llvmlite.build_alloca(builder, i32_ty) + if HandlesVar.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 5. 存储初始值 (类型对齐: start_val 可能是 i64,需截断到 i32) + init_val: llvmlite.Value | t.CPtr = start_val + if start_val is not None and start_val.Ty is not None: + start_bits: int = HandlesExpr.get_llvm_type_bits(start_val.Ty) + if start_bits != 0 and start_bits != 32: + init_val = llvmlite.build_trunc(builder, start_val, i32_ty) + llvmlite.build_store(builder, init_val, var_alloca) + + # 6. 创建基本块: cond / body / incr / end(使用 trans._label_counter,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: t.CChar | t.CPtr = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 7. 跳转到 cond 块 + llvmlite.build_br(builder, cond_bb) + + # 8. cond 块: load i, icmp slt i, stop, cond_br body/end + llvmlite.position_at_end(builder, cond_bb) + cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, var_alloca) + # 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型 + cmp_lhs: llvmlite.Value | t.CPtr = cur_i + cmp_rhs: llvmlite.Value | t.CPtr = stop_val + if stop_val is not None and stop_val.Ty is not None: + stop_bits: int = HandlesExpr.get_llvm_type_bits(stop_val.Ty) + cur_bits: int = HandlesExpr.get_llvm_type_bits(cur_i.Ty) + if stop_bits != 0 and cur_bits != 0 and stop_bits != cur_bits: + if cur_bits < stop_bits: + cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty) + else: + cmp_rhs = llvmlite.build_trunc(builder, stop_val, i32_ty) + cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_SLT, cmp_lhs, cmp_rhs) + llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) + + # 9. body 块: 翻译循环体,跳到 incr + llvmlite.position_at_end(builder, body_bb) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = body.__len__() + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # 10. incr 块: i = i + step, 跳回 cond + llvmlite.position_at_end(builder, incr_bb) + cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, var_alloca) + # 类型对齐: step_val 可能是 i64,需截断到 i32 与 cur_i2 类型一致 + incr_step: llvmlite.Value | t.CPtr = step_val + if step_val is not None and step_val.Ty is not None: + step_bits: int = HandlesExpr.get_llvm_type_bits(step_val.Ty) + cur2_bits: int = HandlesExpr.get_llvm_type_bits(cur_i2.Ty) + if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits: + if step_bits > cur2_bits: + incr_step = llvmlite.build_trunc(builder, step_val, i32_ty) + else: + incr_step = llvmlite.build_sext(builder, step_val, i32_ty) + next_i: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step) + llvmlite.build_store(builder, next_i, var_alloca) + llvmlite.build_br(builder, cond_bb) + + # 11. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + return new_vars + + # ============================================================ + # _handle_ptr_iter - 指针迭代: for x in ptr: + # 遍历指针,依赖隐式 index,直到解引用为空(null 终止符) + # + # 生成 IR 结构: + # %idx = alloca i32 + # store i32 0, i32* %idx + # br label %cond + # cond: + # %i = load i32, i32* %idx + # %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i + # %ev = load elem_ty, elem_ty* %ep + # %null = icmp eq elem_ty %ev, 0 + # br i1 %null, label %end, label %body + # body: + # store elem_ty %ev, elem_ty* %var + # ... 循环体 ... + # br label %incr + # incr: + # %next = add i32 %i, 1 + # store i32 %next, i32* %idx + # br label %cond + # end: + # ============================================================ + def _handle_ptr_iter(self, for_node: ast.For | t.CPtr, + var_name: str) -> int: + """指针迭代: for x in ptr: 直到解引用为空""" + trans: HT.Translator | t.CPtr = self.Trans + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + # 翻译迭代器表达式,获取指针值 + ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, for_node.iter, + trans._funcs, trans._func_count, trans) + if ptr_val is None: + HandlesType.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式") + + # 检查是否是指针类型 + if HandlesExpr.is_ptr_type(ptr_val.Ty) == 0: + HandlesType.fatal_error(for_node, "指针迭代: 迭代器不是指针类型") + + # 获取元素类型 + elem_ty: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty is None: + HandlesType.fatal_error(for_node, "指针迭代: 无法获取元素类型") + + # 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符) + elem_bits: int = HandlesExpr.get_llvm_type_bits(elem_ty) + if elem_bits == 0: + HandlesType.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符") + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 创建循环变量 alloca(存储元素值) + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = llvmlite.build_alloca(builder, elem_ty) + if HandlesVar.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 创建隐式 index 变量,初始为 0 + idx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i32_ty) + llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) + + # 创建基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: t.CChar | t.CPtr = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 跳转到 cond + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, GEP, load elem, icmp eq 0 + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, elem_ty, ptr_val, cur_idx) + cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) + null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0) + is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, cur_elem, null_val) + llvmlite.build_cond_br(builder, is_null, end_bb, body_bb) + + # body 块: store elem to var, 翻译循环体 + llvmlite.position_at_end(builder, body_bb) + llvmlite.build_store(builder, cur_elem, var_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = body.__len__() + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++, br cond + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + return new_vars + + +# ============================================================ +# NewForHandle - 工厂函数 +# ============================================================ +def NewForHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> ForHandle | t.CPtr: + h: ForHandle | t.CPtr = pool.alloc(ForHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, ForHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesFunctions.py b/App/lib/core/Handles/HandlesFunctions.py new file mode 100644 index 0000000..e785cfb --- /dev/null +++ b/App/lib/core/Handles/HandlesFunctions.py @@ -0,0 +1,936 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import stdio +import stdlib +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesBody as HandlesBody +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesImports as HandlesImports + + +# ============================================================ +# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性 +# +# 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式 +# 也支持 @c.Attribute(t.attr.llvm.xxx) 形式 +# +# 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None +# ============================================================ +def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr, + decorator_list: list[ast.AST | t.CPtr] | t.CPtr, + imported_modules: str) -> t.CChar | t.CPtr: + """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串""" + if decorator_list is None: + return None + dn: t.CSizeT = decorator_list.__len__() + if dn == 0: + return None + + attrs_buf: t.CChar | t.CPtr = pool.alloc(256) + if attrs_buf is None: + return None + attrs_buf[0] = '\0' + found_any: int = 0 + + for di in range(dn): + deco: ast.AST | t.CPtr = decorator_list.get(di) + if deco is None or deco.kind() != ast.ASTKind.Call: + continue + call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco) + if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute: + continue + + # 检测 c.Attribute + func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func) + if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0: + continue + if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name: + continue + c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value) + if c_name.id is None or string.strcmp(c_name.id, "c") != 0: + continue + if HandlesImports.is_module_imported(imported_modules, "c") == 0: + continue + + # 遍历参数提取属性 + if call_node.args is None: + continue + args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args + an: t.CSizeT = args_list.__len__() + for ai in range(an): + arg_node: ast.AST | t.CPtr = args_list.get(ai) + if arg_node is None: + continue + + # 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx) + attr_name: str = _get_attr_name_from_node(arg_node) + if attr_name is None: + continue + + # 映射到 LLVM 属性名并追加 + if _append_llvm_attr(attrs_buf, attr_name) != 0: + found_any = 1 + # 追加成功后,如果不是最后一个属性,添加空格分隔 + # 在下一次追加前由 _append_str 处理 + + if found_any == 0: + return None + return attrs_buf + + +def _get_attr_name_from_node(node: ast.AST | t.CPtr) -> str: + """从 AST 节点提取属性名 + + 支持: + - Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline" + - Attribute: t.attr.packed -> "packed" + - Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind" + """ + if node is None: + return None + k: int = node.kind() + + # Call 节点: t.attr.always_inline() + if k == ast.ASTKind.Call: + call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if call.func is None or call.func.kind() != ast.ASTKind.Attribute: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func) + return at.attr + + # Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind + if k == ast.ASTKind.Attribute: + at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + return at2.attr + + return None + + +def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int: + """将属性名映射到 LLVM 属性名并追加到缓冲区 + + 返回 1 表示已追加,0 表示不支持该属性 + """ + if attrs_buf is None or attr_name is None: + return 0 + + # 先确定映射的 LLVM 属性名 + llvm_name: str = None + if string.strcmp(attr_name, "always_inline") == 0: + llvm_name = "alwaysinline" + elif string.strcmp(attr_name, "noinline") == 0: + llvm_name = "noinline" + elif string.strcmp(attr_name, "noreturn") == 0: + llvm_name = "noreturn" + elif string.strcmp(attr_name, "pure") == 0: + llvm_name = "readonly" + elif string.strcmp(attr_name, "const") == 0: + llvm_name = "readnone" + elif string.strcmp(attr_name, "nounwind") == 0: + llvm_name = "nounwind" + elif string.strcmp(attr_name, "noredzone") == 0: + llvm_name = "noredzone" + elif string.strcmp(attr_name, "willreturn") == 0: + llvm_name = "willreturn" + elif string.strcmp(attr_name, "mustprogress") == 0: + llvm_name = "mustprogress" + else: + # packed/aligned/section/visibility/weak 等不支持作为函数内联属性 + return 0 + + # 支持的属性:如果缓冲区非空,先追加空格分隔 + if attrs_buf[0] != '\0': + _append_str(attrs_buf, " ") + _append_str(attrs_buf, llvm_name) + return 1 + + +def _append_str(buf: t.CChar | t.CPtr, s: str) -> None: + """将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)""" + if buf is None or s is None: + return + cur_len: t.CSizeT = string.strlen(buf) + string.strcpy(buf + cur_len, s) + + +# ============================================================ +# HandlesFunctions - 函数定义处理(trans 单参模式) +# +# 参考 Python 版 TransPyC FunctionHandle +# +# 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope +# 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。 +# ============================================================ + + +# ============================================================ +# _mangle_name - 为名称添加 SHA1 前缀 +# +# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带 +# SHA1 前缀(16 hex + '.'),则原样返回。 +# ============================================================ +def _mangle_name(trans: HT.Translator | t.CPtr, name: str) -> str: + """为任意名称添加 SHA1 前缀(不做 main/export 检查)""" + if trans is None or name is None: + return name + if trans.ModuleSha1 is None: + return name + name_len: t.CSizeT = string.strlen(name) + # 已带 SHA1 前缀(16 hex + '.')则跳过 + if name_len > 17: + is_sha1: int = 1 + for i in range(16): + c: t.CChar = name[i] + if not (('0' <= c <= '9') or ('a' <= c <= 'f')): + is_sha1 = 0 + break + if is_sha1 != 0 and name[16] == '.': + return name + sha1: str = trans.ModuleSha1 + sha1_len: t.CSizeT = string.strlen(sha1) + mangled: str = stdlib.malloc(sha1_len + name_len + 2) + if mangled is None: + return name + string.strcpy(mangled, sha1) + mangled[sha1_len] = '.' + string.strcpy(mangled + sha1_len + 1, name) + return mangled + + +# ============================================================ +# _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀 +# +# 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling, +# 而非当前模块的 SHA1。 +# ============================================================ +def _mangle_name_with_sha1(sha1: str, name: str) -> str: + """用指定 SHA1 为名称添加前缀(不做 main/export 检查)""" + if sha1 is None or name is None: + return name + name_len: t.CSizeT = string.strlen(name) + # 已带 SHA1 前缀(16 hex + '.')则跳过 + if name_len > 17: + is_sha1: int = 1 + for i in range(16): + c2: t.CChar = name[i] + if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')): + is_sha1 = 0 + break + if is_sha1 != 0 and name[16] == '.': + return name + sha1_len: t.CSizeT = string.strlen(sha1) + mangled: str = stdlib.malloc(sha1_len + name_len + 2) + if mangled is None: + return name + string.strcpy(mangled, sha1) + mangled[sha1_len] = '.' + string.strcpy(mangled + sha1_len + 1, name) + return mangled + + +# ============================================================ +# _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查) +# +# 规则: +# - main 函数不加前缀(程序入口点) +# - has_export 非 0 时不加前缀(t.CExport 导出函数) +# - 已带 SHA1 前缀的不再加 +# - ModuleSha1 为 None 时不加前缀 +# ============================================================ +def _mangle_func_name(trans: HT.Translator | t.CPtr, name: str, + has_export: int) -> str: + """为函数名添加 SHA1 前缀(检查 main/export)""" + if trans is None or name is None: + return name + if has_export != 0: + return name + if string.strcmp(name, "main") == 0: + return name + return _mangle_name(trans, name) + + +# ============================================================ +# forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明 +# +# 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用 +# vsnprintf(行41),但 vsnprintf 定义在后面。 +# +# 对每个顶层 FunctionDef: +# 1. 推断返回类型和参数类型 +# 2. 计算 mangled name(含 SHA1 前缀) +# 3. 创建 declare(IsDeclared=1) +# 4. 添加参数 +# 5. 注册到函数表 +# +# 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare, +# 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。 +# ============================================================ +def forward_declare_functions(trans: HT.Translator | t.CPtr, + tree: ast.AST | t.CPtr) -> int: + """预扫描所有顶层 FunctionDef,创建前向声明""" + if trans is None or tree is None: + return 0 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + if pool is None or mod is None: + return 0 + + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + return 0 + cn_count: t.CSizeT = ch.__len__() + + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + if child.kind() != ast.ASTKind.FunctionDef: + continue + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + if fd is None or fd.name is None: + continue + + # 推断返回类型 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = HandlesType.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports) + if ret_ty is None and fd.returns is not None: + if HandlesType.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + if ret_ty is None: + ret_ty = i32_ty + + # 检测 CExtern/State/CExport + has_extern: int = 0 + has_state: int = 0 + has_export: int = 0 + if fd.returns is not None: + has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") + has_state = HandlesType.has_decorator_marker(fd.returns, "State") + has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") + is_extern_decl: int = 0 + if has_extern != 0 or has_state != 0: + is_extern_decl = 1 + + # 计算 mangled name + if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main": + mangled_name: str = fd.name + else: + mangled_name = _mangle_func_name(trans, fd.name, 0) + + # 如果函数已存在(如重复定义),跳过 + existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) + if existing is not None: + continue + + # 创建 declare + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + continue + + # 注册到函数表(用裸名 fd.name,不是 mangled_name) + max_funcs: int = 256 + cur_count: int = trans._func_count + if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs) == 0: + trans._func_count = cur_count + 1 + + # 注册 CExport 函数到全局表 + if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: + HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) + + # 添加参数 + args_node: ast.Arguments | t.CPtr = fd.args + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = alist.__len__() + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is None or arg.arg is None: + continue + # t.CVoid 表示空参:跳过 + if arg.annotation is not None: + if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports) + if resolved is not None: + param_ty = resolved + pname: t.CChar | t.CPtr = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + return 0 + + +# ============================================================ +# 翻译函数定义 FunctionDef(name, args, body, ...) +# +# trans 单参模式:所有共享状态从 trans 获取 +# 函数局部作用域通过 enter_scope/exit_scope 管理 +# ============================================================ +def translate_function_def(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)""" + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + imported_modules: str = trans._imported_modules + from_imports: str = trans._from_imports + funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs + func_count: int = trans._func_count + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 推断返回类型:优先使用返回类型注解 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if fd.returns is not None: + ret_ty = HandlesType.resolve_annotation_type( + pool, fd.returns, imported_modules, from_imports) + + # 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void + # 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32 + if ret_ty is None and fd.returns is not None: + if HandlesType.has_decorator_marker(fd.returns, "State") != 0: + ret_ty = llvmlite.Void(pool) + + # 如果仍然为 None,扫描 return 语句推断(至少返回 i32) + if ret_ty is None: + param_types_str: str = HandlesType.build_param_types_str(pool, fd.args) + ret_ty = HandlesType.infer_return_type( + pool, fd.children, param_types_str) + + # 检测是否为外部声明函数(t.CExtern 或 t.State) + # 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号) + # t.State = t.CExtern + t.CExport(既是声明又是导出) + # t.CExport 导出函数不加 SHA1 前缀 + # t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名 + is_extern_decl: int = 0 + has_export: int = 0 + has_extern: int = 0 + has_state: int = 0 + if fd.returns is not None: + has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") + has_state = HandlesType.has_decorator_marker(fd.returns, "State") + has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") + # t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass) + if has_extern != 0 or has_state != 0: + is_extern_decl = 1 + + # SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名 + # (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference) + # main 函数也不加前缀(程序入口点) + if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main": + mangled_name: str = fd.name + else: + mangled_name: str = _mangle_func_name(trans, fd.name, 0) + + # 注册 CExport 函数到全局表(供跨模块调用查表) + # t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func + if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: + HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) + + if is_extern_decl != 0: + # 外部声明函数:生成 declare(仅声明,不定义) + func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, mangled_name, ret_ty) + if func is None: + stdio.printf("[FUNC] create_declare %s failed\n", fd.name) + return 0 + + # 注册到函数表 + max_funcs_extern: int = 256 + if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern) == 0: + trans._func_count = func_count + 1 + + # 添加参数(支持类型注解) + args_node_extern: ast.Arguments | t.CPtr = fd.args + if args_node_extern is not None: + ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern) + if ags_e.args is not None: + alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args + an_e: t.CSizeT = alist_e.__len__() + for ai_e in range(an_e): + arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e)) + if arg_e is not None and arg_e.arg is not None: + # t.CVoid 表示空参:跳过,不添加到函数签名 + if arg_e.annotation is not None: + if HandlesType._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0: + continue + param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty + if arg_e.annotation is not None: + resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg_e.annotation, imported_modules, from_imports) + if resolved_e is not None: + param_ty_e = resolved_e + pname_e: t.CChar | t.CPtr = pool.alloc(32) + if pname_e is not None: + viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg) + llvmlite.add_param(pool, func, param_ty_e, pname_e) + + # 提取 @c.Attribute 装饰器属性并设置到函数 + func_attrs_e: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs_e is not None: + llvmlite.function_set_attrs(func, func_attrs_e) + + return 0 + + # args_node 用于后续 alloca 创建,提前赋值 + args_node: ast.Arguments | t.CPtr = fd.args + + # 检查是否已有前向声明(由 forward_declare_functions 创建) + func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) + if func is not None and llvmlite.function_is_declared(func) != 0: + # 复用前向声明:清除 IsDeclared 标记,转为 define + func.IsDeclared = 0 + # 装饰器属性设置(前向声明时未设置) + func_attrs_reuse: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs_reuse is not None: + llvmlite.function_set_attrs(func, func_attrs_reuse) + else: + # 创建新的 LLVM 函数(使用 SHA1 混淆名) + func = llvmlite.create_function(pool, mod, mangled_name, ret_ty) + if func is None: + stdio.printf("[FUNC] create_function %s failed\n", fd.name) + return 0 + + # 提取 @c.Attribute 装饰器属性并设置到函数 + func_attrs: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) + if func_attrs is not None: + llvmlite.function_set_attrs(func, func_attrs) + + # 注册到函数表 + max_funcs: int = 256 + if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs) == 0: + trans._func_count = func_count + 1 + + # 添加参数(支持类型注解) + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = alist.__len__() + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + # t.CVoid 表示空参:跳过,不添加到函数签名 + if arg.annotation is not None: + if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg.annotation, imported_modules, from_imports) + if resolved is not None: + param_ty = resolved + pname: t.CChar | t.CPtr = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + # 创建 entry 块 + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + + # 创建函数专属 builder + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 进入函数作用域(嵌套符号表) + HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION) + + # 为参数创建 alloca + if args_node is not None: + ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags2.args is not None: + alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args + an2: t.CSizeT = alist2.__len__() + for ai2 in range(an2): + arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) + if arg2 is not None and arg2.arg is not None: + # t.CVoid 表示空参:跳过,不创建 alloca + if arg2.annotation is not None: + if HandlesType._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0: + continue + param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty + if arg2.annotation is not None: + resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg2.annotation, imported_modules, from_imports) + if resolved2 is not None: + param_ty2 = resolved2 + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) + if alloca is not None: + HandlesVar.define_var(trans.SymTab, arg2.arg, alloca) + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + if arg2.annotation is not None: + cls_nm: str = HandlesType.extract_class_name_from_annotation( + arg2.annotation, imported_modules) + if cls_nm is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, arg2.arg, cls_nm) + pname2: t.CChar | t.CPtr = pool.alloc(32) + if pname2 is not None: + viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) + param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, param_ty2, pname2) + llvmlite.build_store(func_builder, param_val, alloca) + + # 保存模块级作用域状态(仅非变量表相关) + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + + trans._cur_func = func + trans._cur_builder = func_builder + # 清空 global/nonlocal 名称集合(新函数作用域) + HT.clear_scope_names(trans) + + # 预扫描函数体:为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = body.__len__() + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.pre_scan_allocas(trans, stmt) + + # 翻译函数体 + if body is not None: + bn2: t.CSizeT = body.__len__() + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + HandlesBody.translate_stmt(trans, stmt2) + + # 如果函数体最后一条语句不是 Return,添加隐式 ret + last_is_return: int = 0 + if body is not None: + bn3: t.CSizeT = body.__len__() + if bn3 > 0: + last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(func_builder, zero_val) + + # 恢复模块级作用域(退出函数作用域) + HandlesVar.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + + return 0 + + +# ============================================================ +# translate_nested_function_def - 嵌套函数提升 + 闭包创建 +# +# 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32, +# 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到 +# 以函数名命名的局部变量中。 +# +# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配) +# Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节) +# ============================================================ +def translate_nested_function_def(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译嵌套函数定义:提升为顶层函数 + 创建闭包""" + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + func_name: str = fd.name + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突) + promoted_name: t.CChar | t.CPtr = pool.alloc(64) + if promoted_name is not None: + viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name) + mangled_promoted: str = _mangle_name(trans, promoted_name) + + # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env) + func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, mangled_promoted, i32_ty) + if func is None: + return 0 + llvmlite.add_param(pool, func, i8_ptr_ty, "%env") + + # 3. 创建 entry 块 + builder + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") + if entry_blk is None: + return 0 + func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) + if func_builder is None: + return 0 + llvmlite.position_at_end(func_builder, entry_blk) + + # 4. 进入嵌套函数作用域(嵌套符号表) + HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION) + + # 5. 创建 _env_ptr alloca 并存储 %env 参数 + env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) + if env_alloca is not None: + HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca) + env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") + llvmlite.build_store(func_builder, env_param_val, env_alloca) + + # 6. 保存父函数作用域状态(仅非变量表相关) + old_func: llvmlite.Function | t.CPtr = trans._cur_func + old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + old_func_name: str = trans._cur_func_name + old_global_count: int = trans._global_name_count + old_nonlocal_count: int = trans._nonlocal_name_count + old_env_count: int = trans._closure_env_count + + # 7. 切换到嵌套函数作用域 + 清空 scope names + trans._cur_func = func + trans._cur_builder = func_builder + trans._cur_func_name = func_name + HT.clear_scope_names(trans) + + # 8. 预扫描函数体:为局部变量提前创建 alloca + body: list[ast.AST | t.CPtr] | t.CPtr = fd.children + if body is not None: + bn: t.CSizeT = body.__len__() + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.pre_scan_allocas(trans, stmt) + + # 9. 翻译函数体(Nonlocal 语句会填充 _nonlocal_names) + if body is not None: + bn2: t.CSizeT = body.__len__() + for bi2 in range(bn2): + stmt2: ast.AST | t.CPtr = body.get(bi2) + if stmt2 is not None: + HandlesBody.translate_stmt(trans, stmt2) + + # 10. 隐式 ret + last_is_return: int = 0 + if body is not None: + bn3: t.CSizeT = body.__len__() + if bn3 > 0: + last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) + if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: + last_is_return = 1 + if last_is_return == 0: + zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(func_builder, zero_val) + + # 11. 保存嵌套函数的 nonlocal 信息 + nested_nonlocal_count: int = trans._nonlocal_name_count + + # 12. 退出嵌套函数作用域,回到父函数作用域(保留 _nonlocal_names 用于 env 创建) + HandlesVar.exit_scope(trans.SymTab) + trans._cur_func = old_func + trans._cur_builder = old_builder + # NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值 + + # 13. 在父函数中创建闭包对象 + parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder + if parent_builder is None: + # 无 builder(模块级嵌套函数?)→ 无法创建闭包,仅恢复状态 + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + return 0 + + # 13a. 创建 env: malloc(4 * nested_nonlocal_count) — env 直接存储 i32 值 + env_ptr: llvmlite.Value | t.CPtr = None + if nested_nonlocal_count > 0: + env_size: t.CInt64T = nested_nonlocal_count * 4 + env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) + if env_size_val is not None: + env_size_val.Next = None + env_ptr = llvmlite.build_call( + parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) + + # 为每个 nonlocal 变量存储值到 env + if env_ptr is not None: + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) + for ni in range(nested_nonlocal_count): + # 从 _nonlocal_names 缓冲区读取名称 + name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8 + nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr) + nl_name: str = nl_slot[0] + if nl_name is not None: + # 在父函数作用域中查找(Current 已回到父作用域) + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nl_name) + if var_alloca is not None: + # 加载变量值 + var_ty: llvmlite.LLVMType | t.CPtr = None + if var_alloca.Ty is not None: + var_ty = var_alloca.Ty.Pointee + if var_ty is None: + var_ty = i32_ty + var_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + parent_builder, var_ty, var_alloca) + if var_val is not None: + # GEP to env[ni*4] + offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 4) + slot: llvmlite.Value | t.CPtr = llvmlite.build_gep( + parent_builder, i8_ty, env_ptr, offset_val) + if slot is not None: + # bitcast to i32* and store value + slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, slot, i32_ptr_ty) + if slot_typed is not None: + # 类型转换(确保 var_val 是 i32) + coerced_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + parent_builder, var_val, i32_ty) + if coerced_val is not None: + llvmlite.build_store(parent_builder, coerced_val, slot_typed) + + # 13b. 创建闭包结构: malloc(16) + closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) + if closure_size_val is not None: + closure_size_val.Next = None + closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( + parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) + if closure_ptr is None: + # malloc 失败,恢复状态 + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + return 0 + + # 13c. 存储 fn_ptr 到 offset 0 + # 创建函数指针类型 i32(i8*)* + fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) + fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) + fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) + + # 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名) + fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64) + if fn_ptr_name is not None: + # SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func") + if string.strchr(mangled_promoted, '.') is not None: + viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) + else: + viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) + fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) + + # bitcast 函数指针到 i8*(闭包存储 i8* 类型) + fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, fn_ptr_val, i8_ptr_ty) + fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) + if fn_slot is not None and fn_as_i8ptr is not None: + llvmlite.build_store(parent_builder, fn_as_i8ptr, fn_slot) + + # 13d. 存储 env_ptr 到 offset 8 + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) + env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + parent_builder, i8_ty, closure_ptr, eight_val) + if env_slot_addr is not None: + env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + parent_builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) + if env_slot is not None: + if env_ptr is not None: + llvmlite.build_store(parent_builder, env_ptr, env_slot) + else: + # 无 nonlocal 变量,存储 null + null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") + llvmlite.build_store(parent_builder, null_val, env_slot) + + # 13e. 将闭包指针存储到父函数的局部变量 {func_name} + closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty) + if closure_alloca is not None: + llvmlite.build_store(parent_builder, closure_ptr, closure_alloca) + HandlesVar.define_var(trans.SymTab, func_name, closure_alloca) + + # 14. 恢复 scope names + trans._cur_func_name = old_func_name + trans._global_name_count = old_global_count + trans._nonlocal_name_count = old_nonlocal_count + trans._closure_env_count = old_env_count + + return 1 + + +# ============================================================ +# 创建 LLVM 函数(简单版本,仅声明) +# ============================================================ +def create_function(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + name: str, + args_node: ast.AST | t.CPtr, + ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr: + """创建 LLVM 函数并添加参数""" + if name is None or mod is None: + return None + + func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty) + if func is None: + return None + + if args_node is not None: + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is not None: + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = alist.__len__() + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + # t.CVoid 表示空参:跳过 + if arg.annotation is not None: + if arg.annotation.kind() == ast.ASTKind.Attribute: + at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) + if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0: + continue + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, arg.annotation, None, None) + if resolved is not None: + param_ty = resolved + pname: t.CChar | t.CPtr = pool.alloc(32) + if pname is not None: + viperlib.snprintf(pname, 32, "%%%s", arg.arg) + llvmlite.add_param(pool, func, param_ty, pname) + + return func diff --git a/App/lib/core/Handles/HandlesIf.py b/App/lib/core/Handles/HandlesIf.py new file mode 100644 index 0000000..64f6af2 --- /dev/null +++ b/App/lib/core/Handles/HandlesIf.py @@ -0,0 +1,141 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import viperlib +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesBody as HandlesBody + + +# ============================================================ +# HandlesIf - if/elif/else 语句处理(Mixin 继承模式) +# +# 翻译 if 语句为 LLVM IR 控制流: +# br i1 %cond, label %then, label %else +# then: +# ... body ... +# br label %end +# else: +# ... orelse ... +# br label %end +# end: +# ============================================================ + + +@t.NoVTable +class IfHandle(HandlesBase.Mixin): + """if/elif/else 语句处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # Handle - 处理 if 语句,返回新增变量数 + # ============================================================ + def Handle(self, node: ast.AST | t.CPtr) -> int: + """翻译 if/elif/else 语句""" + if node is None: + return 0 + + trans: HT.Translator | t.CPtr = self.Trans + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + if builder is None or func is None: + return 0 + + if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(node) + + # 1. 求值条件表达式 + cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, if_node.test, + trans._funcs, trans._func_count, trans) + + # 2. 转换为 i1 条件 + # Compare/Not 表达式已返回 i1,直接使用;其他类型与 0 比较 + if cond_val is None: + cond_val = llvmlite.const_int32(pool, 0) + cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) + if cond_bits == 1: + cond_i1: llvmlite.Value | t.CPtr = cond_val + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, zero) + + # 3. 创建基本块(使用 trans._label_counter 生成唯一标签名,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: t.CChar | t.CPtr = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "if.then.%d", cnt) + then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "if.end.%d", cnt) + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 检查是否有 else 分支 + has_else: int = 0 + orelse_list: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse + if orelse_list is not None: + if orelse_list.__len__() > 0: + has_else = 1 + + else_bb: llvmlite.BasicBlock | t.CPtr = None + if has_else == 1: + viperlib.snprintf(name_buf, 32, "if.else.%d", cnt) + else_bb = llvmlite.create_block(pool, func, name_buf) + + # 4. 发射条件分支 + if has_else == 1: + llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) + else: + llvmlite.build_cond_br(builder, cond_i1, then_bb, merge_bb) + + # 5. 翻译 then body + llvmlite.position_at_end(builder, then_bb) + body: list[ast.AST | t.CPtr] | t.CPtr = if_node.children + if body is not None: + body_count: t.CSizeT = body.__len__() + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + # then 块未终止则跳到 merge + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, merge_bb) + + # 6. 翻译 else body(若有) + if has_else == 1: + llvmlite.position_at_end(builder, else_bb) + else_count: t.CSizeT = orelse_list.__len__() + for ei in range(else_count): + stmt: ast.AST | t.CPtr = orelse_list.get(ei) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, merge_bb) + + # 7. 定位到 merge 块继续后续代码 + llvmlite.position_at_end(builder, merge_bb) + return 0 + + +# ============================================================ +# NewIfHandle - 工厂函数 +# ============================================================ +def NewIfHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> IfHandle | t.CPtr: + h: IfHandle | t.CPtr = pool.alloc(IfHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, IfHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesImports.py b/App/lib/core/Handles/HandlesImports.py new file mode 100644 index 0000000..c129b08 --- /dev/null +++ b/App/lib/core/Handles/HandlesImports.py @@ -0,0 +1,404 @@ +import t, c +from stdint import * +import ast +import memhub +import string +import viperlib +import stdio +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesStruct as HandlesStruct + + +# ============================================================ +# HandlesImports - 导入语句处理(Mixin 继承模式) +# +# 管理 _imported_modules 和 _from_imports 字符串 +# 注意:str = bytes = t.CChar | t.CPtr = i8* +# ============================================================ + + +# ============================================================ +# 模块级工具函数(保留供外部调用) +# ============================================================ + +# ============================================================ +# 添加已导入模块名 +# ============================================================ +def add_imported_module(pool: memhub.MemBuddy | t.CPtr, + imported_modules: str, + name: str) -> str: + """记录已导入的模块名,返回新的 imported_modules 字符串指针""" + if name is None: + return imported_modules + if imported_modules is None: + nlen: t.CSizeT = string.strlen(name) + buf: t.CChar | t.CPtr = pool.alloc(nlen + 1) + if buf is not None: + string.strcpy(buf, name) + return buf + return None + else: + old_len: t.CSizeT = string.strlen(imported_modules) + name_len: t.CSizeT = string.strlen(name) + new_len: t.CSizeT = old_len + 1 + name_len + buf2: t.CChar | t.CPtr = pool.alloc(new_len + 1) + if buf2 is not None: + string.strcpy(buf2, imported_modules) + buf2[old_len] = ' ' + string.strcpy(buf2 + old_len + 1, name) + return buf2 + return imported_modules + + +# ============================================================ +# 检查模块是否已导入 +# ============================================================ +def is_module_imported(imported_modules: str, name: str) -> int: + """检查模块是否已导入(词边界精确匹配,避免子串误匹配)""" + if name is None or imported_modules is None: + return 0 + name_len: t.CSizeT = string.strlen(name) + cur: t.CChar | t.CPtr = imported_modules + total_len: t.CSizeT = string.strlen(imported_modules) + ci: t.CSizeT = 0 + while ci < total_len: + while ci < total_len and cur[ci] == ' ': + ci += 1 + if ci >= total_len: + break + word_start: t.CSizeT = ci + while ci < total_len and cur[ci] != ' ': + ci += 1 + word_len: t.CSizeT = ci - word_start + if word_len == name_len: + match: int = 1 + for ei in range(name_len): + if cur[word_start + ei] != name[ei]: + match = 0 + break + if match == 1: + return 1 + return 0 + + +# ============================================================ +# 添加 from-import 名称映射 +# ============================================================ +def add_from_import(pool: memhub.MemBuddy | t.CPtr, + from_imports: str, + local_name: str, + module_name: str) -> str: + """添加 from-import 映射 "name:module",返回新的 from_imports 字符串""" + if local_name is None or module_name is None: + return from_imports + entry: t.CChar | t.CPtr = pool.alloc(128) + if entry is None: + return from_imports + viperlib.snprintf(entry, 128, "%s:%s", local_name, module_name) + if from_imports is None: + return entry + else: + old_len: t.CSizeT = string.strlen(from_imports) + entry_len: t.CSizeT = string.strlen(entry) + new_len: t.CSizeT = old_len + 1 + entry_len + buf: t.CChar | t.CPtr = pool.alloc(new_len + 1) + if buf is not None: + string.strcpy(buf, from_imports) + buf[old_len] = ' ' + string.strcpy(buf + old_len + 1, entry) + return buf + return from_imports + + +# ============================================================ +# 查找 from-import 名称 → 返回模块名或 None +# +# allow_star_fallback: 是否允许 star import 回退(默认 1=允许)。 +# 当查询明确模块名(如 "BuildPipeline")时,应传 0 禁用回退, +# 避免被 star import 模块名误导(如 from stdint import * 后 +# 查询 "BuildPipeline" 错误回退到 "stdint")。 +# ============================================================ +def lookup_from_import(from_imports: str, name: str, + allow_star_fallback: int = 1) -> str: + """查找 from-import 名称,返回模块名或 None + + 支持 star import: 如果 from_imports 中有 "*:module" 条目, + 且未找到精确名称匹配,且 allow_star_fallback != 0,则返回 star import 的模块名。 + """ + if name is None or from_imports is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: t.CChar | t.CPtr = from_imports + ci: t.CSizeT = 0 + total_len: t.CSizeT = string.strlen(from_imports) + star_mod: str = None + while ci < total_len: + # 跳过前导空格 + while ci < total_len and cur[ci] == ' ': + ci += 1 + if ci >= total_len: + break + # 找到 ':' 的位置 + colon_pos: t.CSizeT = ci + while colon_pos < total_len and cur[colon_pos] != ':' and cur[colon_pos] != ' ': + colon_pos += 1 + if colon_pos >= total_len or cur[colon_pos] != ':': + break + entry_name_len: t.CSizeT = colon_pos - ci + # 检测 star import ("*:module") + if entry_name_len == 1 and cur[ci] == '*': + mod_start: t.CSizeT = colon_pos + 1 + mod_end: t.CSizeT = mod_start + while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0': + mod_end += 1 + star_mod = cur + mod_start + # 比较名称 + elif entry_name_len == name_len: + match: int = 1 + ei: t.CSizeT = 0 + while ei < name_len: + if cur[ci + ei] != name[ei]: + match = 0 + break + ei += 1 + if match == 1: + mod_start2: t.CSizeT = colon_pos + 1 + mod_end2: t.CSizeT = mod_start2 + while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0': + mod_end2 += 1 + return cur + mod_start2 + # 跳到下一个条目 + ci = colon_pos + while ci < total_len and cur[ci] != ' ': + ci += 1 + # 未找到精确匹配,仅在允许时回退到 star import + if allow_star_fallback == 0: + return None + return star_mod + + +# ============================================================ +# _resolve_relative_module - 解析相对导入为完整模块名 +# +# 对于 from .X import Y(level=1, module="X")在包 pkg 中: +# 解析为 "pkg.X" +# 对于 from . import Y(level=1, module=None)在包 pkg 中: +# 解析为 "pkg" +# 对于 from ..X import Y(level=2, module="X")在包 pkg.sub 中: +# 解析为 "pkg.X"(先从 pkg.sub 上溯一级到 pkg,再追加 .X) +# +# Args: +# pool: 内存池 +# current_package: 当前文件所属包名(如 "llvmlite"),None 表示无包 +# level: 相对导入级别(0=绝对,1=., 2=..) +# module: ImportFrom 的 module 字段(可能为 None) +# +# Returns: +# 解析后的完整模块名;绝对导入(level<=0)直接返回 module; +# 无法解析时返回 module(回退到原始值) +# ============================================================ +def _resolve_relative_module(pool: memhub.MemBuddy | t.CPtr, + current_package: str, + level: t.CInt, + module: str) -> str: + """解析相对导入为完整模块名""" + if level <= 0: + return module + if current_package is None: + return module + + # 从 current_package 开始,上溯 (level-1) 级 + pkg: str = current_package + up: t.CInt = level - 1 + while up > 0: + pkg_len: t.CSizeT = string.strlen(pkg) + last_dot: t.CSizeT = 0 + found: int = 0 + i: t.CSizeT = 0 + while i < pkg_len: + if pkg[i] == '.': + last_dot = i + found = 1 + i += 1 + if found == 0: + # 无更多父级,包变为空 + pkg = None + break + # 截断到最后一个 '.' 处 + new_pkg: str = pool.alloc(last_dot + 1) + if new_pkg is None: + return module + string.strncpy(new_pkg, pkg, last_dot) + new_pkg[last_dot] = '\0' + pkg = new_pkg + up -= 1 + + if module is None: + # from . import Y → 模块就是包本身 + return pkg + if pkg is None: + # 包已上溯到空,直接用 module + return module + # 拼接 pkg + "." + module + pkg_len2: t.CSizeT = string.strlen(pkg) + mod_len: t.CSizeT = string.strlen(module) + buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1) + if buf is None: + return module + string.strcpy(buf, pkg) + buf[pkg_len2] = '.' + string.strcpy(buf + pkg_len2 + 1, module) + return buf + + +# ============================================================ +# compute_package_from_relpath - 从相对路径计算包名 +# +# 包名 = 文件所在目录路径,将 / 和 \ 替换为 . +# 对于顶级文件(无目录分隔符),返回 None +# +# 示例: +# "llvmlite/__init__.py" → "llvmlite" +# "llvmlite/__types.py" → "llvmlite" +# "ast/parser.py" → "ast" +# "ast.py" → None(顶级文件) +# ============================================================ +def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr, + rel_path: str) -> str: + """从相对路径计算包名(目录部分,分隔符替换为 .)""" + if rel_path is None: + return None + rlen: t.CSizeT = string.strlen(rel_path) + # 找最后一个 / 或 \ + last_sep: t.CSizeT = 0 + found: int = 0 + i: t.CSizeT = 0 + while i < rlen: + ch: t.CChar = rel_path[i] + if ch == '/' or ch == '\\': + last_sep = i + found = 1 + i += 1 + if found == 0: + # 无目录分隔符 → 顶级文件,无包 + return None + # 复制目录部分,将 / 和 \ 替换为 . + dir_len: t.CSizeT = last_sep + buf: str = pool.alloc(dir_len + 1) + if buf is None: + return None + j: t.CSizeT = 0 + while j < dir_len: + ch2: t.CChar = rel_path[j] + if ch2 == '/' or ch2 == '\\': + buf[j] = '.' + else: + buf[j] = ch2 + j += 1 + buf[dir_len] = '\0' + return buf + + +# ============================================================ +# ImportsHandle - 导入语句处理器(Mixin 继承模式) +# +# 方法版本:直接更新 trans._imported_modules / trans._from_imports +# ============================================================ +@t.NoVTable +class ImportsHandle(HandlesBase.Mixin): + """导入语句处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # HandleImport - 处理 import 语句,更新 trans._imported_modules + # ============================================================ + def HandleImport(self, node: ast.AST | t.CPtr) -> int: + """处理 import 语句,返回 0""" + imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node) + if imp is None: + return 0 + names: list[ast.AST | t.CPtr] | t.CPtr = imp.names + if names is None: + return 0 + nn: t.CSizeT = names.__len__() + for ni in range(nn): + alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) + if alias is not None and alias.name is not None: + pool_val: memhub.MemBuddy | t.CPtr = self.Trans.Pool + im_val: str = self.Trans._imported_modules + self.Trans._imported_modules = add_imported_module( + pool_val, im_val, alias.name) + # 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class()) + if alias.asname is not None: + self.Trans._imported_modules = add_imported_module( + pool_val, self.Trans._imported_modules, alias.asname) + return 0 + + # ============================================================ + # HandleImportFromModule - 处理 from X import Y 的模块部分 + # + # 对相对导入(level > 0),使用 trans.CurrentPackage 解析为 + # 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt + # 记录的模块名与 SHA1 映射表一致。 + # ============================================================ + def HandleImportFromModule(self, node: ast.AST | t.CPtr) -> int: + """处理 from X import Y 的模块部分,更新 trans._imported_modules""" + impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) + if impf is None: + return 0 + # 解析模块名:相对导入需补充包前缀 + resolved: str = _resolve_relative_module( + self.Trans.Pool, self.Trans.CurrentPackage, + impf.level, impf.module) + if resolved is not None: + self.Trans._imported_modules = add_imported_module( + self.Trans.Pool, self.Trans._imported_modules, resolved) + return 0 + + # ============================================================ + # HandleImportFromNames - 处理 from X import Y 的名称部分 + # + # 同样使用解析后的完整模块名,确保 from-import 映射 + # (如 LLVMType:llvmlite.__types)能正确查到 SHA1。 + # ============================================================ + def HandleImportFromNames(self, node: ast.AST | t.CPtr) -> int: + """处理 from X import Y 的名称部分,更新 trans._from_imports""" + impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) + if impf is None: + return 0 + # 解析模块名:相对导入需补充包前缀 + resolved: str = _resolve_relative_module( + self.Trans.Pool, self.Trans.CurrentPackage, + impf.level, impf.module) + if resolved is not None: + names: list[ast.AST | t.CPtr] | t.CPtr = impf.names + if names is not None: + nn: t.CSizeT = names.__len__() + for ni in range(nn): + alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) + if alias is not None and alias.name is not None: + local_name: str = alias.name + if alias.asname is not None: + local_name = alias.asname + self.Trans._from_imports = add_from_import( + self.Trans.Pool, self.Trans._from_imports, + local_name, resolved) + # 命名空间隔离:from-import 的名称标记为可见结构体 + HandlesStruct.add_visible_struct(self.Trans.Pool, local_name) + return 0 + + +# ============================================================ +# NewImportsHandle - 工厂函数 +# ============================================================ +def NewImportsHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> ImportsHandle | t.CPtr: + h: ImportsHandle | t.CPtr = pool.alloc(ImportsHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, ImportsHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesMain.py b/App/lib/core/Handles/HandlesMain.py new file mode 100644 index 0000000..3b29f02 --- /dev/null +++ b/App/lib/core/Handles/HandlesMain.py @@ -0,0 +1,314 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import viperlib +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesBody as HandlesBody +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign + + +# ============================================================ +# HandlesMain - 模块级翻译入口 + wrapper main 创建 +# +# 从 translator.py 拆分出来,负责: +# 1. create_wrapper_main() - 无用户 main 时创建包装 main +# 2. translate_children() - 遍历 AST 子节点并分派翻译 +# +# trans 单参模式:所有共享状态从 trans 获取,无需 11 个参数 +# 注意: str = bytes = t.CChar | t.CPtr = i8* +# ============================================================ + + +# ============================================================ +# _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数 +# +# 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的 +# CExport 函数无法被先翻译的模块正确识别为裸名调用。 +# Phase 1a 预注册所有 CExport/State 函数名到全局表。 +# ============================================================ +def _register_cexport_from_funcdef(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预注册 CExport/State 函数到全局表(仅注册,不生成 IR)""" + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) + if fd is None or fd.name is None: + return 0 + if trans is None or trans.ModuleSha1 is None: + return 0 + + # 检查返回类型是否有 CExport 或 State 标记 + has_export: int = 0 + has_state: int = 0 + if fd.returns is not None: + has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") + has_state = HandlesType.has_decorator_marker(fd.returns, "State") + + if has_export != 0 or has_state != 0: + HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) + + return 0 + + +# ============================================================ +# translate_children - 遍历 AST 子节点并分派翻译 +# +# 对应 TransPyC translator._translate_children() +# 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans +# ============================================================ +def translate_children(trans: HT.Translator | t.CPtr, + tree: ast.AST | t.CPtr) -> int: + """遍历 tree.children 并翻译每个子节点 + + Args: + trans: 翻译器(含所有共享状态) + tree: AST 模块节点 + + Returns: + t.CInt: 新增的变量数 + """ + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is None: + return 0 + + cn_count: t.CSizeT = ch.__len__() + added_total: int = 0 + + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: continue + kd: int = child.kind() + + if kd == ast.ASTKind.Import: + trans.ImportsH.HandleImport(child) + elif kd == ast.ASTKind.ImportFrom: + trans.ImportsH.HandleImportFromModule(child) + trans.ImportsH.HandleImportFromNames(child) + elif kd == ast.ASTKind.FunctionDef: + # Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖) + # Phase 1b 全量翻译:正常翻译函数体 + if trans._declare_only == 0: + added: int = HandlesFunctions.translate_function_def(trans, child) + added_total += added + elif trans._declare_only == 1: + _register_cexport_from_funcdef(trans, child) + elif kd == ast.ASTKind.ClassDef: + # ClassDef 在模块级直接处理(不需要 builder) + # _declare_only=2(import扫描模式)时跳过,只处理 import 依赖 + if trans._declare_only != 2: + cd_node: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) + cd_name: str = "?" if cd_node is None or cd_node.name is None else cd_node.name + HandlesClassDef.translate_class_def(trans, child) + elif trans._declare_only == 0 and trans._cur_builder is not None: + # 有 builder → 委托 HandlesBody 分派 + added = HandlesBody.translate_stmt(trans, child) + added_total += added + elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2: + # 模块级 AnnAssign + # _declare_only=2(import扫描模式)时跳过 + # _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断) + # _declare_only=0(全量翻译)时处理所有模块级 AnnAssign + added = handle_module_level_var(trans, child) + added_total += added + elif trans._declare_only == 0 and kd == ast.ASTKind.Assign: + # 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式) + added = handle_module_level_var(trans, child) + added_total += added + + return added_total + + +# ============================================================ +# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量 +# +# 当用户已定义 main(无 wrapper main builder)时,模块级 +# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域 +# ============================================================ +def handle_module_level_var(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理模块级变量声明,创建全局变量""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # CDefine 注解: 编译期常量,不创建全局变量 + # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 + k: int = node.kind() + if k == ast.ASTKind.AnnAssign: + aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa_cd is not None and aa_cd.target is not None: + if aa_cd.target.kind() == ast.ASTKind.Name: + nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target) + if nm_cd.id is not None: + if HandlesAnnAssign.is_cdefine_annotation(aa_cd.annotation) != 0: + val_cd: int = HandlesAnnAssign.extract_cdefine_int_value(aa_cd.value) + HandlesType.register_cdefine_constant(pool, nm_cd.id, val_cd) + return 0 + + # _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量 + # CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过 + if trans._declare_only == 1: + return 0 + + var_name: str = None + var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + init_val: t.CInt64T = 0 + has_init: int = 0 + + if k == ast.ASTKind.AnnAssign: + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa is None or aa.target is None: + return 0 + if aa.target.kind() != ast.ASTKind.Name: + return 0 + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + var_name = nm.id + # 解析类型 + if aa.annotation is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, aa.annotation, trans._imported_modules, trans._from_imports) + if resolved is not None: + var_ty = resolved + # 解析初始值 + if aa.value is not None and aa.value.kind() == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value) + if cn.const_kind == ast.CONST_INT: + init_val = cn.int_val + has_init = 1 + elif k == ast.ASTKind.Assign: + asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) + if asgn is None or asgn.targets is None: + return 0 + targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets + if targets.__len__() < 1: + return 0 + t0: ast.AST | t.CPtr = targets.get(0) + if t0 is None or t0.kind() != ast.ASTKind.Name: + return 0 + nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0) + var_name = nm2.id + if asgn.value is not None and asgn.value.kind() == ast.ASTKind.Constant: + cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value) + if cn2.const_kind == ast.CONST_INT: + init_val = cn2.int_val + has_init = 1 + + if var_name is None: + return 0 + + # 检查是否已注册 + existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + trans.SymTab, var_name) + if existing is not None: + return 0 + + # 创建全局变量 @var_name + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, var_name, var_ty) + if gv is None: + return 0 + llvmlite.module_add_global(mod, gv) + + # 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值) + gv.Linkage = None + if has_init != 0: + init_buf: t.CChar | t.CPtr = pool.alloc(48) + if init_buf is not None: + viperlib.snprintf(init_buf, 48, "%lld", init_val) + gv.Initializer = init_buf + else: + gv.Initializer = "0" + + # 创建 Value 引用(@var_name, 类型为 var_ty*) + var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) + ref_name: t.CChar | t.CPtr = pool.alloc(64) + if ref_name is not None: + viperlib.snprintf(ref_name, 64, "@%s", var_name) + gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name) + + # 注册到模块作用域 + if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0: + return 1 + return 0 + + +# ============================================================ +# create_wrapper_main - 创建包装 main 函数 +# +# 当用户未定义 main 函数时调用。 +# 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder → +# 预扫描 alloca → 翻译子节点 → ret 0 +# ============================================================ +def create_wrapper_main(trans: HT.Translator | t.CPtr, + tree: ast.AST | t.CPtr, + i32_ty: llvmlite.LLVMType | t.CPtr) -> int: + """创建包装 main 函数并翻译所有顶层语句 + + Args: + trans: 翻译器(含所有共享状态) + tree: AST 模块节点 + i32_ty: i32 LLVMType + + Returns: + t.CInt: 新增的变量数 + """ + pool: memhub.MemBuddy | t.CPtr = trans.Pool + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + main_func: llvmlite.Function | t.CPtr = llvmlite.create_function( + pool, mod, "main", i32_ty) + if main_func is None: + stdio.printf("[TR] CreateFunction main returned NULL\n") + return 0 + + entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, main_func, "entry") + if entry_blk is None: + stdio.printf("[TR] CreateBlock returned NULL\n") + return 0 + + builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func) + if builder is None: + stdio.printf("[TR] NewBuilder returned NULL\n") + return 0 + llvmlite.position_at_end(builder, entry_blk) + + # 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问) + trans._cur_func = main_func + trans._cur_builder = builder + + # 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量 + # 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca, + # 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR) + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is not None: + cn_count: t.CSizeT = ch.__len__() + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is not None: + kd: int = child.kind() + if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign: + handle_module_level_var(trans, child) + + # 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca + # (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们) + if ch is not None: + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is not None: + HandlesBody.pre_scan_allocas(trans, child) + + # 翻译子节点 + added_total: int = translate_children(trans, tree) + + # 返回 0 + zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + llvmlite.build_ret(builder, zero_val) + + return added_total diff --git a/App/lib/core/Handles/HandlesNonlocal.py b/App/lib/core/Handles/HandlesNonlocal.py new file mode 100644 index 0000000..6922f7e --- /dev/null +++ b/App/lib/core/Handles/HandlesNonlocal.py @@ -0,0 +1,127 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesVar as HandlesVar + + +# ============================================================ +# HandlesNonlocal - nonlocal 变量访问(通过闭包 env) +# +# 闭包 env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量一个 i8* 指针) +# 指针指向原始变量(可能是 alloca 或全局变量) +# +# 在提升的嵌套函数中: +# 1. 函数签名: define i32 @__closure_{name}(i8* %env) +# 2. 入口处: %env_alloca = alloca i8*; store i8* %env, i8** %env_alloca +# 3. 访问 nonlocal var: +# a. %env_ptr = load i8*, i8** %env_alloca +# b. %addr = gep i8, i8* %env_ptr, i32 (index * 8) +# c. %ptr_addr = bitcast i8* %addr to i8** +# d. %var_ptr_raw = load i8*, i8** %ptr_addr +# e. %var_ptr = bitcast i8* %var_ptr_raw to i32* +# f. read: %val = load i32, i32* %var_ptr +# write: store i32 %new, i32* %var_ptr +# ============================================================ + + +# ============================================================ +# 获取或创建 _env_ptr 变量(存储 env 参数的 alloca) +# ============================================================ +def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """获取或创建 _env_ptr 变量(存储闭包 env 指针)""" + env_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, "_env_ptr") + if env_var is not None: + return env_var + # 创建 alloca 存储 env + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty) + if alloca is None: + return None + HandlesVar.define_var(trans.SymTab, "_env_ptr", alloca) + return alloca + + +# ============================================================ +# 加载 nonlocal 变量值 → 返回 i32 Value +# +# env 直接存储 i32 值(不是指针),每个 nonlocal 变量占 4 字节 +# ============================================================ +def load_nonlocal_var(trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """从闭包 env 加载 nonlocal 变量值(env 直接存储 i32 值)""" + idx: int = HT.get_nonlocal_index(trans, name) + if idx < 0: + return None + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) + + # 1. 加载 env_ptr + env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans) + if env_alloca is None: + return None + env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca) + if env_ptr is None: + return None + + # 2. GEP to offset (idx * 4) — env 直接存储 i32 值 + offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4) + addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val) + if addr is None: + return None + + # 3. Bitcast to i32* and load + var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i32_ptr_ty) + if var_ptr is None: + return None + return llvmlite.build_load(builder, i32_ty, var_ptr) + + +# ============================================================ +# 获取 nonlocal 变量指针(用于 store) +# +# 返回 env 中 i32 槽位的地址(i32*),用于直接 store +# ============================================================ +def get_nonlocal_var_ptr(trans: HT.Translator | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """获取 nonlocal 变量在 env 中的地址(i32*),用于 store 操作""" + idx: int = HT.get_nonlocal_index(trans, name) + if idx < 0: + return None + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) + + # 1. 加载 env_ptr + env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans) + if env_alloca is None: + return None + env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca) + if env_ptr is None: + return None + + # 2. GEP to offset (idx * 4) — env 直接存储 i32 值 + offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4) + addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val) + if addr is None: + return None + + # 3. Bitcast to i32* and return (直接指向 env 中的 i32 槽位) + return llvmlite.build_bitcast(builder, addr, i32_ptr_ty) diff --git a/App/lib/core/Handles/HandlesReturn.py b/App/lib/core/Handles/HandlesReturn.py new file mode 100644 index 0000000..9b077f7 --- /dev/null +++ b/App/lib/core/Handles/HandlesReturn.py @@ -0,0 +1,101 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesVar as HandlesVar + + +# ============================================================ +# HandlesReturn - Return 语句处理(Mixin 继承模式) +# ============================================================ + + +@t.NoVTable +class ReturnHandle(HandlesBase.Mixin): + """Return 语句处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # Handle - 处理 Return 语句,返回 0 + # + # 翻译返回值(若有)并生成 ret 指令 + # ============================================================ + def Handle(self, node: ast.AST | t.CPtr) -> int: + """翻译 Return 语句""" + rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) + if rt is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module + + val: llvmlite.Value | t.CPtr = None + if rt.value is not None: + # return self: 直接返回指针(self 是 SSA 参数 Ptr(struct_ty)) + # translate_value 会 load 得到结构体值,但 return self 需要指针本身 + if rt.value.kind() == ast.ASTKind.Name: + ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rt.value) + if ret_nm is not None and ret_nm.id is not None: + if string.strcmp(ret_nm.id, "self") == 0: + self_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + self.Trans.SymTab, "self") + if self_ptr is not None: + val = self_ptr + if val is None: + val = HandlesExpr.translate_value( + builder, pool, mod, rt.value, + self.Trans._funcs, self.Trans._func_count, self.Trans) + + # val 为 None 时(裸 return):检查当前函数返回类型 + # void 函数(如 __init__/__before_init__)生成 ret void,否则 ret i32 0 + if val is None: + cur_func: llvmlite.Function | t.CPtr = self.Trans._cur_func + is_void_ret: int = 0 + if cur_func is not None: + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func) + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + is_void_ret = 1 + if is_void_ret != 0: + llvmlite.build_ret_void(builder) + return 0 + val = llvmlite.const_int32(pool, 0) + + # 类型转换:确保 val 类型与函数返回类型匹配 + # 处理 i1(bool 比较结果)→ i8(t.CBool)等情况 + # i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF) + cur_func_rt: llvmlite.Function | t.CPtr = self.Trans._cur_func + if cur_func_rt is not None and val is not None and val.Ty is not None: + ret_ty_rt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func_rt) + if ret_ty_rt is not None: + val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) + ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt) + if val_bits != 0 and ret_bits != 0 and val_bits != ret_bits: + if val_bits == 1 and val_bits < ret_bits: + val = llvmlite.build_zext(builder, val, ret_ty_rt) + else: + val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt) + llvmlite.build_ret(builder, val) + return 0 + + +# ============================================================ +# NewReturnHandle - 工厂函数 +# ============================================================ +def NewReturnHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> ReturnHandle | t.CPtr: + h: ReturnHandle | t.CPtr = pool.alloc(ReturnHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, ReturnHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/HandlesStruct.py b/App/lib/core/Handles/HandlesStruct.py new file mode 100644 index 0000000..460e46d --- /dev/null +++ b/App/lib/core/Handles/HandlesStruct.py @@ -0,0 +1,975 @@ +import t, c +from stdint import * +import memhub +import string +import llvmlite +import stdio +import ast +import hashtable + + +# ============================================================ +# HandlesStruct - 结构体类型注册和字段查找 +# +# 管理 class 定义的结构体类型信息: +# - 类名 → LLVM StructType +# - 字段名 → 字段索引和类型 +# +# 使用全局数组存储,线性查找(结构体数量通常很少) +# ============================================================ + +STRUCT_MAX: t.CDefine = 512 +FIELD_MAX: t.CDefine = 32 +FIELD_NAME_MAX: t.CDefine = 64 + + +# ============================================================ +# FieldEntry - 字段信息条目 +# ============================================================ +@t.NoVTable +class FieldEntry: + Name: t.CChar | t.CPtr # 字段名(字符串) + Index: int # 字段在结构体中的索引 + Ty: llvmlite.LLVMType | t.CPtr # 字段的 LLVM 类型 + DefaultVal: ast.AST | t.CPtr # 默认值 AST 节点(None=无默认值) + AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) + + +# ============================================================ +# StructEntry - 结构体注册条目 +# ============================================================ +@t.NoVTable +class StructEntry: + Name: t.CChar | t.CPtr # 类名 + Ty: llvmlite.LLVMType | t.CPtr # LLVM StructType + FieldCount: int # 字段数量 + Fields: FieldEntry | t.CPtr # 字段数组(FIELD_MAX 个槽位) + IsUnion: int # 1=联合体 / 0=普通结构体 + IsOOP: int # 1=OOP结构体(有方法) / 0=纯内存结构体 + HasInit: int # 1=有__init__方法 / 0=无 + HasNew: int # 1=有__new__方法 / 0=无 + HasVTable: int # 1=有虚表 / 0=无虚表 + IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记 + ParentName: t.CChar | t.CPtr # 父类名(None=无父类) + VTableMethodCount: int # 虚表中的方法数量 + VTableMethods: t.CChar | t.CPtr # 虚表方法名数组(每个方法名 str,VTableMethodCount 个) + ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1(None=无 SHA1) + + +# ============================================================ +# 全局注册表(静态分配) +# ============================================================ +_struct_table: StructEntry | t.CPtr = None +_struct_count: int = 0 + + +# ============================================================ +# 跨模块命名空间隔离:per-file 结构体可见性 +# +# _visible_structs: 当前文件可见的结构体名(HashTable,O(1) 查找) +# _strict_visibility: 1=严格模式(仅本地+import可见)/ 0=宽松模式(全部可见) +# +# 每个文件翻译前调用 reset_visible_structs 重置 +# ============================================================ +_visible_structs: hashtable.HashTable | t.CPtr = None +_strict_visibility: int = 0 + + +# ============================================================ +# reset_visible_structs — 重置可见性状态(每个文件翻译前调用) +# ============================================================ +def reset_visible_structs(pool: memhub.MemBuddy | t.CPtr, strict: int): + """重置可见性状态(每个文件翻译前调用) + + pool: 内存分配器(严格模式下创建 HashTable) + strict: 1=严格模式(用户文件),0=宽松模式(includes 文件) + """ + global _visible_structs + global _strict_visibility + _strict_visibility = strict + if strict != 0: + # 严格模式:创建新的 HashTable 记录可见结构体 + _visible_structs = hashtable.HashTable(pool) + else: + # 宽松模式:全部可见,不需要 HashTable + _visible_structs = None + + +# ============================================================ +# add_visible_struct — 添加可见结构体名 +# ============================================================ +def add_visible_struct(pool: memhub.MemBuddy | t.CPtr, name: str): + """添加可见结构体名(类定义时和 from-import 时调用)""" + global _visible_structs + if name is None: + return + # 宽松模式:全部可见,无需记录 + if _strict_visibility == 0: + return + if _visible_structs is None: + return + # 已存在则跳过(HashTable.__setitem__ 会覆盖,此处提前检查避免重复分配) + if _visible_structs.__contains__(name) != 0: + return + _visible_structs.set_int(name, 1) + + +# ============================================================ +# is_struct_visible — 检查结构体是否在当前文件可见 +# ============================================================ +def is_struct_visible(name: str) -> int: + """检查结构体是否可见,返回 1=可见 / 0=不可见""" + if _strict_visibility == 0: + return 1 + if name is None or _visible_structs is None: + return 0 + return _visible_structs.__contains__(name) + + +# ============================================================ +# 初始化结构体注册表 +# ============================================================ +def init_struct_table(pool: memhub.MemBuddy | t.CPtr) -> int: + """初始化结构体注册表,返回 1 成功""" + global _struct_table + global _struct_count + + if _struct_table is not None: + return 1 + + entry_size: t.CSizeT = StructEntry.__sizeof__() + _struct_table = pool.alloc(entry_size * STRUCT_MAX) + if _struct_table is None: + return 0 + string.memset(_struct_table, 0, entry_size * STRUCT_MAX) + _struct_count = 0 + return 1 + + +# ============================================================ +# _get_struct_entry — 获取第 i 个 StructEntry 槽位 +# ============================================================ +def _get_struct_entry(i: int) -> StructEntry | t.CPtr: + """获取第 i 个结构体条目""" + if _struct_table is None or i < 0 or i >= STRUCT_MAX: + return None + entry_size: t.CSizeT = StructEntry.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(_struct_table) + i * entry_size + return (StructEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) + + +# ============================================================ +# _get_field_entry — 获取结构体中第 i 个 FieldEntry 槽位 +# ============================================================ +def _get_field_entry(struct_entry: StructEntry | t.CPtr, i: int) -> FieldEntry | t.CPtr: + """获取结构体中第 i 个字段条目""" + if struct_entry is None or i < 0 or i >= FIELD_MAX: + return None + field_size: t.CSizeT = FieldEntry.__sizeof__() + addr: t.CUInt64T = t.CUInt64T(struct_entry.Fields) + i * field_size + return (FieldEntry | t.CPtr)(t.CVoid(addr, t.CPtr)) + + +# ============================================================ +# register_struct — 注册结构体类型 +# +# 返回 StructEntry 指针,可用于添加字段 +# ============================================================ +def register_struct(pool: memhub.MemBuddy | t.CPtr, + name: str, + struct_ty: llvmlite.LLVMType | t.CPtr, + sha1: str = None) -> StructEntry | t.CPtr: + """注册结构体类型,返回 StructEntry 指针 + + 用类型指针去重(is 比较),不用类名去重。 + 这样跨模块同名类可以共存,各自有独立的字段定义。 + sha1 参数在注册时直接设置 ModuleSha1(避免 set_struct_sha1 找错 entry)。 + """ + if init_struct_table(pool) == 0: + return None + + # 用类型指针去重(同一类型不重复注册,支持跨模块同名类) + for i in range(_struct_count): + existing: StructEntry | t.CPtr = _get_struct_entry(i) + if existing is not None and existing.Ty is not None: + if existing.Ty is struct_ty: + return existing + + if _struct_count >= STRUCT_MAX: + stdio.printf("[STRUCT] table full, cannot register %s\n", name) + return None + + entry: StructEntry | t.CPtr = _get_struct_entry(_struct_count) + if entry is None: + return None + + # 分配字段数组 + field_size: t.CSizeT = FieldEntry.__sizeof__() + entry.Fields = pool.alloc(field_size * FIELD_MAX) + if entry.Fields is None: + return None + string.memset(entry.Fields, 0, field_size * FIELD_MAX) + + # 复制类名 + name_len: t.CSizeT = string.strlen(name) + name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) + if name_buf is not None: + string.strcpy(name_buf, name) + entry.Name = name_buf + + entry.Ty = struct_ty + entry.FieldCount = 0 + + # 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry) + if sha1 is not None: + sha1_len: t.CSizeT = string.strlen(sha1) + sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1) + if sha1_buf is not None: + string.strcpy(sha1_buf, sha1) + entry.ModuleSha1 = sha1_buf + + _struct_count += 1 + return entry + + +# ============================================================ +# set_struct_sha1 — 设置结构体所属模块的 SHA1 +# +# 在翻译类定义时调用,记录类所属模块的 SHA1。 +# 跨模块方法调用时(如 __before_init__/__init__),通过 SHA1 +# 构造正确的函数名("{sha1}.{ClassName}.{method}")。 +# ============================================================ +def set_struct_sha1(pool: memhub.MemBuddy | t.CPtr, + class_name: str, sha1: str) -> int: + """设置结构体所属模块的 SHA1,返回 1=成功 / 0=失败""" + if class_name is None or sha1 is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(class_name) + if entry is None: + return 0 + # 复制 SHA1 字符串(避免悬空指针) + sha1_len: t.CSizeT = string.strlen(sha1) + sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1) + if sha1_buf is None: + return 0 + string.strcpy(sha1_buf, sha1) + entry.ModuleSha1 = sha1_buf + return 1 + + +# ============================================================ +# get_struct_sha1 — 获取结构体所属模块的 SHA1 +# +# 跨模块方法调用时使用,返回 None=无 SHA1(本模块定义或无 SHA1) +# ============================================================ +def get_struct_sha1(class_name: str) -> str: + """获取结构体所属模块的 SHA1,返回 None=无 SHA1""" + if class_name is None or _struct_table is None: + return None + entry: StructEntry | t.CPtr = find_struct(class_name) + if entry is None: + return None + return entry.ModuleSha1 + + +# ============================================================ +# add_field — 向结构体添加字段信息 +# ============================================================ +def add_field(pool: memhub.MemBuddy | t.CPtr, + struct_entry: StructEntry | t.CPtr, + field_name: str, + field_ty: llvmlite.LLVMType | t.CPtr, + default_val: ast.AST | t.CPtr = None, + annot_class_name: t.CChar | t.CPtr = None) -> int: + """向结构体添加字段,返回字段索引(-1 失败) + + default_val: 字段默认值 AST 节点(可选,None=无默认值) + annot_class_name: 原始类型注解的类名(可选,用于联合类型字段的方法调用解析) + """ + if struct_entry is None or field_name is None or field_ty is None: + return -1 + + if struct_entry.FieldCount >= FIELD_MAX: + stdio.printf("[STRUCT] field table full for %s\n", struct_entry.Name) + return -1 + + idx: int = struct_entry.FieldCount + fe: FieldEntry | t.CPtr = _get_field_entry(struct_entry, idx) + if fe is None: + return -1 + + # 复制字段名 + name_len: t.CSizeT = string.strlen(field_name) + name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1) + if name_buf is not None: + string.strcpy(name_buf, field_name) + fe.Name = name_buf + + fe.Index = idx + fe.Ty = field_ty + fe.DefaultVal = default_val + fe.AnnotClassName = annot_class_name + + struct_entry.FieldCount = idx + 1 + return idx + + +# ============================================================ +# find_struct — 按类名查找结构体 +# ============================================================ +def find_struct(name: str) -> StructEntry | t.CPtr: + """按类名查找结构体,返回 StructEntry 或 None""" + if name is None or _struct_table is None: + return None + for i in range(_struct_count): + entry: StructEntry | t.CPtr = _get_struct_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry + return None + + +# ============================================================ +# find_struct_by_module — 按类名 + SHA1 查找结构体 +# +# 跨模块同名类区分:Phase B 重新翻译时,必须找到当前模块 +# 注册的结构体(而非第一个同名条目),否则 struct type、 +# 字段布局、GEP 索引全部错误。 +# ============================================================ +def find_struct_by_module(name: str, sha1: str) -> StructEntry | t.CPtr: + """按类名 + SHA1 查找结构体,返回 StructEntry 或 None + + SHA1 非 None 时:精确匹配 name+sha1,未找到返回 None(不回退,避免跨模块同名找错) + SHA1 为 None 时:回退到 find_struct(name) 按类名查找第一个 + """ + if name is None or _struct_table is None: + return None + if sha1 is not None: + for i in range(_struct_count): + entry: StructEntry | t.CPtr = _get_struct_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + if entry.ModuleSha1 is not None: + if string.strcmp(entry.ModuleSha1, sha1) == 0: + return entry + # SHA1 查找失败:不回退到 find_struct(会返回跨模块同名错误 entry) + # 返回 None 让调用方创建新类型,避免 Phase B 用错误类型短路 + return None + # 无 SHA1:按类名查找第一个 + return find_struct(name) + + +# ============================================================ +# find_struct_by_type — 按类型指针查找结构体(is 身份比较) +# +# 用于 _translate_oop_methods 等已有 struct_ty 的场景, +# 直接用指针身份定位 entry,规避跨模块同名类 find_struct 找错的问题。 +# ============================================================ +def find_struct_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> StructEntry | t.CPtr: + """按类型指针查找结构体(is 比较),返回 StructEntry 或 None""" + if struct_ty is None or _struct_table is None: + return None + for i in range(_struct_count): + entry: StructEntry | t.CPtr = _get_struct_entry(i) + if entry is not None and entry.Ty is not None: + if entry.Ty is struct_ty: + return entry + return None + + +# ============================================================ +# lookup_field — 按结构体类型和字段名查找字段信息 +# ============================================================ +def lookup_field(struct_ty: llvmlite.LLVMType | t.CPtr, + field_name: str) -> FieldEntry | t.CPtr: + """按结构体类型和字段名查找字段信息 + + 两遍查找策略(跨模块同名类冲突的根本修复): + 第一遍: 类型指针 is 身份比较(最高优先级,类型唯一确定 entry) + 第二遍: 名称回退(is 未匹配时,按类名/strstr 匹配,字段未找到时 continue) + """ + if struct_ty is None or field_name is None or _struct_table is None: + return None + + # ============================================================ + # 两遍查找策略(跨模块同名类冲突的根本修复): + # + # 第一遍: 用类型指针 is 身份比较(最高优先级) + # - is 匹配唯一确定 entry,字段未找到直接返回 None + # - 规避联合类型 == BUG,且不受遍历顺序影响 + # + # 第二遍: 名称回退(is 未匹配到任何 entry 时才执行) + # - 用于未注册类型或 is 不可靠的场景 + # - 名称匹配但字段未找到时 continue(继续检查其他同名 entry) + # ============================================================ + + # 第一遍: is 身份比较 + for i in range(_struct_count): + entry: StructEntry | t.CPtr = _get_struct_entry(i) + if entry is not None and entry.Ty is not None: + if entry.Ty is struct_ty: + # is 匹配,查找字段 + for fi in range(entry.FieldCount): + fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi) + if fe is not None and fe.Name is not None: + if string.strcmp(fe.Name, field_name) == 0: + return fe + # is 匹配但字段未找到(类型唯一确定,无需继续) + return None + + # 第二遍: 名称回退(is 未匹配到) + ty_name: str = _extract_struct_name(struct_ty) + if ty_name is not None: + for i in range(_struct_count): + entry: StructEntry | t.CPtr = _get_struct_entry(i) + if entry is not None and entry.Name is not None: + matched: int = 0 + if string.strcmp(entry.Name, ty_name) == 0: + matched = 1 + elif string.strstr(ty_name, entry.Name) is not None: + matched = 1 + if matched != 0: + # 查找字段 + for fi in range(entry.FieldCount): + fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi) + if fe is not None and fe.Name is not None: + if string.strcmp(fe.Name, field_name) == 0: + return fe + # 名称匹配但字段未找到,继续检查其他同名 entry(跨模块同名) + continue + # 所有条目都未匹配 + return None + + +# ============================================================ +# lookup_field_by_class — 按类名和字段名查找字段信息 +# ============================================================ +def lookup_field_by_class(class_name: str, + field_name: str, + sha1: str = None) -> FieldEntry | t.CPtr: + """按类名和字段名查找字段信息 + + 优先用 SHA1 匹配(跨模块同名类区分),无 SHA1 时按类名查找第一个 + """ + if class_name is None or field_name is None: + return None + + # 优先用 SHA1 匹配(跨模块同名类区分) + if sha1 is not None: + sha1_matched: int = 0 + for i in range(_struct_count): + entry: StructEntry | t.CPtr = _get_struct_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, class_name) == 0: + if entry.ModuleSha1 is not None: + if string.strcmp(entry.ModuleSha1, sha1) == 0: + sha1_matched = 1 + # SHA1 + 类名匹配,查找字段 + for fi in range(entry.FieldCount): + fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi) + if fe is not None and fe.Name is not None: + if string.strcmp(fe.Name, field_name) == 0: + return fe + return None + + # 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个 + entry = find_struct(class_name) + if entry is None: + return None + for fi in range(entry.FieldCount): + fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi) + if fe is not None and fe.Name is not None: + if string.strcmp(fe.Name, field_name) == 0: + return fe + return None + + +# ============================================================ +# get_struct_type — 按类名获取结构体的 LLVM 类型 +# ============================================================ +def get_struct_type(class_name: str) -> llvmlite.LLVMType | t.CPtr: + """按类名获取结构体的 LLVM 类型""" + entry: StructEntry | t.CPtr = find_struct(class_name) + if entry is not None: + return entry.Ty + return None + + +# ============================================================ +# get_field_by_index — 按类名和字段索引获取字段信息 +# +# 用于构造函数 Point(10, 20) 按顺序访问字段 +# ============================================================ +def get_field_by_index(class_name: str, + idx: int) -> FieldEntry | t.CPtr: + """按类名和字段索引获取字段信息""" + if class_name is None: + return None + entry: StructEntry | t.CPtr = find_struct(class_name) + if entry is None: + return None + if idx < 0 or idx >= entry.FieldCount: + return None + return _get_field_entry(entry, idx) + + +# ============================================================ +# struct_has_defaults — 检查结构体是否有任何带默认值的字段 +# ============================================================ +def struct_has_defaults(class_name: str) -> int: + """检查结构体是否有任何带默认值的字段,返回 1=有 / 0=无""" + if class_name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(class_name) + if entry is None: + return 0 + for fi in range(entry.FieldCount): + fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi) + if fe is not None and fe.DefaultVal is not None: + return 1 + return 0 + + +# ============================================================ +# get_struct_type_from_value — 从 LLVM Value 的类型推断结构体类型 +# +# 如果 value 是 Ptr(Struct(...)),返回 Struct 类型 +# ============================================================ +def _is_struct_type(ty: llvmlite.LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Struct 类型(独立函数,规避嵌套 match 编译器 BUG)""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Struct(fields, fcount, name): + return 1 + case _: + return 0 + + +def get_struct_type_from_value(val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """从 Value 的类型推断结构体类型""" + if val is None or val.Ty is None: + return None + match val.Ty: + case llvmlite.LLVMType.Ptr(pointee): + if _is_struct_type(pointee) != 0: + return pointee + return None + case _: + return None + + +# ============================================================ +# 联合体支持函数 +# ============================================================ + +# ============================================================ +# mark_as_union — 标记已注册的结构体为联合体 +# +# 联合体用 Struct([Array(Int8, max_size)]) 表示, +# 注册时用 register_struct 注册类型,再用此函数标记 IsUnion=1 +# ============================================================ +def mark_as_union(name: str) -> int: + """标记已注册的结构体为联合体,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + entry.IsUnion = 1 + return 1 + + +# ============================================================ +# is_union_by_name — 按类名检查是否为联合体 +# ============================================================ +def is_union_by_name(name: str) -> int: + """按类名检查是否为联合体,返回 1=是 / 0=否""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + return entry.IsUnion + + +# ============================================================ +# is_union_by_type — 按类型指针检查是否为联合体 +# ============================================================ +def is_union_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> int: + """按类型指针检查是否为联合体,返回 1=是 / 0=否 + + 先尝试类型指针 == 比较,失败时回退到名称匹配 + """ + if struct_ty is None or _struct_table is None: + return 0 + ty_name: str = _extract_struct_name(struct_ty) + for i in range(_struct_count): + entry: StructEntry | t.CPtr = _get_struct_entry(i) + if entry is not None and entry.Ty is not None: + matched: int = 0 + if entry.Ty is struct_ty: + matched = 1 + elif ty_name is not None and entry.Name is not None: + if string.strcmp(entry.Name, ty_name) == 0: + matched = 1 + elif string.strstr(ty_name, entry.Name) is not None: + matched = 1 + if matched != 0: + return entry.IsUnion + return 0 + + +# ============================================================ +# OOP 支持函数 +# ============================================================ + +# ============================================================ +# mark_as_oop — 标记已注册的结构体为 OOP(有方法) +# ============================================================ +def mark_as_oop(name: str) -> int: + """标记已注册的结构体为 OOP,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + entry.IsOOP = 1 + return 1 + + +# ============================================================ +# is_oop_by_name — 按类名检查是否为 OOP 结构体 +# ============================================================ +def is_oop_by_name(name: str) -> int: + """按类名检查是否为 OOP 结构体,返回 1=是 / 0=否""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + return entry.IsOOP + + +# ============================================================ +# mark_has_init — 标记结构体拥有 __init__ 方法 +# ============================================================ +def mark_has_init(name: str) -> int: + """标记结构体拥有 __init__ 方法,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + entry.HasInit = 1 + return 1 + + +# ============================================================ +# has_init_by_name — 按类名检查是否有 __init__ 方法 +# ============================================================ +def has_init_by_name(name: str) -> int: + """按类名检查是否有 __init__ 方法,返回 1=有 / 0=无""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + return entry.HasInit + + +# ============================================================ +# mark_has_new — 标记结构体拥有 __new__ 方法 +# ============================================================ +def mark_has_new(name: str) -> int: + """标记结构体拥有 __new__ 方法,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + entry.HasNew = 1 + return 1 + + +# ============================================================ +# has_new_by_name — 按类名检查是否有 __new__ 方法 +# ============================================================ +def has_new_by_name(name: str) -> int: + """按类名检查是否有 __new__ 方法,返回 1=有 / 0=无""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + return entry.HasNew + + +# ============================================================ +# get_class_name_by_type — 按 LLVM 类型指针查找类名 +# +# 用于方法调用:从变量类型 Ptr(Struct(...)) 反查类名, +# 以构造 ClassName.method_name 进行方法查找 +# ============================================================ +def get_class_name_by_type(pool: memhub.MemBuddy | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr) -> str: + """按类型指针查找类名,返回类名字符串或 None""" + if struct_ty is None or _struct_table is None: + return None + for i in range(_struct_count): + entry: StructEntry | t.CPtr = _get_struct_entry(i) + if entry is not None and entry.Ty is not None: + if entry.Ty is struct_ty: + return entry.Name + # 回退: 类型指针比较失败时,遍历所有注册的结构体按名称匹配 + # 提取 struct_ty 的 Name 字段(可能是 "SHA1.ClassName" 格式) + ty_name: str = _extract_struct_name(struct_ty) + if ty_name is not None: + for j in range(_struct_count): + entry2: StructEntry | t.CPtr = _get_struct_entry(j) + if entry2 is not None and entry2.Name is not None: + # 构造 "SHA1.ClassName" 格式进行比较 + entry2_sha1: str = entry2.ModuleSha1 + if entry2_sha1 is not None: + full_nm: t.CChar | t.CPtr = pool.alloc(128) + if full_nm is not None: + viperlib.snprintf(full_nm, 128, "%s.%s", entry2_sha1, entry2.Name) + if string.strcmp(full_nm, ty_name) == 0: + return entry2.Name + # 也直接比较类名(struct_ty 的 Name 可能无 SHA1 前缀) + if string.strcmp(entry2.Name, ty_name) == 0: + return entry2.Name + # 最后回退: strstr 检查包含关系 + # ty_name 可能是 "SHA1.Counter",entry2.Name 是 "Counter" + if string.strstr(ty_name, entry2.Name) is not None: + return entry2.Name + return None + + +# ============================================================ +# _extract_struct_name — 从 LLVMType 提取 Struct 变体的 Name 字段 +# ============================================================ +def _extract_struct_name(ty: llvmlite.LLVMType | t.CPtr) -> str: + """从 LLVMType 提取 Struct 变体的 Name 字段,返回 None 非 Struct""" + if ty is None: + return None + match ty: + case llvmlite.LLVMType.Struct(fields, fcount, name): + return name + case _: + return None + + +# ============================================================ +# VTable 支持函数 +# ============================================================ + +# ============================================================ +# mark_has_vtable — 标记结构体拥有虚表 +# ============================================================ +def mark_has_vtable(name: str) -> int: + """标记结构体拥有虚表,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + entry.HasVTable = 1 + return 1 + + +# ============================================================ +# has_vtable_by_name — 按类名检查是否有虚表 +# ============================================================ +def has_vtable_by_name(name: str) -> int: + """按类名检查是否有虚表,返回 1=有 / 0=无""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + return entry.HasVTable + + +# ============================================================ +# mark_novtable — 标记结构体为 @t.NoVTable +# ============================================================ +def mark_novtable(name: str) -> int: + """标记结构体为 NoVTable,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + entry.IsNoVTable = 1 + return 1 + + +# ============================================================ +# is_novtable_by_name — 按类名检查是否为 NoVTable +# ============================================================ +def is_novtable_by_name(name: str) -> int: + """按类名检查是否为 NoVTable,返回 1=是 / 0=否""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + return entry.IsNoVTable + + +# ============================================================ +# set_parent_name — 设置父类名 +# ============================================================ +def set_parent_name(name: str, parent_name: str) -> int: + """设置结构体的父类名,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + entry.ParentName = parent_name + return 1 + + +# ============================================================ +# get_parent_name — 获取父类名 +# ============================================================ +def get_parent_name(name: str) -> str: + """获取结构体的父类名,返回 None=无父类""" + if name is None: + return None + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return None + return entry.ParentName + + +# ============================================================ +# set_vtable_methods — 设置虚表方法名数组 +# +# methods 是一个 str 数组(每个元素是方法名字符串指针), +# count 是方法数量。数组直接引用,不复制。 +# ============================================================ +def set_vtable_methods(name: str, methods: t.CChar | t.CPtr, count: int) -> int: + """设置虚表方法名数组,返回 1=成功 / 0=失败""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + entry.VTableMethods = methods + entry.VTableMethodCount = count + return 1 + + +# ============================================================ +# get_vtable_method_index — 获取方法在虚表中的索引 +# +# 在 VTableMethods 数组中查找方法名,返回索引(-1=未找到) +# ============================================================ +def get_vtable_method_index(name: str, method_name: str) -> int: + """获取方法在虚表中的索引,返回 -1=未找到""" + if name is None or method_name is None: + return -1 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None or entry.VTableMethods is None: + return -1 + # VTableMethods 字段声明为 t.CChar*,但实际存储的是 t.CSizeT 数组 + # 必须转换为 t.CSizeT* 才能正确读取 8 字节指针值 + methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr)) + for i in range(entry.VTableMethodCount): + mname_addr: t.CSizeT = methods_arr[i] + if mname_addr == 0: + continue + mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) + if mname is not None and string.strcmp(mname, method_name) == 0: + return i + return -1 + + +# ============================================================ +# get_vtable_method_count — 获取虚表方法数量 +# ============================================================ +def get_vtable_method_count(name: str) -> int: + """获取虚表方法数量""" + if name is None: + return 0 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return 0 + return entry.VTableMethodCount + + +# ============================================================ +# get_vtable_method_name — 获取虚表中第 idx 个方法名 +# +# 返回方法名字符串指针,None=越界或未设置 +# ============================================================ +def get_vtable_method_name(name: str, idx: int) -> str: + """获取虚表中第 idx 个方法名,返回 None=越界""" + if name is None or idx < 0: + return None + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None or entry.VTableMethods is None: + return None + if idx >= entry.VTableMethodCount: + return None + methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr)) + mname_addr: t.CSizeT = methods_arr[idx] + if mname_addr == 0: + return None + return (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr)) + + +# ============================================================ +# get_field_count — 获取结构体字段数量(访问器,绕过 stub 类型限制) +# ============================================================ +def get_field_count(name: str) -> int: + """获取结构体字段数量,返回 -1=未找到""" + if name is None: + return -1 + entry: StructEntry | t.CPtr = find_struct(name) + if entry is None: + return -1 + return entry.FieldCount + + +# ============================================================ +# get_field_name_ptr — 获取 FieldEntry 的字段名指针(访问器) +# ============================================================ +def get_field_name_ptr(fe: FieldEntry | t.CPtr) -> str: + """获取 FieldEntry 的字段名,返回 None=未设置""" + if fe is None: + return None + return fe.Name + + +# ============================================================ +# get_field_type_ptr — 获取 FieldEntry 的字段类型指针(访问器) +# ============================================================ +def get_field_type_ptr(fe: FieldEntry | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """获取 FieldEntry 的字段类型,返回 None=未设置""" + if fe is None: + return None + return fe.Ty + + +# ============================================================ +# get_field_default_ptr — 获取 FieldEntry 的默认值 AST 指针(访问器) +# ============================================================ +def get_field_default_ptr(fe: FieldEntry | t.CPtr) -> ast.AST | t.CPtr: + """获取 FieldEntry 的默认值 AST 节点,返回 None=无默认值""" + if fe is None: + return None + return fe.DefaultVal + + +# ============================================================ +# get_field_annot_class_name — 获取 FieldEntry 的注解类名(访问器) +# ============================================================ +def get_field_annot_class_name(fe: FieldEntry | t.CPtr) -> str: + """获取 FieldEntry 的原始类型注解类名,返回 None=未设置""" + if fe is None: + return None + return fe.AnnotClassName diff --git a/App/lib/core/Handles/HandlesTranslator.py b/App/lib/core/Handles/HandlesTranslator.py new file mode 100644 index 0000000..87570c7 --- /dev/null +++ b/App/lib/core/Handles/HandlesTranslator.py @@ -0,0 +1,417 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import stdlib +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesMain as HandlesMain +import lib.core.Handles.HandlesAssign as HandlesAssign +import lib.core.Handles.HandlesReturn as HandlesReturn +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.Handles.HandlesAugAssign as HandlesAugAssign +import lib.core.Handles.HandlesIf as HandlesIf +import lib.core.Handles.HandlesWhile as HandlesWhile +import lib.core.Handles.HandlesFor as HandlesFor +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.Projectrans.Config as Config + +# ============================================================ +# HandlesTranslator - 翻译器状态管理 + 主入口 +# +# 从 translator.py 拆分出来,负责: +# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入) +# 2. translate() - 主翻译入口 +# 3. dump_ir() - IR 输出 +# +# 语句/表达式翻译全部委托给 Handles 模块: +# HandlesMain - wrapper main 创建 + children 遍历 +# HandlesBody - 语句分派 +# HandlesExpr - 表达式翻译 +# HandlesFunctions - 函数定义处理 +# 注意:str = bytes = t.CChar | t.CPtr = i8* +# ============================================================ + +# 常量 +MAX_VARS: t.CDefine = 256 +MAX_FUNCS: t.CDefine = 256 +MAX_GLOBAL_NAMES: t.CDefine = 32 + + +@t.NoVTable +class Translator: + """翻译器:管理编译状态,委托 Handles 模块执行翻译""" + + # LLVM 上下文(共享状态) + Module: llvmlite.LLVMModule | t.CPtr + Pool: memhub.MemBuddy | t.CPtr + + # 函数表 + _funcs: HandlesExprCall.FuncEntry | t.CPtr + _func_count: t.CInt + + # 导入模块跟踪 + _imported_modules: str + _from_imports: str + + # 当前翻译上下文 + _cur_func: llvmlite.Function | t.CPtr + _cur_builder: llvmlite.IRBuilder | t.CPtr + + # 循环控制流目标(break/continue) + _break_bb: llvmlite.BasicBlock | t.CPtr + _continue_bb: llvmlite.BasicBlock | t.CPtr + + # 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调) + _label_counter: t.CInt + + # global 声明的变量名集合(当前函数内) + _global_names: str + _global_name_count: t.CInt + + # nonlocal 声明的变量名集合(当前函数内) + _nonlocal_names: str + _nonlocal_name_count: t.CInt + + # 闭包相关:当前函数名(用于嵌套函数提升命名) + _cur_func_name: str + + # 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间) + ModuleSha1: str + # 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...) + # None 表示当前文件是顶级模块(无包),相对导入无法解析 + CurrentPackage: str + # 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移) + _closure_env_offsets: t.CInt + _closure_env_count: t.CInt + + # 泛型特化上下文:当前正在特化的类型参数名/实参名列表 + # 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型 + # None 表示不在泛型特化上下文中 + GenericTypeParamNames: list[str] | t.CPtr + GenericTypeArgs: list[str] | t.CPtr + + # Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译 + _declare_only: t.CInt + + # 子 Handle 指针(每个 Handle 一个槽,通过 Mixin 回指针访问本结构体) + AssignH: HandlesAssign.AssignHandle | t.CPtr + ReturnH: HandlesReturn.ReturnHandle | t.CPtr + ImportsH: HandlesImports.ImportsHandle | t.CPtr + AnnAssignH: HandlesAnnAssign.AnnAssignHandle | t.CPtr + AugAssignH: HandlesAugAssign.AugAssignHandle | t.CPtr + IfH: HandlesIf.IfHandle | t.CPtr + WhileH: HandlesWhile.WhileHandle | t.CPtr + ForH: HandlesFor.ForHandle | t.CPtr + ExprH: HandlesExpr.ExprHandle | t.CPtr + ExprCallH: HandlesExprCall.ExprCallHandle | t.CPtr + + # 嵌套作用域符号表 + SymTab: HandlesVar.SymbolTable | t.CPtr + + def __init__(self): + self.Module = None + self.Pool = None + self._funcs = None + self._func_count = 0 + self._cur_func = None + self._cur_builder = None + self._break_bb = None + self._continue_bb = None + self._label_counter = 0 + self._imported_modules = None + self._from_imports = None + self._global_names = None + self._global_name_count = 0 + self._nonlocal_names = None + self._nonlocal_name_count = 0 + self._cur_func_name = None + self.ModuleSha1 = None + self.CurrentPackage = None + self._closure_env_offsets = 0 + self._closure_env_count = 0 + self.GenericTypeParamNames = None + self.GenericTypeArgs = None + self._declare_only = 0 + self.AssignH = None + self.ReturnH = None + self.ImportsH = None + self.AnnAssignH = None + self.AugAssignH = None + self.IfH = None + self.WhileH = None + self.ForH = None + self.ExprH = None + self.ExprCallH = None + self.SymTab = None + + # ============================================================ + # 状态初始化 + # ============================================================ + def _init_state(self, pool: memhub.MemBuddy | t.CPtr): + """初始化变量表、函数表和子 Handle""" + self.Pool = pool + if self._funcs is None: + self._funcs = HandlesExprCall.init_func_table(pool, MAX_FUNCS) + # 嵌套作用域符号表(新版) + if self.SymTab is None: + self.SymTab = HandlesVar.init_symbol_table(pool) + # global/nonlocal 名称集合缓冲区(32 个 char* 指针 = 256 字节) + if self._global_names is None: + self._global_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8) + if self._global_names is not None: + string.memset(self._global_names, 0, MAX_GLOBAL_NAMES * 8) + self._global_name_count = 0 + if self._nonlocal_names is None: + self._nonlocal_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8) + if self._nonlocal_names is not None: + string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8) + self._nonlocal_name_count = 0 + # 创建子 Handle(传入 self 作为 Mixin 回指针) + if self.AssignH is None: + self.AssignH = HandlesAssign.NewAssignHandle(pool, self) + if self.ReturnH is None: + self.ReturnH = HandlesReturn.NewReturnHandle(pool, self) + if self.ImportsH is None: + self.ImportsH = HandlesImports.NewImportsHandle(pool, self) + if self.AnnAssignH is None: + self.AnnAssignH = HandlesAnnAssign.NewAnnAssignHandle(pool, self) + if self.AugAssignH is None: + self.AugAssignH = HandlesAugAssign.NewAugAssignHandle(pool, self) + if self.IfH is None: + self.IfH = HandlesIf.NewIfHandle(pool, self) + if self.WhileH is None: + self.WhileH = HandlesWhile.NewWhileHandle(pool, self) + if self.ForH is None: + self.ForH = HandlesFor.NewForHandle(pool, self) + if self.ExprH is None: + self.ExprH = HandlesExpr.NewExprHandle(pool, self) + if self.ExprCallH is None: + self.ExprCallH = HandlesExprCall.NewExprCallHandle(pool, self) + + # ============================================================ + # 主翻译入口 + # ============================================================ + def translate(self, tree: ast.AST | t.CPtr) -> int: + """将 AST 翻译为 LLVM IR""" + if tree is None: + return 1 + if _mbuddy is None: + return 1 + + pool: memhub.MemBuddy | t.CPtr = _mbuddy + + # 初始化状态 + self._init_state(pool) + + # 创建 LLVM 模块 + mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main") + if mod is None: + stdio.printf("[TR] NewModule returned NULL\n") + return 1 + self.Module = mod + + # 设置目标(优先使用 project.vpj 中的配置) + triple: str = Config.TargetTriple + if triple is None: + triple = "x86_64-pc-windows-msvc" + llvmlite.module_set_target(mod, triple) + + # 类型 + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 声明 printf + printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, "printf", i32_ty) + if printf_func is None: + stdio.printf("[TR] CreateDeclare printf returned NULL\n") + return 1 + llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt") + printf_func.IsVarArg = 1 + + # 声明 malloc(闭包分配用) + malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare( + pool, mod, "malloc", i8_ptr_ty) + if malloc_func is not None: + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + llvmlite.add_param(pool, malloc_func, i64_ty, "size") + + # 检查用户是否定义了 main 函数 + has_user_main: int = 0 + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is not None: + cn_count: t.CSizeT = ch.__len__() + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is not None and child.kind() == ast.ASTKind.FunctionDef: + fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) + if fd is not None and fd.name is not None: + if string.strcmp(fd.name, "main") == 0: + has_user_main = 1 + break + + if self._declare_only != 0: + # Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder + self._translate_module_level(pool, mod, tree) + elif has_user_main == 0: + # 无用户 main → 只翻译模块级语句,不创建 wrapper main + # 修复:避免每个文件都生成 define i32 @main() 导致链接时 main 冲突 + # 只有包含 def main() 的入口文件才会有 define i32 @main() + self._translate_module_level(pool, mod, tree) + else: + # 用户已定义 main → 委托 HandlesMain 翻译模块级 + self._translate_module_level(pool, mod, tree) + + return 0 + + # ============================================================ + # 包装 main 函数(无用户 main 时)→ 委托 HandlesMain + # ============================================================ + def _translate_wrapper_main(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + tree: ast.AST | t.CPtr, + i32_ty: llvmlite.LLVMType | t.CPtr): + """委托 HandlesMain.create_wrapper_main() 创建包装 main(trans 单参)""" + added: int = HandlesMain.create_wrapper_main(self, tree, i32_ty) + + # ============================================================ + # 模块级翻译(用户已定义 main)→ 委托 HandlesMain + # ============================================================ + def _translate_module_level(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + tree: ast.AST | t.CPtr): + """委托 HandlesMain.translate_children() 翻译模块级语句(trans 单参)""" + # 全量翻译模式下,先处理导入语句,再创建前向声明,解决前向引用问题 + if self._declare_only == 0: + # 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充 + # (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入) + ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children + if ch is not None: + cn_count: t.CSizeT = ch.__len__() + for ci in range(cn_count): + child: ast.AST | t.CPtr = ch.get(ci) + if child is None: + continue + kd: int = child.kind() + if kd == ast.ASTKind.Import: + self.ImportsH.HandleImport(child) + elif kd == ast.ASTKind.ImportFrom: + self.ImportsH.HandleImportFromModule(child) + self.ImportsH.HandleImportFromNames(child) + # 创建前向声明 + HandlesFunctions.forward_declare_functions(self, tree) + added: int = HandlesMain.translate_children(self, tree) + + # ============================================================ + # IR 输出 + # ============================================================ + def dump_ir(self, buf: bytes, size: t.CSizeT, mode: int): + """将 LLVM IR 输出到缓冲区 + + mode: 0=完整, 1=stub(仅声明), 2=text(仅代码) + """ + if self.Module is None or buf is None: + return + if _mbuddy is None: + return + buf[0] = '\0' + llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode) + + +# ============================================================ +# global/nonlocal 名称管理(模块级辅助函数) +# ============================================================ +def add_global_name(trans: HT.Translator | t.CPtr, name: str): + """添加一个 global 变量名""" + if trans is None or name is None: + return + if trans._global_name_count >= MAX_GLOBAL_NAMES: + return + if trans._global_names is None: + return + # 检查是否已存在 + if is_global_name(trans, name) != 0: + return + entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + slot_ptr[0] = name + trans._global_name_count += 1 + + +def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int: + """检查 name 是否在当前函数的 global 集合中""" + if trans is None or name is None or trans._global_names is None: + return 0 + for i in range(trans._global_name_count): + entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + i * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + entry: str = slot_ptr[0] + if entry is not None: + if string.strcmp(entry, name) == 0: + return 1 + return 0 + + +def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str): + """添加一个 nonlocal 变量名""" + if trans is None or name is None: + return + if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES: + return + if trans._nonlocal_names is None: + return + if is_nonlocal_name(trans, name) != 0: + return + entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + slot_ptr[0] = name + trans._nonlocal_name_count += 1 + trans._closure_env_count += 1 + + +def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int: + """检查 name 是否在当前函数的 nonlocal 集合中""" + if trans is None or name is None or trans._nonlocal_names is None: + return 0 + for i in range(trans._nonlocal_name_count): + entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + entry: str = slot_ptr[0] + if entry is not None: + if string.strcmp(entry, name) == 0: + return 1 + return 0 + + +def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int: + """获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1""" + if trans is None or name is None or trans._nonlocal_names is None: + return -1 + for i in range(trans._nonlocal_name_count): + entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8 + slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr) + entry: str = slot_ptr[0] + if entry is not None: + if string.strcmp(entry, name) == 0: + return i + return -1 + + +def clear_scope_names(trans: HT.Translator | t.CPtr): + """清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)""" + if trans is None: + return + trans._global_name_count = 0 + trans._nonlocal_name_count = 0 + trans._closure_env_count = 0 + + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesType.py b/App/lib/core/Handles/HandlesType.py new file mode 100644 index 0000000..fd8c9a2 --- /dev/null +++ b/App/lib/core/Handles/HandlesType.py @@ -0,0 +1,1185 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import sys +import stdlib +import viperlib +import w32.fileio as fileio +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesStruct as HandlesStruct + + +# ============================================================ +# HandlesType - 类型映射与解析(模块级纯函数) +# +# str = bytes = t.CChar | t.CPtr = i8* +# ============================================================ + + +# ============================================================ +# 全局当前文件名(每个文件翻译前由 BuildPipeline 设置) +# ============================================================ +_g_current_file: str = None + + +# ============================================================ +# 全局泛型特化上下文(由 _specialize_generic_class 设置/清除) +# +# 当翻译泛型类方法体时,需要将类型参数 T 替换为具体类型。 +# resolve_annotation_type 在解析 Name 节点时检查此上下文。 +# ============================================================ +_g_generic_tp_names: list[str] | t.CPtr = None +_g_generic_type_args: list[str] | t.CPtr = None + + +# ============================================================ +# 全局 CDefine 编译期常量表 +# +# 存储 NAME: t.CDefine = value 定义的常量, +# 供 t.CArray[elem_ty, NAME] 等 编译期类型解析使用。 +# 每个模块翻译开始时由 clear_cdefine_constants 清空。 +# ============================================================ +_g_cdefine_names: list[str] | t.CPtr = None +_g_cdefine_values: list[str] | t.CPtr = None + + +def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr, + name: str, value: int) -> None: + """注册 CDefine 编译期常量到全局表""" + global _g_cdefine_names, _g_cdefine_values + if _g_cdefine_names is None: + _g_cdefine_names = list[str](pool, 64) + _g_cdefine_values = list[str](pool, 64) + _g_cdefine_names.append(name) + val_buf: str = pool.alloc(32) + if val_buf is not None: + viperlib.snprintf(val_buf, 32, "%d", value) + _g_cdefine_values.append(val_buf) + else: + _g_cdefine_values.append("0") + + +def lookup_cdefine_constant(name: str) -> int: + """查找 CDefine 编译期常量,返回值或 -1(未找到)""" + if _g_cdefine_names is None: + return -1 + n: t.CSizeT = _g_cdefine_names.__len__() + i: t.CSizeT + for i in range(n): + nm: str = _g_cdefine_names.get(i) + if nm is not None and string.strcmp(nm, name) == 0: + val_str: str = _g_cdefine_values.get(i) + if val_str is not None: + return string.atoi(val_str) + return -1 + + +def clear_cdefine_constants() -> None: + """清空 CDefine 常量表(模块切换时调用)""" + global _g_cdefine_names, _g_cdefine_values + _g_cdefine_names = None + _g_cdefine_values = None + + +def set_generic_context(tp_names: list[str] | t.CPtr, + type_args: list[str] | t.CPtr): + """设置泛型特化上下文(进入泛型类方法体翻译时调用)""" + global _g_generic_tp_names, _g_generic_type_args + _g_generic_tp_names = tp_names + _g_generic_type_args = type_args + + +def clear_generic_context(): + """清除泛型特化上下文(离开泛型类方法体翻译时调用)""" + global _g_generic_tp_names, _g_generic_type_args + _g_generic_tp_names = None + _g_generic_type_args = None + + +def resolve_generic_type_name(name: str) -> str: + """如果 name 是泛型类型参数,返回对应的具体类型名;否则返回 name 本身 + + 用于表达式中的 T 替换(如 T.__sizeof__() → int.__sizeof__()) + """ + if name is None: + return name + if _g_generic_tp_names is not None and _g_generic_type_args is not None: + rg_n: t.CSizeT = _g_generic_tp_names.__len__() + rg_i: t.CSizeT + for rg_i in range(rg_n): + rg_tpn: str = _g_generic_tp_names.get(rg_i) + if rg_tpn is not None and string.strcmp(name, rg_tpn) == 0: + rg_ta: str = _g_generic_type_args.get(rg_i) + if rg_ta is not None: + return rg_ta + return name + + +# ============================================================ +# _get_type_name_from_annotation - 从类型注解节点提取类型名字符串 +# +# 用于泛型特化时构造 mangled name(如 "list[AST|t.CPtr]") +# +# Name(id="AST") -> "AST" +# Attribute(value=Name(id="t"), attr="CPtr") -> "t.CPtr" +# BinOp(Name("AST"), BitOr, Attribute(Name("t"), "CPtr")) -> "AST|t.CPtr" +# ============================================================ +def _get_type_name_from_annotation(pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr) -> str: + """从类型注解节点提取类型名(支持 Name/Attribute/BinOp)""" + if node is None: + return None + k: int = node.kind() + # Constant: 字符串注解,直接返回字符串值 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR and cn.str_val is not None: + return cn.str_val + return None + # Name: 直接返回 id + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + return nm.id + # Attribute: 构造 "module.attr" 格式 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return None + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is not None: + total: t.CSizeT = string.strlen(mod_nm.id) + 1 + string.strlen(at.attr) + 1 + buf: str = pool.alloc(total) + if buf is not None: + buf[0] = '\0' + string.strcat(buf, mod_nm.id) + string.strcat(buf, ".") + string.strcat(buf, at.attr) + return buf + return at.attr + # BinOp (BitOr): 构造 "left|right" 格式 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + left_str: str = _get_type_name_from_annotation(pool, bop.left) + right_str: str = _get_type_name_from_annotation(pool, bop.right) + if left_str is not None and right_str is not None: + total2: t.CSizeT = string.strlen(left_str) + 1 + string.strlen(right_str) + 1 + buf2: str = pool.alloc(total2) + if buf2 is not None: + buf2[0] = '\0' + string.strcat(buf2, left_str) + string.strcat(buf2, "|") + string.strcat(buf2, right_str) + return buf2 + return None + return None + + +# ============================================================ +# _parse_type_string - 将类型名字符串解析回 AST 节点 +# +# _get_type_name_from_annotation 的逆操作,用于泛型特化时 +# 从 type_args 字符串重建 AST 节点(_clone_annotation 和 +# resolve_annotation_type 的泛型上下文替换) +# +# "AST" -> Name("AST") +# "t.CPtr" -> Attribute(Name("t"), "CPtr") +# "AST|t.CPtr" -> BinOp(Name("AST"), BitOr, Attribute(Name("t"), "CPtr")) +# ============================================================ +def _parse_type_string(pool: memhub.MemBuddy | t.CPtr, + type_str: str, + ctx: t.CInt) -> ast.AST | t.CPtr: + """将类型名字符串解析为 AST 节点""" + if type_str is None or pool is None: + return None + + # 检查是否包含 | (BinOp) + pipe_pos: str = string.strchr(type_str, 124) # '|' = 124 + if pipe_pos is not None: + # 临时将 | 替换为 \0,分割左右部分 + old_char: t.CInt = pipe_pos[0] + pipe_pos[0] = 0 + left_node: ast.AST | t.CPtr = _parse_type_string(pool, type_str, ctx) + right_str: str = pipe_pos + 1 + pipe_pos[0] = old_char + right_node: ast.AST | t.CPtr = _parse_type_string(pool, right_str, ctx) + if left_node is not None and right_node is not None: + return ast.BinOp(pool, left_node, ast.OpKind.BitOr, right_node) + return None + + # 检查是否包含 . (Attribute) + dot_pos: str = string.strchr(type_str, 46) # '.' = 46 + if dot_pos is not None: + old_char2: t.CInt = dot_pos[0] + dot_pos[0] = 0 + module_node: ast.AST | t.CPtr = ast.Name(pool, type_str, ctx) + attr_str: str = dot_pos + 1 + dot_pos[0] = old_char2 + if module_node is not None: + return ast.Attribute(pool, module_node, attr_str, ctx) + return None + + # 普通 Name + return ast.Name(pool, type_str, ctx) + + +# ============================================================ +# set_current_file - 设置当前编译的文件名 +# +# 在 BuildPipeline.TranslateFileGetTrans 中每翻译一个文件前调用 +# ============================================================ +def set_current_file(file_path: str): + """设置当前编译的文件名(供报错使用)""" + global _g_current_file + _g_current_file = file_path + + +# ============================================================ +# _read_source_line - 从源文件读取第 lineno 行 +# +# 返回行内容字符串(不含换行符),失败返回 None +# ============================================================ +_SRC_BUF_SIZE: t.CDefine = 262144 + +def _read_source_line(file_path: str, lineno: int) -> str: + """从源文件读取第 lineno 行内容""" + if file_path is None or lineno <= 0: + return None + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f.closed: + return None + buf: bytes = stdlib.malloc(_SRC_BUF_SIZE) + if buf is None: + f.close() + return None + bytes_read: LONG = f.read_all(buf, _SRC_BUF_SIZE) + f.close() + if bytes_read <= 0: + stdlib.free(buf) + return None + # 逐行查找第 lineno 行 + cur_line: int = 1 + line_start: t.CSizeT = 0 + for i in range(bytes_read): + if buf[i] == '\n': + if cur_line == lineno: + line_len: t.CSizeT = i - line_start + if line_len > 0 and buf[line_start + line_len - 1] == '\r': + line_len -= 1 + line_buf: bytes = stdlib.malloc(line_len + 1) + if line_buf is not None: + string.strncpy(line_buf, buf + line_start, line_len) + line_buf[line_len] = '\0' + stdlib.free(buf) + return line_buf + stdlib.free(buf) + return None + cur_line += 1 + line_start = i + 1 + stdlib.free(buf) + return None + + +# ============================================================ +# fatal_error - 以 Python 风格报错并退出(带源代码行) +# +# 格式: +# Traceback (most recent call last): +# File "path", line N +# source code line +# SyntaxError: msg +# ============================================================ +def fatal_error(node: ast.AST | t.CPtr, msg: str): + """以 Python 风格报错并退出(带源代码行)""" + lineno: int = 0 + if node is not None: + lineno = node.lineno + file_name: str = _g_current_file + if file_name is None: + file_name = "" + stdio.printf("Traceback (most recent call last):\n") + stdio.printf(' File "%s", line %d\n', file_name, lineno) + if lineno > 0 and file_name != "": + src_line: str = _read_source_line(file_name, lineno) + if src_line is not None: + stdio.printf(" %s\n", src_line) + stdlib.free(src_line) + stdio.printf("SyntaxError: %s\n", msg) + sys.exit(1) + + +# ============================================================ +# fatal_type_error - 兼容别名(指向 fatal_error) +# ============================================================ +def fatal_type_error(node: ast.AST | t.CPtr, msg: str): + """以 Python 风格报错并退出(fatal_error 的别名)""" + fatal_error(node, msg) + +# ============================================================ +# 将 t.CXxx 类型名映射到 LLVMType(纯函数) +# ============================================================ +def map_t_type(pool: memhub.MemBuddy | t.CPtr, + type_name: str) -> llvmlite.LLVMType | t.CPtr: + """将 t.CXxx / c.CXxx 类型名映射到 LLVMType + + 注意: t.CChar | t.CPtr = i8* = str = bytes + """ + if type_name is None: + return None + + # 基本整数类型 + if string.strcmp(type_name, "CInt") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CChar") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CShort") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CLong") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CLongLong") == 0: + return llvmlite.Int64(pool) + # 精确宽度有符号类型 + elif string.strcmp(type_name, "CInt8T") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CInt16T") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CInt32T") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CInt64T") == 0: + return llvmlite.Int64(pool) + # 精确宽度无符号类型 + elif string.strcmp(type_name, "CUInt8T") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CUInt16T") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CUInt32T") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CUInt64T") == 0: + return llvmlite.Int64(pool) + # 浮点类型 + elif string.strcmp(type_name, "CFloat") == 0: + return llvmlite.Float(pool) + elif string.strcmp(type_name, "CDouble") == 0: + return llvmlite.Double(pool) + # 指针/void: t.CPtr = i8*, t.CChar | t.CPtr = i8* = str = bytes + elif string.strcmp(type_name, "CPtr") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "CVoid") == 0: + return llvmlite.Void(pool) + # 无符号修饰 + elif string.strcmp(type_name, "CUnsigned") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CUnsignedInt") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "CUnsignedChar") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CUnsignedShort") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CUnsignedLong") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CUnsignedLongLong") == 0: + return llvmlite.Int64(pool) + # size_t / ptr 类型 + elif string.strcmp(type_name, "CSizeT") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CIntPtrT") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CUIntPtrT") == 0: + return llvmlite.Int64(pool) + # bool + elif string.strcmp(type_name, "CBool") == 0: + return llvmlite.Int8(pool) + # ptrdiff_t + elif string.strcmp(type_name, "CPtrDiffT") == 0: + return llvmlite.Int64(pool) + + # ============================================================ + # stdint.py 大写别名(Win32/TransPyC 风格) + # ============================================================ + # 整数类型 + elif string.strcmp(type_name, "INT") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "BOOL") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "UINT") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "BYTE") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "WORD") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "DWORD") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "QWORD") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "TCHAR") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "VOID") == 0: + return llvmlite.Void(pool) + elif string.strcmp(type_name, "SHORT") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "USHORT") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "LONGLONG") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "ULONGLONG") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "LONG") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "ULONG") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "WCHAR") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "FLOAT") == 0: + return llvmlite.Float(pool) + elif string.strcmp(type_name, "DOUBLE") == 0: + return llvmlite.Double(pool) + elif string.strcmp(type_name, "FSIZE_t") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "LBA_t") == 0: + return llvmlite.Int32(pool) + # 定长整数 + elif string.strcmp(type_name, "INT8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "INT16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "INT32") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "INT64") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "UINT8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "UINT16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "UINT32") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "UINT64") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "CHAR8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "CHAR16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "CHAR32") == 0: + return llvmlite.Int32(pool) + # 小写简写 + elif string.strcmp(type_name, "i8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "i16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "i32") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "i64") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "u8") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "u16") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "u32") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "u64") == 0: + return llvmlite.Int64(pool) + # size_t 系列 + elif string.strcmp(type_name, "SIZE_T") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "SSIZE_T") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "PTRDIFF_T") == 0: + return llvmlite.Int64(pool) + + # stdint 指针类型(XxxPTR = XxxType | t.CPtr) + elif string.strcmp(type_name, "INTPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + elif string.strcmp(type_name, "UINTPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + elif string.strcmp(type_name, "BYTEPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "CHARLIST") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "SHORTPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "USHORTPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "WCHARPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "CHARPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "VOIDPTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "INT8PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "INT16PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "INT32PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + elif string.strcmp(type_name, "INT64PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int64(pool)) + elif string.strcmp(type_name, "UINT8PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "UINT16PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "UINT32PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + elif string.strcmp(type_name, "UINT64PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int64(pool)) + elif string.strcmp(type_name, "CHAR8PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(type_name, "CHAR16PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int16(pool)) + elif string.strcmp(type_name, "CHAR32PTR") == 0: + return llvmlite.Ptr(pool, llvmlite.Int32(pool)) + + # C 标准 小写 _t 类型 + elif string.strcmp(type_name, "int8_t") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "int16_t") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "int32_t") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "int64_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "uint8_t") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "uint16_t") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "uint32_t") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "uint64_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "size_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "ssize_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "ptrdiff_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "intptr_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "uintptr_t") == 0: + return llvmlite.Int64(pool) + elif string.strcmp(type_name, "wchar_t") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "char8_t") == 0: + return llvmlite.Int8(pool) + elif string.strcmp(type_name, "char16_t") == 0: + return llvmlite.Int16(pool) + elif string.strcmp(type_name, "char32_t") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(type_name, "_Bool") == 0: + return llvmlite.Int8(pool) + return None + + +# ============================================================ +# _is_t_attr - 检测节点是否是 t.attr_name 形式(如 t.CPtr, t.CVoid) +# +# 用于联合类型注解中检测指针包装标记 (t.CPtr) 和 void 标记 (t.CVoid) +# ============================================================ +def _is_t_attr(node: ast.AST | t.CPtr, + attr_name: str, + imported_modules: str) -> int: + """检测节点是否是 t.attr_name 形式""" + if node is None or attr_name is None: + return 0 + if node.kind() != ast.ASTKind.Attribute: + return 0 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return 0 + if string.strcmp(at.attr, attr_name) != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if val_nm.id is None: + return 0 + if HandlesImports.is_module_imported(imported_modules, val_nm.id) == 0: + return 0 + if string.strcmp(val_nm.id, "t") == 0: + return 1 + return 0 + + +# ============================================================ +# extract_class_name_from_annotation - 从类型注解 AST 中提取类名 +# +# 用于联合类型简化为 i8* 时,回退查找结构体类名。 +# 支持: +# Name 节点 (MemBuddy) → "MemBuddy" +# Attribute 节点 (memhub.MemBuddy) → "MemBuddy" +# BinOp 联合类型 (MemBuddy | t.CPtr) → 非 CPtr 一边的类名 +# ============================================================ +def extract_class_name_from_annotation(node: ast.AST | t.CPtr, + imported_modules: str) -> str: + """从类型注解 AST 中提取类名,返回 None=无法提取""" + if node is None: + return None + k: int = node.kind() + + # Constant 节点: 字符串注解(如 'MemManager'),简单类名直接返回 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR and cn.str_val is not None: + # 仅处理简单类名(不含 . 和 |),复杂形式返回 None + if string.strchr(cn.str_val, 46) is None and string.strchr(cn.str_val, 124) is None: + if string.strcmp(cn.str_val, "str") == 0: + return None + if string.strcmp(cn.str_val, "int") == 0: + return None + if string.strcmp(cn.str_val, "bytes") == 0: + return None + return cn.str_val + return None + + # Name 节点: MemBuddy → "MemBuddy" + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + return None + # 跳过内置类型名 + if string.strcmp(nm.id, "str") == 0: + return None + if string.strcmp(nm.id, "int") == 0: + return None + if string.strcmp(nm.id, "bytes") == 0: + return None + return nm.id + + # Attribute 节点: memhub.MemBuddy → "memhub.MemBuddy"(模块限定名) + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return None + # 跳过 t.XXX 形式(内置类型) + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + val_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if val_nm2.id is not None and string.strcmp(val_nm2.id, "t") == 0: + return None + # 返回模块限定名 "module.Class"(如 "memhub.MemBuddy") + mod_qual_buf: t.CChar | t.CPtr = stdlib.malloc( + string.strlen(val_nm2.id) + string.strlen(at.attr) + 2) + if mod_qual_buf is not None: + viperlib.snprintf(mod_qual_buf, + string.strlen(val_nm2.id) + string.strlen(at.attr) + 2, + "%s.%s", val_nm2.id, at.attr) + return mod_qual_buf + return at.attr + + # BinOp 节点: 联合类型 A | B + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + left_is_cptr: int = _is_t_attr(bop.left, "CPtr", imported_modules) + right_is_cptr: int = _is_t_attr(bop.right, "CPtr", imported_modules) + # 提取非 CPtr 一边的类名 + if left_is_cptr != 0 and right_is_cptr == 0: + return extract_class_name_from_annotation(bop.right, imported_modules) + if right_is_cptr != 0 and left_is_cptr == 0: + return extract_class_name_from_annotation(bop.left, imported_modules) + # 无 CPtr 标记:尝试两边 + if left_is_cptr == 0 and right_is_cptr == 0: + left_name: str = extract_class_name_from_annotation(bop.left, imported_modules) + if left_name is not None: + return left_name + return extract_class_name_from_annotation(bop.right, imported_modules) + return None + + # Subscript 节点: list[AST | t.CPtr] → "list" + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub.value is not None: + return extract_class_name_from_annotation(sub.value, imported_modules) + return None + + return None + + +# ============================================================ +# 解析类型注解节点为 LLVMType +# +# 支持的注解形式: +# - int → i32 +# - t.CUInt64T → i64 +# - str → i8* (t.CChar | t.CPtr = i8* = bytes) +# - int → i32 +# - bytes → i8* +# ============================================================ +def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + imported_modules: str, + from_imports: str) -> llvmlite.LLVMType | t.CPtr: + """解析类型注解节点为 LLVMType + + Args: + pool: 内存分配器 + node: 类型注解 AST 节点(Name 或 Attribute) + imported_modules: 已导入模块名字符串(空格分隔) + from_imports: from-import 映射字符串("name:module name:module" 格式) + """ + if node is None: + return None + + k: int = node.kind() + + # Constant 节点: 字符串注解(如 'MemManager'),当作无引号的 Name/Attribute/BinOp 处理 + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn.const_kind == ast.CONST_STR and cn.str_val is not None: + sub_node: ast.AST | t.CPtr = _parse_type_string(pool, cn.str_val, ast.Ctx.Load) + if sub_node is not None: + return resolve_annotation_type(pool, sub_node, imported_modules, from_imports) + return None + + # Name 节点: str, int, bytes, from-import 名称, class 名称等 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is None: + return None + # 泛型类型参数 T 替换:在泛型特化上下文中,将 T 替换为具体类型 + if _g_generic_tp_names is not None and _g_generic_type_args is not None: + gp_n: t.CSizeT = _g_generic_tp_names.__len__() + gp_i: t.CSizeT + for gp_i in range(gp_n): + gp_tpn: str = _g_generic_tp_names.get(gp_i) + if gp_tpn is not None and string.strcmp(nm.id, gp_tpn) == 0: + gp_ta: str = _g_generic_type_args.get(gp_i) + if gp_ta is not None: + # 用具体类型名递归解析(支持 BinOp/Attribute 类型实参) + gp_sub_node: ast.AST | t.CPtr = _parse_type_string(pool, gp_ta, nm.ctx) + if gp_sub_node is not None: + return resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports) + # str = bytes = t.CChar | t.CPtr = i8* + if string.strcmp(nm.id, "str") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + elif string.strcmp(nm.id, "int") == 0: + return llvmlite.Int32(pool) + elif string.strcmp(nm.id, "bytes") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # class 名称: 查找已注册的 StructType,返回 StructType 本身(不包装 Ptr) + # 这样 build_alloca 会分配结构体大小的空间,alloca 返回 struct_ty* + # 命名空间隔离:严格模式下仅解析可见的结构体 + if HandlesStruct.is_struct_visible(nm.id) != 0: + struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(nm.id) + if struct_ty is not None: + return struct_ty + # from-import 名称: 查找 from_imports 获取模块名后映射 + mod_name: str = HandlesImports.lookup_from_import(from_imports, nm.id) + if mod_name is not None: + return map_t_type(pool, nm.id) + return None + + # Attribute 节点: t.CInt, t.CUInt64T, namespace_defs.PlainStruct 等 + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is None: + return None + # 检查 value 是否是 Name('t') 或 Name('c') + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if val_name.id is not None: + # 仅当模块已导入时才解析 + mod_imp: int = HandlesImports.is_module_imported(imported_modules, val_name.id) + if mod_imp == 0: + return None + # 先尝试内置类型映射(int 等) + mapped_ty: llvmlite.LLVMType | t.CPtr = map_t_type(pool, at.attr) + if mapped_ty is not None: + return mapped_ty + # 模块限定类类型:Module.ClassName(命名空间隔离) + mod_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(at.attr) + if mod_struct_ty is not None: + return mod_struct_ty + return None + return None + + # BinOp 节点: 联合类型注解 A | B + # 处理三种语义: + # 1. ActualType | t.CPtr → Ptr(ActualType)(指针包装,如 MemBuddy | t.CPtr → MemBuddy*) + # 2. t.CVoid | t.CPtr → i8* (void* 等价于 i8*) + # 3. ActualType | DecoratorMarker → ActualType(忽略装饰器标记如 CExport/CExtern) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + # 检测 t.CPtr 标记(指针包装标记) + left_is_cptr: int = _is_t_attr(bop.left, "CPtr", imported_modules) + right_is_cptr: int = _is_t_attr(bop.right, "CPtr", imported_modules) + + if left_is_cptr != 0 or right_is_cptr != 0: + # 有 CPtr 标记:解析非 CPtr 一边的实际类型,包装为 Ptr + # left 是 CPtr → other 是 right;right 是 CPtr → other 是 left + other_node: ast.AST | t.CPtr = bop.left + if left_is_cptr != 0: + other_node = bop.right + # 检测另一边是否是 t.CVoid (void* = i8*) + other_is_cvoid: int = _is_t_attr(other_node, "CVoid", imported_modules) + if other_is_cvoid != 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( + pool, other_node, imported_modules, from_imports) + if other_ty is None: + # CPtr 单独使用或其他无效类型 → i8* + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + return llvmlite.Ptr(pool, other_ty) + + # 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略) + left_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( + pool, bop.left, imported_modules, from_imports) + if left_ty is not None: + return left_ty + right_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( + pool, bop.right, imported_modules, from_imports) + if right_ty is not None: + return right_ty + return None + + # Subscript 节点: t.CArray[elem_ty, count] → [count x elem_ty] + # t.CArray[elem_ty] → Ptr(elem_ty)(静态推导长度数组) + # list[int] → 特化类 struct type(泛型类类型注解) + # value 是 Attribute(Name('t'), 'CArray') 或 Name('list')(泛型类) + # slice 是 Tuple(elts=[elem_ty_node, count_node]) 或单 elem_ty_node + if k == ast.ASTKind.Subscript: + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub.value is None or sub.slice is None: + fatal_type_error(node, "Subscript 节点缺少 value 或 slice") + # 泛型类类型注解: list[int] → 查找已特化的 struct + # value 是 Name(泛型类名),slice 是类型实参 + if sub.value.kind() == ast.ASTKind.Name: + gen_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if gen_nm.id is not None: + # 先收集类型实参名,再分配缓冲区拼接 mangled name + gen_arg_names: list[str] | t.CPtr = list[str](pool, 4) + if sub.slice.kind() == ast.ASTKind.Tuple: + gen_tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + gen_elts: list[ast.AST | t.CPtr] | t.CPtr = gen_tp.elts + if gen_elts is not None: + gen_en: t.CSizeT = gen_elts.__len__() + gen_ei: t.CSizeT + for gen_ei in range(gen_en): + gen_elt: ast.AST | t.CPtr = gen_elts.get(gen_ei) + gen_tn: str = _get_type_name_from_annotation(pool, gen_elt) + gen_arg_names.append(gen_tn) + else: + gen_tn_single: str = _get_type_name_from_annotation(pool, sub.slice) + gen_arg_names.append(gen_tn_single) + # 计算总长度并分配缓冲区 + gen_total: t.CSizeT = string.strlen(gen_nm.id) + 2 # "[" 和 "]" + gen_an: t.CSizeT = gen_arg_names.__len__() + gen_ai: t.CSizeT + for gen_ai in range(gen_an): + if gen_ai > 0: + gen_total += 1 # "," + gen_atn: str = gen_arg_names.get(gen_ai) + if gen_atn is not None: + gen_total += string.strlen(gen_atn) + gen_total += 1 # NUL + gen_mangled: str = pool.alloc(gen_total) + if gen_mangled is None: + return None + gen_mangled[0] = '\0' + string.strcat(gen_mangled, gen_nm.id) + string.strcat(gen_mangled, "[") + for gen_ai in range(gen_an): + if gen_ai > 0: + string.strcat(gen_mangled, ",") + gen_atn: str = gen_arg_names.get(gen_ai) + if gen_atn is not None: + string.strcat(gen_mangled, gen_atn) + string.strcat(gen_mangled, "]") + # 查找已特化的 struct(特化由实例化调用 list[int](pool) 触发) + gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled) + if gen_spec_ty is not None: + return gen_spec_ty + # 未特化:返回 None(不报错,让后续流程处理) + return None + # 检查 value 是否是 Attribute(Name('t'), 'CArray') + if sub.value.kind() != ast.ASTKind.Attribute: + fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray)") + arr_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) + if arr_at.attr is None: + fatal_type_error(node, "Subscript Attribute 缺少 attr") + if string.strcmp(arr_at.attr, "CArray") != 0: + fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray)") + if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name: + fatal_type_error(node, "t.CArray 必须通过模块名限定") + arr_val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arr_at.value) + if arr_val_name.id is None: + fatal_type_error(node, "t.CArray 模块名为 None") + if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0: + fatal_type_error(node, "t.CArray 模块未导入") + # 单参数形式: t.CArray[elem_ty] → Ptr(elem_ty) + # 相当于 t.CArray[elem_ty, None],表示静态推导长度数组 + if sub.slice.kind() != ast.ASTKind.Tuple: + elem_ty_single: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( + pool, sub.slice, imported_modules, from_imports) + if elem_ty_single is None: + fatal_type_error(sub.slice, "t.CArray[?] 元素类型解析失败") + return llvmlite.Ptr(pool, elem_ty_single) + # 双参数形式: t.CArray[elem_ty, count] → [count x elem_ty] + tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + if tup.elts is None: + fatal_type_error(node, "t.CArray Tuple 缺少 elts") + elts_list: list[ast.AST | t.CPtr] | t.CPtr = tup.elts + elts_n: t.CSizeT = elts_list.__len__() + if elts_n < 2: + fatal_type_error(node, "t.CArray Tuple 元素不足") + elem_node: ast.AST | t.CPtr = elts_list.get(0) + count_node: ast.AST | t.CPtr = elts_list.get(1) + if elem_node is None or count_node is None: + fatal_type_error(node, "t.CArray Tuple 元素为 None") + # 递归解析元素类型 + elem_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( + pool, elem_node, imported_modules, from_imports) + if elem_ty is None: + fatal_type_error(elem_node, "t.CArray 元素类型解析失败") + # 解析 count(必须是整数常量、None 或 CDefine 常量名) + # t.CArray[elem_ty, None] 等价于单参数形式 → Ptr(elem_ty) + # t.CArray[elem_ty, NAME] 其中 NAME: t.CDefine = value → [value x elem_ty] + count_val: int = 0 + if count_node.kind() == ast.ASTKind.Constant: + cnt_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(count_node) + if cnt_cn.const_kind == ast.CONST_NONE: + return llvmlite.Ptr(pool, elem_ty) + if cnt_cn.const_kind != ast.CONST_INT: + fatal_type_error(count_node, "t.CArray count 必须是整数常量、None 或 CDefine 常量名") + count_val = cnt_cn.int_val + elif count_node.kind() == ast.ASTKind.Name: + # CDefine 常量名查找 + cnt_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(count_node) + if cnt_nm.id is None: + fatal_type_error(count_node, "t.CArray count Name 节点 id 为 None") + looked_up: int = lookup_cdefine_constant(cnt_nm.id) + if looked_up < 0: + fatal_type_error(count_node, "t.CArray count 不是已注册的 CDefine 常量") + count_val = looked_up + else: + fatal_type_error(count_node, "t.CArray count 必须是整数常量、None 或 CDefine 常量名") + if count_val <= 0: + fatal_type_error(count_node, "t.CArray count 必须为正数") + # 创建 ArrayType(不包装 Ptr) + # 这样 build_alloca 会分配数组大小的空间,alloca 返回 [N x elem_ty]* + return llvmlite.Array(pool, elem_ty, count_val) + + # 未知 AST kind:fail-fast,不宽容返回 None + fatal_type_error(node, "不支持的类型注解语法") + + +# ============================================================ +# has_decorator_marker - 检测类型注解中是否包含指定的装饰器标记 +# +# 支持联合类型注解:int | t.CExtern | t.CExport +# 递归检测 BinOp 节点的左右子节点。 +# +# marker_name 取值: "CExtern", "CExport", "CInline", "State" +# ============================================================ +def has_decorator_marker(node: ast.AST | t.CPtr, + marker_name: str) -> int: + """检测类型注解中是否包含指定的装饰器标记""" + if node is None or marker_name is None: + return 0 + + k: int = node.kind() + + # Attribute 节点: t.CExtern, t.State, t.CExport, t.CInline + if k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at.attr is not None: + if string.strcmp(at.attr, marker_name) == 0: + return 1 + return 0 + + # BinOp 节点: int | t.CExtern(递归检测左右子节点) + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if has_decorator_marker(bop.left, marker_name) != 0: + return 1 + if has_decorator_marker(bop.right, marker_name) != 0: + return 1 + return 0 + + return 0 + + +# ============================================================ +# is_pass_body - 检测函数体是否为 pass(空体) +# +# pass 体函数用于声明外部函数(t.CExtern / t.State), +# 翻译器应生成 declare 而非 define。 +# ============================================================ +def is_pass_body(body: list[ast.AST | t.CPtr] | t.CPtr) -> int: + """检测函数体是否为 pass(空体或仅含 pass 语句)""" + if body is None: + return 1 + bn: t.CSizeT = body.__len__() + if bn == 0: + return 1 + if bn == 1: + stmt: ast.AST | t.CPtr = body.get(0) + if stmt is not None and stmt.kind() == ast.ASTKind.Pass: + return 1 + return 0 + + +# ============================================================ +# 获取 LLVM 整数类型的位宽 +# ============================================================ +def get_llvm_type_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 整数类型的位宽,非整数类型返回 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Int(bits): + return bits + case _: + return 0 + + +# ============================================================ +# 推断表达式的 LLVM 类型 +# ============================================================ +def infer_expr_type(pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + param_types: str) -> llvmlite.LLVMType | t.CPtr: + """推断表达式的 LLVM 类型 + + param_types 格式: "name:bits,name:bits,..." + """ + if node is None: + return llvmlite.Int32(pool) + + k: int = node.kind() + + if k == ast.ASTKind.Constant: + return llvmlite.Int32(pool) + + elif k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None and param_types is not None: + # 在 param_types 中查找: "name:bits" 格式 + search_key: t.CChar | t.CPtr = pool.alloc(64) + if search_key is not None: + viperlib.snprintf(search_key, 64, "%s:", nm.id) + found: t.CChar | t.CPtr = string.strstr(param_types, search_key) + if found is not None: + colon_pos: t.CSizeT = string.strlen(nm.id) + 1 + bits_str: t.CChar | t.CPtr = found + colon_pos + bits: int = 0 + for bi in range(4): + ch: t.CChar = bits_str[bi] + if ch >= '0' and ch <= '9': + bits = bits * 10 + (ch - '0') + else: + break + if bits == 64: + return llvmlite.Int64(pool) + elif bits == 16: + return llvmlite.Int16(pool) + elif bits == 8: + return llvmlite.Int8(pool) + return llvmlite.Int32(pool) + + elif k == ast.ASTKind.BinOp: + binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + lhs_ty: llvmlite.LLVMType | t.CPtr = infer_expr_type( + pool, binop.left, param_types) + rhs_ty: llvmlite.LLVMType | t.CPtr = infer_expr_type( + pool, binop.right, param_types) + lhs_bits: int = get_llvm_type_bits(lhs_ty) + rhs_bits: int = get_llvm_type_bits(rhs_ty) + if lhs_bits >= rhs_bits: + return lhs_ty + return rhs_ty + + return llvmlite.Int32(pool) + + +# ============================================================ +# 推断函数返回类型 +# ============================================================ +def infer_return_type(pool: memhub.MemBuddy | t.CPtr, + body: list[ast.AST | t.CPtr] | t.CPtr, + param_types: str) -> llvmlite.LLVMType | t.CPtr: + """扫描函数体中的 return 语句,推断返回类型""" + if body is None: + return llvmlite.Int32(pool) + + ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + bn: t.CSizeT = body.__len__() + for bi in range(bn): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None and stmt.kind() == ast.ASTKind.Return: + rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt) + if rt.value is not None: + expr_ty: llvmlite.LLVMType | t.CPtr = infer_expr_type( + pool, rt.value, param_types) + if expr_ty is not None: + cur_bits: int = get_llvm_type_bits(ret_ty) + new_bits: int = get_llvm_type_bits(expr_ty) + if new_bits > cur_bits: + ret_ty = expr_ty + return ret_ty + + +# ============================================================ +# 构建参数类型编码字符串 +# ============================================================ +def build_param_types_str(pool: memhub.MemBuddy | t.CPtr, + args_node: ast.AST | t.CPtr) -> str: + """构建参数类型编码字符串 "name:bits,name:bits,..." """ + if args_node is None: + return None + ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) + if ags.args is None: + return None + alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args + an: t.CSizeT = alist.__len__() + if an == 0: + return None + + buf_size: t.CSizeT = an * 32 + 1 + buf: t.CChar | t.CPtr = pool.alloc(buf_size) + if buf is None: + return None + buf[0] = '\0' + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + for ai in range(an): + arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) + if arg is not None and arg.arg is not None: + param_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if arg.annotation is not None: + # 直接调用 map_t_type 解析 Attribute 注解 + if arg.annotation.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) + if at.attr is not None: + resolved: llvmlite.LLVMType | t.CPtr = map_t_type(pool, at.attr) + if resolved is not None: + param_ty = resolved + bits: int = get_llvm_type_bits(param_ty) + if bits == 0: + bits = 32 + tmp: t.CChar | t.CPtr = pool.alloc(32) + if tmp is not None: + viperlib.snprintf(tmp, 32, "%s:%d", arg.arg, bits) + if ai > 0: + _strappend(buf, buf_size, ",") + _strappend(buf, buf_size, tmp) + return buf + + +# ============================================================ +# 辅助函数 +# ============================================================ +def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: + return + dlen: t.CSizeT = string.strlen(dst) + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: + return + for i in range(min(slen, remain - 1)): + dst[dlen + i] = src[i] + dst[dlen + i] = '\0' \ No newline at end of file diff --git a/App/lib/core/Handles/HandlesVar.py b/App/lib/core/Handles/HandlesVar.py new file mode 100644 index 0000000..455f5fe --- /dev/null +++ b/App/lib/core/Handles/HandlesVar.py @@ -0,0 +1,365 @@ +import t, c +from stdint import * +import llvmlite +import memhub +import string + + +# ============================================================ +# HandlesVar - 嵌套作用域符号表 + 变量管理 +# +# 使用 Scope 链(Parent 指针)管理嵌套作用域, +# 每个作用域包含一个 VarEntry 数组(扁平化,已验证可工作)。 +# +# 作用域类型: +# SCOPE_MODULE — 模块级(根作用域) +# SCOPE_FUNCTION — 函数级 +# SCOPE_BLOCK — 块级(if/for/while,当前未使用块作用域) +# ============================================================ + +# 作用域类型常量 +SCOPE_MODULE: t.CDefine = 0 +SCOPE_FUNCTION: t.CDefine = 1 +SCOPE_BLOCK: t.CDefine = 2 + +# 每个作用域最大变量数 +MAX_VARS: t.CDefine = 256 + + +# ============================================================ +# VarEntry - 变量表条目 +# ============================================================ +@t.NoVTable +class VarEntry: + """变量表条目""" + Name: t.CChar | t.CPtr + Alloca: llvmlite.Value | t.CPtr + Used: t.CInt + AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型) + + +# ============================================================ +# Scope - 作用域节点 +# +# Parent 指向父作用域(None 表示根), +# Vars 是 VarEntry 数组,VarCount 是当前变量数。 +# ============================================================ +@t.NoVTable +class Scope: + """作用域节点""" + Parent: Scope | t.CPtr + Vars: VarEntry | t.CPtr + VarCount: t.CInt + Kind: t.CInt + + +# ============================================================ +# SymbolTable - 嵌套作用域符号表 +# +# Root 是模块级根作用域,Current 是当前作用域。 +# enter_scope/exit_scope 管理作用域栈。 +# ============================================================ +@t.NoVTable +class SymbolTable: + """嵌套作用域符号表""" + Pool: memhub.MemBuddy | t.CPtr + Root: Scope | t.CPtr + Current: Scope | t.CPtr + + +# ============================================================ +# init_vars — 分配并清零 VarEntry 数组 +# ============================================================ +def init_vars(pool: memhub.MemBuddy | t.CPtr) -> VarEntry | t.CPtr: + """分配并清零变量表数组""" + size: t.CSizeT = MAX_VARS * VarEntry.__sizeof__() + vars_ptr: VarEntry | t.CPtr = pool.alloc(size) + if vars_ptr is not None: + string.memset(vars_ptr, 0, size) + return vars_ptr + + +# ============================================================ +# find_var — 在变量表中按名称查找 +# ============================================================ +def find_var(vars_ptr: VarEntry | t.CPtr, + var_count: int, + name: str) -> llvmlite.Value | t.CPtr: + """在变量表中按名称查找""" + if name is None or vars_ptr is None: + return None + entry_size: t.CSizeT = VarEntry.__sizeof__() + for i in range(var_count): + entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size + entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None and entry.Used != 0: + if string.strcmp(entry.Name, name) == 0: + return entry.Alloca + return None + + +# ============================================================ +# find_var_entry — 在变量表中按名称查找,返回 VarEntry(含 AnnotTy) +# ============================================================ +def find_var_entry(vars_ptr: VarEntry | t.CPtr, + var_count: int, + name: str) -> VarEntry | t.CPtr: + """在变量表中按名称查找,返回 VarEntry 或 None""" + if name is None or vars_ptr is None: + return None + entry_size: t.CSizeT = VarEntry.__sizeof__() + for i in range(var_count): + entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size + entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry.Name is not None and entry.Used != 0: + if string.strcmp(entry.Name, name) == 0: + return entry + return None + + +# ============================================================ +# lookup_var_entry — 从当前作用域逐级向上查找变量,返回 VarEntry +# ============================================================ +def lookup_var_entry(symtab: SymbolTable | t.CPtr, + name: str) -> VarEntry | t.CPtr: + """从当前作用域逐级向上查找变量,返回 VarEntry 或 None""" + if symtab is None or name is None: + return None + scope: Scope | t.CPtr = symtab.Current + while scope is not None: + result: VarEntry | t.CPtr = find_var_entry(scope.Vars, scope.VarCount, name) + if result is not None: + return result + scope = scope.Parent + return None + + +# ============================================================ +# set_var_annot_class_name — 设置变量的原始类型注解类名 +# +# 在函数参数定义后调用,存储原始类型注解的类名。 +# 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化), +# 通过 AnnotClassName 查找实际结构体类型。 +# ============================================================ +def set_var_annot_class_name(symtab: SymbolTable | t.CPtr, + name: str, + class_name: str) -> int: + """设置变量的原始类型注解类名,返回 0=成功 / 1=失败""" + if symtab is None or name is None: + return 1 + entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name) + if entry is None: + return 1 + entry.AnnotClassName = class_name + return 0 + + +# ============================================================ +# add_var — 添加变量到变量表 +# ============================================================ +def add_var(vars_ptr: VarEntry | t.CPtr, + var_count: int, + name: str, + alloca: llvmlite.Value | t.CPtr) -> int: + """添加变量到变量表""" + if name is None or alloca is None or vars_ptr is None: + return 1 + if var_count >= MAX_VARS: + return 1 + entry_size: t.CSizeT = VarEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + var_count * entry_size + entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + entry.Name = name + entry.Alloca = alloca + entry.Used = 1 + return 0 + + +# ============================================================ +# get_or_create_var — 查找或创建变量 alloca(旧版兼容) +# ============================================================ +def get_or_create_var(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + vars_ptr: VarEntry | t.CPtr, + var_count: int, + name: str, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """查找或创建变量 alloca""" + existing: llvmlite.Value | t.CPtr = find_var(vars_ptr, var_count, name) + if existing is not None: + return existing + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, ty) + if alloca is None: + return None + if add_var(vars_ptr, var_count, name, alloca) != 0: + return None + return alloca + + +# ============================================================ +# _create_scope — 创建新作用域节点(内部辅助函数) +# ============================================================ +def _create_scope(pool: memhub.MemBuddy | t.CPtr, + parent: Scope | t.CPtr, + kind: int) -> Scope | t.CPtr: + """创建并初始化作用域节点""" + scope: Scope | t.CPtr = pool.alloc(Scope.__sizeof__()) + if scope is None: + return None + string.memset(scope, 0, Scope.__sizeof__()) + scope.Parent = parent + scope.Vars = init_vars(pool) + scope.VarCount = 0 + scope.Kind = kind + if scope.Vars is None: + return None + return scope + + +# ============================================================ +# init_symbol_table — 创建符号表(含模块级根作用域) +# ============================================================ +def init_symbol_table(pool: memhub.MemBuddy | t.CPtr) -> SymbolTable | t.CPtr: + """创建并初始化符号表,包含模块级根作用域""" + if pool is None: + return None + symtab: SymbolTable | t.CPtr = pool.alloc(SymbolTable.__sizeof__()) + if symtab is None: + return None + string.memset(symtab, 0, SymbolTable.__sizeof__()) + symtab.Pool = pool + + # 创建根作用域(模块级) + root: Scope | t.CPtr = _create_scope(pool, None, SCOPE_MODULE) + if root is None: + return None + + symtab.Root = root + symtab.Current = root + return symtab + + +# ============================================================ +# enter_scope — 进入新作用域 +# ============================================================ +def enter_scope(symtab: SymbolTable | t.CPtr, + kind: int) -> Scope | t.CPtr: + """进入新作用域,返回新创建的作用域""" + if symtab is None: + return None + pool: memhub.MemBuddy | t.CPtr = symtab.Pool + scope: Scope | t.CPtr = _create_scope(pool, symtab.Current, kind) + if scope is None: + return None + symtab.Current = scope + return scope + + +# ============================================================ +# exit_scope — 退出当前作用域 +# ============================================================ +def exit_scope(symtab: SymbolTable | t.CPtr): + """退出当前作用域,恢复到父作用域""" + if symtab is not None and symtab.Current is not None: + symtab.Current = symtab.Current.Parent + + +# ============================================================ +# define_var — 在当前作用域定义变量 +# ============================================================ +def define_var(symtab: SymbolTable | t.CPtr, + name: str, + alloca: llvmlite.Value | t.CPtr) -> int: + """在当前作用域定义变量,返回 0 成功""" + if symtab is None or name is None or alloca is None: + return 1 + scope: Scope | t.CPtr = symtab.Current + if scope is None: + return 1 + ret: int = add_var(scope.Vars, scope.VarCount, name, alloca) + if ret == 0: + scope.VarCount = scope.VarCount + 1 + return ret + + +# ============================================================ +# define_module_var — 在模块作用域定义变量 +# ============================================================ +def define_module_var(symtab: SymbolTable | t.CPtr, + name: str, + alloca: llvmlite.Value | t.CPtr) -> int: + """在模块作用域定义变量,返回 0 成功""" + if symtab is None or name is None or alloca is None: + return 1 + scope: Scope | t.CPtr = symtab.Root + if scope is None: + return 1 + ret: int = add_var(scope.Vars, scope.VarCount, name, alloca) + if ret == 0: + scope.VarCount = scope.VarCount + 1 + return ret + + +# ============================================================ +# lookup_var — 从当前作用域逐级向上查找变量 +# ============================================================ +def lookup_var(symtab: SymbolTable | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """从当前作用域逐级向上查找变量,返回 alloca 或 None""" + if symtab is None or name is None: + return None + scope: Scope | t.CPtr = symtab.Current + while scope is not None: + result: llvmlite.Value | t.CPtr = find_var( + scope.Vars, scope.VarCount, name) + if result is not None: + return result + scope = scope.Parent + return None + + +# ============================================================ +# lookup_current — 仅在当前作用域查找变量 +# ============================================================ +def lookup_current(symtab: SymbolTable | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """仅在当前作用域查找变量""" + if symtab is None or name is None: + return None + scope: Scope | t.CPtr = symtab.Current + if scope is None: + return None + return find_var(scope.Vars, scope.VarCount, name) + + +# ============================================================ +# lookup_module_var — 在模块作用域查找变量 +# ============================================================ +def lookup_module_var(symtab: SymbolTable | t.CPtr, + name: str) -> llvmlite.Value | t.CPtr: + """在模块作用域查找变量""" + if symtab is None or name is None: + return None + scope: Scope | t.CPtr = symtab.Root + if scope is None: + return None + return find_var(scope.Vars, scope.VarCount, name) + + +# ============================================================ +# get_or_create_sym — 查找或创建变量(在当前作用域) +# ============================================================ +def get_or_create_sym(symtab: SymbolTable | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + name: str, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """查找或创建变量 alloca(在当前作用域)""" + existing: llvmlite.Value | t.CPtr = lookup_current(symtab, name) + if existing is not None: + return existing + alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, ty) + if alloca is None: + return None + define_var(symtab, name, alloca) + return alloca diff --git a/App/lib/core/Handles/HandlesWhile.py b/App/lib/core/Handles/HandlesWhile.py new file mode 100644 index 0000000..397899e --- /dev/null +++ b/App/lib/core/Handles/HandlesWhile.py @@ -0,0 +1,130 @@ +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import stdio +import viperlib +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesBody as HandlesBody + + +# ============================================================ +# HandlesWhile - while 循环语句处理(Mixin 继承模式) +# +# 翻译 while 语句为 LLVM IR 控制流: +# br label %cond +# cond: +# %t = +# %c = icmp ne i32 %t, 0 +# br i1 %c, label %body, label %end +# body: +# ... body ... +# br label %cond +# end: +# ============================================================ + + +@t.NoVTable +class WhileHandle(HandlesBase.Mixin): + """while 循环语句处理器:继承 Mixin 获得 Trans 回指针""" + + def __init__(self, trans: HT.Translator | t.CPtr): + self.Trans = trans + + # ============================================================ + # Handle - 处理 while 语句,返回新增变量数 + # ============================================================ + def Handle(self, node: ast.AST | t.CPtr) -> int: + """翻译 while 循环语句""" + if node is None: + return 0 + + trans: HT.Translator | t.CPtr = self.Trans + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + if builder is None or func is None: + return 0 + + while_node: ast.While | t.CPtr = (ast.While | t.CPtr)(node) + + # 1. 创建基本块: cond / body / end(使用 trans._label_counter,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: t.CChar | t.CPtr = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "while.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "while.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 2. 跳转到 cond 块 + llvmlite.build_br(builder, cond_bb) + + # 3. cond 块: 求值条件,条件分支 + llvmlite.position_at_end(builder, cond_bb) + cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, while_node.test, + trans._funcs, trans._func_count, trans) + if cond_val is None: + cond_val = llvmlite.const_int32(pool, 0) + + # Compare/Not 表达式已返回 i1,直接使用;其他类型与 0 比较 + cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) + if cond_bits == 1: + cond_i1: llvmlite.Value | t.CPtr = cond_val + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, zero) + llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) + + # 4. body 块: 翻译循环体,跳回 cond + llvmlite.position_at_end(builder, body_bb) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = cond_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = while_node.children + if body is not None: + body_count: t.CSizeT = body.__len__() + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, cond_bb) + + # 5. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + return 0 + + +# ============================================================ +# NewWhileHandle - 工厂函数 +# ============================================================ +def NewWhileHandle(pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr) -> WhileHandle | t.CPtr: + h: WhileHandle | t.CPtr = pool.alloc(WhileHandle.__sizeof__()) + if h is None: + return None + string.memset(h, 0, WhileHandle.__sizeof__()) + h.Trans = trans + return h diff --git a/App/lib/core/Handles/__init__.py b/App/lib/core/Handles/__init__.py new file mode 100644 index 0000000..619fc36 --- /dev/null +++ b/App/lib/core/Handles/__init__.py @@ -0,0 +1,23 @@ +import t, c +from stdint import * + +# Handles 模块(绝对导入,Viper 兼容) +# 参考 Python 版 TransPyC lib/core/Handles 的细粒度拆分 +import lib.core.Handles.HandlesBase as HandlesBase +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesExprOps as HandlesExprOps +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesAssign as HandlesAssign +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.Handles.HandlesReturn as HandlesReturn +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.Handles.HandlesBody as HandlesBody +import lib.core.Handles.HandlesIf as HandlesIf +import lib.core.Handles.HandlesWhile as HandlesWhile +import lib.core.Handles.HandlesFor as HandlesFor +import lib.core.Handles.HandlesAugAssign as HandlesAugAssign +import lib.core.Handles.HandlesMain as HandlesMain +import lib.core.Handles.HandlesTranslator as HandlesTranslator diff --git a/App/lib/core/IncludesScanner.py b/App/lib/core/IncludesScanner.py new file mode 100644 index 0000000..3c0f5b4 --- /dev/null +++ b/App/lib/core/IncludesScanner.py @@ -0,0 +1,364 @@ +import t, c +from stdint import * +import memhub +import string +import stdio +import stdlib +import w32.win32file as win32file +import w32.win32base as win32base +import w32.fileio as fileio +import hashlib +import viperlib + + +# ============================================================ +# IncludesScanner - includes 目录递归扫描 +# +# 递归扫描 includes 目录,收集所有 .py 文件路径和 SHA1, +# 为 Phase1 stub 生成和 Phase2 stub 合并提供基础数据。 +# +# 使用 Win32 FindFirstFileA/FindNextFileA 实现目录遍历。 +# ============================================================ + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemManager | t.CPtr + +# 文件路径最大长度 +MAX_PATH_LEN: t.CDefine = 512 +# 单次扫描最大文件数 +MAX_FILES: t.CDefine = 256 + + +# ============================================================ +# FileEntry - 文件条目(路径 + SHA1) +# ============================================================ +@t.NoVTable +class FileEntry: + """扫描到的文件条目""" + Path: str # 文件绝对路径 + Sha1: str # SHA1 前16字符(16字节+null) + RelPath: str # 相对于 includes 根目录的路径 + ModuleName: str # 模块名(如 "ast.parser") + + +# ============================================================ +# ScanResult - 扫描结果 +# ============================================================ +@t.NoVTable +class ScanResult: + """扫描结果集合""" + Entries: FileEntry | t.CPtr # FileEntry 数组 + Count: t.CInt + Capacity: t.CInt + + +# ============================================================ +# create_scan_result - 创建扫描结果容器 +# ============================================================ +def create_scan_result(pool: memhub.MemBuddy | t.CPtr) -> ScanResult | t.CPtr: + """创建扫描结果容器,预分配 MAX_FILES 个槽位""" + if pool is None: + return None + size: t.CSizeT = MAX_FILES * FileEntry.__sizeof__() + # 使用 stdlib.malloc 避免 mbuddy 池耗尽(与 StubMerger 保持一致) + entries: FileEntry | t.CPtr = stdlib.malloc(size) + if entries is None: + return None + string.memset(entries, 0, size) + + result: ScanResult | t.CPtr = stdlib.malloc(ScanResult.__sizeof__()) + if result is None: + return None + string.memset(result, 0, ScanResult.__sizeof__()) + result.Entries = entries + result.Count = 0 + result.Capacity = MAX_FILES + return result + + +# ============================================================ +# add_file_entry - 向扫描结果添加文件条目 +# ============================================================ +def add_file_entry(result: ScanResult | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + abs_path: str, rel_path: str, + sha1: str) -> int: + """添加文件条目到扫描结果,返回 0 成功""" + if result is None or pool is None: + return 1 + if result.Count >= result.Capacity: + return 1 + + # 计算模块名:rel_path 中的 / 替换为 .,去掉 .py 扩展名 + rel_len: t.CSizeT = string.strlen(rel_path) + mod_buf: str = stdlib.malloc(rel_len + 1) + if mod_buf is None: + return 1 + string.strcpy(mod_buf, rel_path) + # 替换 / 为 . + for i in range(rel_len): + ch: t.CChar = mod_buf[i] + if ch == '/' or ch == '\\': + mod_buf[i] = '.' + # 去掉 .py 扩展名 + if rel_len >= 3: + if mod_buf[rel_len - 3] == '.' and mod_buf[rel_len - 2] == 'p' and mod_buf[rel_len - 1] == 'y': + mod_buf[rel_len - 3] = '\0' + + # 获取条目地址 + entry_size: t.CSizeT = FileEntry.__sizeof__() + entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + result.Count * entry_size + entry: FileEntry | t.CPtr = (FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry is None: + return 1 + + # 复制路径字符串 + abs_len: t.CSizeT = string.strlen(abs_path) + abs_buf: str = stdlib.malloc(abs_len + 1) + if abs_buf is None: + return 1 + string.strcpy(abs_buf, abs_path) + entry.Path = abs_buf + + # 复制 SHA1 + sha1_buf: str = stdlib.malloc(17) + if sha1_buf is None: + return 1 + string.strcpy(sha1_buf, sha1) + entry.Sha1 = sha1_buf + + # 复制相对路径 + rel_buf: str = stdlib.malloc(rel_len + 1) + if rel_buf is None: + return 1 + string.strcpy(rel_buf, rel_path) + entry.RelPath = rel_buf + + # 复制模块名 + entry.ModuleName = mod_buf + + result.Count += 1 + return 0 + + +# ============================================================ +# compute_file_sha1 - 读取文件内容并计算 SHA1 +# +# 与 Projectrans.py 一致:CRLF → LF 转换后计算 SHA1。 +# Projectrans.py 用 Python 文本模式读取(自动 CRLF→LF), +# IncludesScanner 用二进制模式读取,需手动去除 \r。 +# ============================================================ +def compute_file_sha1(pool: memhub.MemBuddy | t.CPtr, + file_path: str) -> str: + """读取文件内容并计算 SHA1 前16字符(CRLF→LF 后计算,与 Projectrans.py 一致)""" + if pool is None or file_path is None: + return None + + # 打开文件 + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f.closed: + return None + + # 分配读取缓冲区(128KB,足够大多数 .py 文件) + # 使用 stdlib.malloc 避免 mbuddy 池耗尽(每文件 128KB,60+ 文件会耗尽 16MB 池) + BUF_SIZE: t.CSizeT = 131072 + buf: bytes = stdlib.malloc(BUF_SIZE) + if buf is None: + f.close() + return None + + # 读取文件内容 + bytes_read: t.CInt64T = f.read_all(buf, BUF_SIZE) + f.close() + if bytes_read <= 0: + return None + + # 原地去除 \r(CRLF → LF),与 Projectrans.py 文本模式读取一致 + write_pos: t.CSizeT = 0 + read_pos: t.CSizeT = 0 + while read_pos < bytes_read: + ch: t.CChar = buf[read_pos] + if ch != '\r': + buf[write_pos] = ch + write_pos += 1 + read_pos += 1 + + # 添加 null 终止符 + buf[write_pos] = 0 + + # 计算 SHA1 + ctx: hashlib.sha1 | t.CPtr = hashlib.sha1() + if ctx is None: + return None + ctx.update(buf) + + digest: bytes = stdlib.malloc(hashlib.SHA1_DIGEST_LEN) + if digest is None: + return None + ctx.final(digest) + + # 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符) + hex_buf: str = stdlib.malloc(17) + if hex_buf is None: + return None + for i in range(8): + hi: int = (digest[i] >> 4) & 0xF + lo: int = digest[i] & 0xF + if hi < 10: + hex_buf[i * 2] = '0' + hi + else: + hex_buf[i * 2] = 'a' + (hi - 10) + if lo < 10: + hex_buf[i * 2 + 1] = '0' + lo + else: + hex_buf[i * 2 + 1] = 'a' + (lo - 10) + hex_buf[16] = '\0' + return hex_buf + + +# ============================================================ +# scan_directory_recursive - 递归扫描目录 +# +# 使用 FindFirstFileA/FindNextFileA 遍历目录树, +# 对每个 .py 文件计算 SHA1 并添加到结果中。 +# ============================================================ +def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr, + root_dir: str, + rel_prefix: str, + result: ScanResult | t.CPtr) -> int: + """递归扫描目录,收集 .py 文件""" + if pool is None or root_dir is None or result is None: + return 1 + + # 构造搜索模式: root_dir/* + root_len: t.CSizeT = string.strlen(root_dir) + pattern: bytes = stdlib.malloc(root_len + 4) + if pattern is None: + return 1 + viperlib.snprintf(pattern, root_len + 4, "%s/*", root_dir) + + # 使用 FindFirstFileA 开始搜索 + find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__()) + if find_data is None: + return 1 + string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__()) + + handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data) + if handle == win32base.INVALID_HANDLE_VALUE: + return 1 + + # 遍历所有文件和子目录 + while True: + # 跳过 . 和 .. + fname: str = find_data.cFileName + if fname is not None: + fname0: t.CChar = fname[0] + if fname0 == '.': + fname1: t.CChar = fname[1] + if fname1 == '\0': + # "." + if win32file.FindNextFileA(handle, find_data) == 0: + break + continue + elif fname1 == '.': + fname2: t.CChar = fname[2] + if fname2 == '\0': + # ".." + if win32file.FindNextFileA(handle, find_data) == 0: + break + continue + + # 检查是否为目录 + is_dir: int = find_data.dwFileAttributes & win32file.FILE_ATTRIBUTE_DIRECTORY + + # 构造完整路径 + fname_len: t.CSizeT = string.strlen(fname) + full_path: bytes = stdlib.malloc(root_len + fname_len + 2) + if full_path is None: + break + viperlib.snprintf(full_path, root_len + fname_len + 2, "%s/%s", root_dir, fname) + + # 构造相对路径 + prefix_len: t.CSizeT = 0 + if rel_prefix is not None: + prefix_len = string.strlen(rel_prefix) + rel_path: bytes = stdlib.malloc(prefix_len + fname_len + 2) + if rel_path is None: + break + if rel_prefix is not None and prefix_len > 0: + viperlib.snprintf(rel_path, prefix_len + fname_len + 2, "%s/%s", rel_prefix, fname) + else: + string.strcpy(rel_path, fname) + + if is_dir != 0: + # 递归扫描子目录 + scan_directory_recursive(pool, full_path, rel_path, result) + else: + # 检查是否为 .py 文件 + is_py: int = 0 + if fname_len >= 3: + if fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y': + is_py = 1 + + if is_py != 0: + # 跳过 __pycache__ 目录下的文件 + is_pycache: int = 0 + if rel_prefix is not None: + if string.strcmp(rel_prefix, "__pycache__") == 0: + is_pycache = 1 + + if is_pycache == 0: + # 计算 SHA1 + sha1: str = compute_file_sha1(pool, full_path) + if sha1 is not None: + add_file_entry(result, pool, full_path, rel_path, sha1) + stdio.printf(" [scan] %s -> %s\n", rel_path, sha1) + + # 继续搜索下一个文件 + if win32file.FindNextFileA(handle, find_data) == 0: + break + + win32file.FindClose(handle) + return 0 + + +# ============================================================ +# scan_includes - 扫描 includes 目录入口 +# +# 扫描指定的 includes 目录,返回所有 .py 文件的路径和 SHA1。 +# ============================================================ +def scan_includes(pool: memhub.MemBuddy | t.CPtr, + includes_dir: str) -> ScanResult | t.CPtr: + """扫描 includes 目录,返回所有 .py 文件的扫描结果""" + if pool is None or includes_dir is None: + return None + + stdio.printf("[Phase1] 扫描 includes 目录: %s\n", includes_dir) + + result: ScanResult | t.CPtr = create_scan_result(pool) + if result is None: + return None + + scan_directory_recursive(pool, includes_dir, None, result) + + stdio.printf("[Phase1] 扫描完成: %d 个 .py 文件\n", result.Count) + return result + + +# ============================================================ +# find_entry_by_module - 按模块名查找文件条目 +# ============================================================ +def find_entry_by_module(result: ScanResult | t.CPtr, + module_name: str) -> FileEntry | t.CPtr: + """按模块名查找文件条目""" + if result is None or module_name is None: + return None + entry_size: t.CSizeT = FileEntry.__sizeof__() + for i in range(result.Count): + entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size + entry: FileEntry | t.CPtr = (FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry is not None: + if entry.ModuleName is not None: + if entry.ModuleName == module_name: + return entry + return None diff --git a/App/lib/core/Phase1.py b/App/lib/core/Phase1.py new file mode 100644 index 0000000..88d62f6 --- /dev/null +++ b/App/lib/core/Phase1.py @@ -0,0 +1,540 @@ +import t, c +from stdint import * +import stdio +import string +import stdlib +import memhub +import viperlib +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import ast +import llvmlite +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.IncludesScanner as IncludesScanner +import lib.core.StubMerger as StubMerger +import lib.Projectrans.Config as Config + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemManager | t.CPtr + +# 源代码缓冲区大小(1MB) +SRC_BUF_SIZE: t.CDefine = 1048576 + +# ============================================================ +# RunPhase1 - Phase1: 扫描 includes 目录,按需翻译并生成 stub +# +# 对每个 .py 文件检查 stub 是否已存在,若不存在则翻译并分离 stub。 +# "按需翻译":仅对 stub 不存在的文件执行翻译,避免重复工作。 +# +# Args: +# mb: 内存池 +# includes_dir: includes 目录路径 +# temp_dir: 临时目录(保存 stub) +# log: 日志器 +# +# Returns: +# 0 成功,非 0 失败 +# ============================================================ +def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str, + log: VLogger.Logger | t.CPtr) -> int: + """Phase1: 扫描 includes 目录,按需翻译并生成 stub""" + if includes_dir is None or temp_dir is None: + stdio.printf("[Phase1] includes_dir 或 temp_dir 为空,跳过\n") + return 1 + + if log is not None: + log.banner("Phase1: 扫描 includes(按需翻译)") + + # 扫描 includes 目录 + result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir) + if result is None: + stdio.printf("[Phase1] 扫描失败\n") + return 1 + + stdio.printf("[Phase1] 共 %d 个文件\n", result.Count) + + # 读取 _sha1_map.txt 获取需要的 includes SHA1 集合 + # 优先使用 Projectrans.py 生成的 _sha1_map.txt(含依赖分析,只包含需要的 includes) + # 若不存在,则从扫描结果生成(包含所有 includes,可能导致结构体表溢出) + sha1_set: str = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17) + if sha1_set is None: + stdio.printf("[Phase1] sha1_set 分配失败\n") + return 1 + string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) + set_count: int = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set) + if set_count <= 0: + stdio.printf("[Phase1] _sha1_map.txt 不存在或为空,从扫描结果生成\n") + StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, None, 0) + set_count = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set) + if set_count < 0: + stdio.printf("[Phase1] 无法加载 _sha1_map.txt,跳过 Phase1\n") + return 1 + stdio.printf("[Phase1] includes SHA1 集合: %d 个\n", set_count) + + # 构建模块 SHA1 映射(供跨模块函数调用名混淆使用) + td_len_p1map: t.CSizeT = string.strlen(temp_dir) + p1_sha1_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17) + p1_mod_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64) + p1_inc_count: int = 0 + if p1_sha1_arr is not None and p1_mod_arr is not None: + p1_inc_count = StubMerger._BuildIncludesSha1Map(temp_dir, td_len_p1map, p1_sha1_arr, p1_mod_arr) + HandlesExprCall.set_module_sha1_map(p1_sha1_arr, p1_mod_arr, p1_inc_count) + + # 初始化 AST 表(只需一次) + ast._init_tables(mb) + + # FileEntry 结构体大小(Phase 1a 和 1b 共用) + entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + + # ============================================================ + # Phase 1a-pre: 扫描所有 includes 文件的 import 依赖 + # + # 只处理 Import/ImportFrom 语句,跳过 ClassDef/FunctionDef 等, + # 不调用 resolve_annotation_type,避免 list[...] 等不支持的语法触发 crash。 + # 生成 .deps.txt 供依赖图按需翻译使用。 + # ============================================================ + stdio.printf("[Phase1a-pre] 扫描 import 依赖\n") + p1a_registered: int = 0 + p1a_skipped: int = 0 + p1a_failed: int = 0 + + for i in range(result.Count): + entry_addr_a: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size + entry_a: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_a, t.CPtr)) + if entry_a is None: + p1a_failed += 1 + continue + + sha1_a: str = entry_a.Sha1 + if sha1_a is None: + p1a_failed += 1 + continue + + if StubMerger._is_in_sha1_set(sha1_a, sha1_set, set_count) == 0: + p1a_skipped += 1 + continue + + # 读取文件内容 + file_path_a: str = entry_a.Path + f_a: fileio.File | t.CPtr = fileio.File(file_path_a, fileio.MODE.R) + if f_a.closed: + p1a_failed += 1 + continue + + src_buf_a: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf_a is None: + f_a.close() + p1a_failed += 1 + continue + + bytes_read_a: LONG = f_a.read_all(src_buf_a, SRC_BUF_SIZE) + f_a.close() + if bytes_read_a <= 0: + stdlib.free(src_buf_a) + p1a_failed += 1 + continue + if bytes_read_a < SRC_BUF_SIZE: + src_buf_a[bytes_read_a] = 0 + else: + src_buf_a[SRC_BUF_SIZE - 1] = 0 + + # 解析 AST + lx_a: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx_a is None: + stdlib.free(src_buf_a) + p1a_failed += 1 + continue + ast._lexer_init(lx_a, src_buf_a, mb) + tokens_a: ast.Token | t.CPtr = ast.tokenize(lx_a) + tree_a: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_a) + if tree_a is None: + stdlib.free(src_buf_a) + p1a_failed += 1 + continue + + # 创建 Translator,设置 _declare_only=2(只扫描 import,跳过 ClassDef) + tr_a: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + if tr_a is None: + stdlib.free(src_buf_a) + p1a_failed += 1 + continue + tr_a.ModuleSha1 = sha1_a + tr_a._declare_only = 2 + tr_a.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_a.RelPath) + HandlesType.set_current_file(file_path_a) + HandlesType.clear_cdefine_constants() + HandlesStruct.reset_visible_structs(mb, 0) + ret_a: int = tr_a.translate(tree_a) + if ret_a != 0: + p1a_failed += 1 + else: + p1a_registered += 1 + + # 生成 .deps.txt(记录依赖模块名,供依赖图按需翻译使用) + td_len_a: t.CSizeT = string.strlen(temp_dir) + deps_path_a: bytes = stdlib.malloc(td_len_a + 32) + if deps_path_a is not None: + viperlib.snprintf(deps_path_a, td_len_a + 32, "%s/%s.deps.txt", temp_dir, sha1_a) + df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W) + if not df_a.closed: + if tr_a._imported_modules is not None: + dl_a: t.CSizeT = string.strlen(tr_a._imported_modules) + df_a.write(tr_a._imported_modules, dl_a) + df_a.close() + stdlib.free(deps_path_a) + + # 释放 Translator 的 C malloc 资源 + if tr_a._global_names is not None: + stdlib.free(tr_a._global_names) + if tr_a._nonlocal_names is not None: + stdlib.free(tr_a._nonlocal_names) + + stdlib.free(src_buf_a) + + stdio.printf("[Phase1a-pre] 完成: 扫描=%d 跳过=%d 失败=%d\n", p1a_registered, p1a_skipped, p1a_failed) + + # ============================================================ + # 依赖图按需翻译:构建可达 SHA1 集合 + # + # 从 Config.SourceDir 的源文件开始,解析 import 语句,递归收集 + # 可达的 includes 文件 SHA1。Phase 1b 只翻译可达集合中的文件, + # 避免翻译不需要的 includes(如 Test 不依赖 llvmlite,则不翻译)。 + # 如果 Config.SourceDir 不可用(仅运行 Phase1),回退到 sha1_set。 + # ============================================================ + reachable_set: str = None + reachable_count: int = 0 + use_reachable: int = 0 + if Config.SourceDir is not None: + reachable_set = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17) + if reachable_set is not None: + string.memset(reachable_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) + reachable_count = StubMerger._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set) + if reachable_count > 0: + use_reachable = 1 + stdio.printf("[Phase1b] 使用可达 SHA1 集合过滤: %d 个\n", reachable_count) + # 用可达集合重新生成 _sha1_map.txt(按图求索的最终产物) + # Phase B+ 只遍历这些条目,避免编译不需要的 includes(如 asm.py) + StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, reachable_set, reachable_count) + # 重新加载 sha1_set,使后续 Phase 1a-pre/1a/1b 的过滤也使用可达集合 + string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17) + set_count = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set) + stdio.printf("[Phase1b] _sha1_map.txt 已重写为可达集合: %d 个\n", set_count) + else: + stdio.printf("[Phase1b] 可达 SHA1 集合构建失败,回退到全量集合\n") + stdlib.free(reachable_set) + reachable_set = None + + # ============================================================ + # Phase 1a: 注册可达 includes 文件的 struct/enum/union + # + # 解决字母序依赖问题:按字母顺序翻译时,后面的 struct 未注册 + # 前面就需要用。Phase 1a 先注册所有 struct/enum/union 到全局表, + # Phase 1b 全量翻译时 struct 已注册,走 existing 路径只翻译方法体。 + # 只处理可达文件,避免翻译不需要的 includes(如 Test 不依赖 ast 模块)。 + # ============================================================ + stdio.printf("[Phase1a] 注册可达文件 struct/enum/union\n") + stdio.fflush(0) + p1a_reg: int = 0 + p1a_skp: int = 0 + p1a_fl: int = 0 + + for i in range(result.Count): + entry_addr_r: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size + entry_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_r, t.CPtr)) + if entry_r is None: + p1a_fl += 1 + continue + + sha1_r: str = entry_r.Sha1 + if sha1_r is None: + p1a_fl += 1 + continue + + # 按需翻译过滤:只处理可达文件 + if use_reachable != 0: + if StubMerger._is_in_sha1_set(sha1_r, reachable_set, reachable_count) == 0: + p1a_skp += 1 + continue + else: + if StubMerger._is_in_sha1_set(sha1_r, sha1_set, set_count) == 0: + p1a_skp += 1 + continue + + # 读取文件内容 + file_path_r: str = entry_r.Path + f_r: fileio.File | t.CPtr = fileio.File(file_path_r, fileio.MODE.R) + if f_r.closed: + p1a_fl += 1 + continue + + src_buf_r: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf_r is None: + f_r.close() + p1a_fl += 1 + continue + + bytes_read_r: LONG = f_r.read_all(src_buf_r, SRC_BUF_SIZE) + f_r.close() + if bytes_read_r <= 0: + stdlib.free(src_buf_r) + p1a_fl += 1 + continue + if bytes_read_r < SRC_BUF_SIZE: + src_buf_r[bytes_read_r] = 0 + else: + src_buf_r[SRC_BUF_SIZE - 1] = 0 + + # 解析 AST + lx_r: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx_r is None: + stdlib.free(src_buf_r) + p1a_fl += 1 + continue + ast._lexer_init(lx_r, src_buf_r, mb) + tokens_r: ast.Token | t.CPtr = ast.tokenize(lx_r) + tree_r: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_r) + if tree_r is None: + stdlib.free(src_buf_r) + p1a_fl += 1 + continue + + # 创建 Translator,设置 _declare_only=1(注册 struct/enum/union) + tr_r: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + if tr_r is None: + stdlib.free(src_buf_r) + p1a_fl += 1 + continue + tr_r.ModuleSha1 = sha1_r + tr_r._declare_only = 1 + tr_r.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_r.RelPath) + HandlesType.set_current_file(file_path_r) + HandlesType.clear_cdefine_constants() + HandlesStruct.reset_visible_structs(mb, 0) + ret_r: int = tr_r.translate(tree_r) + if ret_r != 0: + p1a_fl += 1 + else: + p1a_reg += 1 + + # 释放 Translator 的 C malloc 资源 + if tr_r._global_names is not None: + stdlib.free(tr_r._global_names) + if tr_r._nonlocal_names is not None: + stdlib.free(tr_r._nonlocal_names) + + stdlib.free(src_buf_r) + + stdio.printf("[Phase1a] 完成: 注册=%d 跳过=%d 失败=%d\n", p1a_reg, p1a_skp, p1a_fl) + + # ============================================================ + # Phase 1b: 全量翻译(struct 已注册,走 existing 路径翻译方法体) + # ============================================================ + # 遍历每个文件 + translated: int = 0 + skipped: int = 0 + failed: int = 0 + + for i in range(result.Count): + # 获取 entry + entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size + entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) + if entry is None: + failed += 1 + continue + + sha1: str = entry.Sha1 + if sha1 is None: + failed += 1 + continue + + # 检查 SHA1 是否在翻译集合中(按需翻译:只翻译可达的文件) + if use_reachable != 0: + if StubMerger._is_in_sha1_set(sha1, reachable_set, reachable_count) == 0: + skipped += 1 + continue + else: + if StubMerger._is_in_sha1_set(sha1, sha1_set, set_count) == 0: + skipped += 1 + continue + + # 构造 stub 路径: {temp_dir}/{sha1}.stub.ll + dir_len: t.CSizeT = string.strlen(temp_dir) + sha1_len: t.CSizeT = string.strlen(sha1) + stub_path: bytes = stdlib.malloc(dir_len + sha1_len + 16) + if stub_path is None: + failed += 1 + continue + viperlib.snprintf(stub_path, dir_len + sha1_len + 16, "%s/%s.stub.ll", temp_dir, sha1) + + # 检查 stub 是否已存在(按需翻译:跳过已存在的) + sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R) + if not sf.closed: + sf.close() + # 检查 text.ll 是否也存在(虚表扫描需要 text.ll) + text_path: bytes = stdlib.malloc(dir_len + sha1_len + 16) + if text_path is not None: + viperlib.snprintf(text_path, dir_len + sha1_len + 16, "%s/%s.text.ll", temp_dir, sha1) + tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) + if not tf.closed: + tf.close() + stdlib.free(text_path) + stdlib.free(stub_path) + continue + stdlib.free(text_path) + # text.ll 不存在,需要重新翻译 + stdio.printf("[Phase1] text.ll 不存在,重新翻译: %s (sha1=%s)\n", entry.RelPath, sha1) + else: + # stub 不存在,需要翻译 + stdio.printf("[Phase1] 翻译: %s (sha1=%s)\n", entry.RelPath, sha1) + + stdlib.free(stub_path) + + # 读取文件内容 + file_path: str = entry.Path + f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R) + if f.closed: + stdio.printf("[Phase1] 无法打开: %s\n", file_path) + failed += 1 + continue + + src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf is None: + f.close() + failed += 1 + continue + + bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE) + f.close() + if bytes_read <= 0: + stdio.printf("[Phase1] 读取失败: %s\n", file_path) + stdlib.free(src_buf) + failed += 1 + continue + if bytes_read < SRC_BUF_SIZE: + src_buf[bytes_read] = 0 + else: + src_buf[SRC_BUF_SIZE - 1] = 0 + + # 解析 AST + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx is None: + stdlib.free(src_buf) + failed += 1 + continue + ast._lexer_init(lx, src_buf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + if tree is None: + stdio.printf("[Phase1] AST 解析失败: %s\n", file_path) + stdlib.free(src_buf) + failed += 1 + continue + + # 翻译 AST → LLVM IR + tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + if tr is None: + stdlib.free(src_buf) + failed += 1 + continue + tr.ModuleSha1 = sha1 + tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry.RelPath) + HandlesType.set_current_file(file_path) + HandlesType.clear_cdefine_constants() + HandlesStruct.reset_visible_structs(mb, 0) + ret: int = tr.translate(tree) + if ret != 0: + stdio.printf("[Phase1] 翻译失败: %s\n", file_path) + stdlib.free(src_buf) + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + failed += 1 + continue + + # dump stub IR (declarations only) + PHASE1_IR_SIZE: t.CSizeT = 262144 + stub_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE) + if stub_buf is None: + stdlib.free(src_buf) + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + failed += 1 + continue + tr.dump_ir(stub_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_STUB) + stub_len: t.CSizeT = string.strlen(stub_buf) + + # save stub.ll + dir_len_p1: t.CSizeT = string.strlen(temp_dir) + stub_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32) + if stub_path_p1 is not None: + viperlib.snprintf(stub_path_p1, dir_len_p1 + 32, "%s/%s.stub.ll", temp_dir, sha1) + sf_p1: fileio.File | t.CPtr = fileio.File(stub_path_p1, fileio.MODE.W) + if not sf_p1.closed: + sf_p1.write(stub_buf, stub_len) + sf_p1.close() + stdlib.free(stub_path_p1) + stdlib.free(stub_buf) + + # dump text IR (definitions only) + text_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE) + if text_buf is None: + stdlib.free(src_buf) + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + failed += 1 + continue + tr.dump_ir(text_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_TEXT) + text_len: t.CSizeT = string.strlen(text_buf) + + # save text.ll + text_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32) + if text_path_p1 is not None: + viperlib.snprintf(text_path_p1, dir_len_p1 + 32, "%s/%s.text.ll", temp_dir, sha1) + tf_p1: fileio.File | t.CPtr = fileio.File(text_path_p1, fileio.MODE.W) + if not tf_p1.closed: + tf_p1.write(text_buf, text_len) + tf_p1.close() + stdlib.free(text_path_p1) + stdlib.free(text_buf) + + # save dependencies (_imported_modules) for Phase B + deps_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32) + if deps_path_p1 is not None: + viperlib.snprintf(deps_path_p1, dir_len_p1 + 32, "%s/%s.deps.txt", temp_dir, sha1) + df_p1: fileio.File | t.CPtr = fileio.File(deps_path_p1, fileio.MODE.W) + if not df_p1.closed: + if tr._imported_modules is not None: + dl: t.CSizeT = string.strlen(tr._imported_modules) + df_p1.write(tr._imported_modules, dl) + df_p1.close() + stdlib.free(deps_path_p1) + + # 释放 Translator 的 C malloc 资源 + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + + # 所有 dump_ir 完成,src_buf 不再需要 + stdlib.free(src_buf) + + translated += 1 + + stdio.printf("[Phase1] 完成: 翻译=%d 跳过=%d 失败=%d\n", translated, skipped, failed) + + # 释放可达 SHA1 集合(如果分配了) + if reachable_set is not None: + stdlib.free(reachable_set) + + return 0 diff --git a/App/lib/core/Phase2.py b/App/lib/core/Phase2.py new file mode 100644 index 0000000..ef5c71c --- /dev/null +++ b/App/lib/core/Phase2.py @@ -0,0 +1,680 @@ +import t, c +from stdint import * +import stdio +import string +import stdlib +import memhub +import viperlib +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import sys +import ast +import llvmlite +import subprocess +import argparse +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.BuildPipeline as BuildPipeline +import lib.core.StubMerger as StubMerger +import lib.Projectrans.Utils as Utils +import lib.Projectrans.Config as Config + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemManager | t.CPtr + +# 源代码缓冲区大小(1MB) +SRC_BUF_SIZE: t.CDefine = 1048576 + +# 最大源文件数(递归扫描子目录后文件数增多,增大到 64) +MAX_SRC_FILES: t.CDefine = 64 + + +@t.NoVTable +class SrcFileEntry: + """源文件条目""" + Path: str # 完整路径 + Sha1: str # SHA1 前16字符 + + +# ============================================================ +# _ScanDirForPyFiles - 递归扫描目录,收集 .py 文件到 entries +# +# 替代旧的非递归 FindFirstFileA(dir/*.py) 扫描,支持子目录 +# (如 App/lib/core/Handles/)。遇到目录递归扫描,遇到 .py +# 文件读取内容、计算 SHA1、加入 entries。 +# +# Args: +# mb: 内存池 +# dir_path: 当前扫描目录 +# entries: SrcFileEntry 数组 +# entry_size: 单个条目大小(SrcFileEntry.__sizeof__()) +# file_count: 当前已收集的文件数 +# max_files: 最大文件数 +# +# Returns: +# 新的 file_count +# ============================================================ +def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr, + dir_path: str, + entries: SrcFileEntry | t.CPtr, + entry_size: t.CSizeT, + file_count: int, max_files: int) -> int: + """递归扫描目录,收集 .py 文件到 entries,返回新的 file_count""" + if dir_path is None or entries is None: + return file_count + if file_count >= max_files: + return file_count + + dir_len: t.CSizeT = string.strlen(dir_path) + pattern: bytes = stdlib.malloc(dir_len + 16) + if pattern is None: + return file_count + viperlib.snprintf(pattern, dir_len + 16, "%s/*", dir_path) + + find_data_size: t.CSizeT = w32.win32file.WIN32_FIND_DATAA.__sizeof__() + find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(find_data_size + 16) + if find_data is None: + stdlib.free(pattern) + return file_count + string.memset(find_data, 0, find_data_size + 16) + + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + stdlib.free(pattern) + stdlib.free(find_data) + return file_count + + while True: + fname: str = find_data.cFileName + if fname is not None: + fname_len: t.CSizeT = string.strlen(fname) + if fname_len > 0: + # 跳过 . 和 .. + is_dot: int = 0 + if fname_len == 1 and fname[0] == '.': + is_dot = 1 + elif fname_len == 2 and fname[0] == '.' and fname[1] == '.': + is_dot = 1 + if is_dot == 0: + # 检查是否是目录 + attrs: ULONG = find_data.dwFileAttributes + is_dir: int = 0 + if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + is_dir = 1 + if is_dir != 0: + # 递归扫描子目录 + sub_dir: bytes = stdlib.malloc(dir_len + fname_len + 2) + if sub_dir is not None: + viperlib.snprintf(sub_dir, dir_len + fname_len + 2, "%s/%s", dir_path, fname) + file_count = _ScanDirForPyFiles(mb, sub_dir, entries, entry_size, file_count, max_files) + stdlib.free(sub_dir) + else: + # 检查是否是 .py 文件 + if fname_len > 3: + if fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y': + if file_count < max_files: + full_path: bytes = stdlib.malloc(dir_len + fname_len + 2) + if full_path is not None: + viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", dir_path, fname) + sf: fileio.File | t.CPtr = fileio.File(full_path, fileio.MODE.R) + if not sf.closed: + sbuf: bytes = stdlib.malloc(SRC_BUF_SIZE) + if sbuf is not None: + br: LONG = sf.read_all(sbuf, SRC_BUF_SIZE) + sf.close() + if br > 0: + if br < SRC_BUF_SIZE: + sbuf[br] = 0 + else: + sbuf[SRC_BUF_SIZE - 1] = 0 + sha1_val: str = Utils.compute_sha1(mb, sbuf) + if sha1_val is not None: + ea: t.CUInt64T = t.CUInt64T(entries) + file_count * entry_size + ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) + if ent is not None: + ent.Path = full_path + ent.Sha1 = sha1_val + file_count += 1 + stdio.printf("[project] %s (sha1=%s)\n", fname, sha1_val) + stdlib.free(sbuf) + # full_path 不释放:ent.Path 引用它 + + if w32.win32file.FindNextFileA(handle, find_data) == 0: + break + + w32.win32file.FindClose(handle) + stdlib.free(pattern) + stdlib.free(find_data) + return file_count + + +def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, + source_dir: str, temp_dir: str, output_dir: str, + cc_cmd: str, cc_flags: str, + linker_cmd: str, linker_flags: str, linker_output: str, + includes_binary_dir: str, + includes_dir: str, + do_phase1: int, do_phase2: int, + log: VLogger.Logger | t.CPtr, + args: argparse.ParsedArgs | t.CPtr) -> int: + """多文件项目编译 + + Returns: 0 成功,非 0 失败 + """ + if source_dir is None: + stdio.printf("[project] source_dir 为空\n") + return 1 + + stdio.printf("[project] 多文件项目编译: %s\n", source_dir) + + # === 1. 递归扫描 source_dir 下的 .py 文件(包括子目录)=== + entry_size: t.CSizeT = SrcFileEntry.__sizeof__() + entries: SrcFileEntry | t.CPtr = stdlib.malloc(MAX_SRC_FILES * entry_size) + if entries is None: + return 1 + string.memset(entries, 0, MAX_SRC_FILES * entry_size) + + file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES) + stdio.printf("[project] 共 %d 个源文件\n", file_count) + + if file_count == 0: + stdlib.free(entries) + return 1 + + # 初始化 AST 表 + ast._init_tables(mb) + + # 确保 temp/output 目录存在 + BuildPipeline.ensure_dir(temp_dir) + BuildPipeline.ensure_dir(output_dir) + + # 追加 App 源文件 SHA1 到 _sha1_map.txt(供日志转存和符号查找使用) + # 格式: {sha1}:App/{filename}\n (与 includes 条目格式对应) + td_len_am: t.CSizeT = string.strlen(temp_dir) + map_path_am: bytes = stdlib.malloc(td_len_am + 32) + if map_path_am is not None: + viperlib.snprintf(map_path_am, td_len_am + 32, "%s/_sha1_map.txt", temp_dir) + mf: fileio.File | t.CPtr = fileio.File(map_path_am, fileio.MODE.A) + if not mf.closed: + line_am: bytes = stdlib.malloc(512) + if line_am is not None: + for i in range(file_count): + ea_am: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent_am: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_am, t.CPtr)) + if ent_am is None or ent_am.Path is None or ent_am.Sha1 is None: + continue + # 从路径提取文件名(最后一个 / 或 \\ 之后的部分) + p_str: str = ent_am.Path + p_len: t.CSizeT = string.strlen(p_str) + f_start: t.CSizeT = 0 + for j in range(p_len): + if p_str[j] == '/' or p_str[j] == '\\': + f_start = j + 1 + viperlib.snprintf(line_am, 512, "%s:App/%s\n", ent_am.Sha1, p_str + f_start) + ll_am: t.CSizeT = string.strlen(line_am) + mf.write(line_am, ll_am) + stdlib.free(line_am) + mf.close() + stdio.printf("[project] 已追加 %d 个 App 文件到 _sha1_map.txt\n", file_count) + stdlib.free(map_path_am) + + # 构建模块 SHA1 映射(供跨模块函数调用名混淆使用) + td_len_pb: t.CSizeT = string.strlen(temp_dir) + pb_sha1_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17) + pb_mod_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64) + pb_inc_count: int = 0 + if pb_sha1_arr is not None and pb_mod_arr is not None: + pb_inc_count = StubMerger._BuildIncludesSha1Map(temp_dir, td_len_pb, pb_sha1_arr, pb_mod_arr) + # 追加用户源文件的 (模块名, SHA1) 到全局映射 + # 使跨模块方法调用能通过 from_imports + _lookup_module_sha1 找到正确的 SHA1 + if pb_sha1_arr is not None and pb_mod_arr is not None: + for i in range(file_count): + ea_us: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent_us: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_us, t.CPtr)) + if ent_us is None or ent_us.Path is None or ent_us.Sha1 is None: + continue + if pb_inc_count >= StubMerger.MAX_INCLUDES: + break + # 从路径提取模块名(文件名去掉 .py 后缀) + path_str: str = ent_us.Path + path_len: t.CSizeT = string.strlen(path_str) + fname_start: t.CSizeT = 0 + for j in range(path_len): + if path_str[j] == '/' or path_str[j] == '\\': + fname_start = j + 1 + mod_len: t.CSizeT = path_len - fname_start + if mod_len < 4: + continue + mod_len -= 3 + if mod_len >= 64: + mod_len = 63 + # 写入模块名 + mod_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 64 + for k in range(mod_len): + pb_mod_arr[mod_idx + k] = path_str[fname_start + k] + pb_mod_arr[mod_idx + mod_len] = '\0' + # 写入 SHA1 + sha1_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 17 + string.strcpy(pb_sha1_arr + sha1_idx, ent_us.Sha1) + pb_inc_count += 1 + HandlesExprCall.set_module_sha1_map(pb_sha1_arr, pb_mod_arr, pb_inc_count) + + + # === 2. Phase A: 为每个文件生成 stub + text === + if do_phase1 != 0: + if log is not None: + log.banner("Phase A: 生成 stub + text") + + PHASE_A_IR_SIZE: t.CSizeT = 262144 + td_len_pa: t.CSizeT = string.strlen(temp_dir) + + for i in range(file_count): + ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) + if ent is None or ent.Path is None: + continue + + # 计算源文件的包名(相对 source_dir 的目录部分) + src_dir_len_pa: t.CSizeT = string.strlen(source_dir) + pkg_pa: str = None + if string.strlen(ent.Path) > src_dir_len_pa + 1: + rel_path_pa: str = ent.Path + src_dir_len_pa + 1 + pkg_pa = HandlesImports.compute_package_from_relpath(mb, rel_path_pa) + tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa) + if tr_a is None: + continue + + # dump stub IR (declarations only) + stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE) + if stub_buf_a is None: + continue + tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB) + stub_len_a: t.CSizeT = string.strlen(stub_buf_a) + + # save stub.ll + stub_path_a: bytes = stdlib.malloc(td_len_pa + 32) + if stub_path_a is not None: + viperlib.snprintf(stub_path_a, td_len_pa + 32, "%s/%s.stub.ll", temp_dir, ent.Sha1) + sf_a: fileio.File | t.CPtr = fileio.File(stub_path_a, fileio.MODE.W) + if not sf_a.closed: + sf_a.write(stub_buf_a, stub_len_a) + sf_a.close() + stdlib.free(stub_path_a) + stdlib.free(stub_buf_a) + + # dump text IR (definitions only) + text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE) + if text_buf_a is None: + continue + tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT) + text_len_a: t.CSizeT = string.strlen(text_buf_a) + + # save text.ll + text_path_a: bytes = stdlib.malloc(td_len_pa + 32) + if text_path_a is not None: + viperlib.snprintf(text_path_a, td_len_pa + 32, "%s/%s.text.ll", temp_dir, ent.Sha1) + tf_a: fileio.File | t.CPtr = fileio.File(text_path_a, fileio.MODE.W) + if not tf_a.closed: + tf_a.write(text_buf_a, text_len_a) + tf_a.close() + stdlib.free(text_path_a) + stdlib.free(text_buf_a) + + # save dependencies (_imported_modules) for Phase B + deps_path_a: bytes = stdlib.malloc(td_len_pa + 32) + if deps_path_a is not None: + viperlib.snprintf(deps_path_a, td_len_pa + 32, "%s/%s.deps.txt", temp_dir, ent.Sha1) + df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W) + if not df_a.closed: + if tr_a._imported_modules is not None: + dl_a: t.CSizeT = string.strlen(tr_a._imported_modules) + df_a.write(tr_a._imported_modules, dl_a) + df_a.close() + stdlib.free(deps_path_a) + + if do_phase2 == 0: + stdio.printf("[project] Phase A 完成(仅 stub 生成)\n") + stdlib.free(entries) + return 0 + + # === 3. Phase B: 编译每个文件为 .obj === + if do_phase2 != 0: + if log is not None: + log.banner("Phase B: 编译 .obj") + + # 收集 .obj 路径 + OBJ_PATHS_SIZE: t.CSizeT = 8192 + obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE) + if obj_paths is None: + return 1 + obj_paths[0] = '\0' + obj_pos: t.CSizeT = 0 + # main_obj_path: 存放定义了用户 main 的 .obj 路径(链接时放在最前面, + # 避免 --allow-multiple-definition 选择了其他模块的 wrapper main) + main_obj_path: bytes = stdlib.malloc(512) + if main_obj_path is None: + return 1 + main_obj_path[0] = '\0' + compiled_count: int = 0 + + # 组合 IR 缓冲区大小(4MB,足够容纳本地 stub + 所有依赖 stub + 本地 text) + COMBINED_IR_SIZE: t.CSizeT = 4194304 + + for i in range(file_count): + ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size + ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr)) + if ent is None or ent.Path is None or ent.Sha1 is None: + continue + + stdio.printf("[Phase B] %s\n", ent.Path) + + # 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR + stdio.printf("[Phase B] malloc %d bytes...\n", COMBINED_IR_SIZE) + combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE) + if combined_ir is None: + stdio.printf("[Phase B] combined_ir 分配失败: %s\n", ent.Path) + continue + stdio.printf("[Phase B] malloc OK, calling BuildCombinedIR...\n") + combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE) + if combined_len == 0: + stdio.printf("[Phase B] BuildCombinedIR 失败: %s\n", ent.Path) + stdlib.free(combined_ir) + continue + + # 编译为 .obj + cret: int = BuildPipeline.compile_module_to_obj( + combined_ir, combined_len, temp_dir, output_dir, ent.Sha1, + cc_cmd, cc_flags) + stdlib.free(combined_ir) + if cret != 0: + stdio.printf("[FATAL][Phase B] llc 编译失败,终止编译: %s\n", ent.Path) + sys.exit(1) + + compiled_count += 1 + + # 构造 .obj 路径,检测是否是 main 模块(test_main.py 或 main.py) + od_len: t.CSizeT = string.strlen(output_dir) + sha1_len: t.CSizeT = string.strlen(ent.Sha1) + need: t.CSizeT = od_len + 1 + sha1_len + 6 + is_main_mod: int = 0 + if string.strstr(ent.Path, "test_main.py") is not None: + is_main_mod = 1 + elif string.strstr(ent.Path, "main.py") is not None: + is_main_mod = 1 + + if is_main_mod != 0: + viperlib.snprintf(main_obj_path, 512, "%s/%s.obj", output_dir, ent.Sha1) + else: + if obj_pos + need < OBJ_PATHS_SIZE: + if obj_pos > 0: + obj_paths[obj_pos] = ' ' + obj_pos += 1 + viperlib.snprintf(obj_paths + obj_pos, need, "%s/%s.obj", output_dir, ent.Sha1) + obj_pos += od_len + 1 + sha1_len + 4 + obj_paths[obj_pos] = '\0' + else: + stdio.printf("[Phase B] 警告: .obj 路径缓冲区不足\n") + + stdio.printf("[Phase B] 编译完成: %d/%d\n", compiled_count, file_count) + + if compiled_count == 0: + stdio.printf("[Phase B] 无成功编译的文件\n") + stdlib.free(entries) + return 1 + + # === 3.5 编译缺失的 includes 文件 === + # includes.binary 可能缺少某些 includes .obj(如 testcheck.py), + # 这些文件被用户项目导入但未被 TransPyV 自身依赖,Projectrans.py 未编译它们。 + # 检测并编译缺失的 includes 文件到 output_dir,加入链接命令。 + if includes_dir is not None and includes_binary_dir is not None: + inc_compiled: int = 0 + td_len_mi: t.CSizeT = string.strlen(temp_dir) + map_path_mi: bytes = stdlib.malloc(td_len_mi + 32) + if map_path_mi is not None: + viperlib.snprintf(map_path_mi, td_len_mi + 32, "%s/_sha1_map.txt", temp_dir) + mapf_mi: fileio.File | t.CPtr = fileio.File(map_path_mi, fileio.MODE.R) + if not mapf_mi.closed: + map_buf_mi: bytes = stdlib.malloc(65536) + if map_buf_mi is not None: + map_br_mi: t.CInt64T = mapf_mi.read_all(map_buf_mi, 65536) + mapf_mi.close() + if map_br_mi > 0: + if map_br_mi < 65536: + map_buf_mi[map_br_mi] = '\0' + else: + map_buf_mi[65535] = '\0' + map_len_mi: t.CSizeT = map_br_mi + mpos_mi: t.CSizeT = 0 + while mpos_mi < map_len_mi: + ml_start_mi: t.CSizeT = mpos_mi + while mpos_mi < map_len_mi: + if map_buf_mi[mpos_mi] == '\n': + break + mpos_mi += 1 + ml_len_mi: t.CSizeT = mpos_mi - ml_start_mi + mpos_mi += 1 + + # 最小长度: 16(sha1)+1(:)+9(includes/)+1+1+1 = 29 + if ml_len_mi < 26: + continue + if map_buf_mi[ml_start_mi + 16] != ':': + continue + rp_start_mi: t.CSizeT = ml_start_mi + 17 + if string.strncmp(map_buf_mi + rp_start_mi, "includes/", 9) != 0: + continue + + # 提取 SHA1 + inc_sha1_mi: str = stdlib.malloc(17) + if inc_sha1_mi is None: + continue + string.strncpy(inc_sha1_mi, map_buf_mi + ml_start_mi, 16) + inc_sha1_mi[16] = '\0' + + # 检查 .obj 是否已存在于 includes.binary + ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir) + check_pat_mi: bytes = stdlib.malloc(ibd_len_mi + 35) + if check_pat_mi is None: + continue + viperlib.snprintf(check_pat_mi, ibd_len_mi + 35, "%s/%s*.obj", includes_binary_dir, inc_sha1_mi) + check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + obj_exists_mi: int = 0 + if check_fd_mi is not None: + string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__()) + check_h_mi: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(check_pat_mi, check_fd_mi) + if check_h_mi != w32.win32base.INVALID_HANDLE_VALUE: + w32.win32file.FindClose(check_h_mi) + obj_exists_mi = 1 + if obj_exists_mi != 0: + continue + + # .obj 不存在,需要编译 + # 构造源文件路径: {includes_dir}/{rel_path_without_includes_prefix} + rel_path_len_mi: t.CSizeT = ml_len_mi - 26 + inc_dir_len_mi: t.CSizeT = string.strlen(includes_dir) + src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1) + if src_fp_mi is None: + continue + viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1, + "%s/%s", includes_dir, map_buf_mi + rp_start_mi + 9) + + # 检查是否为声明文件(只有 declare 没有实质 define) + # 判断方法: text.ll 中若有混淆函数 define(含 @\")则为实现文件 + is_decl_mi: int = -1 + tpath_mi: bytes = stdlib.malloc(td_len_mi + 32) + if tpath_mi is not None: + viperlib.snprintf(tpath_mi, td_len_mi + 32, "%s/%s.text.ll", temp_dir, inc_sha1_mi) + tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R) + if not tf_mi.closed: + is_decl_mi = 1 + tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE) + if tbuf_mi is not None: + tbr_mi: t.CInt64T = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE) + if tbr_mi > 0: + if tbr_mi < StubMerger.STUB_READ_BUF_SIZE: + tbuf_mi[tbr_mi] = '\0' + else: + tbuf_mi[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0' + # 逐行扫描: 找 define 行中含 @\" 的(混淆函数名) + tpos_mi: t.CSizeT = 0 + while tpos_mi < tbr_mi: + tls_mi: t.CSizeT = tpos_mi + while tpos_mi < tbr_mi: + if tbuf_mi[tpos_mi] == '\n': + break + tpos_mi += 1 + tll_mi: t.CSizeT = tpos_mi - tls_mi + if tpos_mi < tbr_mi: + tpos_mi += 1 + if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0: + # 临时在行尾加 \0 供 strstr 使用 + saved_mi: t.CChar = tbuf_mi[tls_mi + tll_mi] + tbuf_mi[tls_mi + tll_mi] = '\0' + if string.strstr(tbuf_mi + tls_mi, "@\"") is not None: + tbuf_mi[tls_mi + tll_mi] = saved_mi + is_decl_mi = 0 + break + tbuf_mi[tls_mi + tll_mi] = saved_mi + stdlib.free(tbuf_mi) + tf_mi.close() + stdlib.free(tpath_mi) + if is_decl_mi == 1: + stdio.printf("[Phase B+] 跳过(声明文件): %s (sha1=%s)\n", src_fp_mi, inc_sha1_mi) + continue + + stdio.printf("[Phase B+] 编译缺失 includes: %s (sha1=%s)\n", src_fp_mi, inc_sha1_mi) + + # 尝试 BuildCombinedIR(stub/text 应已由 Phase1 生成) + inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE) + inc_combined_len_mi: t.CSizeT = 0 + if inc_combined_mi is not None: + inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE) + + # 如果 stub/text 不存在,翻译源文件并保存 stub + text,然后重试 + if inc_combined_len_mi == 0 and inc_combined_mi is not None: + stdio.printf("[Phase B+] stub/text 不存在,翻译: %s\n", src_fp_mi) + # 计算 includes 文件的包名(相对 includes_dir 的目录部分) + inc_pkg_mi: str = None + if string.strlen(src_fp_mi) > inc_dir_len_mi + 1: + inc_rel_mi: str = src_fp_mi + inc_dir_len_mi + 1 + inc_pkg_mi = HandlesImports.compute_package_from_relpath(mb, inc_rel_mi) + tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi) + if tr_mi is not None: + PBP_IR_SIZE: t.CSizeT = 262144 + # 保存 stub.ll + inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE) + if inc_stub_buf is not None: + tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB) + inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf) + inc_stub_path: bytes = stdlib.malloc(td_len_mi + 32) + if inc_stub_path is not None: + viperlib.snprintf(inc_stub_path, td_len_mi + 32, "%s/%s.stub.ll", temp_dir, inc_sha1_mi) + isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W) + if not isf.closed: + isf.write(inc_stub_buf, inc_stub_len) + isf.close() + stdlib.free(inc_stub_path) + stdlib.free(inc_stub_buf) + # 保存 text.ll + inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE) + if inc_text_buf is not None: + tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT) + inc_text_len: t.CSizeT = string.strlen(inc_text_buf) + inc_text_path: bytes = stdlib.malloc(td_len_mi + 32) + if inc_text_path is not None: + viperlib.snprintf(inc_text_path, td_len_mi + 32, "%s/%s.text.ll", temp_dir, inc_sha1_mi) + itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W) + if not itf.closed: + itf.write(inc_text_buf, inc_text_len) + itf.close() + stdlib.free(inc_text_path) + stdlib.free(inc_text_buf) + # 重试 BuildCombinedIR + inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE) + + if inc_combined_len_mi == 0: + stdio.printf("[Phase B+] BuildCombinedIR 失败: %s\n", src_fp_mi) + if inc_combined_mi is not None: + stdlib.free(inc_combined_mi) + continue + + # 编译为 .obj + inc_cret_mi: int = BuildPipeline.compile_module_to_obj( + inc_combined_mi, inc_combined_len_mi, temp_dir, output_dir, inc_sha1_mi, + cc_cmd, cc_flags) + stdlib.free(inc_combined_mi) + if inc_cret_mi != 0: + stdio.printf("[FATAL][Phase B+] llc 编译失败,终止编译: %s\n", src_fp_mi) + sys.exit(1) + + inc_compiled += 1 + + # 添加到 obj_paths + od_len_mi: t.CSizeT = string.strlen(output_dir) + sha1_len_mi: t.CSizeT = 16 + need_mi: t.CSizeT = od_len_mi + 1 + sha1_len_mi + 6 + if obj_pos + need_mi < OBJ_PATHS_SIZE: + if obj_pos > 0: + obj_paths[obj_pos] = ' ' + obj_pos += 1 + viperlib.snprintf(obj_paths + obj_pos, need_mi, "%s/%s.obj", output_dir, inc_sha1_mi) + obj_pos += od_len_mi + 1 + sha1_len_mi + 4 + obj_paths[obj_pos] = '\0' + + stdio.printf("[Phase B+] 编译缺失 includes: %d 个\n", inc_compiled) + + # === 4. Phase C: 链接所有 .obj → .exe === + if log is not None: + log.banner("Phase C: 链接") + + od_len2: t.CSizeT = string.strlen(output_dir) + lo_len: t.CSizeT = string.strlen(linker_output) + exe_path: bytes = stdlib.malloc(od_len2 + lo_len + 2) + if exe_path is not None: + viperlib.snprintf(exe_path, od_len2 + lo_len + 2, "%s/%s", output_dir, linker_output) + else: + exe_path = linker_output + + # 构造最终 .obj 路径列表:main_obj_path 在前,其他 .obj 在后 + final_obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE + 512) + if final_obj_paths is None: + stdlib.free(entries) + return 1 + final_obj_paths[0] = '\0' + fop_pos: t.CSizeT = 0 + # main_obj_path 放在最前面(确保 --allow-multiple-definition 选择用户 main) + if main_obj_path[0] != '\0': + mlen: t.CSizeT = string.strlen(main_obj_path) + string.strcpy(final_obj_paths, main_obj_path) + fop_pos = mlen + if obj_paths[0] != '\0': + final_obj_paths[fop_pos] = ' ' + fop_pos += 1 + # 追加其他 .obj + if obj_paths[0] != '\0': + string.strcpy(final_obj_paths + fop_pos, obj_paths) + fop_pos += string.strlen(obj_paths) + final_obj_paths[fop_pos] = '\0' + + obj_paths_len: t.CSizeT = fop_pos + lret: int = BuildPipeline.link_objs_to_exe( + final_obj_paths, obj_paths_len, + linker_cmd, linker_flags, exe_path, + includes_binary_dir) + + if lret == 0: + stdio.printf("输出: %s\n", exe_path) + if args.get_bool("run"): + stdio.printf("[run] 执行: %s\n", exe_path) + rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False) + if rp is not None: + stdio.printf("[run] 退出码: %d\n", rp.returncode) + else: + stdio.printf("[Phase C] 链接失败\n") + stdlib.free(entries) + return 1 + + stdlib.free(entries) + return 0 diff --git a/App/lib/core/StubMerger.py b/App/lib/core/StubMerger.py new file mode 100644 index 0000000..708563a --- /dev/null +++ b/App/lib/core/StubMerger.py @@ -0,0 +1,1477 @@ +import t, c +from stdint import * +import memhub +import string +import stdio +import stdlib +import llvmlite +import w32.win32file as win32file +import w32.win32base as win32base +import w32.fileio as fileio +import viperlib +import sys +import ast +import lib.core.IncludesScanner as IncludesScanner +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesTranslator as HandlesTranslator + + +# ============================================================ +# StubMerger - stub 声明合并模块 +# +# 从 temp 目录加载所有 .stub.ll 文件,将声明内容合并到主 IR。 +# 这是 Phase2 的核心功能:翻译主文件时,将所有依赖的 stub +# 声明合并到主 IR 前面,使链接器能解析跨模块符号引用。 +# +# 合并策略: +# 1. 扫描 temp 目录,收集所有 {sha1}.stub.ll 文件 +# 2. 读取每个 stub 文件内容 +# 3. 过滤去重(避免重复声明) +# 4. 将声明插入到主 IR 的 target triple 之后 +# ============================================================ + +# 全局 mbuddy 指针 +_mbuddy: memhub.MemManager | t.CPtr + +# 最大 includes SHA1 数(用于过滤) +MAX_INCLUDES_SHA1: t.CDefine = 256 +# stub 读取缓冲区大小 +STUB_READ_BUF_SIZE: t.CDefine = 262144 +# 最大 includes 条目数 +MAX_INCLUDES: t.CDefine = 256 + + +# ============================================================ +# _load_includes_sha1_set - 读取 _sha1_map.txt,收集 includes/ 开头的 SHA1 +# +# _sha1_map.txt 格式:{sha16}:{rel_path} +# 仅收集 rel_path 以 "includes/" 开头的 SHA1,用于过滤 stub 文件, +# 避免加载 TransPyV 自身源文件(lib/*)的 stub 导致链接失败。 +# ============================================================ +def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr, + temp_dir: str, + sha1_set: str) -> int: + """读取 _sha1_map.txt,将 includes/ 开头的 SHA1 写入 sha1_set + sha1_set 大小为 MAX_INCLUDES_SHA1 * 17(每个 SHA1 16字符+null) + 返回找到的 includes SHA1 数量,-1 表示错误""" + if pool is None or temp_dir is None or sha1_set is None: + return -1 + + # 构造路径 temp_dir/_sha1_map.txt(使用 stdlib.malloc 避免 mbuddy 池耗尽) + dir_len: t.CSizeT = string.strlen(temp_dir) + map_path: bytes = stdlib.malloc(dir_len + 32) + if map_path is None: + return -1 + viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir) + + # 打开文件 + f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.R) + if f.closed: + stdio.printf("[StubMerger] _sha1_map.txt 不存在: %s\n", map_path) + return -1 + + # 读取内容(使用 stdlib.malloc 避免 mbuddy 池耗尽) + MAP_BUF_SIZE: t.CSizeT = 65536 + content: str = stdlib.malloc(MAP_BUF_SIZE) + if content is None: + f.close() + return -1 + bytes_read: t.CInt64T = f.read_all(content, MAP_BUF_SIZE) + f.close() + if bytes_read <= 0: + return -1 + content[bytes_read] = '\0' + + # 解析行: {sha1}:{rel_path} + count: int = 0 + pos: t.CSizeT = 0 + content_len: t.CSizeT = bytes_read + while pos < content_len: + # 找行尾 + line_start: t.CSizeT = pos + while pos < content_len: + if content[pos] == '\n': + break + pos += 1 + line_len: t.CSizeT = pos - line_start + pos += 1 # skip \n + + # 最小长度: 16(sha1) + 1(:) + 9(includes/) = 26 + if line_len < 26: + continue + # 检查第17个字符是 ':' + if content[line_start + 16] != ':': + continue + + # 检查 rel_path 是否以 "includes/" 开头 + rel_start: t.CSizeT = line_start + 17 + if string.strncmp(content + rel_start, "includes/", 9) == 0: + if count < MAX_INCLUDES_SHA1: + string.strncpy(sha1_set + count * 17, content + line_start, 16) + sha1_set[count * 17 + 16] = '\0' + count += 1 + + return count + + +# ============================================================ +# _is_in_sha1_set - 检查 SHA1 是否在集合中 +# ============================================================ +def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int: + """检查 sha1 是否在集合中""" + if sha1 is None or sha1_set is None: + return 0 + for i in range(set_count): + if string.strcmp(sha1_set + i * 17, sha1) == 0: + return 1 + return 0 + + +# ============================================================ +# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt +# +# TransPyV.exe 自己生成 _sha1_map.txt(不再依赖 Projectrans.py 预生成), +# 确保所有 includes 文件的 SHA1 都被记录,供 StubMerger 加载 stub 时过滤。 +# +# Args: +# mb: 内存池 +# temp_dir: 临时目录(_sha1_map.txt 写入位置) +# scan_result: IncludesScanner 扫描结果 +# +# Returns: +# 0 成功,非 0 失败 +# ============================================================ +def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str, + scan_result: IncludesScanner.ScanResult | t.CPtr, + filter_set: t.CChar | t.CPtr, + filter_count: int) -> int: + """将 includes 扫描结果写入 _sha1_map.txt(供 StubMerger 使用) + + 若 filter_set 不为 None 且 filter_count > 0,只写入 filter_set 中的条目。 + """ + if temp_dir is None or scan_result is None: + return 1 + + # 构造路径 temp_dir/_sha1_map.txt + dir_len: t.CSizeT = string.strlen(temp_dir) + map_path: bytes = stdlib.malloc(dir_len + 32) + if map_path is None: + return 1 + viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir) + + # 打开文件写入(CREATE_ALWAYS) + f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.W) + if f.closed: + stdio.printf("[Phase1] 无法写入 _sha1_map.txt: %s\n", map_path) + return 1 + + # 写入每个 include 条目: {sha1}:includes/{rel_path}\n + entry_size_w: t.CSizeT = IncludesScanner.FileEntry.__sizeof__() + line_buf: bytes = stdlib.malloc(512) + if line_buf is None: + f.close() + return 1 + + written_count: int = 0 + for i in range(scan_result.Count): + ea_w: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_w + ent_w: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_w, t.CPtr)) + if ent_w is None or ent_w.Sha1 is None or ent_w.RelPath is None: + continue + # 若提供过滤集合,只写入集合中的条目 + if filter_set is not None and filter_count > 0: + if _is_in_sha1_set(ent_w.Sha1, filter_set, filter_count) == 0: + continue + viperlib.snprintf(line_buf, 512, "%s:includes/%s\n", ent_w.Sha1, ent_w.RelPath) + line_len_w: t.CSizeT = string.strlen(line_buf) + f.write(line_buf, line_len_w) + written_count += 1 + + f.close() + stdio.printf("[Phase1] 已写入 _sha1_map.txt (%d 个 includes)\n", written_count) + return 0 + + +# ============================================================ +# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define +# +# 逐字节strncmp搜索 func_sig(如 @"sha1.func"(/ @printf( ),每次 +# 找到匹配后检查行首是否以 "declare " 或 "define " 开头,跳过 call 语句。 +# 避免 strstr 子串匹配误匹配 call ... @"func"(...) 中的 @"func"( 子串。 +# +# Args: +# out_buf: 已有的 IR 文本缓冲区 +# func_sig: 函数签名片段,如 @"sha1.func"(/ @printf( +# +# Returns: +# 1=已存在 declare/define, 0=不存在 +# ============================================================ +def _IsFuncDeclaredOrDefined(out_buf: bytes, func_sig: str) -> int: + """检查 out_buf 中是否已有函数的 declare 或 define 行""" + if out_buf is None or func_sig is None: + return 0 + sig_len: t.CSizeT = string.strlen(func_sig) + out_len: t.CSizeT = string.strlen(out_buf) + if sig_len == 0 or out_len == 0 or sig_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + sig_len <= out_len: + if string.strncmp(out_buf + pos, func_sig, sig_len) == 0: + ls: t.CSizeT = pos + while ls > 0 and out_buf[ls - 1] != '\n': + ls -= 1 + if string.strncmp(out_buf + ls, "declare ", 8) == 0: + return 1 + if string.strncmp(out_buf + ls, "define ", 7) == 0: + return 1 + pos += 1 + return 0 + + +# ============================================================ +# _CommentOutDeclareInBuf - 将 out_buf 中匹配 func_sig 的 declare 行注释掉 +# +# 用于解决 declare/define 冲突:当本地 text.ll 包含 define 而依赖 +# text.ll 已生成了同函数的 declare 时,将 declare 行首字符改为 ';' +# 使其成为注释,然后追加 define 行。 +# ============================================================ +def _CommentOutDeclareInBuf(out_buf: bytes, func_sig: str) -> int: + """在 out_buf 中搜索 declare 行(包含 func_sig),将其注释掉""" + if out_buf is None or func_sig is None: + return 0 + sig_len: t.CSizeT = string.strlen(func_sig) + out_len: t.CSizeT = string.strlen(out_buf) + if sig_len == 0 or out_len == 0 or sig_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + sig_len <= out_len: + if string.strncmp(out_buf + pos, func_sig, sig_len) == 0: + ls: t.CSizeT = pos + while ls > 0 and out_buf[ls - 1] != '\n': + ls -= 1 + if string.strncmp(out_buf + ls, "declare ", 8) == 0: + out_buf[ls] = ';' + return 1 + pos += 1 + return 0 + + +# ============================================================ +# _CommentOutGlobalInBuf - 将 out_buf 中匹配全局变量名的行注释掉 +# +# 解决 stub/text 全局变量重复定义问题:stub 中可能是 external 声明 +# 或完整定义,以 text 中的定义为准,将 stub 中的同名行注释掉。 +# ============================================================ +def _CommentOutGlobalInBuf(out_buf: bytes, global_name: str) -> int: + """在 out_buf 中搜索全局变量定义行(以 global_name 开头),将行首改为 ';'""" + if out_buf is None or global_name is None: + return 0 + name_len: t.CSizeT = string.strlen(global_name) + out_len: t.CSizeT = string.strlen(out_buf) + if name_len == 0 or out_len == 0 or name_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + name_len <= out_len: + if string.strncmp(out_buf + pos, global_name, name_len) == 0: + # 确认是行首(前一个是换行或 pos==0) + if pos == 0 or out_buf[pos - 1] == '\n': + out_buf[pos] = ';' + return 1 + pos += 1 + return 0 + + +# ============================================================ +# _CommentOutOpaqueTypeInBuf - 将 out_buf 中匹配类型名的 opaque 声明行注释掉 +# +# 解决跨模块类型定义冲突:本地 stub 可能包含自动生成的 opaque 声明 +#(如 %"sha1.Widget" = type opaque),而依赖 stub 包含完整定义 +#(如 %"sha1.Widget" = type { i8*, i32 })。去重时需要将 opaque 声明 +# 注释掉,让完整定义被追加,否则 LLC 报错 "Cannot allocate unsized type"。 +# ============================================================ +def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int: + """在 out_buf 中搜索 type_name_prefix 对应的 opaque 声明行,将行首改为 ';' + + type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=' 和后续内容) + 返回 1=已注释, 0=未找到 + """ + if out_buf is None or type_name_prefix is None: + return 0 + prefix_len: t.CSizeT = string.strlen(type_name_prefix) + out_len: t.CSizeT = string.strlen(out_buf) + if prefix_len == 0 or out_len == 0 or prefix_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + prefix_len <= out_len: + if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0: + # 确认是行首(前一个是换行或 pos==0) + if pos == 0 or out_buf[pos - 1] == '\n': + # 检查后面是否是 " = type opaque" + p: t.CSizeT = pos + prefix_len + # 跳过空格 + while p < out_len and out_buf[p] == ' ': + p += 1 + if p < out_len and out_buf[p] == '=': + p += 1 + while p < out_len and out_buf[p] == ' ': + p += 1 + if p + 11 <= out_len: + if string.strncmp(out_buf + p, "type opaque", 11) == 0: + # 找到 opaque 声明,将行首改为 ';' + out_buf[pos] = ';' + return 1 + pos += 1 + return 0 + + +# ============================================================ +# _HasFullTypeDefinition - 检查 out_buf 中是否已有完整类型定义(非 opaque) +# +# type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=') +# 完整定义: %"name" = type { ... } 或 %"name" = type < { ... } > +# 返回 1=已有完整定义, 0=无完整定义 +# ============================================================ +def _HasFullTypeDefinition(out_buf: bytes, type_name_prefix: str) -> int: + """检查 out_buf 中是否已有 type_name_prefix 的完整定义""" + if out_buf is None or type_name_prefix is None: + return 0 + prefix_len: t.CSizeT = string.strlen(type_name_prefix) + out_len: t.CSizeT = string.strlen(out_buf) + if prefix_len == 0 or out_len == 0 or prefix_len > out_len: + return 0 + pos: t.CSizeT = 0 + while pos + prefix_len <= out_len: + if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0: + # 确认是行首(前一个是换行或 pos==0),且未被注释(行首不是 ';') + is_line_start: int = 0 + if pos == 0: + is_line_start = 1 + elif out_buf[pos - 1] == '\n': + is_line_start = 1 + if is_line_start == 1: + # 检查后面是否是 " = type {" 或 " = type <" + p: t.CSizeT = pos + prefix_len + while p < out_len and out_buf[p] == ' ': + p += 1 + if p < out_len and out_buf[p] == '=': + p += 1 + while p < out_len and out_buf[p] == ' ': + p += 1 + if p + 5 < out_len: + if string.strncmp(out_buf + p, "type ", 5) == 0: + p += 5 + if p < out_len: + if out_buf[p] == '{' or out_buf[p] == '<': + return 1 + pos += 1 + return 0 + + +# ============================================================ +# _LoadAndAppendStub - 加载依赖 stub 并追加到 out_buf +# +# 读取 {temp_dir}/{sha1}.stub.ll,跳过 header(;, target, source_filename), +# 去重 declare/global,追加到 out_buf。返回新 out_pos。 +# ============================================================ +def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, + dep_buf: bytes, out_buf: bytes, out_size: t.CSizeT, + out_pos: t.CSizeT) -> t.CSizeT: + """加载依赖 stub 并追加(跳过 header,去重)""" + if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None: + return out_pos + + sha1_len: t.CSizeT = string.strlen(dep_sha1) + dep_path: bytes = stdlib.malloc(td_len + sha1_len + 16) + if dep_path is None: + return out_pos + viperlib.snprintf(dep_path, td_len + sha1_len + 16, "%s/%s.stub.ll", temp_dir, dep_sha1) + df_ls: fileio.File | t.CPtr = fileio.File(dep_path, fileio.MODE.R) + if df_ls.closed: + stdlib.free(dep_path) + return out_pos + dep_br_ls: t.CInt64T = df_ls.read_all(dep_buf, STUB_READ_BUF_SIZE) + df_ls.close() + stdlib.free(dep_path) + if dep_br_ls <= 0: + return out_pos + if dep_br_ls < STUB_READ_BUF_SIZE: + dep_buf[dep_br_ls] = '\0' + else: + dep_buf[STUB_READ_BUF_SIZE - 1] = '\0' + + # 注释掉依赖 stub 中的字符串常量行(模块内部的,不需要) + # 简单方案:搜索 "= external unnamed_addr constant" 并将行首的 @ 改为 ;@ + cfs_pos: t.CSizeT = 0 + while cfs_pos + 30 < t.CSizeT(dep_br_ls): + ext_p: t.CPtr = string.strstr(dep_buf + cfs_pos, "= external unnamed_addr constant") + if ext_p is None: + break + ext_off2: t.CSizeT = t.CSizeT(t.CUInt64T(ext_p) - t.CUInt64T(dep_buf)) + # 向前查找行首的 @ + ls: t.CSizeT = ext_off2 + while ls > 0: + if dep_buf[ls] == '\n': + ls += 1 + break + ls -= 1 + if ls < ext_off2 and dep_buf[ls] == '@': + dep_buf[ls] = ';' + cfs_pos = ext_off2 + 30 + + # 跳过 header,追加内容(去重 declare/global) + dep_pos: t.CSizeT = 0 + skipping: int = 1 + while dep_pos < dep_br_ls: + line_start: t.CSizeT = dep_pos + while dep_pos < dep_br_ls: + if dep_buf[dep_pos] == '\n': + break + dep_pos += 1 + line_len: t.CSizeT = dep_pos - line_start + if dep_pos < dep_br_ls: + dep_pos += 1 + if skipping != 0: + if line_len == 0: + continue + ch0: int = dep_buf[line_start] + if ch0 == ';': + continue + if ch0 == 't' and line_len >= 6: + if string.strncmp(dep_buf + line_start, "target", 6) == 0: + continue + if ch0 == 's' and line_len >= 15: + if string.strncmp(dep_buf + line_start, "source_filename", 15) == 0: + continue + skipping = 0 + # 去重:declare(用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句) + if line_len >= 8 and string.strncmp(dep_buf + line_start, "declare ", 8) == 0: + at: t.CSizeT = line_start + 8 + while at < line_start + line_len: + if dep_buf[at] == '@': + break + at += 1 + if at < line_start + line_len: + lp: t.CSizeT = at + 1 + while lp < line_start + line_len: + if dep_buf[lp] == '(': + break + lp += 1 + if lp < line_start + line_len: + saved: t.CChar = dep_buf[lp + 1] + dep_buf[lp + 1] = '\0' + if _IsFuncDeclaredOrDefined(out_buf, dep_buf + at) != 0: + dep_buf[lp + 1] = saved + continue + dep_buf[lp + 1] = saved + # 去重:external global + if line_len > 0 and dep_buf[line_start] == '@': + eq: t.CSizeT = line_start + 1 + while eq < line_start + line_len: + if dep_buf[eq] == '=': + break + eq += 1 + if eq < line_start + line_len: + saved: t.CChar = dep_buf[eq + 1] + dep_buf[eq + 1] = '\0' + if string.strstr(out_buf, dep_buf + line_start) is not None: + dep_buf[eq + 1] = saved + continue + dep_buf[eq + 1] = saved + # 去重:type 定义(如 %"sha1.Point" = type {i32, i32}) + # 区分完整定义(= type { ... } / = type < ... >)和 opaque 声明(= type opaque) + # 当本地 stub 有 opaque 声明而依赖 stub 有完整定义时,注释掉 opaque 行, + # 让完整定义被追加,避免 LLC "Cannot allocate unsized type" 错误。 + if line_len > 0 and dep_buf[line_start] == '%': + eq2: t.CSizeT = line_start + 1 + while eq2 < line_start + line_len: + if dep_buf[eq2] == '=': + break + eq2 += 1 + if eq2 < line_start + line_len: + saved2: t.CChar = dep_buf[eq2 + 1] + dep_buf[eq2 + 1] = '\0' + # 检查依赖行是否为完整定义(= type { 或 = type <) + dep_is_full_def: int = 0 + if eq2 + 8 <= line_start + line_len: + if dep_buf[eq2 + 2] == 't' and dep_buf[eq2 + 3] == 'y' and dep_buf[eq2 + 4] == 'p' and dep_buf[eq2 + 5] == 'e' and dep_buf[eq2 + 6] == ' ': + if dep_buf[eq2 + 7] == '{' or dep_buf[eq2 + 7] == '<': + dep_is_full_def = 1 + if dep_is_full_def == 1: + # 依赖行是完整定义 + # 临时截断到 '=' 之前(不含 '='),辅助函数期望纯类型名前缀 + saved_eq: t.CChar = dep_buf[eq2] + dep_buf[eq2] = '\0' + # 1. 注释掉 out_buf 中的 opaque 声明(如果有) + commented: int = _CommentOutOpaqueTypeInBuf(out_buf, dep_buf + line_start) + # 2. 检查 out_buf 中是否已有完整定义(避免重复) + has_full: int = _HasFullTypeDefinition(out_buf, dep_buf + line_start) + dep_buf[eq2] = saved_eq + if has_full == 1: + dep_buf[eq2 + 1] = saved2 + continue + # 3. 追加完整定义 + else: + # 依赖行是 opaque 声明,用原有子串匹配去重 + found_opaque: t.CPtr = string.strstr(out_buf, dep_buf + line_start) + if found_opaque is not None: + dep_buf[eq2 + 1] = saved2 + continue + dep_buf[eq2 + 1] = saved2 + # 追加 + if out_pos + line_len + 2 < out_size: + string.strncpy(out_buf + out_pos, dep_buf + line_start, line_len) + out_pos += line_len + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + return out_pos + + +# ============================================================ +# _LoadAndAppendTextDeclares - 从依赖 text.ll 提取 declare 追加到 out_buf +# +# 读取 {temp_dir}/{sha1}.text.ll,将 define 行转为 declare(提取函数签名), +# 跳过函数体,去重后追加到 out_buf。返回新 out_pos。 +# ============================================================ +def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str, + dep_buf: bytes, out_buf: bytes, out_size: t.CSizeT, + out_pos: t.CSizeT) -> t.CSizeT: + """从依赖 text.ll 提取 declare(define 转 declare),追加到 out_buf""" + if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None: + return out_pos + + sha1_len_lt: t.CSizeT = string.strlen(dep_sha1) + text_path: bytes = stdlib.malloc(td_len + sha1_len_lt + 16) + if text_path is None: + return out_pos + viperlib.snprintf(text_path, td_len + sha1_len_lt + 16, "%s/%s.text.ll", temp_dir, dep_sha1) + tf_lt: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) + if tf_lt.closed: + stdlib.free(text_path) + return out_pos + text_br: t.CInt64T = tf_lt.read_all(dep_buf, STUB_READ_BUF_SIZE) + tf_lt.close() + stdlib.free(text_path) + if text_br <= 0: + return out_pos + if text_br < STUB_READ_BUF_SIZE: + dep_buf[text_br] = '\0' + else: + dep_buf[STUB_READ_BUF_SIZE - 1] = '\0' + + dep_pos_lt: t.CSizeT = 0 + in_body: int = 0 + while dep_pos_lt < text_br: + ls: t.CSizeT = dep_pos_lt + while dep_pos_lt < text_br: + if dep_buf[dep_pos_lt] == '\n': + break + dep_pos_lt += 1 + ll: t.CSizeT = dep_pos_lt - ls + if dep_pos_lt < text_br: + dep_pos_lt += 1 + + # 函数体跳过:直到单独的 } 行 + if in_body != 0: + if ll == 1 and dep_buf[ls] == '}': + in_body = 0 + continue + + # 跳过空行和 header + if ll == 0: + continue + c0: int = dep_buf[ls] + if c0 == ';': + continue + if c0 == 't' and ll >= 6 and string.strncmp(dep_buf + ls, "target", 6) == 0: + continue + if c0 == 's' and ll >= 15 and string.strncmp(dep_buf + ls, "source_filename", 15) == 0: + continue + + # 处理 define 行:转为 declare + if ll >= 7 and string.strncmp(dep_buf + ls, "define ", 7) == 0: + # 提取 @funcname( 用于去重 + at_lt: t.CSizeT = ls + 7 + while at_lt < ls + ll: + if dep_buf[at_lt] == '@': + break + at_lt += 1 + if at_lt >= ls + ll: + in_body = 1 + continue + lp_lt: t.CSizeT = at_lt + 1 + while lp_lt < ls + ll: + if dep_buf[lp_lt] == '(': + break + lp_lt += 1 + if lp_lt >= ls + ll: + in_body = 1 + continue + # 去重检查:用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句 + saved_lt: t.CChar = dep_buf[lp_lt + 1] + dep_buf[lp_lt + 1] = '\0' + if _IsFuncDeclaredOrDefined(out_buf, dep_buf + at_lt) != 0: + dep_buf[lp_lt + 1] = saved_lt + in_body = 1 + continue + dep_buf[lp_lt + 1] = saved_lt + + # 找行尾的 ' {' 并截断 + decl_end: t.CSizeT = ls + ll + if decl_end > ls + 1: + if dep_buf[decl_end - 1] == '{' and dep_buf[decl_end - 2] == ' ': + decl_end -= 2 + + # 输出: declare + content (skip "define " 7 chars, up to decl_end) + copy_len_lt: t.CSizeT = decl_end - (ls + 7) + if out_pos + 8 + copy_len_lt + 2 < out_size: + string.strncpy(out_buf + out_pos, "declare ", 8) + out_pos += 8 + string.strncpy(out_buf + out_pos, dep_buf + ls + 7, copy_len_lt) + out_pos += copy_len_lt + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + in_body = 1 + continue + + # 跳过其他行(global 带初值定义、type 定义等,stub 已有 external 声明) + return out_pos + + +# ============================================================ +# _PathToModuleName - 将文件路径转换为模块名 +# +# 输入: "includes/stdio.py" 或 "includes/lib/core/Handles/HandlesType.py" +# 输出: "stdio" 或 "lib.core.Handles.HandlesType" +# 去除 includes/ 前缀和 .py 后缀,/ 替换为 . +# 返回 stdlib.malloc 分配的字符串,调用者负责释放 +# ============================================================ +def _PathToModuleName(path: str) -> str: + """将文件路径转换为模块名 + + 特殊处理 __init__.py:includes/ast/__init__.py → ast(而非 ast.__init__) + """ + if path is None: + return None + plen: t.CSizeT = string.strlen(path) + # 跳过 includes/ 前缀 + prefix: str = "includes/" + prefix_len: t.CSizeT = 9 + path_start: t.CSizeT = 0 + if plen > prefix_len and string.strncmp(path, prefix, prefix_len) == 0: + path_start = prefix_len + plen = plen - prefix_len + # 去掉 .py 后缀 + if plen > 3 and path[path_start + plen - 3] == '.' and path[path_start + plen - 2] == 'p' and path[path_start + plen - 1] == 'y': + plen -= 3 + if plen == 0: + return None + # 检查是否以 /__init__ 或 \__init__ 结尾(包的 __init__.py) + # /__init__ 是 9 个字符:/ _ _ i n i t _ _ + # 如果是,去掉分隔符+__init__ 后缀,模块名就是包名(如 ast/__init__ → ast) + # 注意:顶级 __init__.py(plen=8)不会进入此分支,因为 plen > 9 才检查 + # 同时支持 / 和 \ 两种分隔符(TPC 写入的路径可能混合使用) + if plen > 9: + tail_off: t.CSizeT = path_start + plen - 9 + sep_char: t.CChar = path[tail_off] + if (sep_char == '/' or sep_char == '\\') \ + and path[tail_off + 1] == '_' and path[tail_off + 2] == '_' \ + and path[tail_off + 3] == 'i' and path[tail_off + 4] == 'n' and path[tail_off + 5] == 'i' \ + and path[tail_off + 6] == 't' and path[tail_off + 7] == '_' and path[tail_off + 8] == '_': + # 去掉 分隔符+__init__ 后缀,plen 就是包名部分长度 + plen = tail_off - path_start + if plen == 0: + return None + # 复制并替换 / 为 . + result: str = stdlib.malloc(plen + 1) + if result is None: + return None + for ri in range(plen): + ch: t.CChar = path[path_start + ri] + if ch == '/' or ch == '\\': + result[ri] = '.' + else: + result[ri] = ch + result[plen] = '\0' + return result + + +# ============================================================ +# _BuildIncludesSha1Map - 从 _sha1_map.txt 构建 sha1 → module_name 映射 +# +# _sha1_map.txt 格式: {sha1}:includes/{rel_path}\n +# 返回两个数组(sha1_list 和 mod_list),长度存储在 count 中。 +# 所有内存由 stdlib.malloc 分配,调用者负责释放。 +# ============================================================ +def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT, + sha1_list: t.CChar | t.CPtr, + mod_list: t.CChar | t.CPtr) -> int: + """从 _sha1_map.txt 构建 sha1→module_name 映射,返回条目数""" + if temp_dir is None or sha1_list is None or mod_list is None: + return 0 + + map_path: bytes = stdlib.malloc(td_len + 32) + if map_path is None: + return 0 + viperlib.snprintf(map_path, td_len + 32, "%s/_sha1_map.txt", temp_dir) + mf: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.R) + if mf.closed: + stdlib.free(map_path) + return 0 + map_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + if map_buf is None: + mf.close() + stdlib.free(map_path) + return 0 + map_br: t.CInt64T = mf.read_all(map_buf, STUB_READ_BUF_SIZE) + mf.close() + stdlib.free(map_path) + if map_br <= 0: + stdlib.free(map_buf) + return 0 + if map_br < STUB_READ_BUF_SIZE: + map_buf[map_br] = '\0' + else: + map_buf[STUB_READ_BUF_SIZE - 1] = '\0' + + count: int = 0 + pos: t.CSizeT = 0 + while pos < map_br and count < MAX_INCLUDES: + # 提取 SHA1(16 hex) + sha1: t.CChar | t.CPtr = stdlib.malloc(17) + if sha1 is None: + break + string.strncpy(sha1, map_buf + pos, 16) + sha1[16] = '\0' + pos += 16 + # 跳过 ':' + if pos < map_br and map_buf[pos] == ':': + pos += 1 + # 提取路径(到 \r、\n 或 \0) + # 注意: Windows CRLF 换行符是 \r\n,必须同时检查 \r 避免路径包含 \r + path_start: t.CSizeT = pos + while pos < map_br and map_buf[pos] != '\n' and map_buf[pos] != '\r' and map_buf[pos] != '\0': + pos += 1 + path_len: t.CSizeT = pos - path_start + # 跳过 \r\n 或 \n + if pos < map_br and map_buf[pos] == '\r': + pos += 1 + if pos < map_br and map_buf[pos] == '\n': + pos += 1 + if path_len > 0: + # 仅收集 includes/ 前缀的条目(用户文件如 App/ 不应进入 includes 映射) + # 否则用户文件会被误判为 includes,导致 is_module_imported 模块名不匹配而跳过加载 + if path_len >= 9 and string.strncmp(map_buf + path_start, "includes/", 9) == 0: + path_buf: t.CChar | t.CPtr = stdlib.malloc(path_len + 1) + if path_buf is not None: + string.strncpy(path_buf, map_buf + path_start, path_len) + path_buf[path_len] = '\0' + mod_name: str = _PathToModuleName(path_buf) + stdlib.free(path_buf) + if mod_name is not None: + # 存储 sha1 和 mod_name 到数组中 + idx: t.CSizeT = t.CSizeT(count) * 17 + string.strcpy(sha1_list + idx, sha1) + idx2: t.CSizeT = t.CSizeT(count) * 64 + mn_len: t.CSizeT = string.strlen(mod_name) + if mn_len < 64: + string.strcpy(mod_list + idx2, mod_name) + else: + string.strncpy(mod_list + idx2, mod_name, 63) + mod_list[idx2 + 63] = '\0' + stdlib.free(mod_name) + count += 1 + stdlib.free(sha1) + stdlib.free(map_buf) + return count + + +# ============================================================ +# _FindSha1ByModName - 从模块名查找 SHA1(精确匹配) +# +# 在 sha1_arr/mod_arr 映射中查找模块名对应的 SHA1。 +# 用于依赖图分析:模块名 → SHA1。 +# +# Args: +# sha1_arr: SHA1 数组(每个 17 字节) +# mod_arr: 模块名数组(每个 64 字节) +# count: 映射条目数 +# mod_name: 要查找的模块名 +# +# Returns: +# SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None +# ============================================================ +def _FindSha1ByModName(sha1_arr: t.CChar | t.CPtr, mod_arr: t.CChar | t.CPtr, + count: int, mod_name: str) -> str: + """从模块名查找 SHA1(精确匹配)""" + if sha1_arr is None or mod_arr is None or mod_name is None: + return None + if count <= 0: + return None + for i in range(count): + idx: t.CSizeT = t.CSizeT(i) * 64 + if string.strcmp(mod_arr + idx, mod_name) == 0: + sidx: t.CSizeT = t.CSizeT(i) * 17 + return sha1_arr + sidx + return None + + +# ============================================================ +# _AddSha1ToSet - 将 SHA1 加入集合(去重) +# +# 检查 SHA1 是否已在集合中,若不在则加入。返回新的 count。 +# +# Args: +# set_buf: SHA1 集合缓冲区(每个 17 字节) +# count: 当前集合中的 SHA1 数量 +# sha1: 要加入的 SHA1 +# +# Returns: +# 新的 count(如果已存在则不变) +# ============================================================ +def _AddSha1ToSet(set_buf: t.CChar | t.CPtr, count: int, sha1: str) -> int: + """将 SHA1 加入集合,返回新 count""" + if set_buf is None or sha1 is None: + return count + for i in range(count): + idx: t.CSizeT = t.CSizeT(i) * 17 + if string.strcmp(set_buf + idx, sha1) == 0: + return count + if count < MAX_INCLUDES_SHA1: + idx: t.CSizeT = t.CSizeT(count) * 17 + string.strcpy(set_buf + idx, sha1) + return count + 1 + return count + + +# ============================================================ +# _BuildReachableSha1Set - 构建可达 SHA1 集合(依赖图按需翻译) +# +# 从 source_dir 的源文件开始,解析 import 语句,递归收集可达的 +# includes 文件 SHA1。Phase 1b 只翻译可达集合中的文件,避免 +# 翻译不需要的 includes(如 Test 不依赖 llvmlite,则不翻译)。 +# +# 算法(工作列表): +# 1. 扫描 source_dir 下的 .py 文件,解析 AST 获取 _imported_modules +# 2. 构建 SHA1→module_name 映射(从 _sha1_map.txt) +# 3. 工作列表递归:模块名 → 查 SHA1 → 加入 reachable_set → 读 .deps.txt → 追加新模块名 +# +# Args: +# mb: 内存池 +# source_dir: 源文件目录(Config.SourceDir) +# temp_dir: 临时目录(_sha1_map.txt 和 .deps.txt 所在位置) +# reachable_set: 输出参数,可达 SHA1 集合缓冲区(MAX_INCLUDES_SHA1 * 17 字节) +# +# Returns: +# 可达 SHA1 数量(>0 成功,<=0 失败) +# ============================================================ +def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str, + temp_dir: str, + reachable_set: t.CChar | t.CPtr) -> int: + """构建可达 SHA1 集合(依赖图按需翻译)""" + if source_dir is None or temp_dir is None or reachable_set is None: + return -1 + + SRC_BUF_SIZE_R: t.CSizeT = 1048576 + + # 1. 构建 SHA1→module_name 映射 + td_len_r: t.CSizeT = string.strlen(temp_dir) + sha1_arr: bytes = stdlib.malloc(MAX_INCLUDES * 17) + mod_arr: bytes = stdlib.malloc(MAX_INCLUDES * 64) + if sha1_arr is None or mod_arr is None: + if sha1_arr is not None: + stdlib.free(sha1_arr) + if mod_arr is not None: + stdlib.free(mod_arr) + return -1 + map_count: int = _BuildIncludesSha1Map(temp_dir, td_len_r, sha1_arr, mod_arr) + if map_count <= 0: + stdio.printf("[Reachable] 无法构建 SHA1 映射\n") + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + return -1 + stdio.printf("[Reachable] SHA1 映射: %d 个\n", map_count) + + # 2. 扫描 source_dir 下的 .py 文件,收集直接依赖 + dir_len: t.CSizeT = string.strlen(source_dir) + pattern: bytes = stdlib.malloc(dir_len + 8) + if pattern is None: + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + return -1 + viperlib.snprintf(pattern, dir_len + 8, "%s/*.py", source_dir) + + find_data_size: t.CSizeT = win32file.WIN32_FIND_DATAA.__sizeof__() + find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(find_data_size + 16) + if find_data is None: + stdlib.free(pattern) + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + return -1 + string.memset(find_data, 0, find_data_size + 16) + + # 工作列表(空格分隔的模块名) + worklist: bytes = stdlib.malloc(8192) + if worklist is None: + stdlib.free(pattern) + stdlib.free(find_data) + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + return -1 + worklist[0] = '\0' + wl_len: t.CSizeT = 0 + + reachable_count: int = 0 + + handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data) + if handle == win32base.INVALID_HANDLE_VALUE: + stdio.printf("[Reachable] 未找到 .py 文件: %s\n", pattern) + stdlib.free(pattern) + stdlib.free(find_data) + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + stdlib.free(worklist) + return -1 + + while True: + fname: str = find_data.cFileName + if fname is not None: + fname_len: t.CSizeT = string.strlen(fname) + if fname_len > 3: + is_py: int = 0 + if fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y': + is_py = 1 + if is_py != 0: + full_path: bytes = stdlib.malloc(dir_len + fname_len + 2) + if full_path is not None: + viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", source_dir, fname) + sf: fileio.File | t.CPtr = fileio.File(full_path, fileio.MODE.R) + if not sf.closed: + sbuf: bytes = stdlib.malloc(SRC_BUF_SIZE_R) + if sbuf is not None: + br: LONG = sf.read_all(sbuf, SRC_BUF_SIZE_R) + sf.close() + if br > 0: + if br < SRC_BUF_SIZE_R: + sbuf[br] = 0 + else: + sbuf[SRC_BUF_SIZE_R - 1] = 0 + # 解析 AST 获取 _imported_modules + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + if lx is not None: + ast._lexer_init(lx, sbuf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + if tree is not None: + tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + if tr is not None: + tr._declare_only = 2 + # 源文件包名:fname 是顶级文件名(无目录分隔符),包为 None + tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, fname) + HandlesStruct.reset_visible_structs(mb, 0) + tr.translate(tree) + # 获取 _imported_modules + if tr._imported_modules is not None: + im_len: t.CSizeT = string.strlen(tr._imported_modules) + if im_len > 0 and wl_len + im_len + 1 < 8192: + string.strcpy(worklist + wl_len, tr._imported_modules) + wl_len += im_len + worklist[wl_len] = ' ' + wl_len += 1 + worklist[wl_len] = '\0' + # 释放 Translator 资源 + if tr._global_names is not None: + stdlib.free(tr._global_names) + if tr._nonlocal_names is not None: + stdlib.free(tr._nonlocal_names) + stdlib.free(sbuf) + else: + stdlib.free(sbuf) + else: + sf.close() + stdlib.free(full_path) + + if win32file.FindNextFileA(handle, find_data) == 0: + break + win32base.FindClose(handle) + stdlib.free(pattern) + stdlib.free(find_data) + + # 去掉末尾多余空格 + if wl_len > 0 and worklist[wl_len - 1] == ' ': + worklist[wl_len - 1] = '\0' + wl_len -= 1 + + stdio.printf("[Reachable] 源文件直接依赖: '%s'\n", worklist) + + # 2.5. 全局预加入基础容器模块(_list/_dict/json) + # + # 这些模块定义了 list/dict 等内建容器的泛型模板。 + # 使用 list[...]/dict[...] 语法时需要这些模块被翻译并注册模板。 + # 即使源文件和 includes 文件没有显式 import _list,也预加入以确保可达。 + # 这对应 TPC 的 _inject_auto_imports 机制(TPC 在翻译前自动注入 import _list)。 + # _list + if HandlesImports.is_module_imported(worklist, "_list") == 0: + bsha1_l: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, "_list") + if bsha1_l is not None: + if wl_len + 7 < 8192: + if wl_len > 0: + worklist[wl_len] = ' ' + wl_len += 1 + string.strcpy(worklist + wl_len, "_list") + wl_len += 5 + worklist[wl_len] = ' ' + wl_len += 1 + worklist[wl_len] = '\0' + # _dict + if HandlesImports.is_module_imported(worklist, "_dict") == 0: + bsha1_d: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, "_dict") + if bsha1_d is not None: + if wl_len + 7 < 8192: + if wl_len > 0: + worklist[wl_len] = ' ' + wl_len += 1 + string.strcpy(worklist + wl_len, "_dict") + wl_len += 5 + worklist[wl_len] = ' ' + wl_len += 1 + worklist[wl_len] = '\0' + # json + if HandlesImports.is_module_imported(worklist, "json") == 0: + bsha1_j: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, "json") + if bsha1_j is not None: + if wl_len + 6 < 8192: + if wl_len > 0: + worklist[wl_len] = ' ' + wl_len += 1 + string.strcpy(worklist + wl_len, "json") + wl_len += 4 + worklist[wl_len] = ' ' + wl_len += 1 + worklist[wl_len] = '\0' + stdio.printf("[Reachable] 预加入容器模块后: '%s'\n", worklist) + + # 3. 工作列表算法:递归收集可达 SHA1 + processed: bytes = stdlib.malloc(8192) + if processed is None: + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + stdlib.free(worklist) + return -1 + processed[0] = '\0' + proc_len: t.CSizeT = 0 + + wl_pos: t.CSizeT = 0 + wl_iter: int = 0 + while wl_pos < wl_len: + wl_iter += 1 + # 提取一个模块名(到空格或末尾) + name_start: t.CSizeT = wl_pos + while wl_pos < wl_len and worklist[wl_pos] != ' ': + wl_pos += 1 + name_len: t.CSizeT = wl_pos - name_start + if wl_pos < wl_len: + wl_pos += 1 + if name_len == 0: + continue + + # 复制模块名 + mod_buf: bytes = stdlib.malloc(name_len + 1) + if mod_buf is None: + continue + string.strncpy(mod_buf, worklist + name_start, name_len) + mod_buf[name_len] = '\0' + + # 检查是否已处理 + already: int = 0 + if HandlesImports.is_module_imported(processed, mod_buf) != 0: + already = 1 + if already == 0: + # 加入 processed + if proc_len + name_len + 1 < 8192: + string.strcpy(processed + proc_len, mod_buf) + proc_len += name_len + processed[proc_len] = ' ' + proc_len += 1 + processed[proc_len] = '\0' + + # 查找 SHA1 + found_sha1: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, mod_buf) + if found_sha1 is not None: + # 加入 reachable_set + reachable_count = _AddSha1ToSet(reachable_set, reachable_count, found_sha1) + + # 读取 .deps.txt 追加到 worklist + deps_path: bytes = stdlib.malloc(td_len_r + 33) + if deps_path is not None: + viperlib.snprintf(deps_path, td_len_r + 33, "%s/%s.deps.txt", temp_dir, found_sha1) + df: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R) + if not df.closed: + deps_buf: bytes = stdlib.malloc(2048) + if deps_buf is not None: + dbr: t.CInt64T = df.read_all(deps_buf, 2048) + df.close() + if dbr > 0: + if dbr < 2048: + deps_buf[dbr] = '\0' + else: + deps_buf[2047] = '\0' + # 追加到 worklist(确保前面有空格分隔符,避免模块名合并) + dl: t.CSizeT = string.strlen(deps_buf) + if dl > 0 and wl_len + dl + 2 < 8192: + if wl_len > 0 and worklist[wl_len - 1] != ' ': + worklist[wl_len] = ' ' + wl_len += 1 + string.strcpy(worklist + wl_len, deps_buf) + wl_len += dl + worklist[wl_len] = ' ' + wl_len += 1 + worklist[wl_len] = '\0' + stdlib.free(deps_buf) + else: + df.close() + stdlib.free(deps_path) + stdlib.free(mod_buf) + stdlib.free(sha1_arr) + stdlib.free(mod_arr) + stdlib.free(worklist) + stdlib.free(processed) + + stdio.printf("[Reachable] 可达 SHA1: %d 个\n", reachable_count) + return reachable_count + + +# ============================================================ +# BuildCombinedIR - 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR +# +# 按需加载:读取 deps.txt 获取导入模块名,通过 _sha1_map.txt 查找 SHA1, +# 仅加载实际使用的依赖 stub(而非全部扫描)。 +# ============================================================ +def BuildCombinedIR(temp_dir: str, local_sha1: str, + out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT: + """组合本地 stub + 依赖 stubs + 本地 text → out_buf(按需加载)""" + if temp_dir is None or local_sha1 is None or out_buf is None or out_size == 0: + return 0 + + stdio.printf("[BuildCombinedIR] start: sha1=%s\n", local_sha1) + td_len: t.CSizeT = string.strlen(temp_dir) + out_buf[0] = '\0' + out_pos: t.CSizeT = 0 + + # 1. 读取并追加本地 stub.ll(含 header) + stub_path: bytes = stdlib.malloc(td_len + 32) + if stub_path is None: + return 0 + viperlib.snprintf(stub_path, td_len + 32, "%s/%s.stub.ll", temp_dir, local_sha1) + sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R) + if sf.closed: + stdlib.free(stub_path) + return 0 + stub_content: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + if stub_content is None: + sf.close() + stdlib.free(stub_path) + return 0 + stub_br: t.CInt64T = sf.read_all(stub_content, STUB_READ_BUF_SIZE) + sf.close() + stdlib.free(stub_path) + stdio.printf("[BuildCombinedIR] stub read: %d bytes\n", stub_br) + if stub_br <= 0: + stdlib.free(stub_content) + return 0 + if stub_br < STUB_READ_BUF_SIZE: + stub_content[stub_br] = '\0' + else: + stub_content[STUB_READ_BUF_SIZE - 1] = '\0' + slen: t.CSizeT = stub_br + # 修复本地 stub.ll 中字符串常量的非法 IR: + # llvmlite OUTPUT_STUB 模式输出 "= external unnamed_addr constant" 的非法形式。 + # 简单方案:搜索 "= external unnamed_addr constant" 并将 external 替换为 8 个空格。 + fix_pos: t.CSizeT = 0 + while fix_pos + 30 < slen: + ext_ptr: t.CPtr = string.strstr(stub_content + fix_pos, "= external unnamed_addr constant") + if ext_ptr is None: + break + # ext_ptr 指向 "= external ..." 中的 '=' + # 'external' 开始于 ext_ptr + 2 + ext_off: t.CSizeT = t.CSizeT(t.CUInt64T(ext_ptr) - t.CUInt64T(stub_content)) + 2 + if ext_off + 8 <= slen: + stub_content[ext_off] = ' ' + stub_content[ext_off + 1] = ' ' + stub_content[ext_off + 2] = ' ' + stub_content[ext_off + 3] = ' ' + stub_content[ext_off + 4] = ' ' + stub_content[ext_off + 5] = ' ' + stub_content[ext_off + 6] = ' ' + stub_content[ext_off + 7] = ' ' + fix_pos = ext_off + 8 + stdio.printf("[BuildCombinedIR] stub_fix done, slen=%d\n", slen) + # 直接复制修复后的 stub 内容 + if out_pos + slen + 2 < out_size: + string.strcpy(out_buf + out_pos, stub_content) + out_pos += slen + if out_buf[out_pos - 1] != '\n': + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + stdlib.free(stub_content) + + # 2. 按需加载依赖 stubs(根据 deps.txt 过滤,而非扫描全部) + # 先加载依赖 stub(含 type 定义),确保 type 定义在本地 text.ll 的 define 块之前 + # 2a. 构建 includes SHA1 → module_name 映射(从 _sha1_map.txt) + sha1_arr: bytes = stdlib.malloc(MAX_INCLUDES * 17) + mod_arr: bytes = stdlib.malloc(MAX_INCLUDES * 64) + inc_count: int = 0 + if sha1_arr is not None and mod_arr is not None: + inc_count = _BuildIncludesSha1Map(temp_dir, td_len, sha1_arr, mod_arr) + + # 2b. 读取 deps.txt 获取导入模块名集合 + deps_buf: str = None + deps_loaded: int = 0 + deps_path: bytes = stdlib.malloc(td_len + 32) + if deps_path is not None: + viperlib.snprintf(deps_path, td_len + 32, "%s/%s.deps.txt", temp_dir, local_sha1) + df_deps: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R) + if not df_deps.closed: + deps_buf = stdlib.malloc(4096) + if deps_buf is not None: + deps_br: t.CInt64T = df_deps.read_all(deps_buf, 4096) + if deps_br > 0: + if deps_br < 4096: + deps_buf[deps_br] = '\0' + else: + deps_buf[4095] = '\0' + deps_loaded = 1 + df_deps.close() + stdlib.free(deps_path) + + # 2c. 扫描 temp_dir 中所有 .stub.ll,按需加载 + pattern: bytes = stdlib.malloc(td_len + 16) + if pattern is not None: + viperlib.snprintf(pattern, td_len + 16, "%s/*.stub.ll", temp_dir) + find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__()) + if find_data is not None: + string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__()) + handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data) + if handle != win32base.INVALID_HANDLE_VALUE: + dep_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + if dep_buf is not None: + while 1: + fname: str = find_data.cFileName + if fname is not None: + dep_sha1: str = stdlib.malloc(17) + if dep_sha1 is not None: + string.strncpy(dep_sha1, fname, 16) + dep_sha1[16] = '\0' + if string.strcmp(dep_sha1, local_sha1) != 0: + should_load: int = 0 + # 检查是否在 includes 映射中 + is_include: int = 0 + if inc_count > 0: + for ii in range(inc_count): + idx_ii: t.CSizeT = t.CSizeT(ii) * 17 + if string.strcmp(sha1_arr + idx_ii, dep_sha1) == 0: + is_include = 1 + if deps_loaded != 0: + idx_mi: t.CSizeT = t.CSizeT(ii) * 64 + if HandlesImports.is_module_imported(deps_buf, mod_arr + idx_mi) != 0: + should_load = 1 + break + if is_include == 0: + # 非 includes stub(用户文件),总是加载 + should_load = 1 + if should_load != 0: + out_pos = _LoadAndAppendStub(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) + out_pos = _LoadAndAppendTextDeclares(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos) + stdlib.free(dep_sha1) + if win32file.FindNextFileA(handle, find_data) == 0: + break + if dep_buf is not None: + stdlib.free(dep_buf) + win32file.FindClose(handle) + stdlib.free(find_data) + stdlib.free(pattern) + + # 2d. 验证 deps.txt 中所有依赖模块的 stub 文件都存在(fail-fast) + # 避免到 llc 才报 undefined value 错误。 + # 仅验证在 includes 映射中找到的模块(t/c 等内部库无 SHA1 映射,自动跳过)。 + if deps_loaded != 0 and inc_count > 0: + dep_total: t.CSizeT = string.strlen(deps_buf) + dp: t.CSizeT = 0 + while dp < dep_total: + # 跳过前导空格 + while dp < dep_total: + if deps_buf[dp] != ' ': + break + dp += 1 + if dp >= dep_total: + break + # 提取模块名(到下一个空格或末尾) + ms: t.CSizeT = dp + while dp < dep_total: + if deps_buf[dp] == ' ': + break + dp += 1 + ml: t.CSizeT = dp - ms + if ml == 0: + continue + # 复制模块名到临时缓冲区并 null 终止 + mod_nm: str = stdlib.malloc(ml + 1) + if mod_nm is None: + continue + string.strncpy(mod_nm, deps_buf + ms, ml) + mod_nm[ml] = '\0' + # 在 includes 映射中查找模块对应的 SHA1 + found_s: str = None + for mi2 in range(inc_count): + idx_m2: t.CSizeT = t.CSizeT(mi2) * 64 + if string.strcmp(mod_arr + idx_m2, mod_nm) == 0: + idx_s2: t.CSizeT = t.CSizeT(mi2) * 17 + found_s = sha1_arr + idx_s2 + break + if found_s is not None: + # 检查 stub 文件是否存在 + chk_path: bytes = stdlib.malloc(td_len + 32) + if chk_path is not None: + viperlib.snprintf(chk_path, td_len + 32, "%s/%s.stub.ll", temp_dir, found_s) + chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R) + if chk_f.closed: + stdio.printf("[FATAL][BuildCombinedIR] 依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译\n", mod_nm, found_s, chk_path) + sys.exit(1) + chk_f.close() + stdlib.free(chk_path) + stdlib.free(mod_nm) + + # 3. 读取并追加本地 text.ll(行级去重,跳过 stub.ll 中已存在的定义) + text_path: bytes = stdlib.malloc(td_len + 32) + if text_path is None: + return out_pos + viperlib.snprintf(text_path, td_len + 32, "%s/%s.text.ll", temp_dir, local_sha1) + tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R) + if tf.closed: + stdlib.free(text_path) + # text.ll 不存在的情况,继续 + else: + text_content: bytes = stdlib.malloc(STUB_READ_BUF_SIZE) + if text_content is None: + tf.close() + stdlib.free(text_path) + else: + text_br: t.CInt64T = tf.read_all(text_content, STUB_READ_BUF_SIZE) + tf.close() + stdlib.free(text_path) + if text_br > 0: + if text_br < STUB_READ_BUF_SIZE: + text_content[text_br] = '\0' + else: + text_content[STUB_READ_BUF_SIZE - 1] = '\0' + # 行级去重追加(与 _LoadAndAppendStub 相同逻辑) + tx_pos: t.CSizeT = 0 + tx_skip: int = 1 + while tx_pos < text_br: + tx_ls: t.CSizeT = tx_pos + while tx_pos < text_br: + if text_content[tx_pos] == '\n': + break + tx_pos += 1 + tx_ll: t.CSizeT = tx_pos - tx_ls + if tx_pos < text_br: + tx_pos += 1 + if tx_skip != 0: + if tx_ll == 0: + continue + tx_c0: int = text_content[tx_ls] + if tx_c0 == ';': + continue + if tx_c0 == 't' and tx_ll >= 6: + if string.strncmp(text_content + tx_ls, "target", 6) == 0: + continue + if tx_c0 == 's' and tx_ll >= 15: + if string.strncmp(text_content + tx_ls, "source_filename", 15) == 0: + continue + tx_skip = 0 + # 去重:declare(用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句) + if tx_ll >= 8 and string.strncmp(text_content + tx_ls, "declare ", 8) == 0: + tx_at: t.CSizeT = tx_ls + 8 + while tx_at < tx_ls + tx_ll: + if text_content[tx_at] == '@': + break + tx_at += 1 + if tx_at < tx_ls + tx_ll: + tx_lp: t.CSizeT = tx_at + 1 + while tx_lp < tx_ls + tx_ll: + if text_content[tx_lp] == '(': + break + tx_lp += 1 + if tx_lp < tx_ls + tx_ll: + tx_sv: t.CChar = text_content[tx_lp + 1] + text_content[tx_lp + 1] = '\0' + if _IsFuncDeclaredOrDefined(out_buf, text_content + tx_at) != 0: + text_content[tx_lp + 1] = tx_sv + continue + text_content[tx_lp + 1] = tx_sv + # 去重:define(注释掉 out_buf 中已有的 declare,避免 declare/define 冲突) + if tx_ll >= 7 and string.strncmp(text_content + tx_ls, "define ", 7) == 0: + tx_at_d: t.CSizeT = tx_ls + 7 + while tx_at_d < tx_ls + tx_ll: + if text_content[tx_at_d] == '@': + break + tx_at_d += 1 + if tx_at_d < tx_ls + tx_ll: + tx_lp_d: t.CSizeT = tx_at_d + 1 + while tx_lp_d < tx_ls + tx_ll: + if text_content[tx_lp_d] == '(': + break + tx_lp_d += 1 + if tx_lp_d < tx_ls + tx_ll: + tx_sv_d: t.CChar = text_content[tx_lp_d + 1] + text_content[tx_lp_d + 1] = '\0' + _CommentOutDeclareInBuf(out_buf, text_content + tx_at_d) + text_content[tx_lp_d + 1] = tx_sv_d + # 处理:@global = ... + # stub 中可能是 external 声明或完整定义,以 text 中的定义为准 + # 找到 stub 中同名全局变量行并注释掉,然后追加 text 中的 + if tx_ll > 0 and text_content[tx_ls] == '@': + tx_eq: t.CSizeT = tx_ls + 1 + while tx_eq < tx_ls + tx_ll: + if text_content[tx_eq] == '=': + break + tx_eq += 1 + if tx_eq < tx_ls + tx_ll: + tx_sv2: t.CChar = text_content[tx_eq + 1] + text_content[tx_eq + 1] = '\0' + _CommentOutGlobalInBuf(out_buf, text_content + tx_ls) + text_content[tx_eq + 1] = tx_sv2 + # 去重:%type = ... + if tx_ll > 0 and text_content[tx_ls] == '%': + tx_eq2: t.CSizeT = tx_ls + 1 + while tx_eq2 < tx_ls + tx_ll: + if text_content[tx_eq2] == '=': + break + tx_eq2 += 1 + if tx_eq2 < tx_ls + tx_ll: + tx_sv3: t.CChar = text_content[tx_eq2 + 1] + text_content[tx_eq2 + 1] = '\0' + if string.strstr(out_buf, text_content + tx_ls) is not None: + text_content[tx_eq2 + 1] = tx_sv3 + continue + text_content[tx_eq2 + 1] = tx_sv3 + # 追加 + if out_pos + tx_ll + 2 < out_size: + string.strncpy(out_buf + out_pos, text_content + tx_ls, tx_ll) + out_pos += tx_ll + out_buf[out_pos] = '\n' + out_pos += 1 + out_buf[out_pos] = '\0' + stdlib.free(text_content) + + if deps_buf is not None: + stdlib.free(deps_buf) + if sha1_arr is not None: + stdlib.free(sha1_arr) + if mod_arr is not None: + stdlib.free(mod_arr) + + return out_pos diff --git a/App/lib/core/VLogger.py b/App/lib/core/VLogger.py new file mode 100644 index 0000000..c1e5e99 --- /dev/null +++ b/App/lib/core/VLogger.py @@ -0,0 +1,171 @@ +import t, c +from stdint import * +import stdio +import memhub +import w32.win32console as w32cmd +import w32.win32file as w32file +import w32.win32base as w32base + + +# ============================================================ +# VLogger - 原生日志系统(Windows 控制台彩色输出) +# ============================================================ + +# 日志级别 +class LogLevel(t.CEnum): + DEBUG = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + SUCCESS = 4 + + +# Win32 控制台前景色属性 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +FOREGROUND_WHITE: t.CDefine = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE +FOREGROUND_CYAN: t.CDefine = FOREGROUND_BLUE | FOREGROUND_GREEN +FOREGROUND_YELLOW: t.CDefine = FOREGROUND_RED | FOREGROUND_GREEN +FOREGROUND_MAGENTA: t.CDefine = FOREGROUND_RED | FOREGROUND_BLUE + +# Win32 控制台背景色属性 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +BACKGROUND_WHITE: t.CDefine = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE + + +class Logger: + _level: int + _console_handle: w32base.HANDLE + _use_color: int + __mbuddy__: memhub.MemManager | t.CPtr + + def __init__(self, level: int = 1): + self._level = level + self._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE) + self._use_color = 1 + self.__mbuddy__ = _mbuddy + + def _set_color(self, attr: WORD) -> int: + if self._use_color: + return w32cmd.SetConsoleTextAttribute(self._console_handle, attr) + return 0 + + def _reset_color(self) -> int: + if self._use_color: + return w32cmd.SetConsoleTextAttribute(self._console_handle, FOREGROUND_WHITE) + return 0 + + def _log(self, level: int, prefix: str, msg: str, color: WORD, + category: str = "") -> int: + if level < self._level: + return 0 + self._set_color(color) + if category is not None: + if category[0] != 0: + stdio.printf("%s[%s] %s\n", prefix, category, msg) + else: + stdio.printf("%s %s\n", prefix, msg) + else: + stdio.printf("%s %s\n", prefix, msg) + self._reset_color() + return 0 + + def debug(self, msg: str, category: str = "") -> int: + return self._log(LogLevel.DEBUG, "[DEBUG]", msg, + FOREGROUND_INTENSITY, category) + + def info(self, msg: str, category: str = "") -> int: + return self._log(LogLevel.INFO, "[INFO]", msg, + FOREGROUND_GREEN | FOREGROUND_INTENSITY, category) + + def warning(self, msg: str, category: str = "") -> int: + return self._log(LogLevel.WARNING, "[WARN]", msg, + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, + category) + + def error(self, msg: str, category: str = "") -> int: + return self._log(LogLevel.ERROR, "[ERROR]", msg, + FOREGROUND_RED | FOREGROUND_INTENSITY, category) + + def success(self, msg: str, category: str = "") -> int: + return self._log(LogLevel.SUCCESS, "[SUCCESS]", msg, + FOREGROUND_GREEN | FOREGROUND_INTENSITY, category) + + def set_level(self, level: int) -> int: + self._level = level + return 0 + + # ============================================================ + # 高级日志方法 + # ============================================================ + + def banner(self, msg: str) -> int: + """输出分节标题(青色高亮)。""" + self._set_color(FOREGROUND_CYAN | FOREGROUND_INTENSITY) + stdio.printf("\n=== %s ===\n\n", msg) + self._reset_color() + return 0 + + def compile_error(self, msg: str, file: str = "", line: int = 0) -> int: + """格式化编译错误输出(红底白字标题 + 位置 + 错误信息)。""" + self._set_color(BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY) + stdio.printf(" 编译错误 ") + self._set_color(FOREGROUND_RED | FOREGROUND_INTENSITY) + stdio.printf("\n") + if file is not None: + if file[0] != 0 and line > 0: + stdio.printf(" 位置: %s:%d\n", file, line) + elif file[0] != 0: + stdio.printf(" 文件: %s\n", file) + stdio.printf(" 错误: %s\n", msg) + self._reset_color() + return 0 + + def compile_warning(self, msg: str, file: str = "", line: int = 0) -> int: + """格式化编译警告输出(黄底黑字标题 + 位置 + 警告信息)。""" + self._set_color(BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_INTENSITY) + stdio.printf(" 编译警告 ") + self._set_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY) + stdio.printf("\n") + if file is not None: + if file[0] != 0 and line > 0: + stdio.printf(" 位置: %s:%d\n", file, line) + elif file[0] != 0: + stdio.printf(" 文件: %s\n", file) + stdio.printf(" 警告: %s\n", msg) + self._reset_color() + return 0 + + +# 全局 mbuddy 指针(由 lib.InitLib 注入) +_mbuddy: memhub.MemManager | t.CPtr + +# 全局 logger 指针 +_g_logger: Logger | t.CPtr + + +def get_logger() -> Logger | t.CPtr: + """获取全局 logger 实例。若不存在则通过 _mbuddy 分配并初始化。""" + if _g_logger is None: + if _mbuddy is None: + return None + raw: t.CVoid | t.CPtr = _mbuddy.alloc(Logger.__sizeof__()) + if raw is None: + return None + _g_logger = raw + _g_logger._level = LogLevel.INFO + _g_logger._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE) + _g_logger._use_color = 1 + _g_logger.__mbuddy__ = _mbuddy + return _g_logger + + +def set_logger(logger: Logger | t.CPtr) -> int: + """设置全局 logger 实例。""" + _g_logger = logger + return 0 diff --git a/App/lib/core/__init__.py b/App/lib/core/__init__.py new file mode 100644 index 0000000..bc8c2f7 --- /dev/null +++ b/App/lib/core/__init__.py @@ -0,0 +1,9 @@ +import t, c +from stdint import * + +# ============================================================ +# core 包入口 +# +# 子模块通过绝对导入使用(import lib.core.X as X), +# 此 __init__.py 不做 re-export,避免引入未使用的依赖。 +# ============================================================ diff --git a/App/main.py b/App/main.py new file mode 100644 index 0000000..a3c08ed --- /dev/null +++ b/App/main.py @@ -0,0 +1,510 @@ +import t, c +from stdint import * +import stdio +import string +import stdlib +import memhub +import argparse +import w32.win32console as w32cmd +import w32.fileio as fileio +import w32.win32file +import w32.win32base +import sys +import ast +import lib +import lib.core.VLogger as VLogger +import lib.core.Handles.HandlesTranslator as HandlesTranslator +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.BuildPipeline as BuildPipeline +import lib.core.IncludesScanner as IncludesScanner +import lib.core.StubMerger as StubMerger +import lib.core.Phase1 as Phase1 +import lib.core.Phase2 as Phase2 +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils +import llvmlite +import subprocess +import viperlib +import hashlib + + +# 内存大小: fl_bytes=264 (33*8), POOL_SIZE-fl_bytes 必须是 2 的幂以避免浪费 +# 1073742088 - 264 = 1073741824 (1024MB usable = 2^30) +# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件,512MB 不足导致 Phase2 崩溃 +POOL_SIZE: t.CDefine = 1073741824 +# 语言编码页 +CODE_PAGE: t.CDefine = 65001 +# 源代码缓冲区大小(1MB) +SRC_BUF_SIZE: t.CDefine = 1048576 + + +# ============================================================ +# main: 命令行入口 +# +# 解析参数 → 加载配置 → AST 解析 → LLVM IR 翻译 → 编译管线 → 可选执行 +# ============================================================ +def main() -> int: + w32cmd.SetConsoleOutputCP(CODE_PAGE) + w32cmd.SetConsoleCP(CODE_PAGE) + # 初始化 mbuddy 内存池 + arena: bytes = stdlib.malloc(POOL_SIZE) + if arena is None: + stdio.printf("FAIL: malloc for arena failed\n") + return 1 + mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE) + if mb is None: + stdio.printf("FAIL: MemBuddy init failed\n") + return 1 + + # 设置全局 mbuddy 指针(sys 和 argparse 都需要) + sys._mbuddy = mb + argparse._mbuddy = mb + ast._mbuddy = mb + lib._mbuddy = (memhub.MemManager | t.CPtr)(mb) + Config._mbuddy = (memhub.MemManager | t.CPtr)(mb) + Utils._mbuddy = (memhub.MemManager | t.CPtr)(mb) + HandlesTranslator._mbuddy = mb + BuildPipeline._mbuddy = (memhub.MemManager | t.CPtr)(mb) + IncludesScanner._mbuddy = (memhub.MemManager | t.CPtr)(mb) + StubMerger._mbuddy = (memhub.MemManager | t.CPtr)(mb) + Phase1._mbuddy = (memhub.MemManager | t.CPtr)(mb) + Phase2._mbuddy = (memhub.MemManager | t.CPtr)(mb) + subprocess._mbuddy = mb + hashlib._mbuddy = (memhub.MemManager | t.CPtr)(mb) + lib.InitLib((memhub.MemManager | t.CPtr)(mb)) + + # 初始化 VLogger 并打印启动日志 + log: VLogger.Logger | t.CPtr = VLogger.get_logger() + if log is not None: + log.info("TransPyV 启动") + + # 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline) + sys._init_argv() + + # 创建参数解析器 + parser: argparse.ArgumentParser | t.CPtr = argparse.ArgumentParser( + "TransPyV", "TransPyV 命令行参数解析", pool=mb) + + # 注册参数(与 Projectrans.py main() 一致) + parser.add_argument("--project", None, argparse.STRING, 0, None, False, + argparse.STORE, "project.json 路径(默认查找当前目录)") + parser.add_argument("--src", None, argparse.STRING, 0, None, False, + argparse.STORE, "源文件目录(覆盖 project.json)") + parser.add_argument("--temp", None, argparse.STRING, 0, None, False, + argparse.STORE, "声明接口临时目录(覆盖 project.json)") + parser.add_argument("--output", None, argparse.STRING, 0, None, False, + argparse.STORE, "输出目录(覆盖 project.json)") + parser.add_argument("--phase", None, argparse.STRING, 0, None, False, + argparse.STORE, "阶段: 1=生成声明, 2=翻译+编译, all=全部") + parser.add_argument("--cc", None, argparse.STRING, 0, None, False, + argparse.STORE, "LLVM 编译器命令(覆盖 project.json)") + parser.add_argument("--clean", None, argparse.BOOL, 0, None, False, + argparse.STORE_TRUE, "清理 output 和 temp 目录") + parser.add_argument("--run", None, argparse.BOOL, 0, None, False, + argparse.STORE_TRUE, "编译成功后立即执行生成的可执行文件") + parser.add_argument("--rebuild-includes", None, argparse.BOOL, 0, None, False, + argparse.STORE_TRUE, "删除 includes.binary 预编译缓存并重新编译所有 includes") + parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False, + argparse.STORE_TRUE, "清除 .transpyc_cache 全局缓存") + + # 解析命令行参数 + args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv) + if args is None: + if log is not None: + log.error("参数解析失败", "argparse") + return 1 + + # 打印解析结果 + if log is not None: + log.banner("TransPyV 参数解析结果") + + # 字符串参数 + project: str = args.get_str("project") + if project is not None: + stdio.printf(" --project: %s\n", project) + else: + stdio.printf(" --project: (未指定)\n") + + src: str = args.get_str("src") + if src is not None: + stdio.printf(" --src: %s\n", src) + else: + stdio.printf(" --src: (未指定)\n") + + temp: str = args.get_str("temp") + if temp is not None: + stdio.printf(" --temp: %s\n", temp) + else: + stdio.printf(" --temp: (未指定)\n") + + output: str = args.get_str("output") + if output is not None: + stdio.printf(" --output: %s\n", output) + else: + stdio.printf(" --output: (未指定)\n") + + phase: str = args.get_str("phase") + if phase is not None: + stdio.printf(" --phase: %s\n", phase) + else: + stdio.printf(" --phase: (未指定,默认 all)\n") + + cc: str = args.get_str("cc") + if cc is not None: + stdio.printf(" --cc: %s\n", cc) + else: + stdio.printf(" --cc: (未指定)\n") + + # 布尔参数 + _gb_clean: INT = args.get_bool("clean") + if _gb_clean: + stdio.printf(" --clean: True\n") + else: + stdio.printf(" --clean: False\n") + + if args.get_bool("run"): + stdio.printf(" --run: True\n") + else: + stdio.printf(" --run: False\n") + + if args.get_bool("rebuild-includes"): + stdio.printf(" --rebuild-includes: True\n") + else: + stdio.printf(" --rebuild-includes: False\n") + + if args.get_bool("clear-cache"): + stdio.printf(" --clear-cache: True\n") + else: + stdio.printf(" --clear-cache: False\n") + + stdio.printf("\n参数解析完成。\n") + + # 加载 project.vpj 配置 + proj_loaded: int = 0 + proj_path: str = project + if proj_path is not None: + if log is not None: + log.banner("工程配置") + if Config.Load_project_config(proj_path) == 0: + proj_loaded = 1 + else: + stdio.printf(" 警告: 无法加载 project.vpj: %s\n", proj_path) + else: + # 尝试默认路径 project.vpj(当前目录和上级目录) + proj_path = "project.vpj" + if Config.Load_project_config(proj_path) == 0: + proj_loaded = 1 + else: + proj_path = "../project.vpj" + if Config.Load_project_config(proj_path) == 0: + proj_loaded = 1 + if proj_loaded == 1: + # 提取 project.vpj 所在目录,将相对路径解析为基于该目录的路径 + proj_len: t.CSizeT = string.strlen(proj_path) + slash_pos: t.CSizeT = proj_len + for i in range(proj_len): + idx: t.CSizeT = proj_len - 1 - i + ch: t.CChar = proj_path[idx] + if ch == '/' or ch == '\\': + slash_pos = idx + break + proj_dir: str = "" + if slash_pos > 0 and slash_pos < proj_len: + proj_dir = stdlib.malloc(slash_pos + 1) + if proj_dir is not None: + string.memcpy(proj_dir, proj_path, slash_pos) + proj_dir[slash_pos] = '\0' + Config.resolve_paths(proj_dir) + Config.print_config() + + # === --clean: 清理 temp 和 output 目录 === + if _gb_clean: + stdio.printf("\n[clean] 清理临时目录...\n") + if Config.TempDir is not None: + n: int = Utils.CleanDir(Config.TempDir) + stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.TempDir, n) + if Config.OutputDir is not None: + n2: int = Utils.CleanDir(Config.OutputDir) + stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.OutputDir, n2) + + # === --phase 参数控制 === + # phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译 + # phase=2: 仅 stub 合并 + 编译(跳过 stub 分离) + # phase=all: 两者都执行(默认) + phase_mode: str = phase + if phase_mode is None: + phase_mode = "all" + do_phase1: int = 0 + do_phase2: int = 0 + if phase_mode == "1" or phase_mode == "all": + do_phase1 = 1 + if phase_mode == "2" or phase_mode == "all": + do_phase2 = 1 + stdio.printf("[phase] 模式: %s (phase1=%d phase2=%d)\n", phase_mode, do_phase1, do_phase2) + + # === Phase1: 扫描 includes(按需翻译)=== + # 对 includes 目录中每个 .py 文件,若 stub 不存在则翻译并分离 stub + if do_phase1 != 0 and Config.IncludesDir is not None: + ph1_temp: str = Config.TempDir + if ph1_temp is None: + ph1_temp = "." + Phase1.RunPhase1(mb, Config.IncludesDir, ph1_temp, log) + # 如果仅 Phase1(不执行 Phase2),直接退出 + if do_phase2 == 0: + stdio.printf("[phase] Phase1 完成,退出\n") + return 0 + + # AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树 + src_path: str = args.get_str("src") + + # === 多文件项目模式 === + # 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .py 文件编译 + if src_path is None and project is not None and Config.SourceDir is not None: + mf_temp: str = Config.TempDir if Config.TempDir is not None else "." + mf_output: str = Config.OutputDir if Config.OutputDir is not None else "." + mf_cc: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc" + mf_cc_flags: str = Config.CompilerFlags if Config.CompilerFlags is not None else "-filetype=obj -relocation-model=pic" + mf_linker: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++" + mf_linker_flags: str = Config.LinkerFlags if Config.LinkerFlags is not None else "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition" + mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe" + mf_includes_bin: str = Config.get_includes_binary_dir() + + mf_ret: int = Phase2.RunMultiFileProject( + mb, Config.SourceDir, mf_temp, mf_output, + mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out, + mf_includes_bin, Config.IncludesDir, do_phase1, do_phase2, log, args) + argparse.release(args) + if log is not None: + log.success("TransPyV 完成") + return mf_ret + + # === 单文件模式:--src 指定时使用指定文件;--project 但无 SourceDir 时回退 === + if src_path is None and project is not None: + if Config.SourceDir is not None: + # 构造入口路径: SourceDir/main.py + sd_len: t.CSizeT = string.strlen(Config.SourceDir) + path_buf: bytes = stdlib.malloc(sd_len + 16) + if path_buf is not None: + viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir) + src_path = path_buf + stdio.printf("[project] 入口文件: %s\n", src_path) + if src_path is not None: + if log is not None: + log.banner("AST 解析") + # 打开文件 + f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R) + if f.closed: + if log is not None: + log.error("无法打开文件", "fileio") + stdio.printf(" 路径: %s\n", src_path) + argparse.release(args) + return 1 + # 分配源代码缓冲区 + src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE) + if src_buf is None: + if log is not None: + log.error("malloc for src_buf failed", "memhub") + f.close() + argparse.release(args) + return 1 + # 读取文件内容 + bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE) + f.close() + if bytes_read < 0: + if log is not None: + log.error("读取文件失败", "fileio") + stdio.printf(" 错误码: %d\n", bytes_read) + argparse.release(args) + return 1 + # 添加 null 终止符,确保 strlen 和 SHA1 计算正确 + if bytes_read < SRC_BUF_SIZE: + src_buf[bytes_read] = 0 + else: + src_buf[SRC_BUF_SIZE - 1] = 0 + if log is not None: + log.info("文件读取完成", "fileio") + stdio.printf("读取 %d 字节\n", bytes_read) + # 解析 AST(拆分为词法+语法两阶段,便于调试) + ast._init_tables(mb) + lx: ast.Lexer | t.CPtr = ast.new_lexer(mb) + ast._lexer_init(lx, src_buf, mb) + tokens: ast.Token | t.CPtr = ast.tokenize(lx) + tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens) + if tree is None: + if log is not None: + log.error("AST 解析失败", "ast") + argparse.release(args) + return 1 + + # === 翻译 AST → LLVM IR === + if log is not None: + log.banner("LLVM IR 翻译") + tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator() + result: int = tr.translate(tree) + if result == 0: + IR_BUF_SIZE: t.CSizeT = 262144 + ir_buf: bytes = stdlib.malloc(IR_BUF_SIZE) + if ir_buf is not None: + tr.dump_ir(ir_buf, IR_BUF_SIZE, llvmlite.OUTPUT_FULL) + + # === 编译管线: .ll → .obj → .exe === + if log is not None: + log.banner("编译管线") + + # module_name 用源代码内容的 SHA1(前 16 字符),与 Projectrans.py 一致 + # output_name 从文件名推导(如 test.py -> test.exe),保持可读性 + module_name: str = Utils.compute_sha1(mb, src_buf) + if module_name is None: + module_name = "main" + output_name: str = "test_prog.exe" + # 从文件名提取 output_name(去掉路径和 .py 扩展名) + src_len: t.CSizeT = string.strlen(src_path) + if src_len > 0: + # 找到最后一个 / 或 \ 之后的部分 + base_start: t.CSizeT = src_len + i: t.CSizeT = src_len + while i > 0: + i -= 1 + ch: t.CChar = src_path[i] + if ch == '/' or ch == '\\': + base_start = i + 1 + break + if i == 0: + base_start = 0 + # 找到 .py 扩展名 + base_end: t.CSizeT = src_len + j: t.CSizeT = base_start + while j < src_len: + if src_path[j] == '.': + base_end = j + break + j += 1 + # 输出名 = 文件名 + ".exe" + name_len: t.CSizeT = base_end - base_start + if name_len > 0: + out_len: t.CSizeT = name_len + 5 + output_name = stdlib.malloc(out_len) + if output_name is not None: + # 手动复制文件名并追加 .exe(viperlib.snprintf 不支持 %.*s,string 无 strcat) + string.strncpy(output_name, src_path + base_start, name_len) + output_name[name_len] = '.' + output_name[name_len + 1] = 'e' + output_name[name_len + 2] = 'x' + output_name[name_len + 3] = 'e' + output_name[name_len + 4] = '\0' + # 使用 project.vpj 中的配置 + temp_dir: str = Config.TempDir if Config.TempDir is not None else "." + output_dir: str = Config.OutputDir if Config.OutputDir is not None else "." + cc_cmd: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc" + cc_flags: str = "-filetype=obj -relocation-model=pic" + linker_cmd: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++" + linker_flags: str = "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition" + # --project 模式且未显式指定 --src 时:使用 config 中的 linker_output(如 TransPyV.exe) + # 显式指定 --src 时:使用从文件名推导的 output_name(如 test.exe),避免覆盖正在运行的 exe + if project is not None and Config.LinkerOutput is not None and args.get_str("src") is None: + linker_output: str = Config.LinkerOutput + else: + linker_output: str = output_name + + # 计算 includes.binary 目录路径(链接时附加预编译 .obj) + includes_binary_dir: str = Config.get_includes_binary_dir() + + ir_len: t.CSizeT = string.strlen(ir_buf) + + # (--phase 参数已在配置加载后处理,此处直接使用 do_phase1/do_phase2) + + # === Phase1 stub 分离:使用 OUTPUT_STUB/TEXT 模式分别生成 stub.ll 和 text.ll === + if do_phase1 != 0 and temp_dir is not None and module_name is not None: + if log is not None: + log.banner("stub 分离") + SF_IR_SIZE: t.CSizeT = 262144 + td_len_sf: t.CSizeT = string.strlen(temp_dir) + # 保存 stub.ll + sf_stub_buf: bytes = stdlib.malloc(SF_IR_SIZE) + if sf_stub_buf is not None: + tr.dump_ir(sf_stub_buf, SF_IR_SIZE, llvmlite.OUTPUT_STUB) + sf_stub_len: t.CSizeT = string.strlen(sf_stub_buf) + sf_stub_path: bytes = stdlib.malloc(td_len_sf + 32) + if sf_stub_path is not None: + viperlib.snprintf(sf_stub_path, td_len_sf + 32, "%s/%s.stub.ll", temp_dir, module_name) + sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W) + if not sf_f.closed: + sf_f.write(sf_stub_buf, sf_stub_len) + sf_f.close() + stdlib.free(sf_stub_path) + stdlib.free(sf_stub_buf) + # 保存 text.ll + sf_text_buf: bytes = stdlib.malloc(SF_IR_SIZE) + if sf_text_buf is not None: + tr.dump_ir(sf_text_buf, SF_IR_SIZE, llvmlite.OUTPUT_TEXT) + sf_text_len: t.CSizeT = string.strlen(sf_text_buf) + sf_text_path: bytes = stdlib.malloc(td_len_sf + 32) + if sf_text_path is not None: + viperlib.snprintf(sf_text_path, td_len_sf + 32, "%s/%s.text.ll", temp_dir, module_name) + sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W) + if not sf_tf.closed: + sf_tf.write(sf_text_buf, sf_text_len) + sf_tf.close() + stdlib.free(sf_text_path) + stdlib.free(sf_text_buf) + + # phase=1 模式:仅生成 stub,不执行编译 + if do_phase2 == 0: + if log is not None: + log.success("Phase1 完成(仅 stub 分离,跳过编译)") + argparse.release(args) + return 0 + + # === Phase2: 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR === + final_ir: bytes = ir_buf + final_ir_len: t.CSizeT = ir_len + if temp_dir is not None and module_name is not None: + if log is not None: + log.banner("IR 组合") + SF_COMBINED_SIZE: t.CSizeT = 4194304 # 4MB + combined_buf: bytes = stdlib.malloc(SF_COMBINED_SIZE) + if combined_buf is not None: + combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, module_name, combined_buf, SF_COMBINED_SIZE) + if combined_len > 0: + final_ir = combined_buf + final_ir_len = combined_len + else: + stdio.printf("[stub] BuildCombinedIR 失败,使用原始 IR\n") + stdlib.free(combined_buf) + + br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline( + final_ir, final_ir_len, temp_dir, output_dir, module_name, + cc_cmd, cc_flags, linker_cmd, linker_flags, linker_output, + includes_binary_dir + ) + if br is not None and br.Success == 1: + if log is not None: + log.success("编译管线完成") + stdio.printf("输出: %s/%s\n", output_dir, linker_output) + # --run 模式:执行生成的可执行文件 + if args.get_bool("run"): + exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2) + if exe_path is not None: + viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output) + stdio.printf("[run] 执行: %s\n", exe_path) + r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False) + if r is not None: + stdio.printf("[run] 退出码: %d\n", r.returncode) + else: + if log is not None: + log.error("编译管线失败", "pipeline") + if br is not None and br.ErrorMsg is not None: + stdio.printf("[FATAL] 编译管线失败: %s\n", br.ErrorMsg) + sys.exit(1) + else: + if log is not None: + log.error("malloc for IR buffer failed", "memhub") + else: + if log is not None: + log.error("翻译失败", "translator") + + argparse.release(args) + if log is not None: + log.success("TransPyV 完成") + return 0 diff --git a/Test/App/asm_test.py b/Test/App/asm_test.py new file mode 100644 index 0000000..d09ac4b --- /dev/null +++ b/Test/App/asm_test.py @@ -0,0 +1,47 @@ +import stdio +import t, c + + +# ============================================================ +# c.Asm 内联汇编测试 +# ============================================================ + +def asm_test() -> int: + # 1. 简单无操作数汇编(nop + clobber) + c.Asm("nop", op=[t.ASM_DESCR.CLOBBER_MEMORY]) + stdio.printf("asm: nop ok\n") + + # 2. 仅汇编文本无 clobber + c.Asm("nop") + stdio.printf("asm: nop2 ok\n") + + # 3. 多 clobber + c.Asm("nop", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_CC]) + stdio.printf("asm: multi-clobber ok\n") + + # 4. 带输入操作数的汇编(读取 CPU ID) + # 使用 f-string 内联 c.AsmInp + # mov eax, 输入值; nop(保持简单,不使用会产生异常的指令) + val: int = 42 + c.Asm(f"""mov eax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)} +nop""", op=[t.ASM_DESCR.CLOBBER_RAX]) + stdio.printf("asm: input ok val=%d\n", val) + + # 5. 带输出操作数的汇编 + # c.AsmOut 获取结果 + result: int = 0 + c.Asm(f"""mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, 123 +nop""", op=[t.ASM_DESCR.CLOBBER_RAX]) + stdio.printf("asm: output result=%d\n", result) + + # 6. 带输入和输出操作数 + # result2 = val + 1 + result2: int = 0 + input_val: int = 10 + c.Asm(f"""mov eax, {c.AsmInp(input_val, t.ASM_DESCR.REG_ANY)} +add eax, 1 +mov {c.AsmOut(result2, t.ASM_DESCR.OUTPUT_REG)}, eax +nop""", op=[t.ASM_DESCR.CLOBBER_RAX]) + stdio.printf("asm: in+out result2=%d (expect 11)\n", result2) + + return 0 diff --git a/Test/App/attr_test.py b/Test/App/attr_test.py new file mode 100644 index 0000000..4bc8cad --- /dev/null +++ b/Test/App/attr_test.py @@ -0,0 +1,234 @@ +import t, c +from stdint import * +import stdio +import string + + +# ============================================================ +# c.Attribute 装饰器测试 +# +# 测试 @c.Attribute(...) 对函数属性的设置: +# - t.attr.always_inline() -> alwaysinline +# - t.attr.noinline() -> noinline +# - t.attr.noreturn() -> noreturn +# - t.attr.pure() -> readonly (LLVM 函数属性) +# - t.attr.llvm.nounwind -> nounwind +# ============================================================ + + +# Test 1: always_inline 属性 +@c.Attribute(t.attr.always_inline()) +def AlwaysInlineFunc(x: t.CInt) -> t.CInt: + return x * 2 + + +# Test 2: noinline 属性 +@c.Attribute(t.attr.noinline()) +def NoInlineFunc(x: t.CInt) -> t.CInt: + return x + 100 + + +# Test 3: noreturn 属性(函数确实不返回) +@c.Attribute(t.attr.noreturn()) +def NoReturnFunc() -> t.CInt: + stdio.printf("NoReturnFunc called (does not return)\n") + return 0 + + +# Test 4: 普通函数对照(无装饰器) +def NormalFunc(x: t.CInt) -> t.CInt: + return x * 3 + + +# Test 5: 多属性组合 +@c.Attribute(t.attr.always_inline(), t.attr.pure()) +def MultiAttrFunc(x: t.CInt) -> t.CInt: + return x + 1 + + +# Test 6: 无括号属性引用 t.attr.packed +@c.Attribute(t.attr.packed) +def PackedAttrFunc(x: t.CInt) -> t.CInt: + return x - 1 + + +def test_always_inline() -> t.CInt: + stdio.printf("--- Test 1: c.Attribute(always_inline) ---\n") + r: t.CInt = AlwaysInlineFunc(21) + stdio.printf("AlwaysInlineFunc(21)=%d (expect 42)\n", r) + if r == 42: + stdio.printf("AlwaysInlineFunc OK\n") + else: + stdio.printf("AlwaysInlineFunc FAIL\n") + return 0 + + +def test_noinline() -> t.CInt: + stdio.printf("--- Test 2: c.Attribute(noinline) ---\n") + r: t.CInt = NoInlineFunc(5) + stdio.printf("NoInlineFunc(5)=%d (expect 105)\n", r) + if r == 105: + stdio.printf("NoInlineFunc OK\n") + else: + stdio.printf("NoInlineFunc FAIL\n") + return 0 + + +def test_noreturn() -> t.CInt: + stdio.printf("--- Test 3: c.Attribute(noreturn) ---\n") + stdio.printf("NoReturnFunc declared with noreturn attr\n") + stdio.printf("NoReturnFunc OK (not called to avoid UB)\n") + return 0 + + +def test_normal() -> t.CInt: + stdio.printf("--- Test 4: normal function (no attr) ---\n") + r: t.CInt = NormalFunc(7) + stdio.printf("NormalFunc(7)=%d (expect 21)\n", r) + if r == 21: + stdio.printf("NormalFunc OK\n") + else: + stdio.printf("NormalFunc FAIL\n") + return 0 + + +def test_multi_attr() -> t.CInt: + stdio.printf("--- Test 5: c.Attribute(always_inline, pure) ---\n") + r: t.CInt = MultiAttrFunc(10) + stdio.printf("MultiAttrFunc(10)=%d (expect 11)\n", r) + if r == 11: + stdio.printf("MultiAttrFunc OK\n") + else: + stdio.printf("MultiAttrFunc FAIL\n") + return 0 + + +def test_packed_attr() -> t.CInt: + stdio.printf("--- Test 6: c.Attribute(packed) ---\n") + r: t.CInt = PackedAttrFunc(10) + stdio.printf("PackedAttrFunc(10)=%d (expect 9)\n", r) + if r == 9: + stdio.printf("PackedAttrFunc OK\n") + else: + stdio.printf("PackedAttrFunc FAIL\n") + return 0 + + +# Test 7: t.attr.llvm.nounwind 属性 +@c.Attribute(t.attr.llvm.nounwind) +def NoUnwindFunc(x: t.CInt) -> t.CInt: + return x + 1 + + +# Test 8: t.attr.llvm.noredzone 属性 +@c.Attribute(t.attr.llvm.noredzone) +def NoRedZoneFunc(x: t.CInt) -> t.CInt: + return x + 2 + + +# Test 9: t.attr.llvm.willreturn 属性 +@c.Attribute(t.attr.llvm.willreturn) +def WillReturnFunc(x: t.CInt) -> t.CInt: + return x + 3 + + +# Test 10: t.attr.llvm.mustprogress 属性 +@c.Attribute(t.attr.llvm.mustprogress) +def MustProgressFunc(x: t.CInt) -> t.CInt: + return x + 4 + + +# Test 11: t.attr.const() -> readnone +@c.Attribute(t.attr.const()) +def ConstFunc(x: t.CInt) -> t.CInt: + return x * 0 + 42 + + +# Test 12: 多属性组合(alwaysinline + nounwind + noredzone) +@c.Attribute(t.attr.always_inline(), t.attr.llvm.nounwind, t.attr.llvm.noredzone) +def TripleAttrFunc(x: t.CInt) -> t.CInt: + return x + 5 + + +def test_nounwind() -> t.CInt: + stdio.printf("--- Test 7: c.Attribute(llvm.nounwind) ---\n") + r: t.CInt = NoUnwindFunc(10) + stdio.printf("NoUnwindFunc(10)=%d (expect 11)\n", r) + if r == 11: + stdio.printf("NoUnwindFunc OK\n") + else: + stdio.printf("NoUnwindFunc FAIL\n") + return 0 + + +def test_noredzone() -> t.CInt: + stdio.printf("--- Test 8: c.Attribute(llvm.noredzone) ---\n") + r: t.CInt = NoRedZoneFunc(10) + stdio.printf("NoRedZoneFunc(10)=%d (expect 12)\n", r) + if r == 12: + stdio.printf("NoRedZoneFunc OK\n") + else: + stdio.printf("NoRedZoneFunc FAIL\n") + return 0 + + +def test_willreturn() -> t.CInt: + stdio.printf("--- Test 9: c.Attribute(llvm.willreturn) ---\n") + r: t.CInt = WillReturnFunc(10) + stdio.printf("WillReturnFunc(10)=%d (expect 13)\n", r) + if r == 13: + stdio.printf("WillReturnFunc OK\n") + else: + stdio.printf("WillReturnFunc FAIL\n") + return 0 + + +def test_mustprogress() -> t.CInt: + stdio.printf("--- Test 10: c.Attribute(llvm.mustprogress) ---\n") + r: t.CInt = MustProgressFunc(10) + stdio.printf("MustProgressFunc(10)=%d (expect 14)\n", r) + if r == 14: + stdio.printf("MustProgressFunc OK\n") + else: + stdio.printf("MustProgressFunc FAIL\n") + return 0 + + +def test_const_attr() -> t.CInt: + stdio.printf("--- Test 11: c.Attribute(const) ---\n") + r: t.CInt = ConstFunc(99) + stdio.printf("ConstFunc(99)=%d (expect 42)\n", r) + if r == 42: + stdio.printf("ConstFunc OK\n") + else: + stdio.printf("ConstFunc FAIL\n") + return 0 + + +def test_triple_attr() -> t.CInt: + stdio.printf("--- Test 12: c.Attribute(always_inline, nounwind, noredzone) ---\n") + r: t.CInt = TripleAttrFunc(10) + stdio.printf("TripleAttrFunc(10)=%d (expect 15)\n", r) + if r == 15: + stdio.printf("TripleAttrFunc OK\n") + else: + stdio.printf("TripleAttrFunc FAIL\n") + return 0 + + +def attr_test() -> t.CInt: + stdio.printf("=== attr_test: c.Attribute 装饰器测试 ===\n\n") + test_always_inline() + test_noinline() + test_noreturn() + test_normal() + test_multi_attr() + test_packed_attr() + test_nounwind() + test_noredzone() + test_willreturn() + test_mustprogress() + test_const_attr() + test_triple_attr() + stdio.printf("\n=== attr_test 完成 ===\n") + return 0 diff --git a/Test/App/augassign_test.py b/Test/App/augassign_test.py new file mode 100644 index 0000000..20b52ce --- /dev/null +++ b/Test/App/augassign_test.py @@ -0,0 +1,58 @@ +import stdio +import t, c + + +# ============================================================ +# AugAssign 测试:+= -= *= /= %= &= |= ^= <<= >>= +# ============================================================ + +g_count: int = 0 + + +def test_local() -> int: + x: int = 10 + x += 5 + stdio.printf("local +=: %d\n", x) + x -= 3 + stdio.printf("local -=: %d\n", x) + x *= 2 + stdio.printf("local *=: %d\n", x) + x /= 4 + stdio.printf("local /=: %d\n", x) + x %= 7 + stdio.printf("local %%=: %d\n", x) + return 0 + + +def test_global_aug() -> int: + global g_count + g_count += 1 + stdio.printf("global +=: %d\n", g_count) + g_count += 10 + stdio.printf("global +=: %d\n", g_count) + g_count -= 3 + stdio.printf("global -=: %d\n", g_count) + return 0 + + +def test_bitops() -> int: + b: int = 0xFF + b &= 0x0F + stdio.printf("bit &=: %d\n", b) + b |= 0x30 + stdio.printf("bit |=: %d\n", b) + b ^= 0xFF + stdio.printf("bit ^=: %d\n", b) + b = 1 + b <<= 4 + stdio.printf("bit <<=: %d\n", b) + b >>= 2 + stdio.printf("bit >>=: %d\n", b) + return 0 + + +def augassign_test() -> int: + test_local() + test_global_aug() + test_bitops() + return 0 diff --git a/Test/App/closure_test.py b/Test/App/closure_test.py new file mode 100644 index 0000000..c2c876e --- /dev/null +++ b/Test/App/closure_test.py @@ -0,0 +1,45 @@ +import stdio +import t, c + + +# ============================================================ +# 闭包 + nonlocal/global 测试 +# ============================================================ + +# 全局变量 +g_count: int = 0 + + +# global 关键字测试:修改全局变量 +def test_global() -> int: + global g_count + g_count = g_count + 1 + return g_count + + +# nonlocal 关键字测试:嵌套函数修改外层局部变量 +def make_counter() -> t.CPtr: + count: int = 0 + + # 内部函数(闭包)捕获 count + def counter() -> int: + nonlocal count + count = count + 1 + return count + + return counter + + +def closure_test() -> int: + # global 测试 + stdio.printf("global: %d\n", test_global()) + stdio.printf("global: %d\n", test_global()) + stdio.printf("global: %d\n", test_global()) + + # nonlocal/闭包测试 + f: t.CPtr = make_counter() + stdio.printf("closure: %d\n", f()) + stdio.printf("closure: %d\n", f()) + stdio.printf("closure: %d\n", f()) + + return 0 diff --git a/Test/App/deco_test.py b/Test/App/deco_test.py new file mode 100644 index 0000000..9af6396 --- /dev/null +++ b/Test/App/deco_test.py @@ -0,0 +1,183 @@ +import stdio +import t, c +import string + + +# ============================================================ +# deco_test - t/c 装饰器测试 +# +# 测试 t.CDefine / t.CExport / t.CInline / t.CExtern / t.State +# ============================================================ + + +# Test 1: t.CDefine - 常量定义 +MAX_VALUE: t.CDefine = 256 +PI_APPROX: t.CDefine = 314 +# Test 10: t.CDefine 作为 t.CArray 的 count +ARR_SIZE: t.CDefine = 8 + + +# Test 2: t.CExport - 导出函数标记 +def ExportedAdd(a: t.CInt, b: t.CInt) -> t.CInt | t.CExport: + return a + b + + +# Test 3: t.CInline - 内联函数标记 +def InlineSquare(x: t.CInt) -> t.CInt | t.CInline: + return x * x + + +# Test 4: 普通函数(无装饰器,作为对照) +def NormalSub(a: t.CInt, b: t.CInt) -> t.CInt: + return a - b + + +# Test 5: t.CExport 与 t.CInline 组合 +def ExportedInlineCube(x: t.CInt) -> t.CInt | t.CExport | t.CInline: + return x * x * x + + +# Test 6: t.CExport 返回指针 +def ExportedFindChar(s: str, ch: t.CInt) -> str | t.CExport: + return string.strchr(s, ch) + + +def test_cdefine(): + stdio.printf("--- Test 1: t.CDefine ---\n") + stdio.printf("MAX_VALUE=%d (expect 256)\n", MAX_VALUE) + stdio.printf("PI_APPROX=%d (expect 314)\n", PI_APPROX) + if MAX_VALUE == 256: + stdio.printf("MAX_VALUE OK\n") + else: + stdio.printf("MAX_VALUE FAIL\n") + if PI_APPROX == 314: + stdio.printf("PI_APPROX OK\n") + else: + stdio.printf("PI_APPROX FAIL\n") + + +def test_cexport(): + stdio.printf("--- Test 2: t.CExport ---\n") + r: t.CInt = ExportedAdd(3, 4) + stdio.printf("ExportedAdd(3,4)=%d (expect 7)\n", r) + if r == 7: + stdio.printf("ExportedAdd OK\n") + else: + stdio.printf("ExportedAdd FAIL\n") + + +def test_cinline(): + stdio.printf("--- Test 3: t.CInline ---\n") + r: t.CInt = InlineSquare(5) + stdio.printf("InlineSquare(5)=%d (expect 25)\n", r) + if r == 25: + stdio.printf("InlineSquare OK\n") + else: + stdio.printf("InlineSquare FAIL\n") + + +def test_deco_normal(): + stdio.printf("--- Test 4: normal function ---\n") + r: t.CInt = NormalSub(10, 3) + stdio.printf("NormalSub(10,3)=%d (expect 7)\n", r) + if r == 7: + stdio.printf("NormalSub OK\n") + else: + stdio.printf("NormalSub FAIL\n") + + +def test_export_inline(): + stdio.printf("--- Test 5: t.CExport | t.CInline ---\n") + r: t.CInt = ExportedInlineCube(3) + stdio.printf("ExportedInlineCube(3)=%d (expect 27)\n", r) + if r == 27: + stdio.printf("ExportedInlineCube OK\n") + else: + stdio.printf("ExportedInlineCube FAIL\n") + + +def test_export_ptr(): + stdio.printf("--- Test 6: t.CExport return ptr ---\n") + p: str = ExportedFindChar("Hello", 108) # 'l' = 108 + if p is not None: + stdio.printf("ExportedFindChar found, char=%d (expect 108)\n", c.Deref(p)) + if c.Deref(p) == 108: + stdio.printf("ExportedFindChar OK\n") + else: + stdio.printf("ExportedFindChar FAIL\n") + else: + stdio.printf("ExportedFindChar NOT FOUND (FAIL)\n") + + +# Test 7: t.CExtern | t.CExport - 外部声明函数(pass 体) +# 声明一个外部函数,翻译器应生成 declare 而非 define +def ExternalDecl(x: t.CInt) -> t.CInt | t.CExtern | t.CExport: pass + + +# Test 8: t.State - 状态声明(等价于 CExtern | CExport) +def StateDecl(x: t.CInt) -> t.CInt | t.State: pass + + +# Test 9: t.State 返回 void +def StateVoidDecl() -> t.State: pass + + +def test_extern_decl(): + stdio.printf("--- Test 7: t.CExtern | t.CExport ---\n") + # 外部声明函数,不调用(应由链接器解析符号) + stdio.printf("ExternalDecl declared (not called)\n") + stdio.printf("ExternalDecl OK\n") + + +def test_state_decl(): + stdio.printf("--- Test 8: t.State ---\n") + stdio.printf("StateDecl declared (not called)\n") + stdio.printf("StateDecl OK\n") + + +def test_state_void_decl(): + stdio.printf("--- Test 9: t.State (void) ---\n") + stdio.printf("StateVoidDecl declared (not called)\n") + stdio.printf("StateVoidDecl OK\n") + + +# Test 10: t.CDefine 作为 t.CArray count +# ARR_SIZE: t.CDefine = 8 已在文件顶部定义 +def test_cdefine_array_count(): + stdio.printf("--- Test 10: t.CArray[elem, CDefine] ---\n") + # 使用 CDefine 常量名作为数组 count + arr: t.CArray[t.CInt, ARR_SIZE] + i: t.CInt + # 初始化: arr[i] = i * 10 + for i in range(ARR_SIZE): + arr[i] = i * 10 + # 求和验证: 0+10+20+...+70 = 280 + total: t.CInt = 0 + for i in range(ARR_SIZE): + total += arr[i] + stdio.printf("ARR_SIZE=%d (expect 8)\n", ARR_SIZE) + stdio.printf("arr sum=%d (expect 280)\n", total) + stdio.printf("arr[0]=%d (expect 0)\n", arr[0]) + stdio.printf("arr[7]=%d (expect 70)\n", arr[7]) + if ARR_SIZE == 8 and total == 280 and arr[0] == 0 and arr[7] == 70: + stdio.printf("CArray CDefine count OK\n") + else: + stdio.printf("CArray CDefine count FAIL\n") + + +def deco_test() -> int: + stdio.printf("=== deco_test: t/c 装饰器测试 ===\n\n") + + test_cdefine() + test_cexport() + test_cinline() + test_deco_normal() + test_export_inline() + test_export_ptr() + test_extern_decl() + test_state_decl() + test_state_void_decl() + test_cdefine_array_count() + + stdio.printf("\n=== deco_test 完成 ===\n") + return 0 diff --git a/Test/App/deref_min_test.py b/Test/App/deref_min_test.py new file mode 100644 index 0000000..9bc3210 --- /dev/null +++ b/Test/App/deref_min_test.py @@ -0,0 +1,9 @@ +import stdio +import t, c + + +def deref_min_test() -> int: + s: str = "hello" + v: int = c.Deref(s) + stdio.printf("deref: %d\n", v) + return 0 diff --git a/Test/App/deref_test.py b/Test/App/deref_test.py new file mode 100644 index 0000000..b4483cc --- /dev/null +++ b/Test/App/deref_test.py @@ -0,0 +1,13 @@ +import stdio +import t, c + + +def deref_test() -> int: + s: str = "hello" + sp: str = s + slen: int = 0 + while c.Deref(sp) != 0: + slen = slen + 1 + sp = sp + 1 + stdio.printf("ptr: len(hello)=%d\n", slen) + return 0 diff --git a/Test/App/eq_test.py b/Test/App/eq_test.py new file mode 100644 index 0000000..d3c315d --- /dev/null +++ b/Test/App/eq_test.py @@ -0,0 +1,144 @@ +import stdio +import t, c +import string + + +# ============================================================ +# eq_test - ==、!=、is、is not、None 比较测试 +# +# 验证比较表达式的翻译,特别是 None 常量和 is/is not 操作符 +# ============================================================ + + +def test_int_eq(): + stdio.printf("--- Test 1: int == / != ---\n") + + a: t.CInt = 42 + b: t.CInt = 42 + c3: t.CInt = 99 + + if a == b: + stdio.printf("int == int (same) OK\n") + else: + stdio.printf("int == int (same) FAIL\n") + + if a != c3: + stdio.printf("int != int (diff) OK\n") + else: + stdio.printf("int != int (diff) FAIL\n") + + if not (a == c3): + stdio.printf("not (int == diff) OK\n") + else: + stdio.printf("not (int == diff) FAIL\n") + + +def test_int_cmp(): + stdio.printf("--- Test 2: int < > <= >= ---\n") + + a: t.CInt = 5 + b: t.CInt = 10 + + if a < b: + stdio.printf("int < OK\n") + else: + stdio.printf("int < FAIL\n") + + if b > a: + stdio.printf("int > OK\n") + else: + stdio.printf("int > FAIL\n") + + if a <= 5: + stdio.printf("int <= OK\n") + else: + stdio.printf("int <= FAIL\n") + + if b >= 10: + stdio.printf("int >= OK\n") + else: + stdio.printf("int >= FAIL\n") + + +def test_ptr_is_none(): + stdio.printf("--- Test 3: ptr is None / is not None ---\n") + + # strchr 找到字符返回非空指针,找不到返回 None + p: str = string.strchr("Hello", 108) # 'l' = 108 + if p is not None: + stdio.printf("strchr found, is not None OK\n") + else: + stdio.printf("strchr found, is not None FAIL\n") + + p2: str = string.strchr("Hello", 122) # 'z' = 122, not found + if p2 is None: + stdio.printf("strchr not found, is None OK\n") + else: + stdio.printf("strchr not found, is None FAIL\n") + + +def test_ptr_assign_none(): + stdio.printf("--- Test 4: assign None and compare ---\n") + + p: str = None + if p is None: + stdio.printf("None assign, is None OK\n") + else: + stdio.printf("None assign, is None FAIL\n") + + if p is not None: + stdio.printf("None assign, is not None FAIL\n") + else: + stdio.printf("None assign, is not None OK\n") + + +def test_ptr_eq_none(): + stdio.printf("--- Test 5: ptr == None / != None ---\n") + + p: str = string.strstr("Hello World", "World") + if p != None: + stdio.printf("strstr found, != None OK\n") + else: + stdio.printf("strstr found, != None FAIL\n") + + p2: str = string.strstr("Hello", "xyz") + if p2 == None: + stdio.printf("strstr not found, == None OK\n") + else: + stdio.printf("strstr not found, == None FAIL\n") + + +def test_bool_logic(): + stdio.printf("--- Test 6: bool and/or ---\n") + + a: t.CInt = 1 + b: t.CInt = 0 + + if a and b: + stdio.printf("1 and 0 = true FAIL\n") + else: + stdio.printf("1 and 0 = false OK\n") + + if a or b: + stdio.printf("1 or 0 = true OK\n") + else: + stdio.printf("1 or 0 = true FAIL\n") + + if not b: + stdio.printf("not 0 = true OK\n") + else: + stdio.printf("not 0 = true FAIL\n") + + +def eq_test() -> int: + stdio.printf("=== eq_test: ==、!=、is、None 比较测试 ===\n\n") + + test_int_eq() + test_int_cmp() + test_ptr_is_none() + test_ptr_assign_none() + test_ptr_eq_none() + test_bool_logic() + + stdio.printf("\n=== eq_test 完成 ===\n") + return 0 diff --git a/Test/App/float_test.py b/Test/App/float_test.py new file mode 100644 index 0000000..100f4f0 --- /dev/null +++ b/Test/App/float_test.py @@ -0,0 +1,84 @@ +import stdio +import t, c + + +# ============================================================ +# 联合体(t.CUnion)含浮点字段 +# ============================================================ + +class DataUnion(t.CUnion): + i: t.CInt + f: t.CFloat + l: t.CInt64T + + +# ============================================================ +# 主函数 +# ============================================================ +def float_test() -> int: + # ============================================================ + # 测试 1: 基本浮点变量(float / double) + # ============================================================ + f: t.CFloat = 3.14 + stdio.printf("float: f=%f\n", f) + + d: t.CDouble = 3.141592653589793 + stdio.printf("double: d=%lf\n", d) + + # 重新赋值 + f = 2.5 + stdio.printf("float: f=%f\n", f) + + # ============================================================ + # 测试 2: 联合体浮点字段 + # ============================================================ + u: DataUnion + u.f = 3.14 + stdio.printf("union: u.f=%f\n", u.f) + + # 写入 i 字段后,f 的值已被覆盖 + u.i = 42 + stdio.printf("union: u.i=%d (after f overwritten)\n", u.i) + + # ============================================================ + # 测试 3: 联合体共享内存验证(float 与 int 共享) + # ============================================================ + u2: DataUnion + u2.i = 0 + u2.f = 1.0 + # 写入 f 后,i 的值应不再是 0 + if u2.i != 0: + stdio.printf("union: float overwrites int verified\n") + + # ============================================================ + # 测试 4: 浮点算术运算(fadd/fsub/fmul/fdiv/frem) + # ============================================================ + a: t.CFloat = 1.5 + b: t.CFloat = 2.5 + stdio.printf("arith: %.2f + %.2f = %.2f\n", a, b, a + b) + stdio.printf("arith: %.2f - %.2f = %.2f\n", a, b, a - b) + stdio.printf("arith: %.2f * %.2f = %.2f\n", a, b, a * b) + stdio.printf("arith: %.2f / %.2f = %.2f\n", a, b, a / b) + + # ============================================================ + # 测试 5: double 算术运算 + # ============================================================ + x: t.CDouble = 10.0 + y: t.CDouble = 3.0 + stdio.printf("arith: %.4lf + %.4lf = %.4lf\n", x, y, x + y) + stdio.printf("arith: %.4lf - %.4lf = %.4lf\n", x, y, x - y) + stdio.printf("arith: %.4lf * %.4lf = %.4lf\n", x, y, x * y) + stdio.printf("arith: %.4lf / %.4lf = %.4lf\n", x, y, x / y) + + # ============================================================ + # 测试 6: 浮点取模 (frem) + # ============================================================ + stdio.printf("arith: 10.0 %% 3.0 = %.4lf\n", x % y) + + # ============================================================ + # 测试 7: int 与 float 混合运算(int 自动转 float) + # ============================================================ + n: t.CInt = 3 + stdio.printf("arith: %d + %.2f = %.2f\n", n, a, n + a) + + return 0 diff --git a/Test/App/flow_test.py b/Test/App/flow_test.py new file mode 100644 index 0000000..89114ac --- /dev/null +++ b/Test/App/flow_test.py @@ -0,0 +1,23 @@ +import stdio +import t, c + + +def flow_test() -> int: + i: int = 0 + total: int = 0 + while i < 5: + total = total + i + i = i + 1 + stdio.printf("while: total=%d i=%d\n", total, i) + + for k in range(10): + if k == 3: + break + stdio.printf("break: k=%d\n", k) + + for m in range(5): + if m == 2: + continue + stdio.printf("continue: m=%d\n", m) + + return 0 diff --git a/Test/App/for_test.py b/Test/App/for_test.py new file mode 100644 index 0000000..e178457 --- /dev/null +++ b/Test/App/for_test.py @@ -0,0 +1,8 @@ +import stdio +import t, c + + +def for_test() -> int: + for j in range(5): + stdio.printf("for: j=%d\n", j) + return 0 diff --git a/Test/App/func_test.py b/Test/App/func_test.py new file mode 100644 index 0000000..21a3d4b --- /dev/null +++ b/Test/App/func_test.py @@ -0,0 +1,68 @@ +import stdio +import t, c + + +def add(a: int, b: int) -> int: + return a + b + + +def mul(a: int, b: int) -> int: + return a * b + + +def square(x: int) -> int: + return mul(x, x) + + +def factorial(n: int) -> int: + if n <= 1: + return 1 + return n * factorial(n - 1) + + +def greet(greeting: str, name: str, times: int) -> int: + i: int = 0 + while i < times: + stdio.printf("%s, %s!\n", greeting, name) + i = i + 1 + return times + + +def sub(a: int, b: int) -> int: + return a - b + + +def func_test() -> int: + r1: int = add(3, 4) + stdio.printf("add(3,4)=%d\n", r1) + + r2: int = mul(5, 6) + stdio.printf("mul(5,6)=%d\n", r2) + + r3: int = square(7) + stdio.printf("square(7)=%d\n", r3) + + r5: int = factorial(5) + stdio.printf("factorial(5)=%d\n", r5) + + # ============================================================ + # 测试: 函数乱序传参(关键字参数) + # ============================================================ + # 乱序传参:b=4, a=3 等价于 add(3, 4) + r6: int = add(b=4, a=3) + stdio.printf("add(b=4,a=3)=%d\n", r6) + + # 乱序传参:a=10, b=3 等价于 sub(10, 3) + r7: int = sub(b=3, a=10) + stdio.printf("sub(b=3,a=10)=%d\n", r7) + + # 混合传参:位置参数 + 关键字参数 + # greeting="Hello" 是位置参数,name="World" 和 times=2 是关键字 + r8: int = greet("Hello", name="World", times=2) + stdio.printf("greet mixed: returned=%d\n", r8) + + # 全关键字乱序传参 + r9: int = greet(times=1, name="TransPyC", greeting="Hi") + stdio.printf("greet kwargs: returned=%d\n", r9) + + return 0 diff --git a/Test/App/func_vtable_test.py b/Test/App/func_vtable_test.py new file mode 100644 index 0000000..854ab7c --- /dev/null +++ b/Test/App/func_vtable_test.py @@ -0,0 +1,116 @@ +import stdio +import t, c + + +# ============================================================ +# 场景 A: @t.NoVTable 类 + 函数级 @t.CVTable +# +# NoVTableClass 标记 @t.NoVTable(类级别禁用虚表) +# 但 VirtualMethod 标记 @t.CVTable → 该方法单独进入虚表 +# NormalMethod 无装饰器 → 不进入虚表 +# 预期: 虚表 1 个方法 (VirtualMethod) +# ============================================================ +@t.NoVTable +class NoVTableClass: + val: t.CInt + + def __init__(self, v: t.CInt): + self.val = v + + @t.CVTable + def VirtualMethod(self) -> t.CInt: + return self.val + 10 + + def NormalMethod(self) -> t.CInt: + return self.val + 20 + + +# ============================================================ +# 场景 B: @t.CVTable 类 + 函数级 @t.NoVTable +# +# CVTableClass 标记 @t.CVTable(所有方法进入虚表) +# KeptMethod 无装饰器 → 进入虚表 +# ExcludedMethod 标记 @t.NoVTable → 排除出虚表 +# 预期: 虚表 1 个方法 (KeptMethod) +# ============================================================ +@t.CVTable +class CVTableClass: + val: t.CInt + + def __init__(self, v: t.CInt): + self.val = v + + def KeptMethod(self) -> t.CInt: + return self.val + 30 + + @t.NoVTable + def ExcludedMethod(self) -> t.CInt: + return self.val + 40 + + +# ============================================================ +# 场景 C: 默认类(无装饰器无继承)+ 函数级 @t.CVTable +# +# DefaultClass 无装饰器(默认无虚表) +# VirtualMethod 标记 @t.CVTable → 单独进入虚表 +# NormalMethod 无装饰器 → 不进入虚表 +# 预期: 虚表 1 个方法 (VirtualMethod) +# ============================================================ +class DefaultClass: + val: t.CInt + + def __init__(self, v: t.CInt): + self.val = v + + @t.CVTable + def VirtualMethod(self) -> t.CInt: + return self.val + 50 + + def NormalMethod(self) -> t.CInt: + return self.val + 60 + + +def func_vtable_test() -> int: + stdio.printf("funcvt: === Test Start ===\n") + + # 场景 A: NoVTableClass + nvt: NoVTableClass = NoVTableClass(5) + a1: int = nvt.VirtualMethod() + stdio.printf("funcvt: A.VirtualMethod()=%d (expected 15)\n", a1) + if a1 != 15: + stdio.printf("[FAIL] A.VirtualMethod()=%d expected 15\n", a1) + return 1 + a2: int = nvt.NormalMethod() + stdio.printf("funcvt: A.NormalMethod()=%d (expected 25)\n", a2) + if a2 != 25: + stdio.printf("[FAIL] A.NormalMethod()=%d expected 25\n", a2) + return 1 + + # 场景 B: CVTableClass + cvt: CVTableClass = CVTableClass(7) + b1: int = cvt.KeptMethod() + stdio.printf("funcvt: B.KeptMethod()=%d (expected 37)\n", b1) + if b1 != 37: + stdio.printf("[FAIL] B.KeptMethod()=%d expected 37\n", b1) + return 1 + b2: int = cvt.ExcludedMethod() + stdio.printf("funcvt: B.ExcludedMethod()=%d (expected 47)\n", b2) + if b2 != 47: + stdio.printf("[FAIL] B.ExcludedMethod()=%d expected 47\n", b2) + return 1 + + # 场景 C: DefaultClass + dfc: DefaultClass = DefaultClass(9) + c1: int = dfc.VirtualMethod() + stdio.printf("funcvt: C.VirtualMethod()=%d (expected 59)\n", c1) + if c1 != 59: + stdio.printf("[FAIL] C.VirtualMethod()=%d expected 59\n", c1) + return 1 + c2: int = dfc.NormalMethod() + stdio.printf("funcvt: C.NormalMethod()=%d (expected 69)\n", c2) + if c2 != 69: + stdio.printf("[FAIL] C.NormalMethod()=%d expected 69\n", c2) + return 1 + + stdio.printf("funcvt: === All Tests Passed ===\n") + return 0 diff --git a/Test/App/generic_test.py b/Test/App/generic_test.py new file mode 100644 index 0000000..969e41e --- /dev/null +++ b/Test/App/generic_test.py @@ -0,0 +1,102 @@ +import stdio +import stdlib +import t, c +import testcheck +import memhub +import _list + + +# ============================================================ +# 泛型类 list[T] 测试 +# ============================================================ +def generic_test() -> int: + testcheck.begin("GenericTest: list[T] 泛型类测试") + + # 创建 mbuddy arena + arena: bytes = stdlib.malloc(65536) + bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536) + + # === Test 1: 创建和 append === + testcheck.section("Test 1: 创建和 append") + nums = list[int](bd) + nums.append(10) + nums.append(20) + nums.append(30) + v0: t.CInt = nums.get(0) + v1: t.CInt = nums.get(1) + v2: t.CInt = nums.get(2) + stdio.printf("v0=%d v1=%d v2=%d\n", v0, v1, v2) + testcheck.check(v0 == 10 and v1 == 20 and v2 == 30, + "append+get OK (10,20,30)", "append+get FAILED") + + # === Test 2: __len__ === + testcheck.section("Test 2: __len__") + n: t.CSizeT = nums.__len__() + stdio.printf("len=%lu\n", n) + testcheck.check(n == 3, "__len__ OK (3)", "__len__ FAILED expect 3") + + # === Test 3: set === + testcheck.section("Test 3: set") + nums.set(1, 99) + v1b: t.CInt = nums.get(1) + stdio.printf("after set(1,99): v1=%d\n", v1b) + testcheck.check(v1b == 99, "set OK (idx1=99)", "set FAILED") + + # === Test 4: pop === + testcheck.section("Test 4: pop") + popped: t.CInt = nums.pop() + stdio.printf("popped=%d\n", popped) + testcheck.check(popped == 30, "pop OK (30)", "pop FAILED expect 30") + n2: t.CSizeT = nums.__len__() + testcheck.check(n2 == 2, "pop len OK (2)", "pop len FAILED expect 2") + + # === Test 5: clear === + testcheck.section("Test 5: clear") + nums.clear() + n3: t.CSizeT = nums.__len__() + testcheck.check(n3 == 0, "clear OK (0)", "clear FAILED expect 0") + + # === Test 6: 容量增长 (append 超过初始容量 8) === + testcheck.section("Test 6: 容量增长") + nums2 = list[int](bd) + i: t.CInt + for i in range(20): + nums2.append(i * 5) + n4: t.CSizeT = nums2.__len__() + stdio.printf("after 20 appends: len=%lu\n", n4) + testcheck.check(n4 == 20, "grow len OK (20)", "grow len FAILED") + ok: t.CInt = 1 + for i in range(20): + v: t.CInt = nums2.get(i) + if v != i * 5: + stdio.printf("MISMATCH at %d: got %d expect %d\n", i, v, i * 5) + ok = 0 + break + testcheck.check(ok == 1, "grow data OK", "grow data FAILED") + + # === Test 7: 多个 list[int] 实例独立 === + testcheck.section("Test 7: 多实例独立") + lst_a = list[int](bd) + lst_b = list[int](bd) + lst_a.append(111) + lst_b.append(222) + va: t.CInt = lst_a.get(0) + vb: t.CInt = lst_b.get(0) + stdio.printf("lst_a[0]=%d lst_b[0]=%d\n", va, vb) + testcheck.check(va == 111 and vb == 222, + "multi-instance OK (111,222)", "multi-instance FAILED") + + # === Test 8: __getitem__ / __setitem__ === + testcheck.section("Test 8: __getitem__/__setitem__") + nums3 = list[int](bd) + nums3.append(1) + nums3.append(2) + nums3.append(3) + nums3[0] = 100 + gv: t.CInt = nums3[0] + stdio.printf("nums3[0]=%d after setitem\n", gv) + testcheck.check(gv == 100, "__setitem__/__getitem__ OK", + "__setitem__/__getitem__ FAILED") + + stdlib.free(arena) + return testcheck.end() \ No newline at end of file diff --git a/Test/App/inherit_test.py b/Test/App/inherit_test.py new file mode 100644 index 0000000..52bc20e --- /dev/null +++ b/Test/App/inherit_test.py @@ -0,0 +1,121 @@ +import stdio +import t, c + + +# ============================================================ +# 继承测试:字段展平 + vtable 继承 + 方法覆盖 +# ============================================================ + + +# ============================================================ +# 基类 Animal(有虚方法) +# ============================================================ +@t.CVTable +class Animal: + name: t.CInt + + def __init__(self, n: t.CInt): + self.name = n + + def GetName(self) -> t.CInt: + return self.name + + def Speak(self) -> t.CInt: + return 0 + + +# ============================================================ +# 子类 Dog(继承 Animal,覆盖 Speak,新增字段和方法) +# ============================================================ +class Dog(Animal): + breed: t.CInt + + def __init__(self, n: t.CInt, b: t.CInt): + self.name = n + self.breed = b + + def Speak(self) -> t.CInt: + return 1 + + def GetBreed(self) -> t.CInt: + return self.breed + + +# ============================================================ +# 子类 Cat(继承 Animal,不覆盖 Speak,新增字段和方法) +# ============================================================ +class Cat(Animal): + color: t.CInt + + def __init__(self, n: t.CInt, col: t.CInt): + self.name = n + self.color = col + + def GetColor(self) -> t.CInt: + return self.color + + +# ============================================================ +# 主函数 +# ============================================================ +def inherit_test() -> int: + # ============================================================ + # 测试 1: 基类 Animal + # ============================================================ + stdio.printf("inherit: === Test 1: Base Class ===\n") + a: Animal = Animal(42) + aname: int = a.GetName() + stdio.printf("inherit: a.GetName()=%d (expected 42)\n", aname) + if aname != 42: + stdio.printf("[FAIL] a.GetName()=%d expected 42\n", aname) + return 1 + aspeak: int = a.Speak() + stdio.printf("inherit: a.Speak()=%d (expected 0)\n", aspeak) + if aspeak != 0: + stdio.printf("[FAIL] a.Speak()=%d expected 0\n", aspeak) + return 1 + + # ============================================================ + # 测试 2: 子类 Dog(覆盖 Speak,继承 GetName) + # ============================================================ + stdio.printf("inherit: === Test 2: Dog (override Speak) ===\n") + d: Dog = Dog(100, 7) + dname: int = d.GetName() + stdio.printf("inherit: d.GetName()=%d (expected 100)\n", dname) + if dname != 100: + stdio.printf("[FAIL] d.GetName()=%d expected 100\n", dname) + return 1 + dspeak: int = d.Speak() + stdio.printf("inherit: d.Speak()=%d (expected 1)\n", dspeak) + if dspeak != 1: + stdio.printf("[FAIL] d.Speak()=%d expected 1\n", dspeak) + return 1 + dbreed: int = d.GetBreed() + stdio.printf("inherit: d.GetBreed()=%d (expected 7)\n", dbreed) + if dbreed != 7: + stdio.printf("[FAIL] d.GetBreed()=%d expected 7\n", dbreed) + return 1 + + # ============================================================ + # 测试 3: 子类 Cat(不覆盖 Speak,继承 GetName) + # ============================================================ + stdio.printf("inherit: === Test 3: Cat (inherit Speak) ===\n") + ct: Cat = Cat(200, 3) + cname: int = ct.GetName() + stdio.printf("inherit: ct.GetName()=%d (expected 200)\n", cname) + if cname != 200: + stdio.printf("[FAIL] ct.GetName()=%d expected 200\n", cname) + return 1 + cspeak: int = ct.Speak() + stdio.printf("inherit: ct.Speak()=%d (expected 0)\n", cspeak) + if cspeak != 0: + stdio.printf("[FAIL] ct.Speak()=%d expected 0\n", cspeak) + return 1 + ccolor: int = ct.GetColor() + stdio.printf("inherit: ct.GetColor()=%d (expected 3)\n", ccolor) + if ccolor != 3: + stdio.printf("[FAIL] ct.GetColor()=%d expected 3\n", ccolor) + return 1 + + stdio.printf("inherit: === All Tests Passed ===\n") + return 0 diff --git a/Test/App/llvmir_test.py b/Test/App/llvmir_test.py new file mode 100644 index 0000000..c7e44a7 --- /dev/null +++ b/Test/App/llvmir_test.py @@ -0,0 +1,247 @@ +import t, c +from stdint import * +import stdio + + +# ============================================================ +# c.LLVMIR / c.LInp / c.LOut 内联 LLVM IR 测试 +# +# 测试 c.LLVMIR 内联 LLVM IR 指令的生成和执行 +# - c.LInp(expr) 标记输入操作数 +# - c.LOut(expr) 标记输出操作数 +# ============================================================ + + +# Test 1: 基本加法 add +def test_add() -> t.CInt: + stdio.printf("--- Test 1: LLVMIR add ---\n") + a: t.CInt = 10 + b: t.CInt = 20 + r: t.CInt = c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("add(10, 20)=%d (expect 30)\n", r) + if r == 30: + stdio.printf("LLVMIR add OK\n") + else: + stdio.printf("LLVMIR add FAIL\n") + return 0 + + +# Test 2: 基本减法 sub +def test_sub() -> t.CInt: + stdio.printf("--- Test 2: LLVMIR sub ---\n") + a: t.CInt = 50 + b: t.CInt = 20 + r: t.CInt = c.LLVMIR(f"sub i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("sub(50, 20)=%d (expect 30)\n", r) + if r == 30: + stdio.printf("LLVMIR sub OK\n") + else: + stdio.printf("LLVMIR sub FAIL\n") + return 0 + + +# Test 3: 基本乘法 mul +def test_mul() -> t.CInt: + stdio.printf("--- Test 3: LLVMIR mul ---\n") + a: t.CInt = 6 + b: t.CInt = 7 + r: t.CInt = c.LLVMIR(f"mul i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("mul(6, 7)=%d (expect 42)\n", r) + if r == 42: + stdio.printf("LLVMIR mul OK\n") + else: + stdio.printf("LLVMIR mul FAIL\n") + return 0 + + +# Test 4: 基本除法 sdiv +def test_sdiv() -> t.CInt: + stdio.printf("--- Test 4: LLVMIR sdiv ---\n") + a: t.CInt = 100 + b: t.CInt = 4 + r: t.CInt = c.LLVMIR(f"sdiv i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("sdiv(100, 4)=%d (expect 25)\n", r) + if r == 25: + stdio.printf("LLVMIR sdiv OK\n") + else: + stdio.printf("LLVMIR sdiv FAIL\n") + return 0 + + +# Test 5: 位运算 and +def test_and() -> t.CInt: + stdio.printf("--- Test 5: LLVMIR and ---\n") + a: t.CInt = 255 + b: t.CInt = 15 + r: t.CInt = c.LLVMIR(f"and i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("and(255, 15)=%d (expect 15)\n", r) + if r == 15: + stdio.printf("LLVMIR and OK\n") + else: + stdio.printf("LLVMIR and FAIL\n") + return 0 + + +# Test 6: 位运算 or +def test_or() -> t.CInt: + stdio.printf("--- Test 6: LLVMIR or ---\n") + a: t.CInt = 240 + b: t.CInt = 15 + r: t.CInt = c.LLVMIR(f"or i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("or(240, 15)=%d (expect 255)\n", r) + if r == 255: + stdio.printf("LLVMIR or OK\n") + else: + stdio.printf("LLVMIR or FAIL\n") + return 0 + + +# Test 7: 位运算 xor +def test_xor() -> t.CInt: + stdio.printf("--- Test 7: LLVMIR xor ---\n") + a: t.CInt = 255 + b: t.CInt = 15 + r: t.CInt = c.LLVMIR(f"xor i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("xor(255, 15)=%d (expect 240)\n", r) + if r == 240: + stdio.printf("LLVMIR xor OK\n") + else: + stdio.printf("LLVMIR xor FAIL\n") + return 0 + + +# Test 8: 左移 shl +def test_shl() -> t.CInt: + stdio.printf("--- Test 8: LLVMIR shl ---\n") + a: t.CInt = 1 + b: t.CInt = 4 + r: t.CInt = c.LLVMIR(f"shl i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("shl(1, 4)=%d (expect 16)\n", r) + if r == 16: + stdio.printf("LLVMIR shl OK\n") + else: + stdio.printf("LLVMIR shl FAIL\n") + return 0 + + +# Test 9: LOut 输出赋值 +def test_lout() -> t.CInt: + stdio.printf("--- Test 9: LLVMIR LOut ---\n") + a: t.CInt = 10 + b: t.CInt = 20 + out_val: t.CInt = 0 + c.LLVMIR(f"{c.LOut(out_val)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("LOut add(10, 20)=%d (expect 30)\n", out_val) + if out_val == 30: + stdio.printf("LLVMIR LOut OK\n") + else: + stdio.printf("LLVMIR LOut FAIL\n") + return 0 + + +# Test 10: icmp eq 比较 +# 注意: TransPyV 用 sext i1 to i32 扩展布尔结果,true -> -1 +def test_icmp_eq() -> t.CInt: + stdio.printf("--- Test 10: LLVMIR icmp eq ---\n") + a: t.CInt = 5 + b: t.CInt = 5 + r: t.CInt = c.LLVMIR(f"icmp eq i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("icmp eq(5, 5)=%d (expect nonzero)\n", r) + if r != 0: + stdio.printf("LLVMIR icmp eq OK\n") + else: + stdio.printf("LLVMIR icmp eq FAIL\n") + return 0 + + +# Test 11: icmp ne 比较 +def test_icmp_ne() -> t.CInt: + stdio.printf("--- Test 11: LLVMIR icmp ne ---\n") + a: t.CInt = 5 + b: t.CInt = 3 + r: t.CInt = c.LLVMIR(f"icmp ne i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("icmp ne(5, 3)=%d (expect nonzero)\n", r) + if r != 0: + stdio.printf("LLVMIR icmp ne OK\n") + else: + stdio.printf("LLVMIR icmp ne FAIL\n") + return 0 + + +# Test 12: icmp slt 比较 +def test_icmp_slt() -> t.CInt: + stdio.printf("--- Test 12: LLVMIR icmp slt ---\n") + a: t.CInt = 3 + b: t.CInt = 5 + r: t.CInt = c.LLVMIR(f"icmp slt i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("icmp slt(3, 5)=%d (expect nonzero)\n", r) + if r != 0: + stdio.printf("LLVMIR icmp slt OK\n") + else: + stdio.printf("LLVMIR icmp slt FAIL\n") + return 0 + + +# Test 13: srem 取余 +def test_srem() -> t.CInt: + stdio.printf("--- Test 13: LLVMIR srem ---\n") + a: t.CInt = 17 + b: t.CInt = 5 + r: t.CInt = c.LLVMIR(f"srem i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("srem(17, 5)=%d (expect 2)\n", r) + if r == 2: + stdio.printf("LLVMIR srem OK\n") + else: + stdio.printf("LLVMIR srem FAIL\n") + return 0 + + +# Test 14: lshr 逻辑右移 +def test_lshr() -> t.CInt: + stdio.printf("--- Test 14: LLVMIR lshr ---\n") + a: t.CInt = 256 + b: t.CInt = 2 + r: t.CInt = c.LLVMIR(f"lshr i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + stdio.printf("lshr(256, 2)=%d (expect 64)\n", r) + if r == 64: + stdio.printf("LLVMIR lshr OK\n") + else: + stdio.printf("LLVMIR lshr FAIL\n") + return 0 + + +# Test 15: 嵌套在表达式中使用 +def test_nested() -> t.CInt: + stdio.printf("--- Test 15: LLVMIR nested in expression ---\n") + a: t.CInt = 10 + b: t.CInt = 20 + # c.LLVMIR 结果参与后续运算 + llvmir_result: t.CInt = c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + final_result: t.CInt = llvmir_result + 10 + stdio.printf("(LLVMIR add(10,20)) + 10 = %d (expect 40)\n", final_result) + if final_result == 40: + stdio.printf("LLVMIR nested OK\n") + else: + stdio.printf("LLVMIR nested FAIL\n") + return 0 + + +def llvmir_test() -> t.CInt: + stdio.printf("=== llvmir_test: c.LLVMIR 内联 LLVM IR 测试 ===\n\n") + test_add() + test_sub() + test_mul() + test_sdiv() + test_and() + test_or() + test_xor() + test_shl() + test_lout() + test_icmp_eq() + test_icmp_ne() + test_icmp_slt() + test_srem() + test_lshr() + test_nested() + stdio.printf("\n=== llvmir_test 完成 ===\n") + return 0 diff --git a/Test/App/namespace_defs.py b/Test/App/namespace_defs.py new file mode 100644 index 0000000..24e8e63 --- /dev/null +++ b/Test/App/namespace_defs.py @@ -0,0 +1,60 @@ +import stdio +import t, c + + +# ============================================================ +# 命名空间隔离测试:定义类模块 +# +# 本文件定义供其他文件 import 使用的类,验证跨模块命名空间隔离: +# - 裸名 Class(): 需要 from namespace_defs import Class +# - 模块限定 namespace_defs.Class(): 需要 import namespace_defs +# ============================================================ + + +# ============================================================ +# 带虚表的类 Widget +# ============================================================ +@t.CVTable +class Widget: + id: t.CInt + + def __init__(self, i: t.CInt): + self.id = i + + def GetId(self) -> t.CInt: + return self.id + + def Render(self) -> t.CInt: + return 100 + + +# ============================================================ +# 子类 Gadget(继承 Widget,覆盖 Render) +# ============================================================ +class Gadget(Widget): + extra: t.CInt + + def __init__(self, i: t.CInt, e: t.CInt): + self.id = i + self.extra = e + + def Render(self) -> t.CInt: + return 200 + + def GetExtra(self) -> t.CInt: + return self.extra + + +# ============================================================ +# 普通结构体 PlainStruct(无虚表) +# ============================================================ +class PlainStruct: + x: t.CInt + y: t.CInt + + def __init__(self, ax: t.CInt, ay: t.CInt): + self.x = ax + self.y = ay + + def Sum(self) -> t.CInt: + return self.x + self.y diff --git a/Test/App/namespace_test.py b/Test/App/namespace_test.py new file mode 100644 index 0000000..396a901 --- /dev/null +++ b/Test/App/namespace_test.py @@ -0,0 +1,111 @@ +import stdio +import t, c +import namespace_defs +from namespace_defs import Widget, Gadget, PlainStruct + + +# ============================================================ +# 命名空间隔离测试 +# +# 验证跨模块类访问必须通过 import: +# - Test 1: from X import Class → 裸名 Class() 构造 +# - Test 2: import X → 模块限定 X.Class() 构造 +# - Test 3: 类型注解使用导入的类 +# - Test 4: 继承类的虚分派(跨模块继承) +# ============================================================ + + +def namespace_test() -> int: + stdio.printf("nsisol: === Test Start ===\n") + + # ============================================================ + # Test 1: from X import Class → 裸名 Class() 构造 + # ============================================================ + stdio.printf("nsisol: === Test 1: from-import bare constructor ===\n") + + w: Widget = Widget(42) + wid: int = w.GetId() + stdio.printf("nsisol: w.GetId()=%d (expected 42)\n", wid) + if wid != 42: + stdio.printf("[FAIL] w.GetId()=%d expected 42\n", wid) + return 1 + + wrender: int = w.Render() + stdio.printf("nsisol: w.Render()=%d (expected 100)\n", wrender) + if wrender != 100: + stdio.printf("[FAIL] w.Render()=%d expected 100\n", wrender) + return 1 + + g: Gadget = Gadget(7, 9) + grender: int = g.Render() + stdio.printf("nsisol: g.Render()=%d (expected 200)\n", grender) + if grender != 200: + stdio.printf("[FAIL] g.Render()=%d expected 200\n", grender) + return 1 + + gextra: int = g.GetExtra() + stdio.printf("nsisol: g.GetExtra()=%d (expected 9)\n", gextra) + if gextra != 9: + stdio.printf("[FAIL] g.GetExtra()=%d expected 9\n", gextra) + return 1 + + # ============================================================ + # Test 2: import X → 模块限定 X.Class() 构造 + # ============================================================ + stdio.printf("nsisol: === Test 2: module-qualified constructor ===\n") + + ps: PlainStruct = PlainStruct(10, 20) + psum: int = ps.Sum() + stdio.printf("nsisol: ps.Sum()=%d (expected 30)\n", psum) + if psum != 30: + stdio.printf("[FAIL] ps.Sum()=%d expected 30\n", psum) + return 1 + + ps2: namespace_defs.PlainStruct = namespace_defs.PlainStruct(5, 6) + psum2: int = ps2.Sum() + stdio.printf("nsisol: ps2.Sum()=%d (expected 11)\n", psum2) + if psum2 != 11: + stdio.printf("[FAIL] ps2.Sum()=%d expected 11\n", psum2) + return 1 + + # ============================================================ + # Test 3: 类型注解使用导入的类 + # ============================================================ + stdio.printf("nsisol: === Test 3: type annotation with imported class ===\n") + + annot_w: Widget = Widget(99) + annot_id: int = annot_w.GetId() + stdio.printf("nsisol: annot_w.GetId()=%d (expected 99)\n", annot_id) + if annot_id != 99: + stdio.printf("[FAIL] annot_w.GetId()=%d expected 99\n", annot_id) + return 1 + + # ============================================================ + # Test 4: 跨模块继承的虚分派 + # ============================================================ + stdio.printf("nsisol: === Test 4: cross-module inheritance vtable ===\n") + + # Gadget 继承 Widget,覆盖 Render + # Widget.Render()=100, Gadget.Render()=200 + base: Widget = Widget(1) + derived: Gadget = Gadget(2, 3) + base_r: int = base.Render() + deriv_r: int = derived.Render() + stdio.printf("nsisol: base.Render()=%d (expected 100)\n", base_r) + if base_r != 100: + stdio.printf("[FAIL] base.Render()=%d expected 100\n", base_r) + return 1 + stdio.printf("nsisol: derived.Render()=%d (expected 200)\n", deriv_r) + if deriv_r != 200: + stdio.printf("[FAIL] derived.Render()=%d expected 200\n", deriv_r) + return 1 + + # 继承的方法:Gadget 继承 Widget.GetId + gname: int = derived.GetId() + stdio.printf("nsisol: derived.GetId()=%d (expected 2)\n", gname) + if gname != 2: + stdio.printf("[FAIL] derived.GetId()=%d expected 2\n", gname) + return 1 + + stdio.printf("nsisol: === All Tests Passed ===\n") + return 0 diff --git a/Test/App/new_test.py b/Test/App/new_test.py new file mode 100644 index 0000000..1cb9600 --- /dev/null +++ b/Test/App/new_test.py @@ -0,0 +1,119 @@ +import stdio +import t, c + + +# ============================================================ +# __new__ 函数测试:验证 __new__ 在创建 OOP 结构体前被调用, +# 返回的指针作为结构体存储空间。 +# +# __new__ 签名默认和 __init__ 一样(self + args),返回 Ptr(struct_ty)。 +# 如果 __new__ 返回 self,则使用默认 alloca 作为存储空间。 +# ============================================================ + + +# ============================================================ +# Test 1: __new__ 返回 self(默认 alloca) +# 验证 __new__ 被调用且不破坏 __init__ 正常功能 +# ============================================================ +class WithNew: + value: t.CInt + + def __new__(self, v: t.CInt): + stdio.printf("new: WithNew.__new__ called\n") + return self + + def __init__(self, v: t.CInt): + stdio.printf("new: WithNew.__init__ called\n") + self.value = v + + def GetValue(self) -> t.CInt: + return self.value + + +# ============================================================ +# Test 2: __new__ 不接受额外参数(仅 self) +# 验证 __new__ 签名可以与 __init__ 不同 +# ============================================================ +class WithNewNoArgs: + value: t.CInt + + def __new__(self): + stdio.printf("new: WithNewNoArgs.__new__ called\n") + return self + + def __init__(self, v: t.CInt): + self.value = v + + def GetValue(self) -> t.CInt: + return self.value + + +# ============================================================ +# Test 3: __new__ + @t.CVTable 虚表类 +# 验证 __new__ 与虚表机制兼容(__new__ 不进入虚表) +# ============================================================ +@t.CVTable +class WithNewVTable: + value: t.CInt + + def __new__(self, v: t.CInt): + stdio.printf("new: WithNewVTable.__new__ called\n") + return self + + def __init__(self, v: t.CInt): + self.value = v + + def GetValue(self) -> t.CInt: + return self.value + + def Speak(self) -> t.CInt: + return self.value + 1 + + +def new_test() -> int: + stdio.printf("new: === Test Start ===\n") + + # ============================================================ + # Test 1: __new__ 返回 self + # ============================================================ + stdio.printf("new: === Test 1: __new__ returns self ===\n") + + w: WithNew = WithNew(42) + v: int = w.GetValue() + stdio.printf("new: w.GetValue()=%d (expected 42)\n", v) + if v != 42: + stdio.printf("[FAIL] w.GetValue()=%d expected 42\n", v) + return 1 + + # ============================================================ + # Test 2: __new__ 不接受额外参数 + # ============================================================ + stdio.printf("new: === Test 2: __new__ no extra args ===\n") + + n: WithNewNoArgs = WithNewNoArgs(99) + nv: int = n.GetValue() + stdio.printf("new: n.GetValue()=%d (expected 99)\n", nv) + if nv != 99: + stdio.printf("[FAIL] n.GetValue()=%d expected 99\n", nv) + return 1 + + # ============================================================ + # Test 3: __new__ + 虚表类 + # ============================================================ + stdio.printf("new: === Test 3: __new__ + vtable ===\n") + + vt: WithNewVTable = WithNewVTable(10) + vtv: int = vt.GetValue() + stdio.printf("new: vt.GetValue()=%d (expected 10)\n", vtv) + if vtv != 10: + stdio.printf("[FAIL] vt.GetValue()=%d expected 10\n", vtv) + return 1 + + vts: int = vt.Speak() + stdio.printf("new: vt.Speak()=%d (expected 11)\n", vts) + if vts != 11: + stdio.printf("[FAIL] vt.Speak()=%d expected 11\n", vts) + return 1 + + stdio.printf("new: === All Tests Passed ===\n") + return 0 diff --git a/Test/App/oop_test.py b/Test/App/oop_test.py new file mode 100644 index 0000000..ebf66dd --- /dev/null +++ b/Test/App/oop_test.py @@ -0,0 +1,129 @@ +import stdio +import t, c + + +# ============================================================ +# OOP 测试:存在方法的 class 自动升级为 OOP 结构体 +# ============================================================ + +# ============================================================ +# 测试 1: 基本方法(无 __init__,__before_init__ 零值填充) +# ============================================================ +class Point: + x: t.CInt + y: t.CInt + + def MoveTo(self, nx: t.CInt, ny: t.CInt) -> t.CInt: + self.x = nx + self.y = ny + return 0 + + def GetX(self) -> t.CInt: + return self.x + + def GetY(self) -> t.CInt: + return self.y + + +# ============================================================ +# 测试 2: 带默认值的 OOP 结构体(__before_init__ 应用默认值) +# ============================================================ +class Counter: + count: t.CInt = 0 + step: t.CInt = 1 + + def Increment(self) -> t.CInt: + self.count = self.count + self.step + return self.count + + def Reset(self) -> t.CInt: + self.count = 0 + return 0 + + +# ============================================================ +# 测试 3: __init__ 构造函数 +# ============================================================ +class Rect: + width: t.CInt + height: t.CInt + + def __init__(self, w: t.CInt, h: t.CInt): + self.width = w + self.height = h + + def Area(self) -> t.CInt: + return self.width * self.height + + +# ============================================================ +# 主函数 +# ============================================================ +def oop_test() -> int: + # ============================================================ + # 测试 1: 基本方法调用 + # ============================================================ + stdio.printf("oop: === Test 1: Basic Methods ===\n") + p: Point = Point() + p.MoveTo(10, 20) + stdio.printf("oop: p.x=%d p.y=%d\n", p.GetX(), p.GetY()) + + if p.GetX() != 10: + stdio.printf("[FAIL] p.GetX()=%d expected 10\n", p.GetX()) + return 1 + if p.GetY() != 20: + stdio.printf("[FAIL] p.GetY()=%d expected 20\n", p.GetY()) + return 1 + + # 修改字段后再次调用方法 + p.MoveTo(100, 200) + stdio.printf("oop: after move p.x=%d p.y=%d\n", p.GetX(), p.GetY()) + if p.GetX() != 100: + return 1 + + # ============================================================ + # 测试 2: 默认值 + 方法 + # ============================================================ + stdio.printf("oop: === Test 2: Defaults + Methods ===\n") + cnt: Counter = Counter() + stdio.printf("oop: initial count=%d step=%d\n", cnt.count, cnt.step) + if cnt.count != 0: + stdio.printf("[FAIL] cnt.count=%d expected 0\n", cnt.count) + return 1 + if cnt.step != 1: + stdio.printf("[FAIL] cnt.step=%d expected 1\n", cnt.step) + return 1 + + r1: int = cnt.Increment() + r2: int = cnt.Increment() + r3: int = cnt.Increment() + stdio.printf("oop: after 3 increments: %d %d %d\n", r1, r2, r3) + if r1 != 1 or r2 != 2 or r3 != 3: + stdio.printf("[FAIL] increments: %d %d %d\n", r1, r2, r3) + return 1 + + cnt.Reset() + r4: int = cnt.Increment() + stdio.printf("oop: after reset+increment: %d\n", r4) + if r4 != 1: + return 1 + + # ============================================================ + # 测试 3: __init__ 构造函数 + # ============================================================ + stdio.printf("oop: === Test 3: __init__ ===\n") + rect: Rect = Rect(3, 4) + area: int = rect.Area() + stdio.printf("oop: rect %dx%d area=%d\n", rect.width, rect.height, area) + if area != 12: + stdio.printf("[FAIL] area=%d expected 12\n", area) + return 1 + if rect.width != 3: + stdio.printf("[FAIL] width=%d expected 3\n", rect.width) + return 1 + if rect.height != 4: + stdio.printf("[FAIL] height=%d expected 4\n", rect.height) + return 1 + + stdio.printf("oop: === All OOP Tests Passed ===\n") + return 0 diff --git a/Test/App/opovl_test.py b/Test/App/opovl_test.py new file mode 100644 index 0000000..3a68afc --- /dev/null +++ b/Test/App/opovl_test.py @@ -0,0 +1,253 @@ +import stdio +import stdlib +import t, c +import testcheck + + +# ============================================================ +# 运算符重载测试 +# +# 验证: 当 lhs 是结构体指针时,二元/比较运算触发 dunder 方法调用 +# 支持: __add__/__sub__/__mul__/__div__/__mod__/__and__/__or__/__xor__ +# __lshift__/__rshift__/__floordiv__ (BinOp) +# __eq__/__ne__/__lt__/__le__/__gt__/__ge__ (Compare) +# +# 三种测试场景: +# 1. Counter/BitBox: dunder 返回 t.CInt(值类型变量触发重载) +# 2. Vec2: dunder 返回 Vec2|t.CPtr(堆分配结构体,指针类型变量触发重载) +# 3. 原生整数运算回退 +# ============================================================ + + +# ============================================================ +# Counter: 演示 __add__/__mul__/__sub__ + 比较重载 +# dunder 返回 t.CInt +# ============================================================ +class Counter: + val: t.CInt + + def __init__(self, v: t.CInt): + self.val = v + + def __add__(self, n: t.CInt) -> t.CInt: + return self.val + n + + def __sub__(self, n: t.CInt) -> t.CInt: + return self.val - n + + def __mul__(self, n: t.CInt) -> t.CInt: + return self.val * n + + def __div__(self, n: t.CInt) -> t.CInt: + return self.val / n + + def __mod__(self, n: t.CInt) -> t.CInt: + return self.val % n + + def __eq__(self, n: t.CInt) -> t.CInt: + if self.val == n: + return 1 + return 0 + + def __ne__(self, n: t.CInt) -> t.CInt: + if self.val != n: + return 1 + return 0 + + def __lt__(self, n: t.CInt) -> t.CInt: + if self.val < n: + return 1 + return 0 + + def __le__(self, n: t.CInt) -> t.CInt: + if self.val <= n: + return 1 + return 0 + + def __gt__(self, n: t.CInt) -> t.CInt: + if self.val > n: + return 1 + return 0 + + def __ge__(self, n: t.CInt) -> t.CInt: + if self.val >= n: + return 1 + return 0 + + +# ============================================================ +# BitBox: 演示位运算重载 +# dunder 返回 t.CInt +# ============================================================ +class BitBox: + flags: t.CInt + + def __init__(self, v: t.CInt): + self.flags = v + + def __and__(self, mask: t.CInt) -> t.CInt: + return self.flags & mask + + def __or__(self, mask: t.CInt) -> t.CInt: + return self.flags | mask + + def __xor__(self, mask: t.CInt) -> t.CInt: + return self.flags ^ mask + + def __lshift__(self, n: t.CInt) -> t.CInt: + return self.flags << n + + def __rshift__(self, n: t.CInt) -> t.CInt: + return self.flags >> n + + +# ============================================================ +# Vec2: 演示结构体运算重载 +# +# __new__ + stdlib.malloc 在堆上分配内存,使 Vec2|t.CPtr 变量 +# 能正确工作(dunder 方法返回堆上新对象)。 +# +# __new__ 返回 malloc 的堆指针作为结构体存储空间, +# 后续 __init__ 在堆指针上初始化字段。 +# ============================================================ +class Vec2: + x: t.CInt + y: t.CInt + + def __new__(self, x0: t.CInt, y0: t.CInt): + r: Vec2 | t.CPtr = stdlib.malloc(Vec2.__sizeof__()) + return r + + def __init__(self, x0: t.CInt, y0: t.CInt): + self.x = x0 + self.y = y0 + + def __add__(self, other: Vec2 | t.CPtr) -> Vec2 | t.CPtr: + r: Vec2 | t.CPtr = Vec2(0, 0) + r.x = self.x + other.x + r.y = self.y + other.y + return r + + def __sub__(self, other: Vec2 | t.CPtr) -> Vec2 | t.CPtr: + r: Vec2 | t.CPtr = Vec2(0, 0) + r.x = self.x - other.x + r.y = self.y - other.y + return r + + def __eq__(self, other: Vec2 | t.CPtr) -> t.CInt: + if self.x == other.x: + if self.y == other.y: + return 1 + return 0 + + def __ne__(self, other: Vec2 | t.CPtr) -> t.CInt: + if self.x != other.x: + return 1 + if self.y != other.y: + return 1 + return 0 + + +# ============================================================ +# 主测试入口 +# ============================================================ +def opovl_test() -> int: + testcheck.begin("Operator Overload Tests") + + # ============================================================ + # 测试 1: Counter + int 触发 __add__ + # ============================================================ + testcheck.section("Counter __add__") + cnt: Counter = Counter(10) + sum_val: int = cnt + 5 + testcheck.check(sum_val == 15, "cnt(10)+5=15", "cnt+5 expected 15 got ??") + + # ============================================================ + # 测试 2: Counter - int / * int / / int / % int + # ============================================================ + testcheck.section("Counter __sub__/__mul__/__div__/__mod__") + sub_val: int = cnt - 3 + mul_val: int = cnt * 3 + div_val: int = cnt / 3 + mod_val: int = cnt % 3 + testcheck.check(sub_val == 7, "cnt-3=7", "cnt-3 expected 7") + testcheck.check(mul_val == 30, "cnt*3=30", "cnt*3 expected 30") + testcheck.check(div_val == 3, "cnt/3=3", "cnt/3 expected 3") + testcheck.check(mod_val == 1, "cnt%3=1", "cnt%3 expected 1") + + # ============================================================ + # 测试 3: Counter 比较重载 (==, !=, <, <=, >, >=) + # ============================================================ + testcheck.section("Counter compare overloads") + eq_10: int = cnt == 10 + ne_10: int = cnt != 10 + lt_20: int = cnt < 20 + le_10: int = cnt <= 10 + gt_5: int = cnt > 5 + ge_10: int = cnt >= 10 + testcheck.check(eq_10 == 1, "cnt==10:1", "cnt==10 expected 1") + testcheck.check(ne_10 == 0, "cnt!=10:0", "cnt!=10 expected 0") + testcheck.check(lt_20 == 1, "cnt<20:1", "cnt<20 expected 1") + testcheck.check(le_10 == 1, "cnt<=10:1", "cnt<=10 expected 1") + testcheck.check(gt_5 == 1, "cnt>5:1", "cnt>5 expected 1") + testcheck.check(ge_10 == 1, "cnt>=10:1", "cnt>=10 expected 1") + + # ============================================================ + # 测试 4: BitBox 位运算重载 + # ============================================================ + testcheck.section("BitBox bitwise overloads") + bb: BitBox = BitBox(0xFF) + and_val: int = bb & 0x0F + or_val: int = bb | 0x100 + xor_val: int = bb ^ 0x55 + lsh_val: int = bb << 4 + rsh_val: int = bb >> 4 + testcheck.check(and_val == 0x0F, "bb&0x0F=15", "bb&0x0F expected 15") + testcheck.check(or_val == 0x1FF, "bb|0x100=511", "bb|0x100 expected 511") + testcheck.check(xor_val == 0xAA, "bb^0x55=170", "bb^0x55 expected 170") + testcheck.check(lsh_val == 0xFF0, "bb<<4=4080", "bb<<4 expected 4080") + testcheck.check(rsh_val == 0x0F, "bb>>4=15", "bb>>4 expected 15") + + # ============================================================ + # 测试 5: 原生整数运算不受影响(回退路径) + # ============================================================ + testcheck.section("Native int binop") + x: int = 7 + 8 + y: int = 10 - 3 + z: int = 4 * 5 + testcheck.check(x == 15, "7+8=15", "7+8 expected 15") + testcheck.check(y == 7, "10-3=7", "10-3 expected 7") + testcheck.check(z == 20, "4*5=20", "4*5 expected 20") + + # ============================================================ + # 测试 6: 原生整数比较不受影响 + # ============================================================ + testcheck.section("Native int compare") + testcheck.check(3 < 5, "3<5", "3<5 broken") + testcheck.check(10 == 10, "10==10", "10==10 broken") + + # ============================================================ + # 测试 7: Vec2 结构体运算重载 + # ============================================================ + testcheck.section("Vec2 struct overloads") + a: Vec2 | t.CPtr = Vec2(3, 4) + b: Vec2 | t.CPtr = Vec2(1, 2) + c: Vec2 | t.CPtr = a + b + d: Vec2 | t.CPtr = a - b + testcheck.check(c.x == 4, "a+b x=4", "a+b x expected 4") + testcheck.check(c.y == 6, "a+b y=6", "a+b y expected 6") + testcheck.check(d.x == 2, "a-b x=2", "a-b x expected 2") + testcheck.check(d.y == 2, "a-b y=2", "a-b y expected 2") + + # ============================================================ + # 测试 8: Vec2 比较重载 + # ============================================================ + testcheck.section("Vec2 compare overloads") + p: Vec2 | t.CPtr = Vec2(5, 5) + q: Vec2 | t.CPtr = Vec2(5, 5) + eq_v: int = p == q + ne_v: int = p != q + testcheck.check(eq_v == 1, "(5,5)==(5,5):1", "p==q expected 1") + testcheck.check(ne_v == 0, "(5,5)!=(5,5):0", "p!=q expected 0") + + return testcheck.end() diff --git a/Test/App/ptr_only_test.py b/Test/App/ptr_only_test.py new file mode 100644 index 0000000..5050881 --- /dev/null +++ b/Test/App/ptr_only_test.py @@ -0,0 +1,26 @@ +import stdio +import t, c + + +def ptr_only_test() -> int: + s: str = "hello" + sp: str = s + slen: int = 0 + while c.Deref(sp) != 0: + slen = slen + 1 + sp = sp + 1 + stdio.printf("ptr: len(hello)=%d\n", slen) + + x: int = 65 + px: str = c.Addr(x) + c.DerefAs(px, 88) + stdio.printf("ptr: after DerefAs x=%d\n", x) + + p2: str = "ABC" + total_ch: int = 0 + while c.Deref(p2) != 0: + total_ch = total_ch + c.Deref(p2) + p2 = p2 + 1 + stdio.printf("ptr: sum(A,B,C)=%d\n", total_ch) + + return 0 diff --git a/Test/App/ptr_test.py b/Test/App/ptr_test.py new file mode 100644 index 0000000..cf6fb02 --- /dev/null +++ b/Test/App/ptr_test.py @@ -0,0 +1,111 @@ +import stdio +import t, c + + +# ============================================================ +# 简单指针 + 逻辑测试 +# ============================================================ + +def ptr_test() -> int: + # 逻辑测试:if 语句 + x: int = 10 + if x: + stdio.printf("if: x is truthy\n") + + if 1 == 1: + stdio.printf("if: 1==1 is truthy\n") + + # While 循环 + 累加 + i: int = 0 + total: int = 0 + while i < 5: + total = total + i + i = i + 1 + stdio.printf("while: total=%d i=%d\n", total, i) + + # For 循环 + for j in range(5): + stdio.printf("for: j=%d\n", j) + + # Break 测试 + for k in range(10): + if k == 3: + break + stdio.printf("break: k=%d\n", k) + + # Continue 测试 + for m in range(5): + if m == 2: + continue + stdio.printf("continue: m=%d\n", m) + + # 布尔运算 and(短路求值) + if x > 5 and x < 100: + stdio.printf("bool: x>5 and x<100 is true\n") + + # 布尔运算 or(短路求值) + if x > 100 or x > 5: + stdio.printf("bool: x>100 or x>5 is true\n") + + # ============================================================ + # 指针 + c.Deref / c.DerefAs 测试 + # ============================================================ + + # 字符串遍历: while c.Deref(p) != 0 + s: str = "hello" + sp: str = s + slen: int = 0 + while c.Deref(sp) != 0: + slen = slen + 1 + sp = sp + 1 + stdio.printf("ptr: len(hello)=%d\n", slen) + + # c.DerefAs 写入字符(使用 c.Addr 获取栈变量地址,字符串字面量是只读的) + v: int = 65 # 'A' + px: str = c.Addr(v) + c.DerefAs(px, 88) # *px = 88 + stdio.printf("ptr: after DerefAs v=%d\n", v) + + # 遍历字符串并累加字符值 + p2: str = "ABC" + total_ch: int = 0 + while c.Deref(p2) != 0: + total_ch = total_ch + c.Deref(p2) + p2 = p2 + 1 + stdio.printf("ptr: sum(A,B,C)=%d\n", total_ch) + + # ============================================================ + # c.Load 测试: *a = *b(加载源指针的值,存储到目标指针) + # ============================================================ + + # 基本复制: v2 = v1 + v1: int = 42 + v2: int = 0 + c.Load(c.Addr(v2), c.Addr(v1)) + stdio.printf("ptr: c.Load v2=%d (expected 42)\n", v2) + if v2 != 42: + stdio.printf("[FAIL] c.Load expected 42 got %d\n", v2) + return 1 + + # 覆盖已有值: v3 = v4 + v3: int = 100 + v4: int = 200 + c.Load(c.Addr(v3), c.Addr(v4)) + stdio.printf("ptr: c.Load overwrite v3=%d (expected 200)\n", v3) + if v3 != 200: + stdio.printf("[FAIL] c.Load overwrite expected 200 got %d\n", v3) + return 1 + + # 验证源不被修改: v5 保持原值 + v5: int = 999 + v6: int = 0 + c.Load(c.Addr(v6), c.Addr(v5)) + stdio.printf("ptr: c.Load src unchanged v5=%d v6=%d (expected 999, 999)\n", v5, v6) + if v5 != 999: + stdio.printf("[FAIL] c.Load src changed v5=%d\n", v5) + return 1 + if v6 != 999: + stdio.printf("[FAIL] c.Load dst expected 999 got %d\n", v6) + return 1 + + return 0 diff --git a/Test/App/simple_test.py b/Test/App/simple_test.py new file mode 100644 index 0000000..bc5c64e --- /dev/null +++ b/Test/App/simple_test.py @@ -0,0 +1,6 @@ +import stdio + +def simple_test() -> int: + stdio.printf("hello\n") + return 0 + diff --git a/Test/App/string_min_test.py b/Test/App/string_min_test.py new file mode 100644 index 0000000..5be13ea --- /dev/null +++ b/Test/App/string_min_test.py @@ -0,0 +1,9 @@ +import stdio +import t, c +import string + + +def string_min_test() -> int: + l: t.CSizeT = string.strlen("Hello") + stdio.printf("strlen(Hello)=%lu\n", l) + return 0 diff --git a/Test/App/string_test.py b/Test/App/string_test.py new file mode 100644 index 0000000..3880db4 --- /dev/null +++ b/Test/App/string_test.py @@ -0,0 +1,106 @@ +import stdio +import t, c +import string + + +# ============================================================ +# string_test - string.py 库函数测试 +# +# 测试 strlen / strcmp / strncmp / atoi / strchr / strstr +# ============================================================ + + +def test_strlen(): + stdio.printf("--- Test 1: strlen ---\n") + + l1: t.CSizeT = string.strlen("Hello") + stdio.printf("strlen(Hello)=%lu (expect 5)\n", l1) + + l2: t.CSizeT = string.strlen("") + stdio.printf("strlen()=%lu (expect 0)\n", l2) + + l3: t.CSizeT = string.strlen("Hello, World!") + stdio.printf("strlen(Hello, World!)=%lu (expect 13)\n", l3) + + +def test_strcmp(): + stdio.printf("--- Test 2: strcmp ---\n") + + r1: t.CInt = string.strcmp("abc", "abc") + stdio.printf("strcmp(abc,abc)=%d (expect 0)\n", r1) + + r2: t.CInt = string.strcmp("abc", "abd") + stdio.printf("strcmp(abc,abd)=%d (expect <0)\n", r2) + + r3: t.CInt = string.strcmp("abd", "abc") + stdio.printf("strcmp(abd,abc)=%d (expect >0)\n", r3) + + +def test_strncmp(): + stdio.printf("--- Test 3: strncmp ---\n") + + r1: t.CInt = string.strncmp("abcdef", "abcXYZ", 3) + stdio.printf("strncmp(abcdef,abcXYZ,3)=%d (expect 0)\n", r1) + + r2: t.CInt = string.strncmp("abcdef", "abcXYZ", 4) + stdio.printf("strncmp(abcdef,abcXYZ,4)=%d (expect <0)\n", r2) + + +def test_atoi(): + stdio.printf("--- Test 4: atoi ---\n") + + n1: t.CInt = string.atoi("123") + stdio.printf("atoi(123)=%d (expect 123)\n", n1) + + n2: t.CInt = string.atoi("-456") + stdio.printf("atoi(-456)=%d (expect -456)\n", n2) + + n3: t.CInt = string.atoi(" 789") + stdio.printf("atoi( 789)=%d (expect 789)\n", n3) + + +def test_strchr(): + stdio.printf("--- Test 5: strchr ---\n") + + # strchr 返回指向字符的指针,不为 None 表示找到 + p: str = string.strchr("Hello", 108) # 'l' = 108 + if p is not None: + stdio.printf("strchr(Hello,'l') found, char=%d (expect 108)\n", c.Deref(p)) + else: + stdio.printf("strchr(Hello,'l') NOT FOUND (FAIL)\n") + + p2: str = string.strchr("Hello", 122) # 'z' = 122 + if p2 is None: + stdio.printf("strchr(Hello,'z') not found OK\n") + else: + stdio.printf("strchr(Hello,'z') FAIL (should be None)\n") + + +def test_strstr(): + stdio.printf("--- Test 6: strstr ---\n") + + p: str = string.strstr("Hello World", "World") + if p is not None: + stdio.printf("strstr(Hello,World) found OK\n") + else: + stdio.printf("strstr(Hello,World) NOT FOUND (FAIL)\n") + + p2: str = string.strstr("Hello World", "xyz") + if p2 is None: + stdio.printf("strstr(Hello,xyz) not found OK\n") + else: + stdio.printf("strstr(Hello,xyz) FAIL (should be None)\n") + + +def string_test() -> int: + stdio.printf("=== string_test: string.py 库函数测试 ===\n\n") + + test_strlen() + test_strcmp() + test_strncmp() + test_atoi() + test_strchr() + test_strstr() + + stdio.printf("\n=== string_test 完成 ===\n") + return 0 diff --git a/Test/App/struct_test.py b/Test/App/struct_test.py new file mode 100644 index 0000000..2b883e0 --- /dev/null +++ b/Test/App/struct_test.py @@ -0,0 +1,235 @@ +import stdio +import t, c + + +# ============================================================ +# 纯内存结构体(class)测试 +# ============================================================ + +class Point: + x: t.CInt + y: t.CInt + + +class Box: + width: t.CInt + height: t.CInt + depth: t.CInt + + +class Size: + w: t.CInt = 100 + h: t.CInt = 200 + + +# ============================================================ +# 枚举(t.CEnum)测试 +# ============================================================ + +class State(t.CEnum): + Idle: t.State + Run: t.State + Stop: t.State + + +class Color(t.CEnum): + Red: t.State = 10 + Green: t.State + Blue: t.State = 20 + Yellow: t.State + + +class MixedType(t.CEnum): + Small: t.CInt8T + Big: t.CInt64T + Medium: t.CInt16T + + +# ============================================================ +# 联合体(t.CUnion)测试 +# ============================================================ + +class DataUnion(t.CUnion): + i: t.CInt + f: t.CFloat + l: t.CInt64T + + +# ============================================================ +# 主函数 +# ============================================================ +def struct_test() -> int: + # ============================================================ + # 测试 1: 结构体字段读写 + # ============================================================ + p: Point = Point() + p.x = 10 + p.y = 20 + stdio.printf("struct: p.x=%d p.y=%d\n", p.x, p.y) + + # 修改字段 + p.x = 100 + p.y = 200 + stdio.printf("struct: modified p.x=%d p.y=%d\n", p.x, p.y) + + # 字段运算 + sum_xy: int = p.x + p.y + stdio.printf("struct: sum=%d\n", sum_xy) + + # ============================================================ + # 测试 2: 多字段结构体 + # ============================================================ + b: Box + b.width = 3 + b.height = 4 + b.depth = 5 + vol: int = b.width * b.height * b.depth + stdio.printf("struct: volume=%d\n", vol) + + # ============================================================ + # 测试 3: t.CArray 数组遍历 + # ============================================================ + arr: t.CArray[t.CInt, 5] + arr[0] = 100 + arr[1] = 200 + arr[2] = 300 + arr[3] = 400 + arr[4] = 500 + + arr_total: int = 0 + for i in range(5): + arr_total = arr_total + arr[i] + stdio.printf("array: total=%d\n", arr_total) + + # 修改数组元素 + arr[2] = 999 + stdio.printf("array: arr[2]=%d\n", arr[2]) + + # ============================================================ + # 测试 4: 指针遍历(字符串) + # ============================================================ + s: str = "hello" + sp: str = s + slen: int = 0 + while c.Deref(sp) != 0: + slen = slen + 1 + sp = sp + 1 + stdio.printf("ptr: len(hello)=%d\n", slen) + + # 累加字符值 + p2: str = "ABC" + total_ch: int = 0 + while c.Deref(p2) != 0: + total_ch = total_ch + c.Deref(p2) + p2 = p2 + 1 + stdio.printf("ptr: sum(A,B,C)=%d\n", total_ch) + + # ============================================================ + # 测试 5: 结构体构造函数 Point() / Point(x, y) + # ============================================================ + # 无参数构造:零初始化 + z: Point = Point() + stdio.printf("ctor: z.x=%d z.y=%d\n", z.x, z.y) + + # 带参数构造:按位置赋值 + p3: Point = Point(7, 8) + stdio.printf("ctor: p3.x=%d p3.y=%d\n", p3.x, p3.y) + + # 多字段构造 + bx: Box = Box(10, 20, 30) + stdio.printf("ctor: bx.w=%d bx.h=%d bx.d=%d\n", bx.width, bx.height, bx.depth) + + # ============================================================ + # 测试 6: 结构体关键字参数(乱序传参) + # ============================================================ + # 全关键字乱序 + p4: Point = Point(y=20, x=10) + stdio.printf("kw: p4.x=%d p4.y=%d\n", p4.x, p4.y) + + # 混合:位置 + 关键字 + p5: Point = Point(5, y=15) + stdio.printf("kw: p5.x=%d p5.y=%d\n", p5.x, p5.y) + + # 多字段关键字乱序 + bx2: Box = Box(depth=30, width=10, height=20) + stdio.printf("kw: bx2.w=%d bx2.h=%d bx2.d=%d\n", bx2.width, bx2.height, bx2.depth) + + # ============================================================ + # 测试 7: 结构体默认赋值 + # ============================================================ + # 无参数构造:使用默认值 + sz: Size = Size() + stdio.printf("def: sz.w=%d sz.h=%d\n", sz.w, sz.h) + + # 位置参数覆盖默认值 + sz2: Size = Size(5, 6) + stdio.printf("def: sz2.w=%d sz2.h=%d\n", sz2.w, sz2.h) + + # 关键字参数覆盖默认值(乱序) + sz3: Size = Size(h=999, w=888) + stdio.printf("def: sz3.w=%d sz3.h=%d\n", sz3.w, sz3.h) + + # 混合:位置参数 + 默认值(w=7 覆盖默认值,h 保持默认值 200) + sz4: Size = Size(7) + stdio.printf("def: sz4.w=%d sz4.h=%d\n", sz4.w, sz4.h) + + # ============================================================ + # 测试 8: 枚举自动赋值(Idle=0, Run=1, Stop=2) + # ============================================================ + s_idle: int = State.Idle + s_run: int = State.Run + s_stop: int = State.Stop + stdio.printf("enum: Idle=%d Run=%d Stop=%d\n", s_idle, s_run, s_stop) + + # ============================================================ + # 测试 9: 枚举手动赋值(Red=10, Green=11, Blue=20, Yellow=21) + # ============================================================ + c_red: int = Color.Red + c_green: int = Color.Green + c_blue: int = Color.Blue + c_yellow: int = Color.Yellow + stdio.printf("enum: Red=%d Green=%d Blue=%d Yellow=%d\n", + c_red, c_green, c_blue, c_yellow) + + # ============================================================ + # 测试 10: 枚举混用数字类型(基准类型应为 i64) + # ============================================================ + m_small: int = MixedType.Small + m_big: int = MixedType.Big + m_medium: int = MixedType.Medium + stdio.printf("enum: Small=%d Big=%d Medium=%d\n", m_small, m_big, m_medium) + + # 枚举参与运算 + s_sum: int = State.Idle + State.Run + State.Stop + stdio.printf("enum: sum(Idle,Run,Stop)=%d\n", s_sum) + + # 枚举比较 + if State.Idle == 0: + stdio.printf("enum: Idle==0 true\n") + if Color.Red == 10: + stdio.printf("enum: Red==10 true\n") + if State.Run != State.Stop: + stdio.printf("enum: Run!=Stop true\n") + + # ============================================================ + # 测试 11: 联合体字段读写 + # ============================================================ + u: DataUnion + u.i = 42 + stdio.printf("union: u.i=%d\n", u.i) + + # 写入 l 字段(覆盖 i 的内存,因为 l 是 i64) + u.l = 20015998343868 + stdio.printf("union: u.l=%lld\n", u.l) + + # ============================================================ + # 测试 12: 联合体共享内存验证 + # ============================================================ + u2: DataUnion + u2.i = 1 + # 写入 l 后,i 的值已被覆盖(不再是 1) + u2.l = 100 + if u2.i != 1: + stdio.printf("union: shared memory verified\n") + + return 0 diff --git a/Test/App/test_main.py b/Test/App/test_main.py new file mode 100644 index 0000000..796d916 --- /dev/null +++ b/Test/App/test_main.py @@ -0,0 +1,109 @@ +import stdio +import t, c +import testcheck +from stdint import * +from asm_test import asm_test +from attr_test import attr_test +from augassign_test import augassign_test +from closure_test import closure_test +from deco_test import deco_test +from deref_min_test import deref_min_test +from deref_test import deref_test +from eq_test import eq_test +from float_test import float_test +from flow_test import flow_test +from for_test import for_test +from func_test import func_test +from llvmir_test import llvmir_test +from oop_test import oop_test +from ptr_only_test import ptr_only_test +from ptr_test import ptr_test +from simple_test import simple_test +from string_min_test import string_min_test +from string_test import string_test +from struct_test import struct_test +from type_bit_test import type_bit_test +from vtable_test import vtable_test +from inherit_test import inherit_test +from func_vtable_test import func_vtable_test +from virtual_dispatch_test import virtual_dispatch_test +from new_test import new_test +from namespace_test import namespace_test +from testcheck_test import testcheck_test +from opovl_test import opovl_test +from generic_test import generic_test + + +def main() -> int: + stdio.printf("===== TransPyV Test Suite =====\n\n") + + r: int = 0 + + stdio.fflush(None) + r = asm_test() + stdio.fflush(None) + r = attr_test() + stdio.fflush(None) + r = augassign_test() + stdio.fflush(None) + r = closure_test() + stdio.fflush(None) + r = deco_test() + stdio.fflush(None) + r = deref_min_test() + stdio.fflush(None) + r = deref_test() + stdio.fflush(None) + r = eq_test() + stdio.fflush(None) + r = float_test() + stdio.fflush(None) + r = flow_test() + stdio.fflush(None) + r = for_test() + stdio.fflush(None) + r = func_test() + stdio.fflush(None) + r = llvmir_test() + stdio.fflush(None) + r = oop_test() + stdio.fflush(None) + r = ptr_only_test() + stdio.fflush(None) + r = ptr_test() + stdio.fflush(None) + r = simple_test() + stdio.fflush(None) + r = string_min_test() + stdio.fflush(None) + r = string_test() + stdio.fflush(None) + r = struct_test() + stdio.fflush(None) + r = type_bit_test() + stdio.fflush(None) + r = vtable_test() + stdio.fflush(None) + r = inherit_test() + stdio.fflush(None) + r = func_vtable_test() + stdio.fflush(None) + r = virtual_dispatch_test() + stdio.fflush(None) + r = new_test() + stdio.fflush(None) + r = namespace_test() + stdio.fflush(None) + r = testcheck_test() + stdio.fflush(None) + r = opovl_test() + stdio.fflush(None) + + stdio.printf("[TM] before generic_test\n") + stdio.fflush(None) + r = generic_test() + stdio.printf("[TM] after generic_test r=%d\n", r) + stdio.fflush(None) + + stdio.printf("\n===== Test Suite Complete =====\n") + return r \ No newline at end of file diff --git a/Test/App/testcheck_test.py b/Test/App/testcheck_test.py new file mode 100644 index 0000000..2540bdb --- /dev/null +++ b/Test/App/testcheck_test.py @@ -0,0 +1,37 @@ +import stdio +import t, c +import string +import testcheck + + +# ============================================================ +# testcheck_test - 测试 includes/testcheck 库导入与调用 +# +# 验证命名空间隔离下,import testcheck + 模块限定函数调用能正常工作。 +# 同时测试 string 库的模块限定调用。 +# ============================================================ +def testcheck_test() -> int: + testcheck.begin("testcheck_test") + + testcheck.section("Arithmetic") + a: int = 3 + 4 + testcheck.check(a == 7, "3+4=7", "3+4!=7") + + b: int = 10 - 3 + testcheck.check(b == 7, "10-3=7", "10-3!=7") + + m: int = 6 * 7 + testcheck.check(m == 42, "6*7=42", "6*7!=42") + + testcheck.section("String") + slen: int = string.strlen("hello") + testcheck.check(slen == 5, "strlen(hello)=5", "strlen(hello)!=5") + + scmp: int = string.strcmp("abc", "abc") + testcheck.check(scmp == 0, "strcmp(abc,abc)=0", "strcmp(abc,abc)!=0") + + testcheck.section("Module Import") + testcheck.info("testcheck module imported and called successfully") + testcheck.ok("import testcheck works") + + return testcheck.end() diff --git a/Test/App/type_bit_test.py b/Test/App/type_bit_test.py new file mode 100644 index 0000000..817020f --- /dev/null +++ b/Test/App/type_bit_test.py @@ -0,0 +1,26 @@ +import stdio +import t, c + + +def type_bit_test() -> int: + ti: t.CInt = 100 + ti32: t.CInt32T = 200 + tui32: t.CUInt32T = 300 + stdio.printf("type: CInt=%d CInt32T=%d CUInt32T=%d\n", ti, ti32, tui32) + + tl: t.CLong = 1000 + tll: t.CLongLong = 2000 + ti64: t.CInt64T = 3000 + tsize: t.CSizeT = 4000 + stdio.printf("type: CLong=%d CLongLong=%d CInt64T=%d CSizeT=%d\n", tl, tll, ti64, tsize) + + ba: int = 240 + bb: int = 15 + stdio.printf("bit: 240&15=%d\n", ba & bb) + stdio.printf("bit: 240|15=%d\n", ba | bb) + stdio.printf("bit: 240^15=%d\n", ba ^ bb) + stdio.printf("bit: 240<<2=%d\n", ba << 2) + stdio.printf("bit: 240>>2=%d\n", ba >> 2) + stdio.printf("bit: 17%%5=%d\n", 17 % 5) + + return 0 diff --git a/Test/App/virtual_dispatch_test.py b/Test/App/virtual_dispatch_test.py new file mode 100644 index 0000000..d3ca34b --- /dev/null +++ b/Test/App/virtual_dispatch_test.py @@ -0,0 +1,83 @@ +import stdio +import t, c +import string +from inherit_test import Animal, Dog + + +# ============================================================ +# 虚分派测试:通过虚表指针验证虚分派机制 +# +# 本测试验证:方法调用通过对象的 __vtable__ 字段进行虚分派, +# 而非通过变量声明类型直接调用。 +# +# 测试方法: +# 1. 创建 Animal 对象 a(Animal 虚表,Speak 返回 0) +# 2. 创建 Dog 对象 d +# 3. 用内联汇编将 d 的虚表指针复制到 a +# 4. 调用 a.Speak() — 应返回 1(Dog.Speak),证明虚分派生效 +# +# 如果是直接调用(非虚分派),a.Speak() 会调用 Animal.Speak 返回 0 +# +# 注意:Animal 和 Dog 类从 inherit_test.py 导入(命名空间隔离) +# ============================================================ + + +def virtual_dispatch_test() -> int: + stdio.printf("vdispatch: === Test Start ===\n") + + # 创建对象 + a: Animal = Animal(42) + d: Dog = Dog(100, 7) + + # ============================================================ + # 测试 1: 直接分派(基线验证) + # ============================================================ + stdio.printf("vdispatch: === Test 1: Direct Dispatch ===\n") + + a_speak: int = a.Speak() + stdio.printf("vdispatch: a.Speak()=%d (expected 0)\n", a_speak) + if a_speak != 0: + stdio.printf("[FAIL] a.Speak()=%d expected 0\n", a_speak) + return 1 + + d_speak: int = d.Speak() + stdio.printf("vdispatch: d.Speak()=%d (expected 1)\n", d_speak) + if d_speak != 1: + stdio.printf("[FAIL] d.Speak()=%d expected 1\n", d_speak) + return 1 + + # ============================================================ + # 测试 2: 虚分派验证(复制虚表指针) + # + # 将 Dog 的虚表指针复制到 Animal 对象 a + # 虚表指针位于结构体偏移 0(__vtable__ 字段) + # 复制后 a.Speak() 应通过虚表分发到 Dog.Speak(返回 1) + # ============================================================ + stdio.printf("vdispatch: === Test 2: Virtual Dispatch ===\n") + + # 使用 string.memcpy 复制虚表指针(8字节,结构体偏移0) + # 将 d 的虚表指针复制到 a,使 a.Speak() 分发到 Dog.Speak + string.memcpy(c.Addr(a), c.Addr(d), 8) + + a_speak2: int = a.Speak() + stdio.printf("vdispatch: a.Speak()=%d (expected 1 after vtable copy)\n", a_speak2) + if a_speak2 != 1: + stdio.printf("[FAIL] a.Speak()=%d expected 1 after vtable copy\n", a_speak2) + return 1 + + # ============================================================ + # 测试 3: GetName 验证(未被覆盖的虚方法) + # + # Dog 没有覆盖 GetName,Dog 虚表中 GetName 槽位指向 Animal.GetName + # a.GetName() 应返回 a.name (42),证明虚表槽位一致性 + # ============================================================ + stdio.printf("vdispatch: === Test 3: GetName After VTable Copy ===\n") + + a_name: int = a.GetName() + stdio.printf("vdispatch: a.GetName()=%d (expected 42)\n", a_name) + if a_name != 42: + stdio.printf("[FAIL] a.GetName()=%d expected 42\n", a_name) + return 1 + + stdio.printf("vdispatch: === All Tests Passed ===\n") + return 0 diff --git a/Test/App/vtable_test.py b/Test/App/vtable_test.py new file mode 100644 index 0000000..0964412 --- /dev/null +++ b/Test/App/vtable_test.py @@ -0,0 +1,63 @@ +import stdio +import t, c + + +@t.CVTable +class Animal: + name: t.CInt + + def __init__(self, n: t.CInt): + self.name = n + + def GetName(self) -> t.CInt: + return self.name + + def Speak(self) -> t.CInt: + return 0 + + +@t.CVTable +class Shape: + sides: t.CInt + + def SetSides(self, n: t.CInt) -> t.CInt: + self.sides = n + return 0 + + def GetSides(self) -> t.CInt: + return self.sides + + +def vtable_test() -> int: + stdio.printf("vtable: === Test Start ===\n") + + # 测试 1: Animal 虚方法调用(无参,访问 self 字段) + a: Animal = Animal(42) + name: int = a.GetName() + stdio.printf("vtable: a.GetName()=%d (expected 42)\n", name) + if name != 42: + stdio.printf("[FAIL] a.GetName()=%d expected 42\n", name) + return 1 + + speak: int = a.Speak() + stdio.printf("vtable: a.Speak()=%d (expected 0)\n", speak) + if speak != 0: + stdio.printf("[FAIL] a.Speak()=%d expected 0\n", speak) + return 1 + + # 测试 2: Shape 虚方法调用(带参,修改 self 字段) + s: Shape = Shape() + r: int = s.SetSides(4) + stdio.printf("vtable: s.SetSides(4)=%d (expected 0)\n", r) + if r != 0: + stdio.printf("[FAIL] s.SetSides(4)=%d expected 0\n", r) + return 1 + + sides: int = s.GetSides() + stdio.printf("vtable: s.GetSides()=%d (expected 4)\n", sides) + if sides != 4: + stdio.printf("[FAIL] s.GetSides()=%d expected 4\n", sides) + return 1 + + stdio.printf("vtable: === All Tests Passed ===\n") + return 0 diff --git a/Test/NegativeTest/App/defs.py b/Test/NegativeTest/App/defs.py new file mode 100644 index 0000000..a6b825e --- /dev/null +++ b/Test/NegativeTest/App/defs.py @@ -0,0 +1,20 @@ +import stdio +import t, c + + +# ============================================================ +# 负向测试定义模块:定义 SecretClass +# +# 此文件定义 SecretClass,但 main.py 不 import 它。 +# 严格模式下 main.py 中的 SecretClass() 构造应编译失败。 +# ============================================================ + + +class SecretClass: + val: t.CInt + + def __init__(self, v: t.CInt): + self.val = v + + def GetVal(self) -> t.CInt: + return self.val diff --git a/Test/NegativeTest/App/main.py b/Test/NegativeTest/App/main.py new file mode 100644 index 0000000..dc9a2ba --- /dev/null +++ b/Test/NegativeTest/App/main.py @@ -0,0 +1,21 @@ +import stdio +import t, c +# 故意不 import defs.SecretClass — 严格模式下应编译失败 + + +# ============================================================ +# 负向测试主入口 +# +# 此文件故意不 import SecretClass,但尝试使用 SecretClass()。 +# 命名空间隔离严格模式下,SecretClass 不可见, +# 构造器路径被跳过,生成 call i32 @SecretClass(...), +# llc 报错 "use of undefined value '@SecretClass'"。 +# +# 预期:TransPyV 编译失败(exit code != 0) +# ============================================================ +def main() -> int: + # SecretClass 未导入,严格模式下不可见 + s: SecretClass = SecretClass(42) + v: int = s.GetVal() + stdio.printf("negtest: v=%d (should not reach here)\n", v) + return 0 diff --git a/Test/NegativeTest/project.vpj b/Test/NegativeTest/project.vpj new file mode 100644 index 0000000..6064058 --- /dev/null +++ b/Test/NegativeTest/project.vpj @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "NegativeTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"], + "output": "neg_app.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/Sha1Test/App/main.py b/Test/Sha1Test/App/main.py new file mode 100644 index 0000000..c7e4533 --- /dev/null +++ b/Test/Sha1Test/App/main.py @@ -0,0 +1,62 @@ +import t, c +from stdint import * +import stdio +import stdlib +import memhub +import hashlib + + +POOL_SIZE: t.CDefine = 16777480 + + +@t.CExport +def main() -> int: + arena: bytes = stdlib.malloc(POOL_SIZE) + if arena is None: + return 1 + mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE) + if mb is None: + return 1 + hashlib._mbuddy = (memhub.MemManager | t.CPtr)(mb) + + # 测试 "abc" 的 SHA1 + # 期望: a9993e364706816aba3e25717850c26c9cd0d89d + s: str = "abc" + stdio.printf("input: %s\n", s) + + # 计算 len(s) + n: t.CSizeT = len(s) + stdio.printf("len=%d\n", n) + + # 构造 sha1 对象 + ctx: hashlib.sha1 | t.CPtr = hashlib.sha1() + if ctx is None: + stdio.printf("ctx is None\n") + return 1 + + ctx.update(s) + + digest: bytes = mb.alloc(hashlib.SHA1_DIGEST_LEN) + if digest is None: + stdio.printf("digest alloc failed\n") + return 1 + + ctx.final(digest) + + # 打印 digest(十六进制) + stdio.printf("SHA1: ") + for i in range(hashlib.SHA1_DIGEST_LEN): + b: t.CUInt8T = digest[i] + hi: t.CInt = (b >> 4) & 0xF + lo: t.CInt = b & 0xF + if hi < 10: + stdio.printf("%c", '0' + hi) + else: + stdio.printf("%c", 'a' + (hi - 10)) + if lo < 10: + stdio.printf("%c", '0' + lo) + else: + stdio.printf("%c", 'a' + (lo - 10)) + stdio.printf("\n") + stdio.printf("expect: a9993e364706816aba3e25717850c26c9cd0d89d\n") + return 0 diff --git a/Test/Sha1Test/project.vpj b/Test/Sha1Test/project.vpj new file mode 100644 index 0000000..f3e807d --- /dev/null +++ b/Test/Sha1Test/project.vpj @@ -0,0 +1,28 @@ +{ + "name": "Sha1Test", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"], + "output": "sha1test.exe" + }, + "includes": [ + "../../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/project.vpj b/Test/project.vpj new file mode 100644 index 0000000..dd18769 --- /dev/null +++ b/Test/project.vpj @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "AstTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"], + "output": "app.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/project.json b/project.json new file mode 100644 index 0000000..7fe93e3 --- /dev/null +++ b/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "TransPyV", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition", "-Wl,--stack,0x1000000"], + "output": "TransPyV.exe" + }, + "includes": [ + "../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} \ No newline at end of file