修正了逻辑,使 TPV 可以编译 Test,但自举还有一段距离
This commit is contained in:
1 parent
9dcf34599d
commit
a3b9bdc409
25 files changed
+9125
-6478
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 语句
|
||||
# ============================================================
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
+5827
-5367
File diff suppressed because it is too large.
Load diff
@@ -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
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 比较),不用类名去重。
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 可用时,检查是否是泛型模板并触发特化
|
||||
|
||||
@@ -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 — 查找或创建变量(在当前作用域)
|
||||
# ============================================================
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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 分离)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user