修正了逻辑,使 TPV 可以编译 Test,但自举还有一段距离

This commit is contained in:
TermiNexus committed 2026-08-03 02:01:20 +08:00
1 parent 9dcf34599d
commit a3b9bdc409
25 files changed
+9125 -6478

No files matched your search

+14 -1
View File
@@ -614,7 +614,20 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
pos = _PyiEmit(buf, buf_size, pos, ": ")
pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation)
# 如果有值(如 CDefine 常量),输出 = value
if aa.value is not None and aa.value.kind() == ast.ASTKind.Constant:
# CTypedef 特殊处理:值是类型表达式(如 VOIDPTR / t.CVoid | t.CPtr),
# 不是整数,用 _PyiTypeStr 输出类型字符串
is_ctypedef_ann: int = 0
if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Attribute:
ctd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa.annotation)
if ctd_at.attr is not None and string.strcmp(ctd_at.attr, "CTypedef") == 0:
if ctd_at.value is not None and ctd_at.value.kind() == ast.ASTKind.Name:
ctd_mod: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ctd_at.value)
if ctd_mod.id is not None and string.strcmp(ctd_mod.id, "t") == 0:
is_ctypedef_ann = 1
if is_ctypedef_ann != 0 and aa.value is not None:
pos = _PyiEmit(buf, buf_size, pos, " = ")
pos = _PyiTypeStr(buf, buf_size, pos, aa.value)
elif aa.value is not None and aa.value.kind() == ast.ASTKind.Constant:
cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
if cv.const_kind == ast.CONST_INT:
num_buf: bytes = mb.alloc(32)
+479
View File
@@ -0,0 +1,479 @@
import t, c
from stdint import *
import ast
import string
import stdlib
import stdio
import sys
import memhub
import llvmlite
import w32.fileio as fileio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesTranslator as HT
# ============================================================
# _ddebug_exit - DDEBUG 拦截退出辅助函数
#
# 刷新 stderr 缓冲区并通过 VLogger 输出可见消息后退出。
# 解决 sys.exit(1) 不刷新缓冲区导致 DDEBUG 消息丢失的问题。
# ============================================================
def _ddebug_exit() -> None:
stdio.fflush(stdio.stderr)
VLogger.error("DDEBUG intercept triggered - check stderr for details")
# ============================================================
# VpiReader - .vpi AST 解析器
#
# 从 .vpi 存根文件读取函数签名和 CTypedef 定义,注入 declare
# 到当前模块。用于跨模块函数调用时补充缺失的函数声明。
#
# .vpi 文件由 StubGen.Converter._GeneratePyiFromAst 生成,
# 包含函数签名(无函数体)、类定义、变量声明、import 语句。
# VpiReader 解析 .vpi 为 AST,提取 FunctionDef 和 CTypedef
# AnnAssign,在当前模块创建对应的 declare 声明。
# ============================================================
# .vpi 读取缓冲区大小(256KB,与 PYI_BUF_SIZE 一致)
VPI_READ_BUF_SIZE: t.CSizeT = 262144
# SHA1 字符串长度(16 hex 字符)
SHA1_LEN: t.CSizeT = 16
# ============================================================
# _extract_sha1_from_path - 从 .vpi 文件路径提取 SHA1
#
# .vpi 文件名格式为 {sha1}.vpi,sha1 是 16 位十六进制字符。
# 从路径中找到最后一个路径分隔符(/ 或 \),取后续文件名的前
# 16 个字符作为 SHA1。分配新缓冲区存储 SHA1(调用者负责 free)。
#
# Args:
# vpi_path: .vpi 文件路径
#
# Returns:
# SHA1 字符串(stdlib.malloc 分配,需 stdlib.free),None 失败
# ============================================================
def _extract_sha1_from_path(vpi_path: str) -> str:
"""从 .vpi 文件路径提取 SHA1(文件名前16字符,malloc 分配)"""
if vpi_path is None:
return None
# 查找最后一个路径分隔符 / 或 \
total_len: t.CSizeT = string.strlen(vpi_path)
if total_len < SHA1_LEN + 4: # 至少需要 "xxxx.vpi" 的长度
return None
# 从后向前查找最后一个 / 或 \
sep_pos: t.CSizeT = total_len
while sep_pos > 0:
sep_pos -= 1
ch: t.CChar = vpi_path[sep_pos]
if ch == '/' or ch == '\\':
sep_pos += 1
break
if sep_pos + SHA1_LEN > total_len:
return None
# 分配缓冲区并复制 SHA1(16 字符 + null 终止符)
sha1_buf: str = stdlib.malloc(SHA1_LEN + 1)
if sha1_buf is None:
return None
string.strncpy(sha1_buf, vpi_path + sep_pos, SHA1_LEN)
sha1_buf[SHA1_LEN] = '\0'
# DDEBUG: 检测从路径提取的 SHA1 是否带尾随点(>=17 字符),发现问题立即终止
_ext_sl: t.CSizeT = string.strlen(sha1_buf)
if _ext_sl >= 17:
stdio.printf("[DDEBUG] _extract_sha1_from_path too long: len=%d sha1='%s' path='%s'\n", _ext_sl, sha1_buf, vpi_path)
_ddebug_exit()
return sha1_buf
# ============================================================
# ParseVpiIntoModule - 解析 .vpi 文件,将函数声明注入到当前模块
#
# 读取 .vpi 文件 → AST 解析 → 遍历顶层节点 → 创建 declare 声明。
# 对每个 FunctionDef:
# 1. 提取函数名、参数、返回类型
# 2. 检测 CExport/CExtern/State 标记(决定是否用裸名)
# 3. 用 find_func_in_module 去重(已存在则跳过)
# 4. 用 create_declare + add_param 创建 declare 声明
# 5. 注册到函数表(用裸名,非 mangled_name)
# 对 AnnAssign with t.CTypedef:调用 register_ctypedef 注册
# ClassDef/Import/ImportFrom:跳过
#
# Args:
# pool: 内存池
# mod: 当前 LLVM 模块
# vpi_path: .vpi 文件路径
# trans: 翻译器对象
#
# Returns:
# 1=成功,0=失败
# ============================================================
def ParseVpiIntoModule(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
vpi_path: str,
trans: HT.Translator | t.CPtr) -> int:
"""解析 .vpi 文件,将函数声明注入到当前模块"""
if pool is None or mod is None or vpi_path is None or trans is None:
return 0
# 获取当前翻译器的导入信息(供 resolve_annotation_type 使用)
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
# 1. 读取 .vpi 文件
f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R)
if f.closed:
return 0
vpi_buf: bytes = stdlib.malloc(VPI_READ_BUF_SIZE)
if vpi_buf is None:
f.close()
return 0
bytes_read: LONG = f.read_all(vpi_buf, VPI_READ_BUF_SIZE)
f.close()
if bytes_read <= 0:
stdlib.free(vpi_buf)
return 0
if bytes_read < VPI_READ_BUF_SIZE:
vpi_buf[bytes_read] = 0
else:
vpi_buf[VPI_READ_BUF_SIZE - 1] = 0
# 2. 解析为 AST
lx: ast.Lexer | t.CPtr = ast.new_lexer(pool)
if lx is None:
stdlib.free(vpi_buf)
return 0
ast._lexer_init(lx, vpi_buf, pool)
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
tree: ast.AST | t.CPtr = ast.parse_tokens(pool, tokens)
stdlib.free(vpi_buf)
if tree is None:
return 0
# 提取源模块 SHA1(用于函数名混淆,在 AST 解析成功后提取避免提前返回时泄漏)
src_sha1: str = _extract_sha1_from_path(vpi_path)
# 3. 遍历 AST 顶层节点
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
if ch is None:
if src_sha1 is not None:
stdlib.free(src_sha1)
return 1
n: t.CSizeT = ch.__len__()
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)
# 函数表信息
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
max_funcs: int = 256
i: t.CSizeT
for i in range(n):
child: ast.AST | t.CPtr = ch.get(i)
if child is None:
continue
kd: int = child.kind()
# FunctionDef → 提取函数名、参数、返回类型 → 注入 declare
if kd == ast.ASTKind.FunctionDef:
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
if fd is None or fd.name is None:
continue
_inject_function_declare(pool, mod, fd, trans, src_sha1,
imported_modules, from_imports,
i32_ty, i8_ptr_ty,
funcs_ptr, max_funcs)
continue
# AnnAssign with t.CTypedef → 注册 CTypedef
if kd == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child)
if aa is None:
continue
if HandlesType._is_ctypedef_annotation(aa.annotation) != 0:
_register_ctypedef_from_annassign(pool, aa)
continue
# ClassDef → 递归注入类内方法(如 MemBuddy.__init__/alloc)
# 方法 declare 使用 {sha1}.{ClassName}.{method} 混淆名,
# 参数类型从 vpi 注解解析(避免调用时 _ensure_method_declare 用实参类型
# 创建错误 declare,如 size: t.CSizeT 被写成 i32 而非 i64)
if kd == ast.ASTKind.ClassDef:
class_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
if class_cd is None or class_cd.name is None:
continue
cls_name_v: str = class_cd.name
cls_children: list[ast.AST | t.CPtr] | t.CPtr = class_cd.children
if cls_children is not None:
cn2: t.CSizeT = cls_children.__len__()
for ci2 in range(cn2):
m_child: ast.AST | t.CPtr = cls_children.get(ci2)
if m_child is None:
continue
if m_child.kind() != ast.ASTKind.FunctionDef:
continue
m_fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m_child)
if m_fd is None or m_fd.name is None:
continue
_inject_method_declare(pool, mod, m_fd, cls_name_v, trans,
src_sha1, imported_modules, from_imports,
i32_ty, i8_ptr_ty, funcs_ptr, max_funcs)
continue
# Import/ImportFrom → 跳过
# (import 不需要处理)
# 释放 SHA1 缓冲区(_extract_sha1_from_path 用 stdlib.malloc 分配)
if src_sha1 is not None:
stdlib.free(src_sha1)
return 1
# ============================================================
# _inject_function_declare - 为单个 FunctionDef 创建 declare 声明
#
# 检测 CExport/CExtern/State 标记,计算 mangled name,
# 用 find_func_in_module 去重,创建 declare 并添加参数,
# 注册到函数表。
# ============================================================
def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
fd: ast.FunctionDef | t.CPtr,
trans: HT.Translator | t.CPtr,
src_sha1: str,
imported_modules: str,
from_imports: str,
i32_ty: llvmlite.LLVMType | t.CPtr,
i8_ptr_ty: llvmlite.LLVMType | t.CPtr,
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr,
max_funcs: int) -> None:
"""为 FunctionDef 创建 declare 声明并注入到模块"""
if fd.name is None:
return
# 检测 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")
# 计算 mangled name
# CExport/CExtern/State/main 函数用裸名,其他函数用源模块 SHA1 前缀
use_bare_name: int = 0
if has_extern != 0 or has_state != 0 or has_export != 0 or string.strcmp(fd.name, "main") == 0:
mangled_name: str = fd.name
use_bare_name = 1
else:
mangled_name = HandlesFunctions._mangle_name_with_sha1(src_sha1, fd.name)
# DDEBUG: VpiReader 是注入模块级函数 declare 的路径(无拦截,最可疑双点源头)
# 检测 src_sha1 带尾随点 / fd.name 带前导点 / mangled_name 含双点,发现立即终止
if mangled_name is not None and src_sha1 is not None and fd.name is not None:
_vpi_sl: t.CSizeT = string.strlen(src_sha1)
if _vpi_sl >= 17:
stdio.printf("[DDEBUG] VpiReader src_sha1 too long: len=%d sha1='%s' func='%s'\n", _vpi_sl, src_sha1, fd.name)
_ddebug_exit()
_vpi_fn_len: t.CSizeT = string.strlen(fd.name)
if _vpi_fn_len > 0 and fd.name[0] == '.':
stdio.printf("[DDEBUG] VpiReader fd.name starts with dot: name='%s' sha1='%s'\n", fd.name, src_sha1)
_ddebug_exit()
_vpi_mi: int = 0
_vpi_ml: t.CSizeT = string.strlen(mangled_name)
while _vpi_mi < _vpi_ml - 1:
if mangled_name[_vpi_mi] == 46 and mangled_name[_vpi_mi + 1] == 46:
stdio.printf("[DDEBUG] VpiReader mangled double-dot: sha1='%s' func='%s' mangled='%s'\n", src_sha1, fd.name, mangled_name)
_ddebug_exit()
_vpi_mi += 1
# 去重:如果函数已存在则跳过
existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
if existing is not None:
return
# 也检查裸名(非裸名模式时,CExport 函数可能已通过其他途径注册)
if use_bare_name == 0:
existing_bare: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, fd.name)
if existing_bare is not None:
return
# 推断返回类型
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, trans)
# 如果返回类型是纯 t.State(无实际类型),用 Void
if ret_ty is None and fd.returns is not None:
if has_state != 0:
ret_ty = llvmlite.Void(pool)
# 默认返回 i32
if ret_ty is None:
ret_ty = i32_ty
# 创建 declare
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, mangled_name, ret_ty)
if func is None:
return
# 提取参数并添加到 declare
param_count: int = 0
if fd.args is not None:
args_node: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args)
if args_node.args is not None:
args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args
param_count = args_list.__len__()
pi: t.CSizeT
for pi in range(param_count):
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi))
if ag is None:
continue
pname: str = ag.arg
if pname is None:
pname = "arg"
# 解析参数类型
param_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty
if ag.annotation is not None:
resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, ag.annotation, imported_modules, from_imports, trans)
if resolved_ty is not None:
param_ty = resolved_ty
llvmlite.add_param(pool, func, param_ty, pname)
# 注册到函数表(用裸名 fd.name,不是 mangled_name)
if funcs_ptr is not None:
cur_count: int = trans._func_count
if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs,
None, 0, param_count) == 0:
trans._func_count = cur_count + 1
# ============================================================
# _inject_method_declare - 为 ClassDef 内的方法创建 declare
#
# 方法混淆名: {src_sha1}.{ClassName}.{method}
# 参数类型从 vpi 注解解析(self 无注解时默认为 i8*)。
# 注入正确签名避免调用时 _ensure_method_declare 用实参类型
# 创建错误 declare(如 size: t.CSizeT 被写成 i32 而非 i64)。
# ============================================================
def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
m_fd: ast.FunctionDef | t.CPtr,
cls_name: str,
trans: HT.Translator | t.CPtr,
src_sha1: str,
imported_modules: str,
from_imports: str,
i32_ty: llvmlite.LLVMType | t.CPtr,
i8_ptr_ty: llvmlite.LLVMType | t.CPtr,
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr,
max_funcs: int) -> None:
"""为 ClassDef 内方法创建 declare 声明并注入到模块"""
if m_fd is None or m_fd.name is None or cls_name is None:
return
if src_sha1 is None:
return
# 构造方法查找名: ClassName.method
lookup_name_len: t.CSizeT = string.strlen(cls_name) + 1 + string.strlen(m_fd.name) + 1
lookup_name: str = pool.alloc(lookup_name_len)
if lookup_name is None:
return
viperlib.snprintf(lookup_name, lookup_name_len, "%s.%s", cls_name, m_fd.name)
# mangled name: {src_sha1}.{ClassName}.{method}
mangled_len: t.CSizeT = string.strlen(src_sha1) + 1 + lookup_name_len
mangled_name: str = pool.alloc(mangled_len)
if mangled_name is None:
return
viperlib.snprintf(mangled_name, mangled_len, "%s.%s", src_sha1, lookup_name)
# 去重:如果方法已存在则跳过
existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
if existing is not None:
return
# 推断返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = None
if m_fd.returns is not None:
ret_ty = HandlesType.resolve_annotation_type(
pool, m_fd.returns, imported_modules, from_imports, trans)
# __new__ 无返回注解时推断为类指针(__new__ 返回 self 指针,默认 i32 会截断指针)
if ret_ty is None and string.strcmp(m_fd.name, "__new__") == 0:
cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(cls_name)
if cls_ty is not None:
ret_ty = llvmlite.Ptr(pool, cls_ty)
if ret_ty is None:
ret_ty = i32_ty
# 创建 declare
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, mangled_name, ret_ty)
if func is None:
return
# 提取参数并添加到 declare
param_count: int = 0
if m_fd.args is not None:
args_node: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(m_fd.args)
if args_node.args is not None:
args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args
param_count = args_list.__len__()
pi: t.CSizeT
for pi in range(param_count):
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi))
if ag is None:
continue
pname: str = ag.arg
if pname is None:
pname = "arg"
# 解析参数类型
param_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty
if ag.annotation is not None:
resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, ag.annotation, imported_modules, from_imports, trans)
if resolved_ty is not None:
param_ty = resolved_ty
llvmlite.add_param(pool, func, param_ty, pname)
# 注册到函数表(用裸名 ClassName.method,与调用方 lookup_name 一致)
if funcs_ptr is not None:
cur_count: int = trans._func_count
if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, lookup_name, func, max_funcs,
None, 0, param_count) == 0:
trans._func_count = cur_count + 1
# ============================================================
# _register_ctypedef_from_annassign - 从 AnnAssign 节点注册 CTypedef
#
# 提取 NAME: t.CTypedef = Type 中的名称和类型表达式字符串,
# 调用 register_ctypedef 注册到动态 CTypedef 表。
# ============================================================
def _register_ctypedef_from_annassign(pool: memhub.MemBuddy | t.CPtr,
aa: ast.AnnAssign | t.CPtr) -> None:
"""从 AnnAssign 节点提取并注册 CTypedef"""
if aa is None or pool is None:
return
# 提取目标名称(必须是 Name 节点)
if aa.target is None or aa.target.kind() != ast.ASTKind.Name:
return
tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
if tgt.id is None:
return
# 提取类型表达式字符串(从 value AST 节点)
if aa.value is None:
return
type_str: str = HandlesType._get_type_name_from_annotation(pool, aa.value)
if type_str is None:
return
# 注册 CTypedef
HandlesType.register_ctypedef(pool, tgt.id, type_str)
+32 -2
View File
@@ -15,6 +15,8 @@ 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
import lib.core.StubMerger as StubMerger
import lib.StubGen.Converter as StubConverter
import lib.Projectrans.Config as Config
# ============================================================
@@ -32,11 +34,14 @@ _mbuddy: memhub.MemBuddy | t.CPtr
# 源代码缓冲区大小(1MB)
SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB
# .vpi 存根缓冲区大小(256KB,与 Phase1 一致)
PYI_BUF_SIZE: t.CSizeT = 262144
# ============================================================
# TranslateFileGetTrans - 翻译单个文件,返回 Translator 对象
#
# 读取文件 → AST 解析 → LLVM IR 翻译,返回 Translator 对象供
# 读取文件 → AST 解析 → .vpi 生成 → LLVM IR 翻译,返回 Translator 对象供
# 调用者 dump_ir。命名空间隔离:includes 文件宽松模式(全部可见),
# 用户文件严格模式(仅本地+import)。
#
@@ -44,6 +49,9 @@ SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB
# mb: 内存池
# file_path: 源文件路径
# sha1_val: 文件内容的 SHA1 前16字符(用于函数名混淆)
# current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块
# declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体)
# temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件)
#
# Returns:
# Translator 对象(None 失败)
@@ -51,11 +59,13 @@ SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB
def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
sha1_val: str,
current_package: str = None,
declare_only: int = 0) -> HandlesTranslator.Translator | t.CPtr:
declare_only: int = 0,
temp_dir: str = None) -> HandlesTranslator.Translator | t.CPtr:
"""翻译文件,返回 Translator 对象(调用者负责 dump_ir),None 失败
current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块
declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体)
temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件)
"""
if file_path is None:
return None
@@ -83,6 +93,24 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
stdlib.free(src_buf)
if tree is None:
return None
# 生成 .vpi 存根文件(从 AST 直接生成,在 tr.translate 之前,与 Phase1 一致)
# .vpi 供其他模块跨模块查询函数签名和 CTypedef 定义
if temp_dir is not None:
pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE)
if pyi_buf is not None:
pyi_buf[0] = 0
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, None, pyi_buf, PYI_BUF_SIZE)
if pyi_pos > 0:
# 写入 {sha1}.vpi 到 temp_dir(切片路径)
td_len_vpi: t.CSizeT = string.strlen(temp_dir)
pyi_path: str = StubMerger._sliced_path(temp_dir, td_len_vpi, sha1_val, "vpi")
if pyi_path is not None:
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W)
if not pf.closed:
pf.write(pyi_buf, pyi_pos)
pf.close()
stdlib.free(pyi_path)
stdlib.free(pyi_buf)
tr: HandlesTranslator.Translator | t.CPtr = mb.alloc(HandlesTranslator.Translator.__sizeof__())
tr.__before_init__()
tr.__init__()
@@ -95,6 +123,8 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
HandlesType.clear_trace()
# 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离
HandlesType.clear_cdefine_constants()
# 模块切换:清空 CTypedef 表,确保每个模块的 CTypedef 正确隔离
HandlesType.clear_ctypedefs()
# 命名空间隔离:includes 文件宽松模式(全部可见),用户文件严格模式(仅本地+import)
strict_mode: int = 1
if string.strstr(file_path, "includes") is not None:
+18 -12
View File
@@ -244,7 +244,7 @@ def _init_global_array_from_list(builder: llvmlite.IRBuilder | t.CPtr,
store_val: llvmlite.Value | t.CPtr = elem_val
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
store_val = HandlesExpr.coerce_to_type(
builder, elem_val, elem_ptr.Ty.Pointee)
builder, elem_val, elem_ptr.Ty.Pointee, elem_node)
llvmlite.build_store(builder, store_val, elem_ptr)
i += 1
@@ -296,10 +296,12 @@ class AnnAssignHandle(HandlesBase.Mixin):
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
return 0
# 模块级全局变量已由 handle_module_level_var 注册到模块作用域,
# 不需要创建局部 alloca(否则会导致局部变量遮蔽全局变量)
if HandlesVar.lookup_module_var(self.Trans.SymTab, nm.id) is not None:
return 0
# 模块级全局变量已由 handle_module_level_var 注册到模块作用域。
# Python 语义:仅模块级代码(Current == Root)时跳过局部 alloca;
# 函数内无 global 声明时应创建局部变量(不遮蔽全局)。
if HandlesVar.is_module_scope(self.Trans.SymTab) != 0:
if HandlesVar.lookup_module_var(self.Trans.SymTab, nm.id) is not None:
return 0
# 检查是否已存在
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
@@ -434,7 +436,7 @@ class AnnAssignHandle(HandlesBase.Mixin):
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)
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node)
llvmlite.build_store(builder, rhs_val, mod_alloca)
return 0
@@ -460,14 +462,18 @@ class AnnAssignHandle(HandlesBase.Mixin):
"HandlesAnnAssign")
return 0
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, rhs_val, nl_target_ty)
builder, rhs_val, nl_target_ty, node)
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
return 0
# 模块级全局变量(由 handle_module_level_var 注册到模块作用域)
# 非函数内 global 声明,但变量已在模块作用域中(如模块级 t.CArray 初始化)
mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
# Python 语义:仅模块级代码(Current == Root)时修改全局变量;
# 函数内无 global 声明时应创建局部变量(走后面的 get_or_create_sym 路径)。
if HandlesVar.is_module_scope(self.Trans.SymTab) != 0:
mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
else:
mod_glob = None
if mod_glob is not None:
if aa.value is not None:
# 列表字面量 → 逐元素 GEP + store 初始化数组
@@ -483,7 +489,7 @@ class AnnAssignHandle(HandlesBase.Mixin):
if mod_glob.Ty is not None:
target_ty_mg = mod_glob.Ty.Pointee
if target_ty_mg is not None:
rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg)
rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node)
llvmlite.build_store(builder, rhs_val_mg, mod_glob)
return 0
@@ -523,7 +529,7 @@ class AnnAssignHandle(HandlesBase.Mixin):
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)
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node)
llvmlite.build_store(builder, rhs_val, alloca)
return 0
+21 -7
View File
@@ -152,7 +152,7 @@ class AssignHandle(HandlesBase.Mixin):
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)
builder, pool, list_obj, list_idx_val, rhs_val, target)
continue
# 普通 Subscript 赋值
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
@@ -163,7 +163,7 @@ class AssignHandle(HandlesBase.Mixin):
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)
builder, rhs_val, elem_ty, node)
llvmlite.build_store(builder, store_val, elem_ptr)
else:
# get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载
@@ -281,7 +281,7 @@ class AssignHandle(HandlesBase.Mixin):
pt_gen: llvmlite.LLVMType | t.CPtr = elem_ptr_gen.Ty.Pointee
if pt_gen is not None:
store_val_gen = HandlesExpr.coerce_to_type(
builder, rhs_val, pt_gen)
builder, rhs_val, pt_gen, node)
llvmlite.build_store(builder, store_val_gen, elem_ptr_gen)
setitem_done = 1
if setitem_done == 0:
@@ -301,7 +301,7 @@ class AssignHandle(HandlesBase.Mixin):
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)
builder, rhs_val, field_ty, node)
llvmlite.build_store(builder, store_val, field_ptr)
else:
# 构造详细错误信息
@@ -336,7 +336,7 @@ class AssignHandle(HandlesBase.Mixin):
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)
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node)
llvmlite.build_store(builder, rhs_val, mod_alloca)
continue
@@ -357,10 +357,24 @@ class AssignHandle(HandlesBase.Mixin):
"HandlesAssign")
continue
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, rhs_val, nl_target_ty)
builder, rhs_val, nl_target_ty, node)
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
continue
# 拦截:函数内对模块级全局变量赋值但没 global 声明
# 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃
# (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃)
if HandlesVar.is_module_scope(self.Trans.SymTab) == 0:
mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if mod_gv is not None:
fb_g: t.CChar | t.CPtr = VLogger.fmt_buf()
msg_g: str = "global 声明缺失"
if fb_g is not None:
viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id)
msg_g = fb_g
HandlesType.fatal_error(target, msg_g, "SyntaxError")
# 普通局部变量
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
self.Trans.SymTab, pool, builder, nm.id, rhs_val.Ty)
@@ -371,7 +385,7 @@ class AssignHandle(HandlesBase.Mixin):
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)
builder, rhs_val, alloca_ty, node)
llvmlite.build_store(builder, store_val, alloca)
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
self.Trans.SymTab, nm.id)
+13 -12
View File
@@ -82,7 +82,7 @@ class AugAssignHandle(HandlesBase.Mixin):
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val)
pool, builder, aug.op, cur_val, rhs_val, node)
if result is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
@@ -91,7 +91,7 @@ class AugAssignHandle(HandlesBase.Mixin):
return 0
# 5. 类型对齐并存储
result = HandlesExpr.coerce_to_type(builder, result, target_ty)
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
return 0
llvmlite.build_store(builder, result, field_ptr)
@@ -130,7 +130,7 @@ class AugAssignHandle(HandlesBase.Mixin):
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val)
pool, builder, aug.op, cur_val, rhs_val, node)
if result is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
@@ -139,7 +139,7 @@ class AugAssignHandle(HandlesBase.Mixin):
return 0
# 5. 类型对齐并存储
result = HandlesExpr.coerce_to_type(builder, result, target_ty)
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
return 0
llvmlite.build_store(builder, result, elem_ptr)
@@ -208,7 +208,7 @@ class AugAssignHandle(HandlesBase.Mixin):
# 4. 类型对齐 + 应用二元运算
# 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__)
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val)
pool, builder, aug.op, cur_val, rhs_val, node)
if result is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
@@ -217,7 +217,7 @@ class AugAssignHandle(HandlesBase.Mixin):
return 0
# 5. 存储结果
result = HandlesExpr.coerce_to_type(builder, result, target_ty)
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
return 0
@@ -249,7 +249,8 @@ 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:
rhs: llvmlite.Value | t.CPtr,
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)"""
lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
@@ -267,8 +268,8 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
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)
lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node)
rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty, node)
if op == ast.OpKind.Add:
return llvmlite.build_fadd(builder, lhs, rhs)
if op == ast.OpKind.Sub:
@@ -286,7 +287,7 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
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)
int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty, node)
if ptr_as_int is None or int_val is None:
return None
if op == ast.OpKind.Add:
@@ -300,9 +301,9 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
# 整数运算:类型提升
if lhs_bits > rhs_bits and rhs_bits > 0:
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty)
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node)
elif rhs_bits > lhs_bits and lhs_bits > 0:
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty)
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node)
if op == ast.OpKind.Add:
return llvmlite.build_add(builder, lhs, rhs)
+43 -2
View File
@@ -11,6 +11,7 @@ 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
import lib.core.Handles.HandlesVar as HandlesVar
# ============================================================
@@ -67,6 +68,8 @@ def translate_stmt(trans: HT.Translator | t.CPtr,
return translate_break(trans)
elif k == ast.ASTKind.Continue:
return translate_continue(trans)
elif k == ast.ASTKind.Match:
return trans.MatchH.Handle(node)
return 0
@@ -101,7 +104,10 @@ def translate_global(trans: HT.Translator | t.CPtr,
# ============================================================
def translate_nonlocal(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 nonlocal 语句:记录 nonlocal 变量名"""
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型
类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。
"""
nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node)
if nl is None:
return 0
@@ -114,7 +120,22 @@ def translate_nonlocal(trans: HT.Translator | t.CPtr,
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)
# 查找父作用域中的变量 alloca,获取类型信息
var_ty: llvmlite.LLVMType | t.CPtr = None
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, nm.id)
if var_alloca is not None and var_alloca.Ty is not None:
var_ty = var_alloca.Ty.Pointee
# Void 类型视为无效(Pointee 访问异常时可能返回 Void),
# 设为 None 让 add_nonlocal_name 回退为 i32,避免生成
# "bitcast ... to void*" / "load void, void*" 非法 IR
if var_ty is not None:
match var_ty:
case llvmlite.LLVMType.Void():
var_ty = None
case _:
pass
HT.add_nonlocal_name(trans, nm.id, var_ty)
return 0
@@ -166,6 +187,26 @@ def pre_scan_allocas(trans: HT.Translator | t.CPtr,
return trans.AnnAssignH.PreScan(node)
# ============================================================
# 预扫描:Global/Nonlocal 声明(Python 作用域语义)
#
# Python 中 global/nonlocal 声明对整个函数作用域生效,与声明
# 位置无关。必须在翻译任何赋值之前注册 global/nonlocal 名称,
# 否则 global 声明前的赋值会错误创建局部变量遮蔽全局。
# ============================================================
def pre_scan_scope_decls(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预扫描 Global/Nonlocal 声明,提前注册作用域名称"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Global:
return translate_global(trans, node)
if k == ast.ASTKind.Nonlocal:
return translate_nonlocal(trans, node)
return 0
# ============================================================
# 翻译 break 语句
# ============================================================
+41 -4
View File
@@ -985,7 +985,11 @@ def _translate_union_def(trans: HT.Translator | t.CPtr,
field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
if field_ty is None:
# fast-fail: 字段类型解析失败,用 fatal_error 输出 Python 风格 traceback
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
# 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类)
if trans._declare_only == 1:
return 1
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止
type_name: str = HandlesType.annotation_to_str(aa.annotation)
HandlesType.fatal_error(
aa,
@@ -2070,6 +2074,31 @@ def _specialize_generic_class(trans: HT.Translator | t.CPtr,
if spec_name is None:
return None
# 治本修复:Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前)
# Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0),
# Phase B(declare_only==0)重复进入时若方法体未译,补译方法体生成 define,
# 避免 GSList[Line].append 等符号只有 declare 无 define → 链接失败。
# 首次 Phase B 特化(Phase 1a 未特化)find_struct 返回 None,不补译,走下方正常全量翻译。
if trans._declare_only == 0:
pre_existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if pre_existing is not None and pre_existing.MethodsEmitted == 0:
tp_names_pre: list[str] | t.CPtr = template_cd.type_params
spec_cd_pre: ast.ClassDef | t.CPtr = _clone_classdef_for_spec(
pool, template_cd, spec_name, tp_names_pre, type_args)
if spec_cd_pre is not None:
trans.GenericTypeParamNames = tp_names_pre
trans.GenericTypeArgs = type_args
HandlesType.set_generic_context(tp_names_pre, type_args)
saved_ms_pre: str = trans.ModuleSha1
template_sha1_pre: str = _find_generic_template_sha1(class_name)
if template_sha1_pre is not None:
trans.ModuleSha1 = template_sha1_pre
_translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0)
trans.ModuleSha1 = saved_ms_pre
trans.GenericTypeParamNames = None
trans.GenericTypeArgs = None
HandlesType.clear_generic_context()
# 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突)
# 分配新缓冲区避免原地 strcat 溢出
sk_n: t.CSizeT = type_args.__len__()
@@ -2393,13 +2422,16 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
# 泛型未特化:回退为 Ptr(i8),依赖 AnnotClassName 做后续类型恢复
field_ty = llvmlite.Ptr(pool, llvmlite.Int8(pool))
else:
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
# 静默 return 0 让多遍收敛机制生效(下一遍依赖类已注册即可成功)
if trans._declare_only == 1:
return 0
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止
type_name2: str = HandlesType.annotation_to_str(aa.annotation)
HandlesType.fatal_error(
aa,
f"'{type_name2}' is not defined",
"NameError")
if trans._declare_only == 1:
return 0
return 0
# 存储到数组(指针转 CSizeT)
@@ -3033,6 +3065,11 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr,
# 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置)
_generate_before_init(trans, struct_ty, class_name)
# 治本修复:标记方法体已翻译,供 _specialize_generic_class 已注册分支判断
# Phase 1a mark_only==1 不设此标志,Phase B 补译时据此判断需补译方法体
if oop_entry is not None:
oop_entry.MethodsEmitted = 1
return 0
@@ -3439,7 +3476,7 @@ def _generate_before_init(trans: HT.Translator | t.CPtr,
if field_ptr is None:
continue
# 类型转换并 store
default_val = HandlesExpr.coerce_to_type(func_builder, default_val, fe.Ty)
default_val = HandlesExpr.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal)
llvmlite.build_store(func_builder, default_val, field_ptr)
# 3. ret void
+2 -2
View File
@@ -55,8 +55,7 @@ _enum_count: int = 0
# ============================================================
def init_enum_table(pool: memhub.MemBuddy | t.CPtr) -> int:
"""初始化枚举注册表,返回 1 成功"""
global _enum_table
global _enum_count
global _enum_table, _enum_count
if _enum_table is not None:
return 1
@@ -102,6 +101,7 @@ def _get_enum_member(enum_entry: EnumEntry | t.CPtr, i: int) -> EnumMember | t.C
def register_enum(pool: memhub.MemBuddy | t.CPtr,
name: str,
base_ty: llvmlite.LLVMType | t.CPtr) -> EnumEntry | t.CPtr:
global _enum_count
"""注册枚举类型,返回 EnumEntry 指针"""
if init_enum_table(pool) == 0:
return None
+40 -12
View File
@@ -249,13 +249,16 @@ def _deref_if_ptr_ptr(builder: llvmlite.IRBuilder | t.CPtr,
# ============================================================
def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr,
val: llvmlite.Value | t.CPtr,
target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
target_ty: llvmlite.LLVMType | t.CPtr,
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""将 val 强制转换为 target_ty
整数: sext(扩展)/ trunc(截断)
浮点: fpext(扩展)/ fptrunc(截断)
int→float: sitofp
float→int: fptosi
node: AST 节点(用于错误定位),可为 None
"""
if val is None or target_ty is None:
return val
@@ -284,7 +287,7 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr,
# float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径)
if (val_fbits != 0 and is_ptr_type(target_ty) != 0) or \
(is_ptr_type(val.Ty) != 0 and target_fbits != 0):
VLogger.error("coerce_to_type: 不支持的类型转换 float↔ptr", "Coerce")
HandlesType.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError")
return val
if val_fbits != 0 and target_fbits != 0:
if val_fbits == target_fbits:
@@ -784,21 +787,21 @@ def translate_ifexp(builder: llvmlite.IRBuilder | t.CPtr,
# coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针)
if body_is_ptr != orelse_is_ptr:
llvmlite.position_at_end(builder, else_blk_for_phi)
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty)
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node)
elif body_bits > orelse_bits and orelse_bits > 0:
# 在 else 块中转换 orelse_val
llvmlite.position_at_end(builder, else_blk_for_phi)
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty)
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node)
elif orelse_bits > body_bits and body_bits > 0:
# 回到 then 块转换 body_val
llvmlite.position_at_end(builder, then_blk_for_phi)
body_val = coerce_to_type(builder, body_val, orelse_val.Ty)
body_val = coerce_to_type(builder, body_val, orelse_val.Ty, node)
elif body_bits == orelse_bits and body_bits > 0:
# bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI
# 此分支理论上不会触发(已被情况0覆盖),保留作为防御
if is_ptr_type(body_val.Ty) != is_ptr_type(orelse_val.Ty):
llvmlite.position_at_end(builder, else_blk_for_phi)
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty)
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node)
# 现在分别在 then/else 块中 br 到 merge(在类型转换之后)
llvmlite.position_at_end(builder, then_blk_for_phi)
@@ -940,6 +943,7 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
# None 比较: None 被翻译为 i8* null(一级指针)
# 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型
# 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较)
# 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1
lhs_ptr_level_none: int = get_ptr_level(lhs.Ty)
rhs_ptr_level_none: int = get_ptr_level(rhs.Ty)
if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0:
@@ -950,6 +954,19 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
# lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针
rhs = llvmlite.ConstNull(pool, lhs.Ty, None)
elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0:
# 检查 lhs 是否是结构体值类型(非指针的 Struct)
lhs_is_struct_none: int = 0
match lhs.Ty:
case llvmlite.LLVMType.Struct(_, _, _):
lhs_is_struct_none = 1
case _:
lhs_is_struct_none = 0
if lhs_is_struct_none != 0:
# 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true
if op == ast.OpKind.Eq or op == ast.OpKind.Is:
return llvmlite.const_int(pool, 1, 0)
else: # Ne, IsNot
return llvmlite.const_int(pool, 1, 1)
# lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变)
rhs = llvmlite.const_int32(pool, 0)
@@ -1054,6 +1071,15 @@ def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr,
# 指针类型:与 null 比较
null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null")
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op)
# 结构体值类型:永远为真(非空),not 返回 false
operand_is_struct_not: int = 0
match operand.Ty:
case llvmlite.LLVMType.Struct(_, _, _):
operand_is_struct_not = 1
case _:
operand_is_struct_not = 0
if operand_is_struct_not != 0:
return llvmlite.const_int(pool, 1, 0)
operand_bits_not: int = get_llvm_type_bits(operand.Ty)
zero = llvmlite.const_int32(pool, 0)
if operand_bits_not == 64:
@@ -1942,7 +1968,8 @@ def NewExprHandle(pool: memhub.MemBuddy | t.CPtr,
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:
idx_val: llvmlite.Value | t.CPtr,
node: ast.AST | t.CPtr = None) -> 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
@@ -1963,7 +1990,7 @@ def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr,
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)
g_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty, node)
if g_idx_i64 is None:
return None
g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize)
@@ -2021,7 +2048,8 @@ 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:
rhs_val: llvmlite.Value | t.CPtr,
node: ast.AST | t.CPtr = None) -> 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
@@ -2042,7 +2070,7 @@ def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr,
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)
s_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty, node)
if s_idx_i64 is None:
return 0
s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize)
@@ -2051,7 +2079,7 @@ def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr,
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)
s_val_ptr: llvmlite.Value | t.CPtr = coerce_to_type(builder, rhs_val, i8_ptr_ty, node)
if s_val_ptr is None:
return 0
llvmlite.build_store(builder, s_val_ptr, s_addr)
@@ -2169,7 +2197,7 @@ def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr,
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)
builder, pool, ptr_val_list, idx_val, node)
if elem_addr_list is not None:
# 根据类型名提取元素类型,bitcast 后 load
elem_ty_list: llvmlite.LLVMType | t.CPtr = _list_elem_type_from_name(
File diff suppressed because it is too large. Load diff
+16 -6
View File
@@ -222,8 +222,8 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr,
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)
lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node)
rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty, node)
if op == ast.OpKind.Add:
return llvmlite.build_fadd(builder, lhs, rhs)
if op == ast.OpKind.Sub:
@@ -243,7 +243,7 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr,
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)
int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty, node)
if op == ast.OpKind.Add:
result: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, ptr_as_int, int_val)
else:
@@ -252,7 +252,7 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr,
else:
# rhs 是指针,lhs 是整数(仅 Add 支持交换)
ptr_as_int = llvmlite.build_ptrtoint(builder, rhs, i64_ty)
int_val = HandlesExpr.coerce_to_type(builder, lhs, i64_ty)
int_val = HandlesExpr.coerce_to_type(builder, lhs, i64_ty, node)
if op == ast.OpKind.Add:
result = llvmlite.build_add(builder, int_val, ptr_as_int)
else:
@@ -260,9 +260,19 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr,
return llvmlite.build_inttoptr(builder, result, rhs.Ty)
if lhs_bits > rhs_bits:
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty)
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node)
elif rhs_bits > lhs_bits:
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty)
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node)
# 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时,
# 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。
# 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。
if lhs_bits == 0 and rhs_bits == 0:
if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift:
VLogger.error(
"位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算",
"BinOp")
return None
if op == ast.OpKind.Add:
return llvmlite.build_add(builder, lhs, rhs)
File diff suppressed because it is too large. Load diff
+852
View File
@@ -0,0 +1,852 @@
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
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesStruct as HandlesStruct
# ============================================================
# HandlesMatch - match 语句处理(Mixin 继承模式)
#
# 逻辑移植自 TPC 的 HandlesMatch.py,用 Viper 语法重写。
# 两条路径:
# 1. REnum 路径:bitcast subject 到 i32* 读 __tag + switch 分派
# 2. 非 REnum 路径:subject ptrtoint 到 i32 + switch 分派
#
# IR 模式(REnum):
# %tag_ptr = bitcast <struct>* %subj to i32*
# %tag = load i32, i32* %tag_ptr
# switch i32 %tag, label %default [ i32 <tag1>, label %case1 ... ]
# case1:
# ... body ...
# br label %end (若无 c.NoBreak)
# end:
# ============================================================
# match case 数量上限
MAX_MATCH_CASES: t.CDefine = 32
# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分)
SCOPE_MATCH: t.CDefine = 6
@t.NoVTable
class MatchHandle(HandlesBase.Mixin):
"""match 语句处理器:REnum + 非 REnum 两条路径"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# Handle - match 语句主入口,返回 0
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
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
stdio.printf("[MATCHDBG] Handle entry: _renum_class_count=%d\n",
HandlesClassDef._renum_class_count)
dbg_i: int = 0
while dbg_i < HandlesClassDef._renum_class_count:
dbg_nm: str = HandlesClassDef._renum_class_names[dbg_i]
if dbg_nm is not None:
stdio.printf("[MATCHDBG] REnum[%d]=%s\n", dbg_i, dbg_nm)
dbg_i = dbg_i + 1
m_node: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node)
# 1. 求值 subject
subject_node: ast.AST | t.CPtr = m_node.subject
if subject_node is None:
return 0
subject_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, subject_node,
trans._funcs, trans._func_count, trans)
if subject_val is None:
stdio.printf("[MATCHDBG] subject_val is None (translate_value failed)\n")
return 0
stdio.printf("[MATCHDBG] subject_val OK\n")
# 2. 检测是否 REnum match
is_renum: int = 0
renum_name: str = None
subject_ptr: llvmlite.Value | t.CPtr = None
# 2a. 若 subject 是 Name,查变量注解类名
if subject_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(subject_node)
if nm.id is not None:
stdio.printf("[MATCHDBG] subject Name='%s'\n", nm.id)
entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nm.id)
if entry is None:
stdio.printf("[MATCHDBG] VarEntry None for '%s'\n", nm.id)
if entry is not None and entry.AnnotClassName is not None:
stdio.printf("[MATCHDBG] AnnotClassName='%s'\n",
entry.AnnotClassName)
rn_chk: int = HandlesClassDef._is_renum_class_name(
entry.AnnotClassName)
stdio.printf("[MATCHDBG] _is_renum_class_name=%d\n", rn_chk)
if rn_chk != 0:
is_renum = 1
renum_name = entry.AnnotClassName
subject_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id)
stdio.printf("[MATCHDBG] REnum detected: %s\n",
renum_name)
# 2b. 若未确定,遍历 cases 查 MatchClass 变体
if is_renum == 0:
cases_list: list[ast.AST | t.CPtr] | t.CPtr = m_node.cases
if cases_list is not None:
cn: t.CSizeT = cases_list.__len__()
ci: int = 0
while ci < cn and is_renum == 0:
case_node: ast.AST | t.CPtr = cases_list.get(ci)
if case_node is not None:
if case_node.kind() == ast.ASTKind.MatchCase:
mc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = mc.pattern
if pat is not None:
if pat.kind() == ast.ASTKind.MatchClass:
rnm: str = self._extract_renum_name_from_cls(pat)
if rnm is not None:
if HandlesClassDef._is_renum_class_name(rnm) != 0:
is_renum = 1
renum_name = rnm
if subject_ptr is None:
subject_ptr = subject_val
ci = ci + 1
# 3. 分派
stdio.printf("[MATCHDBG] dispatch: is_renum=%d\n", is_renum)
if is_renum != 0 and subject_ptr is not None:
stdio.printf("[MATCHDBG] -> _handle_renum_match\n")
return self._handle_renum_match(m_node, renum_name, subject_ptr)
stdio.printf("[MATCHDBG] -> _handle_simple_match\n")
return self._handle_simple_match(m_node, subject_val)
# ============================================================
# _extract_renum_name_from_cls - 从 MatchClass.cls 提取 REnum 类名
#
# LLVMType.Ptr -> Attribute(value=Name('LLVMType'), attr='Ptr') -> 'LLVMType'
# llvmlite.LLVMType.Ptr -> Attribute(Attribute(Name('llvmlite'),'LLVMType'),'Ptr') -> 'LLVMType'
# Ptr -> Name('Ptr') -> 遍历查找
# ============================================================
def _extract_renum_name_from_cls(self,
pattern: ast.AST | t.CPtr) -> str:
if pattern is None:
return None
mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern)
cls_node: ast.AST | t.CPtr = mc.cls
if cls_node is None:
return None
# Attribute 形式
if cls_node.kind() == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node)
if at.value is not None:
if at.value.kind() == ast.ASTKind.Name:
inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
return inner_nm.id
if at.value.kind() == ast.ASTKind.Attribute:
inner_at: ast.Attribute | t.CPtr = (
ast.Attribute | t.CPtr)(at.value)
return inner_at.attr
# Name 形式:遍历所有 REnum 类反查
if cls_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node)
return self._find_renum_class_for_variant(nm.id)
return None
# ============================================================
# _extract_variant_name_from_cls - 从 MatchClass.cls 提取变体名
# ============================================================
def _extract_variant_name_from_cls(self,
pattern: ast.AST | t.CPtr) -> str:
if pattern is None:
return None
mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern)
cls_node: ast.AST | t.CPtr = mc.cls
if cls_node is None:
return None
if cls_node.kind() == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node)
return at.attr
if cls_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node)
return nm.id
return None
# ============================================================
# _find_renum_class_for_variant - 从变体名反查 REnum 类名
# ============================================================
def _find_renum_class_for_variant(self, variant_name: str) -> str:
if variant_name is None:
return None
i: int = 0
while i < HandlesClassDef._renum_class_count:
cls_nm: str = HandlesClassDef._renum_class_names[i]
if cls_nm is not None:
tag: int = HandlesClassDef._lookup_renum_variant_in_class(
cls_nm, variant_name)
if tag >= 0:
return cls_nm
i = i + 1
return None
# ============================================================
# _has_no_break - 检测 case body 是否含 c.NoBreak() 调用
#
# 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak')))
# ============================================================
def _has_no_break(self, body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int:
if body_list is None:
return 0
n: t.CSizeT = body_list.__len__()
i: int = 0
while i < n:
stmt: ast.AST | t.CPtr = body_list.get(i)
if stmt is not None:
if stmt.kind() == ast.ASTKind.Expr:
expr_node: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt)
val: ast.AST | t.CPtr = expr_node.value
if val is not None and val.kind() == ast.ASTKind.Call:
call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val)
fn: ast.AST | t.CPtr = call_node.func
if fn is not None and fn.kind() == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (
ast.Attribute | t.CPtr)(fn)
if at.value is not None:
if at.value.kind() == ast.ASTKind.Name:
base_nm: ast.Name | t.CPtr = (
ast.Name | t.CPtr)(at.value)
if base_nm.id is not None:
if string.strcmp(base_nm.id, "c") == 0:
if at.attr is not None:
if string.strcmp(at.attr, "NoBreak") == 0:
return 1
i = i + 1
return 0
# ============================================================
# _handle_renum_match - REnum 路径
#
# 1. bitcast subject 到 i32* 读 __tag
# 2. 收集 case 值 + 创建 BB + 构建 SwitchCase 链表
# 3. 发射 build_switch
# 4. 翻译每个 case body(含作用域隔离 + 变体字段绑定)
# ============================================================
def _handle_renum_match(self, node: ast.Match | t.CPtr,
renum_name: str,
subject_ptr: llvmlite.Value | t.CPtr) -> int:
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
# 0. subject 归一化:确保 subject_ptr 是指向 REnum 结构体的指针
# (对齐 TPC HandlesMatch.py:238-259 的 _HandleRenumMatchLlvm)
# 情况1: subject_ptr 是 T**(变量 alloca)→ load 一次得 T*
# 情况2: subject_ptr 不是指针(值型,如 REnum payload 槽位 load 出的 i64)
# → alloca REnum 结构体 + store 值 + 用 alloca 指针
# 情况3: 指针但 pointee 不是结构体 → bitcast 到 REnum 结构体指针
subj_ty: llvmlite.LLVMType | t.CPtr = subject_ptr.Ty
if subj_ty is not None and HandlesExpr.is_ptr_type(subj_ty) != 0:
pointee_ty: llvmlite.LLVMType | t.CPtr = subj_ty.Pointee
if pointee_ty is not None:
if HandlesExpr.is_ptr_type(pointee_ty) != 0:
# 情况1: T** → load 一次得 T*
load_sub_ty: llvmlite.LLVMType | t.CPtr = pointee_ty
loaded_sub: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, load_sub_ty, subject_ptr)
if loaded_sub is not None:
subject_ptr = loaded_sub
# 情况2: 值型 subject(非指针)→ inttoptr 转回指针
# 值型 subject 来自 REnum payload 槽位 load(槽位类型 i64,存的是指针),
# 所以直接 inttoptr 到 renum_sty* 即可,无需 alloca+store
if subject_ptr.Ty is None or HandlesExpr.is_ptr_type(subject_ptr.Ty) == 0:
renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
renum_name)
renum_sty: llvmlite.LLVMType | t.CPtr = None
if renum_se is not None:
renum_sty = renum_se.Ty
if renum_sty is None:
# 找不到结构体类型时无法构造,直接放弃 REnum 路径
stdio.printf("[MATCHDBG] renum struct type not found for '%s'\n",
renum_name)
return 0
i64_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
int_val: llvmlite.Value | t.CPtr = subject_ptr
# 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽)
# 仅当 subj_ty 是已知整数类型时转换;类型未知时保持原值
if subj_ty is not None and HandlesExpr.get_llvm_type_bits(subj_ty) != 64:
if HandlesExpr.is_ptr_type(subj_ty) == 0:
if HandlesExpr.get_llvm_type_bits(subj_ty) > 64:
int_val = llvmlite.build_trunc(builder, subject_ptr, i64_ty0)
else:
int_val = llvmlite.build_zext(builder, subject_ptr, i64_ty0)
renum_ptr_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_sty)
subj_ptr0: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr(
builder, int_val, renum_ptr_ty0)
if subj_ptr0 is not None:
subject_ptr = subj_ptr0
# 1. bitcast subject 到 i32* 读 __tag
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty)
tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, subject_ptr, i32_ptr_ty)
if tag_ptr is None:
stdio.printf("[MATCHDBG] tag_ptr None (bitcast failed)\n")
return 0
tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i32_ty, tag_ptr)
if tag_val is None:
stdio.printf("[MATCHDBG] tag_val None (load failed)\n")
return 0
stdio.printf("[MATCHDBG] _handle_renum_match: tag loaded OK\n")
# 2. 创建 default/end BB
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
if name_buf is None:
return 0
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "match.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
# 3. 准备收集数组(用 CSizeT 数组存指针)
cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases
if cases_list is None:
return 0
case_count: t.CSizeT = cases_list.__len__()
# BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组
bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
return 0
collected: int = 0
has_default: int = 0
# SwitchCase 链表
sw_head: llvmlite.SwitchCase | t.CPtr = None
sw_tail: llvmlite.SwitchCase | t.CPtr = None
sw_count: int = 0
# 4. 第一遍:收集 case 信息 + 创建 BB + 构建链表
i: int = 0
while i < case_count:
case_node: ast.AST | t.CPtr = cases_list.get(i)
if case_node is None:
i = i + 1
continue
if case_node.kind() != ast.ASTKind.MatchCase:
i = i + 1
continue
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = mc.pattern
is_def: int = 0
cv: llvmlite.Value | t.CPtr = None
if pat is not None:
pk: int = pat.kind()
if pk == ast.ASTKind.MatchClass:
vnm: str = self._extract_variant_name_from_cls(pat)
if vnm is not None:
tag: int = HandlesClassDef._lookup_renum_variant_in_class(
renum_name, vnm)
stdio.printf("[MATCHDBG] case vnm='%s' renum='%s' -> tag=%d\n",
vnm if vnm is not None else "(null)",
renum_name if renum_name is not None else "(null)",
tag)
if tag >= 0:
tag_buf: t.CChar | t.CPtr = pool.alloc(32)
if tag_buf is not None:
viperlib.snprintf(tag_buf, 32, "%d", tag)
cv = llvmlite.ConstInt(pool, i32_ty, tag,
tag_buf if tag_buf is not None else "0")
elif pk == ast.ASTKind.MatchAs:
ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat)
if ma.pattern is None:
is_def = 1
has_default = 1
elif pk == ast.ASTKind.MatchValue:
mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat)
cv = HandlesExpr.translate_value(
builder, pool, trans.Module, mv.value,
trans._funcs, trans._func_count, trans)
elif pk == ast.ASTKind.MatchOr:
# MatchOr: 多个值共享一个 BB(取第一个值做 case)
mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat)
pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns
if pats is not None and pats.__len__() > 0:
first_pat: ast.AST | t.CPtr = pats.get(0)
if first_pat is not None:
if first_pat.kind() == ast.ASTKind.MatchValue:
mv2: ast.MatchValue | t.CPtr = (
ast.MatchValue | t.CPtr)(first_pat)
cv = HandlesExpr.translate_value(
builder, pool, trans.Module, mv2.value,
trans._funcs, trans._func_count, trans)
# 创建 case BB
if is_def == 0:
if collected >= MAX_MATCH_CASES:
break
viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i)
bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
else:
bb = default_bb
# 检测 NoBreak
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
nb: int = self._has_no_break(body_list)
# 存入数组
if collected < MAX_MATCH_CASES:
bb_arr[collected] = t.CSizeT(bb)
cv_arr[collected] = t.CSizeT(cv)
def_arr[collected] = is_def
nb_arr[collected] = nb
collected = collected + 1
# 构建 SwitchCase 链表(非 default case 且有值)
if is_def == 0 and cv is not None:
sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case(
pool, cv, bb)
if sc is not None:
if sw_head is None:
sw_head = sc
sw_tail = sc
else:
sw_tail.Next = sc
sw_tail = sc
sw_count = sw_count + 1
i = i + 1
# 5. 发射 switch 指令
llvmlite.build_switch(builder, tag_val, default_bb, sw_head, sw_count)
# 6. 查找 REnum 结构体类型(用于变体字段绑定的 GEP)
renum_entry: HandlesStruct.StructEntry | t.CPtr = None
renum_ty: llvmlite.LLVMType | t.CPtr = None
se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(renum_name)
if se is not None:
renum_entry = se
renum_ty = se.Ty
# 7. 第二遍:翻译每个 case body
i = 0
while i < collected:
case_node: ast.AST | t.CPtr = cases_list.get(i)
if case_node is None:
i = i + 1
continue
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = mc.pattern
# 取 BB
bb_addr: t.CSizeT = bb_arr[i]
case_bb: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr))
is_def: int = def_arr[i]
nb: int = nb_arr[i]
# default case 的 body 在 step 8 单独翻译,这里跳过避免重复
if is_def == 1:
i = i + 1
continue
# 定位到 case BB
llvmlite.position_at_end(builder, case_bb)
# 进入 case 作用域(变体字段绑定隔离)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
# 变体字段绑定(MatchClass)
if pat is not None and pat.kind() == ast.ASTKind.MatchClass:
if renum_entry is not None and renum_ty is not None:
self._bind_variant_fields(
pat, renum_name, renum_entry, renum_ty,
subject_ptr, trans, pool, builder)
# 翻译 case body
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
if body_list is not None:
bc: t.CSizeT = body_list.__len__()
bi: int = 0
while bi < bc:
stmt: ast.AST | t.CPtr = body_list.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
bi = bi + 1
# 退出 case 作用域
HandlesVar.exit_scope(trans.SymTab)
# 若未终止且无 NoBreak,跳到 end
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
if nb == 0:
llvmlite.build_br(builder, end_bb)
i = i + 1
# 8. 处理 default 块
llvmlite.position_at_end(builder, default_bb)
if has_default == 0:
# 无显式 default:default 直接跳 end
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, end_bb)
else:
# 有显式 default:翻译 default case body(找到 is_def==1 的 case)
di: int = 0
while di < collected:
if def_arr[di] == 1:
dcase: ast.AST | t.CPtr = cases_list.get(di)
if dcase is not None:
dmc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(dcase)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
if dbody is not None:
dn: t.CSizeT = dbody.__len__()
dj: int = 0
while dj < dn:
stmt: ast.AST | t.CPtr = dbody.get(dj)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
dj = dj + 1
HandlesVar.exit_scope(trans.SymTab)
break
di = di + 1
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, end_bb)
# 9. 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
return 0
# ============================================================
# _bind_variant_fields - 绑定 MatchClass 的变体字段
#
# case LLVMType.Ptr(pointee) 中的 pointee 绑定到 subject 的 payload 字段
# ============================================================
def _bind_variant_fields(self, pat: ast.AST | t.CPtr,
renum_name: str,
renum_entry: HandlesStruct.StructEntry | t.CPtr,
renum_ty: llvmlite.LLVMType | t.CPtr,
subject_ptr: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr):
if pat is None or renum_entry is None or renum_ty is None:
return
mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pat)
pats: list[ast.AST | t.CPtr] | t.CPtr = mc.patterns
if pats is None:
return
# bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配)
renum_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_ty)
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, subject_ptr, renum_ptr_ty)
if casted_ptr is None:
casted_ptr = subject_ptr
pn: t.CSizeT = pats.__len__()
j: int = 0
while j < pn:
sub_pat: ast.AST | t.CPtr = pats.get(j)
if sub_pat is not None:
if sub_pat.kind() == ast.ASTKind.MatchAs:
ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(sub_pat)
bind_name: str = ma.name
if bind_name is not None:
# 按位置绑定:MatchClass 第 j 个参数 → payload 索引 j+1
# 对应 TPC HandlesMatch.py:305-306(不依赖字段名大小写匹配)
payload_idx: int = j + 1
# 字段名查找作为回退(若字段名与 MatchAs 名一致可直接命中)
if payload_idx >= renum_entry.FieldCount:
alt_idx: int = HandlesClassDef._lookup_renum_field_alias(
renum_name, bind_name)
if alt_idx >= 1:
payload_idx = alt_idx
else:
j = j + 1
continue
# 获取字段类型
fe: HandlesStruct.FieldEntry | t.CPtr = (
HandlesStruct._get_field_entry(
renum_entry, payload_idx))
field_ty: llvmlite.LLVMType | t.CPtr = None
if fe is not None:
field_ty = fe.Ty
if field_ty is None:
field_ty = llvmlite.Int8(pool)
# GEP 取字段地址
elem_ptr: llvmlite.Value | t.CPtr = (
llvmlite.build_gep_struct(
builder, renum_ty, field_ty,
casted_ptr, payload_idx))
if elem_ptr is not None:
HandlesVar.define_var(
trans.SymTab, bind_name, elem_ptr)
j = j + 1
# ============================================================
# _handle_simple_match - 非 REnum 路径
#
# subject ptrtoint 到 i32 + switch 分派
# ============================================================
def _handle_simple_match(self, node: ast.Match | t.CPtr,
subject_val: llvmlite.Value | t.CPtr) -> int:
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
stdio.printf("[MATCHDBG] _handle_simple_match entry\n")
# 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
subj_bits: int = HandlesExpr.get_llvm_type_bits(subject_val.Ty)
subj_val: llvmlite.Value | t.CPtr = subject_val
if subj_bits != 32:
if HandlesExpr.is_ptr_type(subject_val.Ty) != 0:
subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty)
elif subj_bits > 32:
# trunc 到 i32
subj_val = llvmlite.build_trunc(builder, subject_val, i32_ty)
elif subj_bits == 0:
# 未知类型,尝试 ptrtoint
subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty)
if subj_val is None:
return 0
# 2. 创建 default/end BB
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
if name_buf is None:
return 0
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "match.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
# 3. 收集 case 信息
cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases
if cases_list is None:
return 0
case_count: t.CSizeT = cases_list.__len__()
bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
return 0
collected: int = 0
has_default: int = 0
sw_head: llvmlite.SwitchCase | t.CPtr = None
sw_tail: llvmlite.SwitchCase | t.CPtr = None
sw_count: int = 0
# 4. 第一遍:收集 + 创建 BB + 构建链表
i: int = 0
while i < case_count:
case_node: ast.AST | t.CPtr = cases_list.get(i)
if case_node is None:
i = i + 1
continue
if case_node.kind() != ast.ASTKind.MatchCase:
i = i + 1
continue
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
pat: ast.AST | t.CPtr = mc.pattern
is_def: int = 0
cv: llvmlite.Value | t.CPtr = None
if pat is not None:
pk: int = pat.kind()
if pk == ast.ASTKind.MatchValue:
mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat)
cv = HandlesExpr.translate_value(
builder, pool, trans.Module, mv.value,
trans._funcs, trans._func_count, trans)
elif pk == ast.ASTKind.MatchSingleton:
ms: ast.MatchSingleton | t.CPtr = (
ast.MatchSingleton | t.CPtr)(pat)
# None -> 0
cv = llvmlite.const_int32(pool, 0)
elif pk == ast.ASTKind.MatchAs:
ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat)
if ma.pattern is None:
is_def = 1
has_default = 1
elif pk == ast.ASTKind.MatchOr:
mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat)
pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns
if pats is not None and pats.__len__() > 0:
first_pat: ast.AST | t.CPtr = pats.get(0)
if first_pat is not None:
if first_pat.kind() == ast.ASTKind.MatchValue:
mv2: ast.MatchValue | t.CPtr = (
ast.MatchValue | t.CPtr)(first_pat)
cv = HandlesExpr.translate_value(
builder, pool, trans.Module, mv2.value,
trans._funcs, trans._func_count, trans)
if is_def == 0:
if collected >= MAX_MATCH_CASES:
break
viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i)
bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
else:
bb = default_bb
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
nb: int = self._has_no_break(body_list)
if collected < MAX_MATCH_CASES:
bb_arr[collected] = t.CSizeT(bb)
cv_arr[collected] = t.CSizeT(cv)
def_arr[collected] = is_def
nb_arr[collected] = nb
collected = collected + 1
if is_def == 0 and cv is not None:
sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case(
pool, cv, bb)
if sc is not None:
if sw_head is None:
sw_head = sc
sw_tail = sc
else:
sw_tail.Next = sc
sw_tail = sc
sw_count = sw_count + 1
i = i + 1
# 5. 发射 switch
llvmlite.build_switch(builder, subj_val, default_bb, sw_head, sw_count)
# 6. 第二遍:翻译 case body
i = 0
while i < collected:
case_node: ast.AST | t.CPtr = cases_list.get(i)
if case_node is None:
i = i + 1
continue
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
bb_addr: t.CSizeT = bb_arr[i]
case_bb: llvmlite.BasicBlock | t.CPtr = (
llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr))
is_def: int = def_arr[i]
nb: int = nb_arr[i]
# default case 的 body 在 step 7 单独翻译,这里跳过避免重复
if is_def == 1:
i = i + 1
continue
llvmlite.position_at_end(builder, case_bb)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
if body_list is not None:
bc: t.CSizeT = body_list.__len__()
bi: int = 0
while bi < bc:
stmt: ast.AST | t.CPtr = body_list.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
bi = bi + 1
HandlesVar.exit_scope(trans.SymTab)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
if nb == 0:
llvmlite.build_br(builder, end_bb)
i = i + 1
# 7. default 块
llvmlite.position_at_end(builder, default_bb)
if has_default == 0:
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, end_bb)
else:
di: int = 0
while di < collected:
if def_arr[di] == 1:
dcase: ast.AST | t.CPtr = cases_list.get(di)
if dcase is not None:
dmc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(dcase)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
if dbody is not None:
dn: t.CSizeT = dbody.__len__()
dj: int = 0
while dj < dn:
stmt: ast.AST | t.CPtr = dbody.get(dj)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
dj = dj + 1
HandlesVar.exit_scope(trans.SymTab)
break
di = di + 1
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, end_bb)
# 8. 定位到 end
llvmlite.position_at_end(builder, end_bb)
return 0
# ============================================================
# NewMatchHandle - 工厂函数
# ============================================================
def NewMatchHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> MatchHandle | t.CPtr:
h: MatchHandle | t.CPtr = pool.alloc(MatchHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, MatchHandle.__sizeof__())
h.Trans = trans
return h
+86 -38
View File
@@ -5,6 +5,7 @@ import llvmlite
import memhub
import string
import stdio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
@@ -13,7 +14,8 @@ import lib.core.Handles.HandlesVar as HandlesVar
# HandlesNonlocal - nonlocal 变量访问(通过闭包 env)
#
# 闭包 env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量一个 i8* 指针)
# 指针指向原始变量(可能是 alloca 或全局变量)
# 指针指向父函数中变量的 alloca(原始存储位置),父与子共享同一存储,
# 子函数修改对父函数可见(符合 Python nonlocal 语义)。
#
# 在提升的嵌套函数中:
# 1. 函数签名: define i32 @__closure_{name}(i8* %env)
@@ -23,12 +25,32 @@ import lib.core.Handles.HandlesVar as HandlesVar
# 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
# e. %var_ptr = bitcast i8* %var_ptr_raw to <var_ty>*
# f. read: %val = load <var_ty>, <var_ty>* %var_ptr
# write: store <var_ty> %new, <var_ty>* %var_ptr
#
# 变量类型通过 HT.get_nonlocal_type() 获取(注册 nonlocal 时记录)。
# ============================================================
# ============================================================
# _is_void_type — 判断是否为 Void 类型(非法用作变量类型)
#
# 由于某些路径(如 c.DerefAs 设置的 Pointee 字段访问异常)可能导致
# 类型被设为 Void 而非 None,这里显式检测 Void 类型并视为无效,
# 回退为 i32,避免生成 "bitcast ... to void*" / "load void, void*" 的非法 IR。
# ============================================================
def _is_void_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
"""判断是否为 Void 类型,是则返回 1,否则 0"""
if ty is None:
return 0
match ty:
case llvmlite.LLVMType.Void():
return 1
case _:
return 0
# ============================================================
# 获取或创建 _env_ptr 变量(存储 env 参数的 alloca)
# ============================================================
@@ -51,13 +73,16 @@ def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
# ============================================================
# 加载 nonlocal 变量值 → 返回 i32 Value
# 从 env 加载原始变量指针(i8*)→ 调用方 bitcast 为具体类型
#
# env 直接存储 i32 值(不是指针),每个 nonlocal 变量占 4 字节
# env 存储指针数组(8 字节/槽),每个指针指向父函数的 alloca。
# ============================================================
def load_nonlocal_var(trans: HT.Translator | t.CPtr,
def _load_raw_var_ptr(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从闭包 env 加载 nonlocal 变量值(env 直接存储 i32 值)"""
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)
返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。
"""
idx: int = HT.get_nonlocal_index(trans, name)
if idx < 0:
return None
@@ -66,8 +91,7 @@ def load_nonlocal_var(trans: HT.Translator | t.CPtr,
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)
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
# 1. 加载 env_ptr
env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans)
@@ -77,51 +101,75 @@ def load_nonlocal_var(trans: HT.Translator | t.CPtr,
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)
# 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8)
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)
# 3. Bitcast to i8** and load the raw pointer
ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty)
if ptr_addr is None:
return None
return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr)
# ============================================================
# 加载 nonlocal 变量值 → 返回具体类型的 Value
#
# env 存储指向父函数 alloca 的指针,通过类型恢复 load 正确类型的值。
# ============================================================
def load_nonlocal_var(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从闭包 env 加载 nonlocal 变量值
通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。
"""
raw_ptr: llvmlite.Value | t.CPtr = _load_raw_var_ptr(trans, name)
if raw_ptr is None:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
# 获取变量类型(从注册时存储的类型信息)
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
if var_ty is None or _is_void_type(var_ty) != 0:
# Void 类型视为无效(会导致 "load void, void*" 非法 IR),回退为 i32
var_ty = llvmlite.Int32(pool)
# bitcast raw i8* to var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
if var_ptr is None:
return None
return llvmlite.build_load(builder, i32_ty, var_ptr)
return llvmlite.build_load(builder, var_ty, var_ptr)
# ============================================================
# 获取 nonlocal 变量指针(用于 store)
#
# 返回 env 中 i32 槽位的地址(i32*),用于直接 store
# 返回具体类型指针(var_ty*),用于直接 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:
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作
返回的指针指向父函数的 alloca,store 操作对父函数可见。
"""
raw_ptr: llvmlite.Value | t.CPtr = _load_raw_var_ptr(trans, name)
if raw_ptr is None:
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
# 获取变量类型
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
if var_ty is None or _is_void_type(var_ty) != 0:
# Void 类型视为无效(会导致 "bitcast ... to void*" 非法 IR),回退为 i32
var_ty = llvmlite.Int32(pool)
# 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)
# bitcast raw i8* to var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
+2 -2
View File
@@ -105,12 +105,12 @@ class ReturnHandle(HandlesBase.Mixin):
ret_is_ptr: int = HandlesExpr.is_ptr_type(ret_ty_rt)
# ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换
if val_is_ptr != ret_is_ptr:
val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt)
val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node)
elif 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)
val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node)
llvmlite.build_ret(builder, val)
return 0
+3 -2
View File
@@ -57,6 +57,7 @@ class StructEntry:
VTableMethodCount: int # 虚表中的方法数量
VTableMethods: t.CChar | t.CPtr # 虚表方法名数组(每个方法名 str,VTableMethodCount 个)
ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1(None=无 SHA1)
MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译)
# ============================================================
@@ -134,8 +135,7 @@ def is_struct_visible(name: str) -> int:
# ============================================================
def init_struct_table(pool: memhub.MemBuddy | t.CPtr) -> int:
"""初始化结构体注册表,返回 1 成功"""
global _struct_table
global _struct_count
global _struct_table, _struct_count
if _struct_table is not None:
return 1
@@ -182,6 +182,7 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr,
name: str,
struct_ty: llvmlite.LLVMType | t.CPtr,
sha1: str = None) -> StructEntry | t.CPtr:
global _struct_count
"""注册结构体类型,返回 StructEntry 指针
用类型指针去重(is 比较),不用类名去重。
+115 -6
View File
@@ -19,8 +19,10 @@ 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.HandlesMatch as HandlesMatch
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesType as HandlesType
import lib.Projectrans.Config as Config
# ============================================================
@@ -79,10 +81,19 @@ class Translator:
# nonlocal 声明的变量名集合(当前函数内)
_nonlocal_names: str
_nonlocal_name_count: t.CInt
# nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应)
# 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型
_nonlocal_types: str
# 闭包相关:当前函数名(用于嵌套函数提升命名)
_cur_func_name: str
# *args 变长参数支持:当前函数的 va_list 指针(i8* alloca)
# 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用
_va_list_ptr: llvmlite.Value | t.CPtr
# *args 参数名(如 "args"),用于符号表注册
_vararg_name: str
# 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间)
ModuleSha1: str
# 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...)
@@ -112,6 +123,7 @@ class Translator:
ForH: HandlesFor.ForHandle | t.CPtr
ExprH: HandlesExpr.ExprHandle | t.CPtr
ExprCallH: HandlesExprCall.ExprCallHandle | t.CPtr
MatchH: HandlesMatch.MatchHandle | t.CPtr
# 嵌套作用域符号表
SymTab: HandlesVar.SymbolTable | t.CPtr
@@ -132,7 +144,10 @@ class Translator:
self._global_name_count = 0
self._nonlocal_names = None
self._nonlocal_name_count = 0
self._nonlocal_types = None
self._cur_func_name = None
self._va_list_ptr = None
self._vararg_name = None
self.ModuleSha1 = None
self.CurrentPackage = None
self._closure_env_offsets = 0
@@ -150,6 +165,7 @@ class Translator:
self.ForH = None
self.ExprH = None
self.ExprCallH = None
self.MatchH = None
self.SymTab = None
# ============================================================
@@ -174,6 +190,11 @@ class Translator:
if self._nonlocal_names is not None:
string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8)
self._nonlocal_name_count = 0
# nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应)
if self._nonlocal_types is None:
self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
if self._nonlocal_types is not None:
string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8)
# 创建子 Handle(传入 self 作为 Mixin 回指针)
if self.AssignH is None:
self.AssignH = HandlesAssign.NewAssignHandle(pool, self)
@@ -191,6 +212,8 @@ class Translator:
self.WhileH = HandlesWhile.NewWhileHandle(pool, self)
if self.ForH is None:
self.ForH = HandlesFor.NewForHandle(pool, self)
if self.MatchH is None:
self.MatchH = HandlesMatch.NewMatchHandle(pool, self)
if self.ExprH is None:
self.ExprH = HandlesExpr.NewExprHandle(pool, self)
if self.ExprCallH is None:
@@ -238,6 +261,19 @@ class Translator:
llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt")
printf_func.IsVarArg = 1
# 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用)
# declare void @llvm.va_start(i8*)
# declare void @llvm.va_end(i8*)
void_ty_decl: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
va_start_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, "llvm.va_start", void_ty_decl)
if va_start_func is not None:
llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap")
va_end_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, "llvm.va_end", void_ty_decl)
if va_end_func is not None:
llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap")
# 声明 malloc(闭包分配用)
malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, "malloc", i8_ptr_ty)
@@ -307,6 +343,17 @@ class Translator:
elif kd == ast.ASTKind.ImportFrom:
self.ImportsH.HandleImportFromModule(child)
self.ImportsH.HandleImportFromNames(child)
# 扫描当前模块的 CTypedef 声明(NAME: t.CTypedef = Type),
# 注册到动态 CTypedef 表,供 resolve_annotation_type 查询
HandlesType.ScanCTypedefDeclarations(pool, tree)
# 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件,
# 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题
# 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁)
if self._imported_modules is not None:
import lib.core.StubMerger as StubMerger
StubMerger.LoadDepVpiIntoModule(
pool, mod, self._imported_modules, self._from_imports,
HandlesExprCall._g_temp_dir, self)
# 预注册模块级变量(AnnAssign/Assign)到 SymTab
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
@@ -349,13 +396,22 @@ 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
if trans._global_name_count >= MAX_GLOBAL_NAMES:
pool_err: memhub.MemBuddy | t.CPtr = trans.Pool
err_buf: str = None
if pool_err is not None:
err_buf = pool_err.alloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
VLogger.error(err_buf, "ScopeDecl")
else:
VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
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
@@ -376,23 +432,76 @@ def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int:
return 0
def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str):
"""添加一个 nonlocal 变量名"""
def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str,
var_ty: llvmlite.LLVMType | t.CPtr = None):
"""添加一个 nonlocal 变量名
Args:
name: nonlocal 变量名
var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复,
None 时回退为 i32)
"""
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:
# 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新)
# _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。
# 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致),
# [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。
if var_ty is not None and trans._nonlocal_types is not None:
idx: int = get_nonlocal_index(trans, name)
if idx >= 0:
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
ty_slot[0] = var_ty
return
if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES:
pool_err_nl: memhub.MemBuddy | t.CPtr = trans.Pool
err_buf_nl: str = None
if pool_err_nl is not None:
err_buf_nl = pool_err_nl.alloc(256)
if err_buf_nl is not None:
viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
VLogger.error(err_buf_nl, "ScopeDecl")
else:
VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
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
# 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致)
if trans._nonlocal_types is not None:
ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8
ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2)
# var_ty 为 None 时存入 i32 作为默认类型
stored_ty: llvmlite.LLVMType | t.CPtr = var_ty
if stored_ty is None:
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if pool is not None:
stored_ty = llvmlite.Int32(pool)
ty_slot2[0] = stored_ty
trans._nonlocal_name_count += 1
trans._closure_env_count += 1
def get_nonlocal_type(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.LLVMType | t.CPtr:
"""获取 nonlocal 变量的 LLVM 类型
Returns: 找到的类型指针,找不到返回 None
"""
if trans is None or name is None or trans._nonlocal_types is None:
return None
idx: int = get_nonlocal_index(trans, name)
if idx < 0:
return None
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
return (llvmlite.LLVMType | t.CPtr)(ty_slot[0])
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:
+237 -4
View File
@@ -73,6 +73,7 @@ def _get_trace_frame(i: int) -> TraceFrame | t.CPtr:
def push_trace(file_name: str, lineno: int, col_start: int = 0, col_end: int = 0):
"""压入一个翻译上下文帧(进入新的翻译作用域时调用)"""
global _g_trace_count
if _ensure_trace_init() == 0:
return
if _g_trace_count >= TRACE_MAX:
@@ -89,6 +90,7 @@ def push_trace(file_name: str, lineno: int, col_start: int = 0, col_end: int = 0
def pop_trace():
"""弹出栈顶帧(退出翻译作用域时调用)"""
global _g_trace_count
if _g_trace_count <= 0:
return
_g_trace_count -= 1
@@ -231,6 +233,208 @@ def clear_cdefine_constants() -> None:
_g_cdefine_values = None
# ============================================================
# 动态 CTypedef 表
#
# 存储 NAME: t.CTypedef = Type 定义的类型别名,
# 供 resolve_annotation_type 动态解析用户自定义 CTypedef。
# 每个模块翻译开始时由 clear_ctypedefs 清空(模块级隔离)。
# 与 CDefine 表类似,但存储类型表达式字符串而非整数。
# ============================================================
_g_ctypedef_names: list[str] | t.CPtr = None
_g_ctypedef_type_strs: list[str] | t.CPtr = None
# CTypedef 查找结果标志(区分"未找到"和"值为空字符串")
_g_ctypedef_found: int = 0
# CTypedef 递归解析深度计数器(防止无限递归)
_g_ctypedef_resolve_depth: int = 0
# CTypedef 递归解析最大深度
MAX_CTYPEDEF_DEPTH: t.CDefine = 10
# CTypedef 循环检测已访问列表(存储正在解析的 CTypedef 名)
_g_ctypedef_visiting: list[str] | t.CPtr = None
def register_ctypedef(pool: memhub.MemBuddy | t.CPtr,
name: str, type_str: str) -> None:
"""注册 CTypedef 到本地表
Args:
pool: 内存池
name: CTypedef 名称(如 "HANDLE")
type_str: 类型表达式字符串(如 "VOIDPTR" 或 "t.CVoid | t.CPtr")
"""
global _g_ctypedef_names, _g_ctypedef_type_strs
if name is None or type_str is None or pool is None:
return
if _g_ctypedef_names is None:
_g_ctypedef_names = list[str](pool, 64)
_g_ctypedef_type_strs = list[str](pool, 64)
# 去重:若已存在同名 CTypedef,更新其类型字符串
if _g_ctypedef_names is not None:
exist_n: t.CSizeT = _g_ctypedef_names.__len__()
ei: t.CSizeT
for ei in range(exist_n):
en: str = _g_ctypedef_names.get(ei)
if en is not None and string.strcmp(en, name) == 0:
# 已存在,更新类型字符串
_g_ctypedef_type_strs.set(ei, type_str)
return
_g_ctypedef_names.append(name)
_g_ctypedef_type_strs.append(type_str)
def lookup_ctypedef(name: str) -> str:
"""查找 CTypedef,返回类型表达式字符串
返回找到的类型表达式字符串,未找到返回 None。
调用方应在调用后检查 _g_ctypedef_found 标志区分"未找到"和"空字符串"。
"""
global _g_ctypedef_found
_g_ctypedef_found = 0
if name is None:
return None
if _g_ctypedef_names is None:
return None
n: t.CSizeT = _g_ctypedef_names.__len__()
i: t.CSizeT
for i in range(n):
nm: str = _g_ctypedef_names.get(i)
if nm is not None and string.strcmp(nm, name) == 0:
ts: str = _g_ctypedef_type_strs.get(i)
_g_ctypedef_found = 1
return ts
return None
def is_ctypedef_found() -> int:
"""检查上次 lookup_ctypedef 是否找到值"""
return _g_ctypedef_found
def clear_ctypedefs() -> None:
"""清空 CTypedef 表(模块切换时调用)"""
global _g_ctypedef_names, _g_ctypedef_type_strs
global _g_ctypedef_resolve_depth, _g_ctypedef_visiting
_g_ctypedef_names = None
_g_ctypedef_type_strs = None
_g_ctypedef_resolve_depth = 0
_g_ctypedef_visiting = None
def _ctypedef_push_visiting(pool: memhub.MemBuddy | t.CPtr, name: str) -> int:
"""将 CTypedef 名加入正在解析列表(循环检测)
Returns:
0=成功加入(无循环),1=检测到循环
"""
global _g_ctypedef_visiting
if name is None:
return 0
if _g_ctypedef_visiting is None:
_g_ctypedef_visiting = list[str](pool, 32)
if _g_ctypedef_visiting is None:
return 0
vn: t.CSizeT = _g_ctypedef_visiting.__len__()
vi: t.CSizeT
for vi in range(vn):
vs: str = _g_ctypedef_visiting.get(vi)
if vs is not None and string.strcmp(vs, name) == 0:
return 1 # 循环检测
_g_ctypedef_visiting.append(name)
return 0
def _ctypedef_pop_visiting() -> None:
"""从正在解析列表弹出最后一个 CTypedef 名"""
global _g_ctypedef_visiting
if _g_ctypedef_visiting is None:
return
vn: t.CSizeT = _g_ctypedef_visiting.__len__()
if vn > 0:
_g_ctypedef_visiting.pop()
def _is_ctypedef_annotation(annotation: ast.AST | t.CPtr) -> int:
"""检测类型注解是否为 t.CTypedef
Args:
annotation: 类型注解 AST 节点
Returns:
1=是 t.CTypedef,0=否
"""
if annotation is None:
return 0
if annotation.kind() != ast.ASTKind.Attribute:
return 0
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation)
if at.attr is None:
return 0
if string.strcmp(at.attr, "CTypedef") != 0:
return 0
if at.value is None or at.value.kind() != ast.ASTKind.Name:
return 0
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if mod_nm.id is None:
return 0
if string.strcmp(mod_nm.id, "t") != 0:
return 0
return 1
def ScanCTypedefDeclarations(pool: memhub.MemBuddy | t.CPtr,
tree: ast.AST | t.CPtr) -> int:
"""扫描 AST 顶层节点,注册所有 NAME: t.CTypedef = Type 声明
在 _translate_module_level 中、模块级变量预注册之前调用,
确保 CTypedef 名称在类型解析时可用。
Args:
pool: 内存池
tree: 模块 AST 根节点
Returns:
注册的 CTypedef 数量
"""
if pool is None or tree is None:
return 0
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
if ch is None:
return 0
n: t.CSizeT = ch.__len__()
count: int = 0
i: t.CSizeT
for i in range(n):
child: ast.AST | t.CPtr = ch.get(i)
if child is None:
continue
if child.kind() != ast.ASTKind.AnnAssign:
continue
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child)
# 检测注解是否为 t.CTypedef
if _is_ctypedef_annotation(aa.annotation) == 0:
continue
# 提取目标名称(必须是 Name 节点)
if aa.target is None or aa.target.kind() != ast.ASTKind.Name:
continue
tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
if tgt.id is None:
continue
# 提取类型表达式字符串(从 value AST 节点)
if aa.value is None:
continue
type_str: str = _get_type_name_from_annotation(pool, aa.value)
if type_str is None:
continue
# 注册 CTypedef
register_ctypedef(pool, tgt.id, type_str)
count += 1
return count
# 常量整数表达式计算成功标志(供 _eval_const_int_expr 使用)
_g_const_eval_ok: int = 0
@@ -1169,6 +1373,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
if node is None:
return None
global _g_ctypedef_resolve_depth
k: int = node.kind()
# Constant 节点: 字符串注解(如 'MemManager'),当作无引号的 Name/Attribute/BinOp 处理
@@ -1215,12 +1420,30 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
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)
# CTypedef 动态查表:查动态 CTypedef 表,递归解析类型表达式
# 用户自定义 CTypedef(如 MyHandle: t.CTypedef = VOIDPTR)在此解析
# 递归深度限制 MAX_CTYPEDEF_DEPTH 防止无限递归,循环检测防止 A→B→A
if _g_ctypedef_resolve_depth < MAX_CTYPEDEF_DEPTH:
ctypedef_str: str = lookup_ctypedef(nm.id)
if ctypedef_str is not None and _g_ctypedef_found != 0:
# 循环检测:将当前 CTypedef 名加入正在解析列表
if _ctypedef_push_visiting(pool, nm.id) == 0:
# 用 _parse_type_string 把类型字符串转回 AST,递归解析
inner_node: ast.AST | t.CPtr = _parse_type_string(pool, ctypedef_str, nm.ctx)
if inner_node is not None:
_g_ctypedef_resolve_depth += 1
inner_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
pool, inner_node, imported_modules, from_imports, trans)
_g_ctypedef_resolve_depth -= 1
_ctypedef_pop_visiting()
if inner_ty is not None:
return inner_ty
else:
_ctypedef_pop_visiting()
# 兜底: 尝试 map_t_type 中的硬编码 typedef 映射(VOIDPTR, HANDLE, ULONG 等)
# 这些是跨模块通用的 C typedef 名,即使 from-import 查找失败也能解析
# 注意:from-import 的结构体名若未注册,get_struct_type 已返回 None,
# 此处 map_t_type 对结构体名也返回 None,由上层 declare_only 机制延迟到下一遍
mapped_ty_fallback: llvmlite.LLVMType | t.CPtr = map_t_type(pool, nm.id)
if mapped_ty_fallback is not None:
return mapped_ty_fallback
@@ -1357,6 +1580,16 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
# 查找已特化的 struct(特化由实例化调用 list[int](pool) 触发)
gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled)
if gen_spec_ty is not None:
# 治本修复:Phase B 补译泛型特化类方法体
# Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0),
# Phase B(declare_only==0)解析字段类型命中已注册结构体时本会早返回,
# 导致方法体永远不生成 → GSList[Line].append 等符号只有 declare 无 define → 链接失败。
# 此处 Phase B 且方法体未译时,调用 _specialize_generic_class 走其已注册分支补译方法体。
if trans is not None and trans._declare_only == 0:
import lib.core.Handles.HandlesClassDef as HandlesClassDef
gen_spec_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(gen_mangled)
if gen_spec_entry is not None and gen_spec_entry.MethodsEmitted == 0:
HandlesClassDef._specialize_generic_class(trans, gen_nm.id, gen_arg_names)
return gen_spec_ty
# 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐)
# 当 trans 可用时,检查是否是泛型模板并触发特化
+22
View File
@@ -387,6 +387,28 @@ def lookup_module_var(symtab: SymbolTable | t.CPtr,
return find_var(scope.Vars, scope.VarCount, name)
# ============================================================
# is_module_scope - 判断当前是否在模块级作用域
#
# 用于区分模块级代码和函数内代码:
# - 模块级代码:AnnAssign 应修改模块级变量(Python 语义)
# - 函数内代码:无 global 声明时 AnnAssign 应创建局部变量(Python 语义)
# ============================================================
def is_module_scope(symtab: SymbolTable | t.CPtr) -> int:
"""判断当前作用域是否为模块级作用域(Current == Root)
Returns: 1=模块级作用域, 0=函数内作用域
"""
if symtab is None:
return 0
if symtab.Root is None or symtab.Current is None:
return 0
# 比较指针:Current 与 Root 相同则为模块级
if t.CUInt64T(symtab.Current) == t.CUInt64T(symtab.Root):
return 1
return 0
# ============================================================
# get_or_create_sym — 查找或创建变量(在当前作用域)
# ============================================================
+4
View File
@@ -627,6 +627,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
HandlesType.set_current_file(file_path_a)
HandlesType.set_current_module_sha1(sha1_a)
HandlesType.clear_cdefine_constants()
HandlesType.clear_ctypedefs()
HandlesStruct.reset_visible_structs(mb, 0)
ret_a: int = tr_a.translate(tree_a)
if ret_a != 0:
@@ -828,6 +829,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
HandlesType.set_current_file(gen_path)
HandlesType.set_current_module_sha1(gen_entry.Sha1)
HandlesType.clear_cdefine_constants()
HandlesType.clear_ctypedefs()
HandlesStruct.reset_visible_structs(mb, 0)
gen_tr.translate(gen_tree)
@@ -920,6 +922,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
HandlesType.set_current_file(file_path_r)
HandlesType.set_current_module_sha1(sha1_r)
HandlesType.clear_cdefine_constants()
HandlesType.clear_ctypedefs()
HandlesStruct.reset_visible_structs(mb, 0)
ret_r: int = tr_r.translate(tree_r)
if ret_r != 0:
@@ -1101,6 +1104,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
HandlesType.set_current_file(file_path)
HandlesType.set_current_module_sha1(sha1)
HandlesType.clear_cdefine_constants()
HandlesType.clear_ctypedefs()
HandlesStruct.reset_visible_structs(mb, 0)
ret: int = tr.translate(tree)
if ret != 0:
+1 -1
View File
@@ -383,7 +383,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
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)
tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir)
if tr_a is None:
continue
+174 -1
View File
@@ -17,9 +17,21 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesTranslator as HandlesTranslator
import lib.core.BuildPipeline as BuildPipeline
import lib.StubGen.VpiReader as VpiReader
import lib.Projectrans.Config as Config
# ============================================================
# _ddebug_exit - DDEBUG 拦截退出辅助函数
#
# 刷新 stderr 缓冲区并通过 VLogger 输出可见消息后退出。
# 解决 sys.exit(1) 不刷新缓冲区导致 DDEBUG 消息丢失的问题。
# ============================================================
def _ddebug_exit() -> None:
stdio.fflush(stdio.stderr)
VLogger.error("DDEBUG intercept triggered - check stderr for details")
# ============================================================
# StubMerger - stub 声明合并模块
#
@@ -365,6 +377,11 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
global _sha1_store_arr, _sha1_store_mod, _sha1_store_rel, _sha1_store_count
if scan_result is None:
return -1
# [DDEBUG] 诊断:入口输出扫描条目数
fb_ps_in: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_ps_in is not None:
viperlib.snprintf(fb_ps_in, 1024, "PopulateSha1MapStore 入口: scan_result.Count=%d MAX_INCLUDES=%d", scan_result.Count, MAX_INCLUDES)
VLogger.warning(fb_ps_in, "Reachable")
# 释放旧存储器
if _sha1_store_arr is not None:
stdlib.free(_sha1_store_arr)
@@ -382,21 +399,59 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
string.memset(_sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
_sha1_store_count = 0
entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
# [DDEBUG] 诊断:循环前输出 range 参数和 entry_size
fb_rng: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_rng is not None:
viperlib.snprintf(fb_rng, 1024, "PopulateSha1MapStore 循环前: scan_result.Count=%d entry_size_p=%d", scan_result.Count, entry_size_p)
VLogger.warning(fb_rng, "Reachable")
for i in range(scan_result.Count):
if i == 0:
# [DDEBUG] 诊断:确认循环体是否执行
fb_lp: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_lp is not None:
viperlib.snprintf(fb_lp, 1024, "PopulateSha1MapStore 进入循环体 i=0 (Count=%d)", scan_result.Count)
VLogger.warning(fb_lp, "Reachable")
if _sha1_store_count >= MAX_INCLUDES:
# [DDEBUG] 诊断:break 触发
fb_brk: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_brk is not None:
viperlib.snprintf(fb_brk, 1024, "PopulateSha1MapStore break: _sha1_store_count=%d >= MAX_INCLUDES=%d (i=%d)", _sha1_store_count, MAX_INCLUDES, i)
VLogger.warning(fb_brk, "Reachable")
break
ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p
ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
if ent is None or ent.Sha1 is None or ent.RelPath is None:
# [DDEBUG] 诊断:跳过原因
fb_sk: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_sk is not None:
if ent is None:
viperlib.snprintf(fb_sk, 1024, "PopulateSha1MapStore 跳过[%d]: ent=None", i)
elif ent.Sha1 is None:
viperlib.snprintf(fb_sk, 1024, "PopulateSha1MapStore 跳过[%d]: Sha1=None", i)
else:
viperlib.snprintf(fb_sk, 1024, "PopulateSha1MapStore 跳过[%d]: RelPath=None", i)
VLogger.warning(fb_sk, "Reachable")
continue
# 构建完整路径 includes/{RelPath}(_PathToModuleName 需要)
rp_len: t.CSizeT = string.strlen(ent.RelPath)
full_path_buf: bytes = stdlib.malloc(rp_len + 10)
if full_path_buf is None:
# [DDEBUG] 诊断:malloc 返回 None 判断
if i < 3:
fb_fp: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_fp is not None:
viperlib.snprintf(fb_fp, 1024, "PopulateSha1MapStore 跳过[%d]: full_path_buf is None (rp_len=%d)", i, rp_len)
VLogger.warning(fb_fp, "Reachable")
continue
viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath)
mod_name: str = _PathToModuleName(full_path_buf)
stdlib.free(full_path_buf)
if mod_name is None:
# [DDEBUG] 诊断:_PathToModuleName 失败
fb_pn: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_pn is not None:
viperlib.snprintf(fb_pn, 1024, "PopulateSha1MapStore 跳过[%d]: _PathToModuleName 返回 None (RelPath=%s)", i, ent.RelPath)
VLogger.warning(fb_pn, "Reachable")
if mod_name is not None:
idx: t.CSizeT = t.CSizeT(_sha1_store_count) * 17
string.strcpy(_sha1_store_arr + idx, ent.Sha1)
@@ -416,6 +471,17 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
string.strncpy(_sha1_store_rel + idx3, ent.RelPath, MAX_REL_PATH_LEN - 1)
_sha1_store_rel[idx3 + MAX_REL_PATH_LEN - 1] = '\0'
_sha1_store_count += 1
# [DDEBUG] 诊断:+= 后的 count(确认是否写入全局)
if i < 3:
fb_inc: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_inc is not None:
viperlib.snprintf(fb_inc, 1024, "PopulateSha1MapStore 填充[%d]: _sha1_store_count=%d", i, _sha1_store_count)
VLogger.warning(fb_inc, "Reachable")
# [DDEBUG] 诊断:出口输出最终计数
fb_ps_out: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_ps_out is not None:
viperlib.snprintf(fb_ps_out, 1024, "PopulateSha1MapStore 出口: _sha1_store_count=%d", _sha1_store_count)
VLogger.warning(fb_ps_out, "Reachable")
return _sha1_store_count
@@ -526,6 +592,11 @@ def LookupSha1ByModName(mod_name: str) -> str:
idx_em: t.CSizeT = t.CSizeT(i_em) * 64
if string.strcmp(_sha1_store_mod + idx_em, mod_name) == 0:
sidx_em: t.CSizeT = t.CSizeT(i_em) * 17
# DDEBUG: 检测存储的 sha1 是否带尾随点(长度>=17),发现问题立即终止
_ck_len: t.CSizeT = string.strlen(_sha1_store_arr + sidx_em)
if _ck_len >= 17:
stdio.printf("[DDEBUG] StubMerger sha1 too long: len=%d sha1='%s' mod='%s'\n", _ck_len, _sha1_store_arr + sidx_em, mod_name)
_ddebug_exit()
return _sha1_store_arr + sidx_em
# 第二遍:包名回退("ast" → "ast.__init__")
nm_len_em: t.CSizeT = string.strlen(mod_name)
@@ -1352,6 +1423,21 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。
数据来源是 PopulateSha1MapStore 填充的全局存储器。
"""
# [DDEBUG] 诊断:入口输出全局存储器状态(区分填充失败/读取失败)
fb_bim: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_bim is not None:
viperlib.snprintf(fb_bim, 1024, "_BuildIncludesSha1Map 入口: _sha1_store_count=%d", _sha1_store_count)
VLogger.warning(fb_bim, "Reachable")
if _sha1_store_arr is None:
fb_na: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_na is not None:
viperlib.snprintf(fb_na, 1024, "_BuildIncludesSha1Map: _sha1_store_arr is None")
VLogger.warning(fb_na, "Reachable")
if _sha1_store_mod is None:
fb_nm: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_nm is not None:
viperlib.snprintf(fb_nm, 1024, "_BuildIncludesSha1Map: _sha1_store_mod is None")
VLogger.warning(fb_nm, "Reachable")
if sha1_list is None or mod_list is None:
return 0
if _sha1_store_arr is None or _sha1_store_mod is None:
@@ -1994,7 +2080,7 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
if fb is not None:
viperlib.snprintf(fb, 1024, "依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译", mod_nm, found_s, chk_path)
VLogger.error(fb, "BuildCombinedIR")
sys.exit(1)
_ddebug_exit()
chk_f.close()
stdlib.free(chk_path)
stdlib.free(mod_nm)
@@ -2129,3 +2215,90 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
stdlib.free(mod_arr)
return out_pos
# ============================================================
# LoadDepVpiIntoModule - 加载依赖模块的 .vpi 文件,注入 declare 到当前模块
#
# 遍历 imported_modules(空格分隔的模块名),对每个模块:
# 1. 用 LookupSha1ByModName 获取 SHA1
# 2. 用 _sliced_path 构造 .vpi 文件路径
# 3. 调用 VpiReader.ParseVpiIntoModule 解析 .vpi 并注入 declare
#
# 在 _translate_module_level 中、Import 处理完成后、translate_children
# 之前调用,确保跨模块函数调用时 declare 已存在。
#
# Args:
# pool: 内存池
# mod: 当前 LLVM 模块
# imported_modules: 已导入模块名字符串(空格分隔)
# from_imports: from-import 映射字符串("name:module name:module" 格式)
# temp_dir: temp 目录路径
# trans: 翻译器对象
#
# Returns:
# 成功加载的 .vpi 文件数
# ============================================================
def LoadDepVpiIntoModule(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
imported_modules: str,
from_imports: str,
temp_dir: str,
trans: HandlesTranslator.Translator | t.CPtr) -> int:
"""加载依赖模块的 .vpi 文件,将函数声明注入到当前模块"""
if pool is None or mod is None or temp_dir is None or trans is None:
return 0
if imported_modules is None:
return 0
td_len: t.CSizeT = string.strlen(temp_dir)
total_len: t.CSizeT = string.strlen(imported_modules)
success_count: int = 0
# 遍历 imported_modules 中的每个模块名(空格分隔)
ci: t.CSizeT = 0
while ci < total_len:
# 跳过前导空格
while ci < total_len and imported_modules[ci] == ' ':
ci += 1
if ci >= total_len:
break
# 提取模块名(到下一个空格或字符串末尾)
word_start: t.CSizeT = ci
while ci < total_len and imported_modules[ci] != ' ':
ci += 1
word_len: t.CSizeT = ci - word_start
if word_len == 0:
continue
# 复制模块名到临时缓冲区并 null 终止
mod_nm_buf: str = stdlib.malloc(word_len + 1)
if mod_nm_buf is None:
continue
string.strncpy(mod_nm_buf, imported_modules + word_start, word_len)
mod_nm_buf[word_len] = '\0'
# 用 LookupSha1ByModName 查找模块的 SHA1
sha1_val: str = LookupSha1ByModName(mod_nm_buf)
# 如果精确查找失败,尝试包名回退(如 "ast" → "ast.__init__")
# LookupSha1ByModName 内部已处理包名回退,此处无需重复
if sha1_val is not None:
# 构造 .vpi 文件路径
vpi_path: str = _sliced_path(temp_dir, td_len, sha1_val, "vpi")
if vpi_path is not None:
# 检查 .vpi 文件是否存在(可读)
vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R)
if not vf.closed:
vf.close()
# 调用 VpiReader 解析 .vpi 并注入 declare
ret: int = VpiReader.ParseVpiIntoModule(pool, mod, vpi_path, trans)
if ret == 1:
success_count += 1
stdlib.free(vpi_path)
# sha1_val 指向内部存储,无需 free
stdlib.free(mod_nm_buf)
return success_count
+28 -1
View File
@@ -62,7 +62,7 @@ def main() -> int:
# 设置全局 mbuddy 指针(sys 和 argparse 都需要)
sys._mbuddy = mb
argparse._mbuddy = mb
ast._mbuddy = mb
ast._mbuddy = (memhub.MemBuddy | t.CPtr)(mb)
lib._mbuddy = (memhub.MemBuddy | t.CPtr)(mb)
Config._mbuddy = (memhub.MemBuddy | t.CPtr)(mb)
Utils._mbuddy = (memhub.MemBuddy | t.CPtr)(mb)
@@ -255,6 +255,33 @@ def main() -> int:
viperlib.snprintf(fb3, 1024, "%s: 删除 %d 个文件", mf_inc_bin_clean, n3)
log.info(fb3, "clean")
# === --rebuild-includes: 删除 includes.binary 预编译缓存 ===
# 强制下次编译时重新编译所有 includes(不清 temp/output)
if args.get_bool("rebuild-includes"):
if log is not None:
log.info("重建 includes 缓存...", "rebuild-includes")
mf_inc_bin_rb: str = Config.get_includes_binary_dir()
if mf_inc_bin_rb is not None:
n_rb: int = Utils.CleanDir(mf_inc_bin_rb)
if log is not None:
fb_rb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_rb is not None:
viperlib.snprintf(fb_rb, 1024, "%s: 删除 %d 个文件(includes 将重新编译)", mf_inc_bin_rb, n_rb)
log.info(fb_rb, "rebuild-includes")
# === --clear-cache: 清除 temp 目录缓存(.vpi/.stub.ll/.text.ll) ===
# 强制下次 Phase1 重新生成 stub(不清 output/includes.binary)
if args.get_bool("clear-cache"):
if log is not None:
log.info("清除 temp 缓存...", "clear-cache")
if Config.TempDir is not None:
n_cc: int = Utils.CleanDir(Config.TempDir)
if log is not None:
fb_cc: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cc is not None:
viperlib.snprintf(fb_cc, 1024, "%s: 删除 %d 个文件(.vpi/.stub.ll 缓存)", Config.TempDir, n_cc)
log.info(fb_cc, "clear-cache")
# === --phase 参数控制 ===
# phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译
# phase=2: 仅 stub 合并 + 编译(跳过 stub 分离)
+12 -1
View File
@@ -25,15 +25,25 @@ _NMATCH_POOL_SIZE: t.CDefine = 65536
def _init_mbuddy() -> int:
"""初始化内存池,返回 0=成功, 1=失败"""
global _mbuddy
stdio.printf("[DBG] _init_mbuddy: start\n")
arena: bytes = stdlib.malloc(_NMATCH_POOL_SIZE)
stdio.printf("[DBG] _init_mbuddy: malloc arena=%d\n", arena is None)
if arena is None:
stdio.printf("FAIL: malloc for arena failed\n")
return 1
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, _NMATCH_POOL_SIZE)
mb: memhub.MemBuddy | t.CPtr = stdlib.malloc(memhub.MemBuddy.__sizeof__())
stdio.printf("[DBG] _init_mbuddy: malloc mb=%d\n", mb is None)
if mb is None:
stdio.printf("FAIL: MemBuddy init failed\n")
return 1
stdio.printf("[DBG] _init_mbuddy: before_init\n")
mb.__before_init__()
stdio.printf("[DBG] _init_mbuddy: init\n")
mb.__init__(arena, t.CSizeT(_NMATCH_POOL_SIZE))
stdio.printf("[DBG] _init_mbuddy: store\n")
_mbuddy = mb
stdio.printf("[DBG] _init_mbuddy: done\n")
return 0
@@ -42,6 +52,7 @@ def test_single_match() -> int:
stdio.printf("--- Test 1: 单层 match LLVMType ---\n")
ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(_mbuddy)
stdio.printf("[DBG] Int32 done: %d\n", ty is None)
if ty is None:
stdio.printf("FAIL: Int32 returned None\n")
return 1