修正了一些错误

This commit is contained in:
2026-07-26 20:33:17 +08:00
parent 909792bc8f
commit 03d0bba534
40 changed files with 6939 additions and 827 deletions

View File

@@ -12,6 +12,7 @@ import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesStruct as HandlesStruct
# ============================================================
@@ -62,6 +63,64 @@ def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
return cn.int_val
# ============================================================
# _annotation_contains_name - 递归检查注解中是否包含指定名称
#
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
# ============================================================
def _annotation_contains_name(annot: ast.AST | t.CPtr, name: str) -> int:
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含"""
if annot is None or name is None:
return 0
k: int = annot.kind()
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
if at.attr is not None and string.strcmp(at.attr, name) == 0:
return 1
return 0
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
if nm.id is not None and string.strcmp(nm.id, name) == 0:
return 1
return 0
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
if _annotation_contains_name(bop.left, name) != 0:
return 1
if _annotation_contains_name(bop.right, name) != 0:
return 1
return 0
# ============================================================
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
#
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
#
# 规则:
# bytes|t.CPtr / str|t.CPtr → i8**8 字节步长)→ 返回 1
# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*1 字节步长)→ 返回 0
# 纯 bytes / str → i8*1 字节步长)→ 返回 0
#
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
# ============================================================
def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int:
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式"""
if annot is None:
return 0
k: int = annot.kind()
if k != ast.ASTKind.BinOp:
return 0
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
if bop.op != ast.OpKind.BitOr:
return 0
if _annotation_contains_name(annot, "str") != 0:
return 1
if _annotation_contains_name(annot, "bytes") != 0:
return 1
return 0
@t.NoVTable
class AnnAssignHandle(HandlesBase.Mixin):
"""AnnAssign 语句处理器:继承 Mixin 获得 Trans 回指针"""
@@ -121,7 +180,7 @@ class AnnAssignHandle(HandlesBase.Mixin):
annot: ast.AST | t.CPtr = aa.annotation
if annot is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
if resolved is None:
# 尝试特化泛型类注解(如 list[str]
# resolve_annotation_type 返回 None 可能是因为泛型类未特化
@@ -138,11 +197,13 @@ class AnnAssignHandle(HandlesBase.Mixin):
self.Trans, sub_nm.id, type_args_ps)
if spec_name_ps is not None:
resolved = HandlesType.resolve_annotation_type(
pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
if resolved is not None:
var_ty = resolved
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, var_ty)
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
HandlesStruct.ensure_struct_def_in_module(pool, self.Trans.Module, var_ty)
alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, var_ty)
if alloca is not None:
if HandlesVar.define_var(
self.Trans.SymTab, nm.id, alloca) == 0:
@@ -153,6 +214,10 @@ class AnnAssignHandle(HandlesBase.Mixin):
if cls_nm_ps is not None:
HandlesVar.set_var_annot_class_name(
self.Trans.SymTab, nm.id, cls_nm_ps)
# 检查是否为 bytes|t.CPtr 或 str|t.CPtri8** 语义8 字节步长)
if _is_ptr_element_annotation(annot) != 0:
HandlesVar.set_var_ptr_element(
self.Trans.SymTab, nm.id)
return 0
return 0
@@ -193,7 +258,7 @@ class AnnAssignHandle(HandlesBase.Mixin):
annot: ast.AST | t.CPtr = aa.annotation
if annot is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
if resolved is not None:
var_ty = resolved
@@ -243,6 +308,10 @@ class AnnAssignHandle(HandlesBase.Mixin):
if cls_nm_hd is not None:
HandlesVar.set_var_annot_class_name(
self.Trans.SymTab, nm.id, cls_nm_hd)
# 检查是否为 bytes|t.CPtr 或 str|t.CPtri8** 语义8 字节步长)
if _is_ptr_element_annotation(annot) != 0:
HandlesVar.set_var_ptr_element(
self.Trans.SymTab, nm.id)
new_vars: int = 0
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(

View File

@@ -6,6 +6,7 @@ import memhub
import string
import stdio
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
@@ -44,12 +45,12 @@ class AssignHandle(HandlesBase.Mixin):
def Handle(self, node: ast.AST | t.CPtr) -> int:
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
if asgn is None:
stdio.printf("[ASGN] cast failed\n")
VLogger.error("cast failed", "ASGN")
return 0
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
if targets is None:
stdio.printf("[ASGN] targets is None\n")
VLogger.error("targets is None", "ASGN")
return 0
# 从 self.Trans 取共享状态(替代 11 个参数)
@@ -61,7 +62,23 @@ class AssignHandle(HandlesBase.Mixin):
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, asgn.value, None, 0, self.Trans)
if rhs_val is None:
stdio.printf("[ASGN] rhs_val is None\n")
# 增强错误信息:包含 sha1 + lineno + AST 节点类型,便于定位
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None and asgn.value is not None:
sha1: str = self.Trans.ModuleSha1
val_kind: int = asgn.value.kind()
val_line: t.CInt = asgn.value.lineno
if sha1 is not None:
viperlib.snprintf(fb, 1024,
"rhs_val is None [sha1=%s lineno=%d kind=%d]",
sha1, val_line, val_kind)
else:
viperlib.snprintf(fb, 1024,
"rhs_val is None [lineno=%d kind=%d]",
val_line, val_kind)
VLogger.error(fb, "ASGN")
else:
VLogger.error("rhs_val is None", "ASGN")
return 0
new_vars: int = 0
@@ -116,23 +133,115 @@ class AssignHandle(HandlesBase.Mixin):
sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee
if sub_pointee is not None:
cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee)
if cls_nm_set is not None:
obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, sub_pointee, sub_alloca)
if obj_val_set is not None:
key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
if key_val_set is not None:
arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16)
if arg_vals_set is not None:
arg_vals_set[0] = t.CSizeT(key_val_set)
arg_vals_set[1] = t.CSizeT(rhs_val)
HandlesExprCall._call_method_on_ptr(
pool, builder, mod, cls_nm_set, "__setitem__",
obj_val_set, arg_vals_set, 2, self.Trans)
setitem_done = 1
obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, sub_pointee, sub_alloca)
# 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct),
# 需 load 获取 Ptr(Struct) 再检查 inner struct
if cls_nm_set is None and obj_val_set is not None:
if HandlesExpr.is_ptr_type(sub_pointee) != 0:
inner_ty_set: llvmlite.LLVMType | t.CPtr = sub_pointee.Pointee
if inner_ty_set is not None:
cls_nm_set = HandlesStruct.get_class_name_by_type(pool, inner_ty_set)
if cls_nm_set is not None and obj_val_set is not None:
key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
if key_val_set is not None:
arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16)
if arg_vals_set is not None:
arg_vals_set[0] = t.CSizeT(key_val_set)
arg_vals_set[1] = t.CSizeT(rhs_val)
HandlesExprCall._call_method_on_ptr(
pool, builder, mod, cls_nm_set, "__setitem__",
obj_val_set, arg_vals_set, 2, self.Trans)
setitem_done = 1
elif sub_asgn.value.kind() == ast.ASTKind.Attribute:
# self._ht[key] = val → self._ht.__setitem__(key, val)
# 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__
field_ptr_set: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, sub_asgn.value, self.Trans)
if field_ptr_set is not None and field_ptr_set.Ty is not None:
if HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0:
field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee
if field_pointee_set is not None:
cls_nm_attr: str = HandlesStruct.get_class_name_by_type(pool, field_pointee_set)
obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set
# field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段):
# load 解引用获取 Ptr(Struct)
if cls_nm_attr is None and HandlesExpr.is_ptr_type(field_pointee_set) != 0:
inner_struct_attr: llvmlite.LLVMType | t.CPtr = field_pointee_set.Pointee
if inner_struct_attr is not None:
cls_nm_attr = HandlesStruct.get_class_name_by_type(pool, inner_struct_attr)
if cls_nm_attr is not None:
obj_val_attr = llvmlite.build_load(
builder, field_pointee_set, field_ptr_set)
if cls_nm_attr is not None and obj_val_attr is not None:
key_val_attr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
if key_val_attr is not None:
arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16)
if arg_vals_attr is not None:
arg_vals_attr[0] = t.CSizeT(key_val_attr)
arg_vals_attr[1] = t.CSizeT(rhs_val)
HandlesExprCall._call_method_on_ptr(
pool, builder, mod, cls_nm_attr, "__setitem__",
obj_val_attr, arg_vals_attr, 2, self.Trans)
setitem_done = 1
if setitem_done == 0:
HandlesType.fatal_error(target, "subscript ptr is None")
# 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store
# 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况
if sub_asgn is not None and sub_asgn.value is not None:
obj_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.value, None, 0, self.Trans)
key_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
if obj_val_gen is not None and key_val_gen is not None \
and obj_val_gen.Ty is not None:
# 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数)
cls_nm_gen: str = HandlesStruct.get_class_name_by_type(
pool, obj_val_gen.Ty)
if cls_nm_gen is None and HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0:
inner_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
if inner_gen is not None:
cls_nm_gen = HandlesStruct.get_class_name_by_type(pool, inner_gen)
if cls_nm_gen is not None:
# 自定义结构体: 调用 __setitem__
arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16)
if arg_vals_gen is not None:
arg_vals_gen[0] = t.CSizeT(key_val_gen)
arg_vals_gen[1] = t.CSizeT(rhs_val)
HandlesExprCall._call_method_on_ptr(
pool, builder, mod, cls_nm_gen, "__setitem__",
obj_val_gen, arg_vals_gen, 2, self.Trans)
setitem_done = 1
else:
# 非自定义结构体: 直接 GEP + store
# 处理 get_subscript_ptr 因边界情况返回 None 的指针下标
if HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0:
elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
if elem_gen is not None:
store_val_gen: llvmlite.Value | t.CPtr = rhs_val
elem_ptr_gen: llvmlite.Value | t.CPtr = None
match elem_gen:
case llvmlite.LLVMType.Array(arr_elem_gen, _):
elem_ptr_gen = llvmlite.build_gep_array(
builder, elem_gen, arr_elem_gen,
obj_val_gen, key_val_gen)
case _:
elem_ptr_gen = llvmlite.build_gep(
builder, elem_gen, obj_val_gen, key_val_gen)
if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None:
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)
llvmlite.build_store(builder, store_val_gen, elem_ptr_gen)
setitem_done = 1
if setitem_done == 0:
sub_vk: int = sub_asgn.value.kind()
stdio.printf("[ASGN-SUB] fallback failed: val_kind=%d\n", sub_vk)
stdio.fflush(0)
if setitem_done == 0:
HandlesType.fatal_error(target, "subscript ptr is None")
continue
# Attribute 赋值: obj.field = val
@@ -140,14 +249,25 @@ class AssignHandle(HandlesBase.Mixin):
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, target, self.Trans)
if field_ptr is not None:
stdio.printf("[ASGN-ATTR] field_ptr ok ty_not_null=%d\n",
1 if field_ptr.Ty is not None else 0)
stdio.fflush(0)
# 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64
store_val: llvmlite.Value | t.CPtr = rhs_val
if field_ptr.Ty is not None:
field_ty: llvmlite.LLVMType | t.CPtr = field_ptr.Ty.Pointee
if field_ty is not None:
stdio.printf("[ASGN-ATTR] coerce rhs_ty=%d field_ty=%d\n",
HandlesExpr.get_llvm_type_bits(rhs_val.Ty),
HandlesExpr.get_llvm_type_bits(field_ty))
stdio.fflush(0)
store_val = HandlesExpr.coerce_to_type(
builder, rhs_val, field_ty)
stdio.printf("[ASGN-ATTR] pre_store\n")
stdio.fflush(0)
llvmlite.build_store(builder, store_val, field_ptr)
stdio.printf("[ASGN-ATTR] post_store\n")
stdio.fflush(0)
else:
# 构造详细错误信息
attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
@@ -213,7 +333,10 @@ class AssignHandle(HandlesBase.Mixin):
if existing is None:
new_vars += 1
else:
stdio.printf("[ASGN] alloca failed for %s\n", nm.id)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "alloca failed for %s", nm.id)
VLogger.error(fb, "ASGN")
return new_vars

View File

@@ -5,6 +5,8 @@ import llvmlite
import memhub
import stdio
import string
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
@@ -58,7 +60,7 @@ class AugAssignHandle(HandlesBase.Mixin):
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, target, self.Trans)
if field_ptr is None:
stdio.printf("[AUGASGN] attribute ptr is None\n")
VLogger.error("attribute ptr is None", "AUGASGN")
return 0
# 2. 确定字段类型并加载当前值
@@ -68,21 +70,24 @@ class AugAssignHandle(HandlesBase.Mixin):
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, target_ty, field_ptr)
if cur_val is None:
stdio.printf("[AUGASGN] cannot load attribute\n")
VLogger.error("cannot load attribute", "AUGASGN")
return 0
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
stdio.printf("[AUGASGN] rhs is None\n")
VLogger.error("rhs is None", "AUGASGN")
return 0
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val)
if result is None:
stdio.printf("[AUGASGN] binop failed for attr op=%d\n", aug.op)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "binop failed for attr op=%d", aug.op)
VLogger.error(fb, "AUGASGN")
return 0
# 5. 类型对齐并存储
@@ -92,8 +97,56 @@ class AugAssignHandle(HandlesBase.Mixin):
llvmlite.build_store(builder, result, field_ptr)
return 0
# Subscript 目标: self.state[i] += x / arr[i] += x
# 流程: get_subscript_ptr → load → binop → store
if tk == ast.ASTKind.Subscript:
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
# 1. 获取元素指针
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
builder, pool, mod, target, self.Trans)
if elem_ptr is None:
VLogger.error("subscript ptr is None", "AUGASGN")
return 0
# 2. 确定元素类型并加载当前值
target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
target_ty = elem_ptr.Ty.Pointee
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, target_ty, elem_ptr)
if cur_val is None:
VLogger.error("cannot load subscript element", "AUGASGN")
return 0
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
VLogger.error("rhs is None", "AUGASGN")
return 0
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val)
if result is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "binop failed for sub op=%d", aug.op)
VLogger.error(fb, "AUGASGN")
return 0
# 5. 类型对齐并存储
result = HandlesExpr.coerce_to_type(builder, result, target_ty)
if result is None:
return 0
llvmlite.build_store(builder, result, elem_ptr)
return 0
if tk != ast.ASTKind.Name:
stdio.printf("[AUGASGN] only Name/Attribute target supported\n")
VLogger.error("only Name/Attribute/Subscript target supported", "AUGASGN")
return 0
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
@@ -139,14 +192,17 @@ class AugAssignHandle(HandlesBase.Mixin):
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
if cur_val is None:
stdio.printf("[AUGASGN] cannot load target %s\n", nm.id)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "cannot load target %s", nm.id)
VLogger.error(fb, "AUGASGN")
return 0
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
stdio.printf("[AUGASGN] rhs is None\n")
VLogger.error("rhs is None", "AUGASGN")
return 0
# 4. 类型对齐 + 应用二元运算
@@ -154,7 +210,10 @@ class AugAssignHandle(HandlesBase.Mixin):
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val)
if result is None:
stdio.printf("[AUGASGN] binop failed for op=%d\n", aug.op)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "binop failed for op=%d", aug.op)
VLogger.error(fb, "AUGASGN")
return 0
# 5. 存储结果
@@ -226,6 +285,8 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
return llvmlite.build_mul(builder, lhs, rhs)
elif op == ast.OpKind.Div:
return llvmlite.build_sdiv(builder, lhs, rhs)
elif op == ast.OpKind.FloorDiv:
return llvmlite.build_sdiv(builder, lhs, rhs)
elif op == ast.OpKind.Mod:
return llvmlite.build_srem(builder, lhs, rhs)
elif op == ast.OpKind.BitAnd:

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,8 @@ import memhub
import string
import llvmlite
import stdio
import viperlib
import lib.core.VLogger as VLogger
# ============================================================
@@ -110,7 +112,10 @@ def register_enum(pool: memhub.MemBuddy | t.CPtr,
return existing
if _enum_count >= ENUM_MAX:
stdio.printf("[ENUM] table full, cannot register %s\n", name)
fb_et: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_et is not None:
viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name)
VLogger.error(fb_et, "ENUM")
return None
entry: EnumEntry | t.CPtr = _get_enum_entry(_enum_count)
@@ -151,7 +156,10 @@ def add_enum_member(pool: memhub.MemBuddy | t.CPtr,
return -1
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
stdio.printf("[ENUM] member table full for %s\n", enum_entry.Name)
fb_em: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_em is not None:
viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name)
VLogger.error(fb_em, "ENUM")
return -1
idx: int = enum_entry.MemberCount

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -272,6 +272,8 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr,
return llvmlite.build_mul(builder, lhs, rhs)
elif op == ast.OpKind.Div:
return llvmlite.build_sdiv(builder, lhs, rhs)
elif op == ast.OpKind.FloorDiv:
return llvmlite.build_sdiv(builder, lhs, rhs)
elif op == ast.OpKind.Mod:
return llvmlite.build_srem(builder, lhs, rhs)
elif op == ast.OpKind.BitAnd:

View File

@@ -138,7 +138,7 @@ class ForHandle(HandlesBase.Mixin):
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = llvmlite.build_alloca(builder, i32_ty)
var_alloca = HandlesVar._alloca_at_entry(builder, i32_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
@@ -294,13 +294,13 @@ class ForHandle(HandlesBase.Mixin):
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = llvmlite.build_alloca(builder, elem_ty)
var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 创建隐式 index 变量,初始为 0
idx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i32_ty)
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty)
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
# 创建基本块: cond / body / incr / end

View File

@@ -7,6 +7,7 @@ import string
import viperlib
import stdio
import stdlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprCall as HandlesExprCall
@@ -17,6 +18,10 @@ import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesImports as HandlesImports
# 作用域类型常量(本地副本,避免旧编译器跨模块 CDefine 查找 bug
SCOPE_FUNCTION: t.CDefine = 1
# ============================================================
# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性
#
@@ -311,7 +316,7 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr,
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)
pool, fd.returns, imported_modules, from_imports, trans)
if ret_ty is None and fd.returns is not None:
if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
ret_ty = llvmlite.Void(pool)
@@ -347,10 +352,24 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr,
if func is None:
continue
# 提取默认参数信息
fd_args_node: ast.Arguments | t.CPtr = fd.args
fd_defaults: t.CVoid | t.CPtr = None
fd_default_count: int = 0
fd_param_count: int = 0
if fd_args_node is not None:
fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node)
if fd_ags.args is not None:
fd_param_count = fd_ags.args.__len__()
if fd_ags.defaults is not None:
fd_defaults = fd_ags.defaults
fd_default_count = fd_ags.defaults.__len__()
# 注册到函数表(用裸名 fd.name不是 mangled_name
max_funcs: int = 256
cur_count: int = trans._func_count
if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs) == 0:
if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs,
fd_defaults, fd_default_count, fd_param_count) == 0:
trans._func_count = cur_count + 1
# 注册 CExport 函数到全局表
@@ -375,7 +394,7 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr,
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports)
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
@@ -412,7 +431,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
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)
pool, fd.returns, imported_modules, from_imports, trans)
# 如果返回类型注解纯装饰器标记(如 t.State无实际类型使用 void
# 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32
@@ -490,7 +509,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty
if arg_e.annotation is not None:
resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg_e.annotation, imported_modules, from_imports)
pool, arg_e.annotation, imported_modules, from_imports, trans)
if resolved_e is not None:
param_ty_e = resolved_e
pname_e: t.CChar | t.CPtr = pool.alloc(32)
@@ -521,7 +540,10 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
if func is None:
stdio.printf("[FUNC] create_function %s failed\n", fd.name)
fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cf is not None:
viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name)
VLogger.error(fb_cf, "FUNC")
return 0
# 提取 @c.Attribute 装饰器属性并设置到函数
@@ -529,9 +551,22 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
if func_attrs is not None:
llvmlite.function_set_attrs(func, func_attrs)
# 提取默认参数信息
tfd_defaults: t.CVoid | t.CPtr = None
tfd_default_count: int = 0
tfd_param_count: int = 0
if args_node is not None:
tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
if tfd_ags.args is not None:
tfd_param_count = tfd_ags.args.__len__()
if tfd_ags.defaults is not None:
tfd_defaults = tfd_ags.defaults
tfd_default_count = tfd_ags.defaults.__len__()
# 注册到函数表
max_funcs: int = 256
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs) == 0:
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs,
tfd_defaults, tfd_default_count, tfd_param_count) == 0:
trans._func_count = func_count + 1
# 添加参数(支持类型注解)
@@ -550,7 +585,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports)
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
@@ -569,7 +604,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
llvmlite.position_at_end(func_builder, entry_blk)
# 进入函数作用域(嵌套符号表)
HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION)
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
# 为参数创建 alloca
if args_node is not None:
@@ -587,7 +622,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty
if arg2.annotation is not None:
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg2.annotation, imported_modules, from_imports)
pool, arg2.annotation, imported_modules, from_imports, trans)
if resolved2 is not None:
param_ty2 = resolved2
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
@@ -633,6 +668,8 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
for bi2 in range(bn2):
stmt2: ast.AST | t.CPtr = body.get(bi2)
if stmt2 is not None:
stdio.printf("[DBG] TR body stmt=%d kind=%d\n", bi2, stmt2.kind())
stdio.fflush(0)
HandlesBody.translate_stmt(trans, stmt2)
# 如果函数体最后一条语句不是 Return添加隐式 ret
@@ -644,8 +681,24 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
last_is_return = 1
if last_is_return == 0:
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(func_builder, zero_val)
if llvmlite.builder_cur_block_is_terminated(func_builder) == 0:
# 根据返回类型生成正确的零值返回
_is_void: int = 0
_is_ptr: int = 0
if ret_ty is not None:
match ret_ty:
case llvmlite.LLVMType.Void():
_is_void = 1
case llvmlite.LLVMType.Ptr(_pe):
_is_ptr = 1
if _is_void != 0:
llvmlite.build_ret_void(func_builder)
elif _is_ptr != 0:
_null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
llvmlite.build_ret(func_builder, _null_val)
else:
_zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(func_builder, _zero_val)
# 恢复模块级作用域(退出函数作用域)
HandlesVar.exit_scope(trans.SymTab)
@@ -706,7 +759,7 @@ def translate_nested_function_def(trans: HT.Translator | t.CPtr,
llvmlite.position_at_end(func_builder, entry_blk)
# 4. 进入嵌套函数作用域(嵌套符号表)
HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION)
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
# 5. 创建 _env_ptr alloca 并存储 %env 参数
env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty)
@@ -927,7 +980,7 @@ def create_function(pool: memhub.MemBuddy | t.CPtr,
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if arg.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, None, None)
pool, arg.annotation, None, None, None)
if resolved is not None:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)

View File

@@ -3,6 +3,7 @@ from stdint import *
import ast
import memhub
import string
import stdlib
import viperlib
import stdio
import lib.core.Handles.HandlesBase as HandlesBase
@@ -88,14 +89,24 @@ def is_module_imported(imported_modules: str, name: str) -> int:
def add_from_import(pool: memhub.MemBuddy | t.CPtr,
from_imports: str,
local_name: str,
module_name: str) -> str:
"""添加 from-import 映射 "name:module",返回新的 from_imports 字符串"""
module_name: str,
original_name: str = None) -> str:
"""添加 from-import 映射,返回新的 from_imports 字符串
格式:
无别名: "local_name:module_name"
有别名: "local_name:module_name:original_name"
original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰)
"""
if local_name is None or module_name is None:
return from_imports
entry: t.CChar | t.CPtr = pool.alloc(128)
entry: t.CChar | t.CPtr = pool.alloc(256)
if entry is None:
return from_imports
viperlib.snprintf(entry, 128, "%s:%s", local_name, module_name)
if original_name is not None and original_name != local_name:
viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name)
else:
viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name)
if from_imports is None:
return entry
else:
@@ -111,6 +122,75 @@ def add_from_import(pool: memhub.MemBuddy | t.CPtr,
return from_imports
# ============================================================
# 查找 from-import 名称 → 返回原始函数名(别名场景)
#
# 对于 from X import Y as Z返回 Y源模块中的真实函数名
# 无别名时返回 Nonelocal_name 即为原始名)。
# ============================================================
def lookup_from_import_original(from_imports: str,
local_name: str) -> str:
"""查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到"""
if local_name is None or from_imports is None:
return None
name_len: t.CSizeT = string.strlen(local_name)
cur: t.CChar | t.CPtr = from_imports
ci: t.CSizeT = 0
total_len: t.CSizeT = string.strlen(from_imports)
while ci < total_len:
# 跳过前导空格
while ci < total_len and cur[ci] == ' ':
ci += 1
if ci >= total_len:
break
# 找到第一个 ':' 的位置
colon1: t.CSizeT = ci
while colon1 < total_len and cur[colon1] != ':' and cur[colon1] != ' ':
colon1 += 1
if colon1 >= total_len or cur[colon1] != ':':
break
entry_name_len: t.CSizeT = colon1 - ci
# 跳过 star import
if entry_name_len == 1 and cur[ci] == '*':
ci = colon1
while ci < total_len and cur[ci] != ' ':
ci += 1
continue
# 比较名称
if entry_name_len == name_len:
match: int = 1
ei: t.CSizeT = 0
while ei < name_len:
if cur[ci + ei] != local_name[ei]:
match = 0
break
ei += 1
if match == 1:
# 找到匹配,检查是否有第三个字段(原始名)
pos: t.CSizeT = colon1 + 1
# 跳过模块名
while pos < total_len and cur[pos] != ':' and cur[pos] != ' ' and cur[pos] != '\0':
pos += 1
if pos < total_len and cur[pos] == ':':
# 有第三个字段: original_name
orig_start: t.CSizeT = pos + 1
orig_end: t.CSizeT = orig_start
while orig_end < total_len and cur[orig_end] != ' ' and cur[orig_end] != '\0':
orig_end += 1
orig_len: t.CSizeT = orig_end - orig_start
if orig_len > 0:
orig_buf: str = cur + orig_start
# 返回指向内部的指针(调用方需在使用期内保持 from_imports 有效)
return orig_buf
return None
return None
# 跳到下一个条目
ci = colon1
while ci < total_len and cur[ci] != ' ':
ci += 1
return None
# ============================================================
# 查找 from-import 名称 → 返回模块名或 None
#
@@ -150,7 +230,7 @@ def lookup_from_import(from_imports: str, name: str,
if entry_name_len == 1 and cur[ci] == '*':
mod_start: t.CSizeT = colon_pos + 1
mod_end: t.CSizeT = mod_start
while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0':
while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0' and cur[mod_end] != ':':
mod_end += 1
star_mod = cur + mod_start
# 比较名称
@@ -165,7 +245,8 @@ def lookup_from_import(from_imports: str, name: str,
if match == 1:
mod_start2: t.CSizeT = colon_pos + 1
mod_end2: t.CSizeT = mod_start2
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0':
# 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符)
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':':
mod_end2 += 1
return cur + mod_start2
# 跳到下一个条目
@@ -178,6 +259,93 @@ def lookup_from_import(from_imports: str, name: str,
return star_mod
# ============================================================
# 全局 re-export 映射表module_sha1 + func_name → source_module
#
# 当 ast/__init__.py 中有 from .lexer import _lexer_init 时,
# _lexer_init 被 re-export 为 ast._lexer_init。
# 跨模块调用 ast._lexer_init(...) 需使用 ast.lexer 的 SHA1 混淆,
# 而非 ast 的 SHA1。
#
# 数据布局:
# _g_reexport_sha1s: 每条 17 字节SHA1 16字符 + null
# _g_reexport_funcs: 每条 64 字节(函数名 + null
# _g_reexport_srcs: 每条 64 字节(源模块名 + null
# ============================================================
MAX_REEXPORT: t.CDefine = 512
_g_reexport_sha1s: bytes = None
_g_reexport_funcs: bytes = None
_g_reexport_srcs: bytes = None
_g_reexport_count: int = 0
# ============================================================
# register_reexport - 注册 re-export 映射
#
# 在 HandleImportFromNames 中调用:当处理 from .X import Y 时,
# 记录当前模块(通过 ModuleSha1re-export 了函数 Y源模块为 X。
#
# 幂等:重复注册相同映射不会增加条目。
# 内存用 stdlib.malloc 分配(全局存储器,跨 Phase 持久化)。
# ============================================================
def register_reexport(mod_sha1: str, func_name: str, source_module: str) -> int:
"""注册 re-export 映射(幂等),返回 0 成功,-1 失败"""
global _g_reexport_sha1s, _g_reexport_funcs, _g_reexport_srcs, _g_reexport_count
if mod_sha1 is None or func_name is None or source_module is None:
return -1
# 懒初始化
if _g_reexport_sha1s is None:
_g_reexport_sha1s = stdlib.malloc(MAX_REEXPORT * 17)
_g_reexport_funcs = stdlib.malloc(MAX_REEXPORT * 64)
_g_reexport_srcs = stdlib.malloc(MAX_REEXPORT * 64)
if _g_reexport_sha1s is None or _g_reexport_funcs is None or _g_reexport_srcs is None:
return -1
string.memset(_g_reexport_sha1s, 0, MAX_REEXPORT * 17)
string.memset(_g_reexport_funcs, 0, MAX_REEXPORT * 64)
string.memset(_g_reexport_srcs, 0, MAX_REEXPORT * 64)
if _g_reexport_count >= MAX_REEXPORT:
return -1
# 幂等检查:查找是否已存在相同映射
for i in range(_g_reexport_count):
sidx: t.CSizeT = t.CSizeT(i) * 17
fidx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
# 已存在,更新 source_module以防变化
string.strcpy(_g_reexport_srcs + fidx, source_module)
return 0
# 添加新条目
idx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 17
fidx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 64
string.strcpy(_g_reexport_sha1s + idx2, mod_sha1)
string.strcpy(_g_reexport_funcs + fidx2, func_name)
string.strcpy(_g_reexport_srcs + fidx2, source_module)
_g_reexport_count += 1
return 0
# ============================================================
# lookup_reexport - 查找 re-export 映射
#
# 给定模块 SHA1 和函数名,返回源模块名(如 "ast.lexer")或 None。
# 调用方通过 _lookup_module_sha1(source_module) 获取源模块的 SHA1。
# ============================================================
def lookup_reexport(mod_sha1: str, func_name: str) -> str:
"""查找 re-export 映射,返回源模块名或 None"""
if mod_sha1 is None or func_name is None:
return None
if _g_reexport_sha1s is None or _g_reexport_count <= 0:
return None
for i in range(_g_reexport_count):
sidx: t.CSizeT = t.CSizeT(i) * 17
fidx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
return _g_reexport_srcs + fidx
return None
# ============================================================
# _resolve_relative_module - 解析相对导入为完整模块名
#
@@ -335,6 +503,24 @@ class ImportsHandle(HandlesBase.Mixin):
if alias.asname is not None:
self.Trans._imported_modules = add_imported_module(
pool_val, self.Trans._imported_modules, alias.asname)
# 别名也加入 from_importsasname:fullname
# 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1
# 否则 _lookup_module_sha1("HT") 找不到mod_arr 只存文件名 HandlesTranslator
self.Trans._from_imports = add_from_import(
pool_val, self.Trans._from_imports, alias.asname, alias.name)
else:
# 无别名时import a.b.c将顶层包名 "a" 也加入 _imported_modules
# 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查
dot_ptr: str = string.strstr(alias.name, '.')
if dot_ptr is not None:
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name))
if pkg_len > 0 and pkg_len < 256:
pkg_buf: bytes = pool_val.alloc(pkg_len + 1)
if pkg_buf is not None:
string.strncpy(pkg_buf, alias.name, pkg_len)
pkg_buf[pkg_len] = '\0'
self.Trans._imported_modules = add_imported_module(
pool_val, self.Trans._imported_modules, pkg_buf)
return 0
# ============================================================
@@ -381,13 +567,19 @@ class ImportsHandle(HandlesBase.Mixin):
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
if alias is not None and alias.name is not None:
local_name: str = alias.name
orig_name: str = None
if alias.asname is not None:
local_name = alias.asname
orig_name = alias.name
self.Trans._from_imports = add_from_import(
self.Trans.Pool, self.Trans._from_imports,
local_name, resolved)
local_name, resolved, orig_name)
# 命名空间隔离from-import 的名称标记为可见结构体
HandlesStruct.add_visible_struct(self.Trans.Pool, local_name)
# 注册 re-export 映射:当前模块 re-export 了 local_name源模块为 resolved
# 使跨模块调用 module.func() 能解析到正确的源模块 SHA1
if self.Trans.ModuleSha1 is not None:
register_reexport(self.Trans.ModuleSha1, local_name, resolved)
return 0

View File

@@ -6,6 +6,7 @@ import memhub
import string
import stdio
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprCall as HandlesExprCall
@@ -96,6 +97,10 @@ def translate_children(trans: HT.Translator | t.CPtr,
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
# Phase 1b 全量翻译:正常翻译函数体
if trans._declare_only == 0:
fd_dbg: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
if fd_dbg is not None and fd_dbg.name is not None:
stdio.printf("[DBG] TR func=%s\n", fd_dbg.name)
stdio.fflush(0)
added: int = HandlesFunctions.translate_function_def(trans, child)
added_total += added
elif trans._declare_only == 1:
@@ -104,6 +109,10 @@ def translate_children(trans: HT.Translator | t.CPtr,
# ClassDef 在模块级直接处理(不需要 builder
# _declare_only=2import扫描模式时跳过只处理 import 依赖
if trans._declare_only != 2:
cd_dbg: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
if cd_dbg is not None and cd_dbg.name is not None:
stdio.printf("[DBG] TR class=%s\n", cd_dbg.name)
stdio.fflush(0)
HandlesClassDef.translate_class_def(trans, child)
elif trans._declare_only == 0 and trans._cur_builder is not None:
# 有 builder → 委托 HandlesBody 分派
@@ -171,7 +180,7 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
# 解析类型
if aa.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, aa.annotation, trans._imported_modules, trans._from_imports)
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
if resolved is not None:
var_ty = resolved
# 解析初始值
@@ -208,6 +217,11 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
return 0
# 创建全局变量 @var_name
# 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明
# 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报
# "use of undefined type named 'sha1.ClassName'" 错误
# (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager"))
llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty)
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, var_name, var_ty)
if gv is None:
return 0
@@ -221,7 +235,9 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
viperlib.snprintf(init_buf, 48, "%lld", init_val)
gv.Initializer = init_buf
else:
gv.Initializer = "0"
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer
# 整数/聚合类型也兼容 zeroinitializer避免 "integer constant must have integer type"
gv.Initializer = "zeroinitializer"
# 创建 Value 引用(@var_name, 类型为 var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
@@ -232,6 +248,16 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
# 注册到模块作用域
if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
# 设置 AnnotClassName联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
if k == ast.ASTKind.AnnAssign:
aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa_ml is not None and aa_ml.annotation is not None:
cls_nm_ml: str = HandlesType.extract_class_name_from_annotation(
aa_ml.annotation, trans._imported_modules)
if cls_nm_ml is not None:
HandlesVar.set_var_annot_class_name(
trans.SymTab, var_name, cls_nm_ml)
return 1
return 0
@@ -262,18 +288,18 @@ def create_wrapper_main(trans: HT.Translator | t.CPtr,
main_func: llvmlite.Function | t.CPtr = llvmlite.create_function(
pool, mod, "main", i32_ty)
if main_func is None:
stdio.printf("[TR] CreateFunction main returned NULL\n")
VLogger.error("CreateFunction main returned NULL", "TR")
return 0
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, main_func, "entry")
if entry_blk is None:
stdio.printf("[TR] CreateBlock returned NULL\n")
VLogger.error("CreateBlock returned NULL", "TR")
return 0
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
if builder is None:
stdio.printf("[TR] NewBuilder returned NULL\n")
VLogger.error("NewBuilder returned NULL", "TR")
return 0
llvmlite.position_at_end(builder, entry_blk)

View File

@@ -55,31 +55,47 @@ class ReturnHandle(HandlesBase.Mixin):
self.Trans._funcs, self.Trans._func_count, self.Trans)
# val 为 None 时(裸 return检查当前函数返回类型
# void 函数(如 __init__/__before_init__生成 ret void否则 ret i32 0
# void 函数(如 __init__/__before_init__生成 ret void
# ptr 函数生成 ret ptr null否则 ret i32 0
if val is None:
cur_func: llvmlite.Function | t.CPtr = self.Trans._cur_func
is_void_ret: int = 0
is_ptr_ret: int = 0
ret_ty: llvmlite.LLVMType | t.CPtr = None
if cur_func is not None:
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func)
ret_ty = llvmlite.function_get_ret_ty(cur_func)
if ret_ty is not None:
match ret_ty:
case llvmlite.LLVMType.Void():
is_void_ret = 1
case llvmlite.LLVMType.Ptr(_pe):
is_ptr_ret = 1
if is_void_ret != 0:
llvmlite.build_ret_void(builder)
return 0
if is_ptr_ret != 0:
null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
llvmlite.build_ret(builder, null_val)
return 0
val = llvmlite.const_int32(pool, 0)
# 类型转换:确保 val 类型与函数返回类型匹配
# 处理 i1bool 比较结果)→ i8t.CBool等情况
# i1 → 更宽整数用 zextbool 语义1 保持 1而非 sext 的 0xFF
# 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr
# 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type"
cur_func_rt: llvmlite.Function | t.CPtr = self.Trans._cur_func
if cur_func_rt is not None and val is not None and val.Ty is not None:
ret_ty_rt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func_rt)
if ret_ty_rt is not None:
val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt)
if val_bits != 0 and ret_bits != 0 and val_bits != ret_bits:
val_is_ptr: int = HandlesExpr.is_ptr_type(val.Ty)
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)
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:

View File

@@ -6,6 +6,8 @@ import llvmlite
import stdio
import ast
import hashtable
import viperlib
import lib.core.VLogger as VLogger
# ============================================================
@@ -19,7 +21,7 @@ import hashtable
# ============================================================
STRUCT_MAX: t.CDefine = 512
FIELD_MAX: t.CDefine = 32
FIELD_MAX: t.CDefine = 48
FIELD_NAME_MAX: t.CDefine = 64
@@ -196,7 +198,10 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr,
return existing
if _struct_count >= STRUCT_MAX:
stdio.printf("[STRUCT] table full, cannot register %s\n", name)
fb_st: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_st is not None:
viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name)
VLogger.error(fb_st, "STRUCT")
return None
entry: StructEntry | t.CPtr = _get_struct_entry(_struct_count)
@@ -290,7 +295,10 @@ def add_field(pool: memhub.MemBuddy | t.CPtr,
return -1
if struct_entry.FieldCount >= FIELD_MAX:
stdio.printf("[STRUCT] field table full for %s\n", struct_entry.Name)
fb_sf: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_sf is not None:
viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name)
VLogger.error(fb_sf, "STRUCT")
return -1
idx: int = struct_entry.FieldCount
@@ -314,18 +322,41 @@ def add_field(pool: memhub.MemBuddy | t.CPtr,
return idx
# ============================================================
# get_struct_count — 获取已注册结构体数量(供 Phase2 多遍预注册判断收敛)
# ============================================================
def get_struct_count() -> int:
"""返回当前已注册的结构体数量"""
return _struct_count
# ============================================================
# find_struct — 按类名查找结构体
# ============================================================
def find_struct(name: str) -> StructEntry | t.CPtr:
"""按类名查找结构体,返回 StructEntry 或 None"""
"""按类名查找结构体,返回 StructEntry 或 None
支持模块限定名(如 "HT.Translator"
第一遍精确匹配,第二遍按类名(最后一个 '.' 之后的部分)回退
"""
if name is None or _struct_table is None:
return None
# 第一遍:精确匹配
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
# 第二遍:类名回退(处理模块限定名 "HT.Translator" → "Translator"
dot_pos: str = string.strrchr(name, '.')
if dot_pos is not None:
class_name: str = dot_pos + 1
if class_name is not None and class_name[0] != '\0':
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, class_name) == 0:
return entry
return None
@@ -455,12 +486,27 @@ def lookup_field_by_class(class_name: str,
return None
# 优先用 SHA1 匹配(跨模块同名类区分)
# 支持模块限定名class_name 可能是 "HT.Translator"entry.Name 是 "Translator"
# 先精确匹配,失败后用 strrchr 提取类名部分回退匹配
if sha1 is not None:
sha1_matched: int = 0
# 计算类名回退部分("HT.Translator" → "Translator"
bare_name: str = class_name
dot_pos_lfbc: str = string.strrchr(class_name, '.')
if dot_pos_lfbc is not None:
bare_name = dot_pos_lfbc + 1
if bare_name is None or bare_name[0] == '\0':
bare_name = class_name
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
# 精确匹配或类名回退匹配
name_match: int = 0
if string.strcmp(entry.Name, class_name) == 0:
name_match = 1
elif bare_name is not class_name and string.strcmp(entry.Name, bare_name) == 0:
name_match = 1
if name_match != 0:
if entry.ModuleSha1 is not None:
if string.strcmp(entry.ModuleSha1, sha1) == 0:
sha1_matched = 1
@@ -475,12 +521,65 @@ def lookup_field_by_class(class_name: str,
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
entry = find_struct(class_name)
if entry is None:
# 诊断:遍历打印所有已注册结构体名,确认目标类是否在注册表中
stdio.printf("[LFBC-DIAG] FAIL class=%s field=%s sha1=%s count=%d\n",
class_name, field_name,
sha1 if sha1 is not None else "(null)", _struct_count)
for diag_i in range(_struct_count):
diag_entry: StructEntry | t.CPtr = _get_struct_entry(diag_i)
if diag_entry is not None and diag_entry.Name is not None:
stdio.printf("[LFBC-DIAG] [%d] %s sha1=%s fc=%d\n",
diag_i, diag_entry.Name,
diag_entry.ModuleSha1 if diag_entry.ModuleSha1 is not None else "(null)",
diag_entry.FieldCount)
return None
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
# 诊断:找到结构体但字段未找到
stdio.printf("[LFBC-DIAG] NOFIELD class=%s field=%s sname=%s fc=%d\n",
class_name, field_name, entry.Name, entry.FieldCount)
return None
# ============================================================
# find_subclass_with_field — 在基类的所有子类中搜索包含指定字段的结构体
#
# 用于处理 "注解类型是基类但实际值是派生类" 的场景:
# node: AST | t.CPtr = If(...)
# node.orelse = orelse ← orelse 在 If 上,不在 AST 上
#
# 遍历所有已注册结构体,通过 ParentName 链检查继承关系,
# 返回第一个包含 field_name 的子类 StructEntry。
# ============================================================
def find_subclass_with_field(base_class_name: str,
field_name: str) -> StructEntry | t.CPtr:
"""在 base_class_name 的所有子类中搜索包含 field_name 的结构体
返回第一个找到的 StructEntry包含正确的 TyNone=未找到
"""
if base_class_name is None or field_name is None:
return None
sc_i: int
for sc_i in range(_struct_count):
sc_entry: StructEntry | t.CPtr = _get_struct_entry(sc_i)
if sc_entry is None or sc_entry.Name is None:
continue
# 检查 sc_entry 是否是 base_class_name 的子类(传递性)
cur_parent: str = get_parent_name(sc_entry.Name)
while cur_parent is not None:
if string.strcmp(cur_parent, base_class_name) == 0:
# 是子类,检查是否有该字段
sc_fi: int
for sc_fi in range(sc_entry.FieldCount):
sc_fe: FieldEntry | t.CPtr = _get_field_entry(sc_entry, sc_fi)
if sc_fe is not None and sc_fe.Name is not None:
if string.strcmp(sc_fe.Name, field_name) == 0:
return sc_entry
break
cur_parent = get_parent_name(cur_parent)
return None
@@ -546,6 +645,28 @@ def _is_struct_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
return 0
def _is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
"""检查 ty 是否是 Ptr 类型(独立函数,规避嵌套 match 编译器 BUG"""
if ty is None:
return 0
match ty:
case llvmlite.LLVMType.Ptr(pointee):
return 1
case _:
return 0
def _get_ptr_pointee(ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""获取 Ptr 类型的 pointee独立函数规避嵌套 match 编译器 BUG"""
if ty is None:
return None
match ty:
case llvmlite.LLVMType.Ptr(pointee):
return pointee
case _:
return None
def get_struct_type_from_value(val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""从 Value 的类型推断结构体类型"""
if val is None or val.Ty is None:
@@ -935,6 +1056,119 @@ def get_field_count(name: str) -> int:
return entry.FieldCount
# ============================================================
# ensure_struct_def_in_module — 确保跨模块结构体的完整定义在当前模块中可用
#
# 当局部变量声明为值类型(如 f: Filealloca 需要完整类型定义。
# 如果结构体定义在另一个模块(名称含 SHA1 前缀,如 "0035c95a18d4f8e8.File"
# 将其完整定义复制到当前模块。module_add_named_type 会用完整定义替换
# 已存在的 opaque 声明,使 alloca 能正确分配空间。
#
# Args:
# pool: 内存池
# mod: 当前 LLVM 模块
# ty: 变量类型Struct/Ptr/其他)
# ============================================================
def ensure_struct_def_in_module(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr):
"""确保跨模块结构体的完整定义在当前模块中可用(供 alloca 使用)
处理两种情况:
1. Struct 值类型:需要完整定义(供 alloca 分配空间)
2. Ptr(Struct) 指针类型:需要 pointee 至少有 opaque 声明
"""
if ty is None or mod is None or pool is None:
return
# 指针类型:确保 pointee 至少有 opaque 声明
# 用 _is_ptr_type 检查(独立函数,规避嵌套 match BUG
if _is_ptr_type(ty) != 0:
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
# 如果 pointee 是 Struct递归复制完整定义
# GEP 访问字段需要 sized 类型,仅 opaque 会导致 llc 报错)
pointee: llvmlite.LLVMType | t.CPtr = _get_ptr_pointee(ty)
if pointee is not None:
ensure_struct_def_in_module(pool, mod, pointee)
return
# 获取结构体名称(非 Struct 类型返回 None
sname: t.CChar | t.CPtr = llvmlite.get_struct_name(ty)
if sname is None:
return
# 检查是否为跨模块引用(名称包含 '.'
if string.strchr(sname, 46) is None:
return # 非跨模块引用,无需处理
# 提取类名(第一个 '.' 之后的部分)
# 必须用 strchr 而非 strrchr泛型特化名如 "list[ast.AST|t.CPtr]"
# 内部含 '.'ast.ASTstrrchr 会错误地把类名解析为 "AST|t.CPtr]"
dot_pos: str = string.strchr(sname, '.')
if dot_pos is None:
return
class_name: str = dot_pos + 1
if class_name is None or class_name[0] == '\0':
return
# 提取 SHA1sname 到 dot_pos 之间,用 strlen 避免指针减法)
total_len: t.CSizeT = string.strlen(sname)
class_name_len: t.CSizeT = string.strlen(class_name)
sha1_len: t.CSizeT = total_len - class_name_len - 1
sha1_buf: t.CChar | t.CPtr = pool.alloc(32)
if sha1_buf is None:
return
string.strncpy(sha1_buf, sname, sha1_len)
sha1_buf[sha1_len] = '\0'
# 按类名 + SHA1 查找结构体定义
entry: StructEntry | t.CPtr = find_struct_by_module(class_name, sha1_buf)
if entry is None:
# 回退到按类名查找(可能找到不同模块的同名类,但总比没有好)
entry = find_struct(class_name)
if entry is None:
return
if entry.Ty is None:
return
# 将完整定义添加到当前模块(会替换已存在的 opaque 声明)
llvmlite.module_add_named_type(mod, pool, entry.Ty)
# 递归扫描字段类型,确保值类型子结构体(如 WIN32_FIND_DATAA 中的 FILETIME
# 也有完整定义。指针类型字段只需 opaque 声明(已由 module_ensure_opaque_for_type 处理)。
_ensure_field_types_in_module(pool, mod, entry.Ty)
# ============================================================
# _ensure_field_types_in_module - 递归扫描结构体字段类型
#
# 遍历 Struct 的 Fields 链表,对每个值类型子结构体调用
# ensure_struct_def_in_module。指针/数组/基本类型递归到 pointee/element。
# ============================================================
def _ensure_field_types_in_module(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr):
"""递归扫描类型树,确保值类型子结构体有完整定义"""
if ty is None or mod is None or pool is None:
return
# 用 match 遍历类型(独立函数,规避嵌套 match BUG
match ty:
case llvmlite.LLVMType.Struct(fields, fcount, sname):
# 遍历字段链表
if fields is not None:
fld: llvmlite.ParamNode | t.CPtr = fields
while fld is not None:
if fld.Ty is not None:
# 值类型子结构体(如 FILETIME需要完整定义
if _is_struct_type(fld.Ty) != 0:
ensure_struct_def_in_module(pool, mod, fld.Ty)
_ensure_field_types_in_module(pool, mod, fld.Ty)
fld = fld.Next
case llvmlite.LLVMType.Ptr(pointee):
# 指针类型pointee 只需 opaque 声明,不需要完整定义
# 但如果 pointee 是 Struct确保 opaque 声明存在
if pointee is not None:
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
case llvmlite.LLVMType.Array(elem_ty, acount):
# 数组类型:元素如果是值类型结构体,需要完整定义
if elem_ty is not None:
_ensure_field_types_in_module(pool, mod, elem_ty)
case _:
pass
# ============================================================
# get_field_name_ptr — 获取 FieldEntry 的字段名指针(访问器)
# ============================================================

View File

@@ -6,6 +6,7 @@ import memhub
import string
import stdio
import stdlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesMain as HandlesMain
@@ -212,7 +213,7 @@ class Translator:
# 创建 LLVM 模块
mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main")
if mod is None:
stdio.printf("[TR] NewModule returned NULL\n")
VLogger.error("NewModule returned NULL", "TR")
return 1
self.Module = mod
@@ -231,7 +232,7 @@ class Translator:
printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, "printf", i32_ty)
if printf_func is None:
stdio.printf("[TR] CreateDeclare printf returned NULL\n")
VLogger.error("CreateDeclare printf returned NULL", "TR")
return 1
llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt")
printf_func.IsVarArg = 1
@@ -305,6 +306,21 @@ class Translator:
elif kd == ast.ASTKind.ImportFrom:
self.ImportsH.HandleImportFromModule(child)
self.ImportsH.HandleImportFromNames(child)
# 预注册模块级变量AnnAssign/Assign到 SymTab
# 解决时序问题class Logger 的 __init__ 引用 _mbuddy 时,
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
# 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None
# 预处理先于 translate_children 注册所有模块级变量,
# 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var
# 通过 lookup_module_var 检测已存在并跳过HandlesMain.py:206-209
if ch is not None:
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is None:
continue
kd_mv: int = child.kind()
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
HandlesMain.handle_module_level_var(self, child)
# 创建前向声明
HandlesFunctions.forward_declare_functions(self, tree)
added: int = HandlesMain.translate_children(self, tree)

View File

@@ -26,6 +26,27 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
_g_current_file: str = None
# ============================================================
# 全局 temp_dirpyi 文件所在目录,由 BuildPipeline/Phase1 设置)
#
# 用于跨模块 CDefine 常量查找:当当前模块的 CDefine 表中找不到
# 某个 Name 时,从 from_imports 解析出源模块,再从该模块的 pyi
# 文件中解析 CDefine 常量值。
# ============================================================
_g_temp_dir: str = None
def set_temp_dir(temp_dir: str) -> None:
"""设置全局 temp_dir每个项目编译开始时由 BuildPipeline/Phase1 设置)"""
global _g_temp_dir
_g_temp_dir = temp_dir
def get_temp_dir() -> str:
"""获取全局 temp_dir"""
return _g_temp_dir
# ============================================================
# 全局泛型特化上下文(由 _specialize_generic_class 设置/清除)
#
@@ -46,11 +67,55 @@ _g_generic_type_args: list[str] | t.CPtr = None
_g_cdefine_names: list[str] | t.CPtr = None
_g_cdefine_values: list[str] | t.CPtr = None
# ============================================================
# 全局跨模块 CDefine 表(按模块 SHA1 索引,跨模块持久化)
#
# 本地表在模块切换时被 clear_cdefine_constants 清空,
# 导致跨模块引用(如 HandlesVar.SCOPE_FUNCTION找不到常量。
# 全局表在模块切换时不清空,跨模块查找直接查表,无需文件 I/O。
#
# 数据布局:
# _g_gcdef_sha1s: 每条 17 字节(模块 SHA1 16字符 + null
# _g_gcdef_names: 每条 64 字节(常量名 + null
# _g_gcdef_values: 每条 32 字节(值字符串 + null
# ============================================================
MAX_GLOBAL_CDEFINE: t.CDefine = 1024
_g_gcdef_sha1s: bytes = None
_g_gcdef_names: bytes = None
_g_gcdef_values: bytes = None
_g_gcdef_count: int = 0
_g_current_module_sha1: str = None
def set_current_module_sha1(sha1: str) -> None:
"""设置当前正在编译的模块 SHA1Phase1 在模块开始翻译前调用)"""
global _g_current_module_sha1
_g_current_module_sha1 = sha1
def _global_cdefine_init(pool: memhub.MemBuddy | t.CPtr) -> int:
"""懒初始化全局 CDefine 表"""
global _g_gcdef_sha1s, _g_gcdef_names, _g_gcdef_values
if _g_gcdef_sha1s is None:
_g_gcdef_sha1s = stdlib.malloc(MAX_GLOBAL_CDEFINE * 17)
_g_gcdef_names = stdlib.malloc(MAX_GLOBAL_CDEFINE * 64)
_g_gcdef_values = stdlib.malloc(MAX_GLOBAL_CDEFINE * 32)
if _g_gcdef_sha1s is None or _g_gcdef_names is None or _g_gcdef_values is None:
return 1
string.memset(_g_gcdef_sha1s, 0, MAX_GLOBAL_CDEFINE * 17)
string.memset(_g_gcdef_names, 0, MAX_GLOBAL_CDEFINE * 64)
string.memset(_g_gcdef_values, 0, MAX_GLOBAL_CDEFINE * 32)
return 0
def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
name: str, value: int) -> None:
"""注册 CDefine 编译期常量到全局表"""
global _g_cdefine_names, _g_cdefine_values
"""注册 CDefine 编译期常量到本地表和全局表
值以十进制字符串存储。注意value 是 32 位有符号整数,
0xFFFFFFFF 会存储为 "-1"lookup 时用 found 标志区分"未找到"和值为 -1。
"""
global _g_cdefine_names, _g_cdefine_values, _g_gcdef_count
if _g_cdefine_names is None:
_g_cdefine_names = list[str](pool, 64)
_g_cdefine_values = list[str](pool, 64)
@@ -61,12 +126,54 @@ def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
_g_cdefine_values.append(val_buf)
else:
_g_cdefine_values.append("0")
# 同时注册到全局跨模块表(用当前模块 SHA1 索引)
if _g_current_module_sha1 is not None and _g_gcdef_count < MAX_GLOBAL_CDEFINE:
if _global_cdefine_init(pool) == 0:
sidx: t.CSizeT = t.CSizeT(_g_gcdef_count) * 17
nidx: t.CSizeT = t.CSizeT(_g_gcdef_count) * 64
vidx: t.CSizeT = t.CSizeT(_g_gcdef_count) * 32
string.strcpy(_g_gcdef_sha1s + sidx, _g_current_module_sha1)
string.strcpy(_g_gcdef_names + nidx, name)
vbuf: str = _g_gcdef_values + vidx
viperlib.snprintf(vbuf, 32, "%d", value)
_g_gcdef_count += 1
def lookup_global_cdefine(module_sha1: str, name: str) -> int:
"""从全局跨模块表查找 CDefine 常量
用 module_sha1 + name 精确匹配。
找到时设置 _g_cdefine_found=1 并返回值;未找到返回 0。
"""
global _g_cdefine_found
if module_sha1 is None or name is None:
return 0
if _g_gcdef_sha1s is None or _g_gcdef_count <= 0:
return 0
i: t.CSizeT = 0
while i < _g_gcdef_count:
sidx: t.CSizeT = t.CSizeT(i) * 17
nidx: t.CSizeT = t.CSizeT(i) * 64
vidx: t.CSizeT = t.CSizeT(i) * 32
if string.strcmp(_g_gcdef_sha1s + sidx, module_sha1) == 0:
if string.strcmp(_g_gcdef_names + nidx, name) == 0:
_g_cdefine_found = 1
return string.atoi(_g_gcdef_values + vidx)
i += 1
return 0
def lookup_cdefine_constant(name: str) -> int:
"""查找 CDefine 编译期常量,返回值或 -1未找到"""
"""查找 CDefine 编译期常量
返回找到的值。由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1
用全局 _g_cdefine_found 标志区分"未找到"和值为 -1。
调用方应在调用后检查 _g_cdefine_found。
"""
global _g_cdefine_found
_g_cdefine_found = 0
if _g_cdefine_names is None:
return -1
return 0
n: t.CSizeT = _g_cdefine_names.__len__()
i: t.CSizeT
for i in range(n):
@@ -74,8 +181,23 @@ def lookup_cdefine_constant(name: str) -> int:
if nm is not None and string.strcmp(nm, name) == 0:
val_str: str = _g_cdefine_values.get(i)
if val_str is not None:
_g_cdefine_found = 1
return string.atoi(val_str)
return -1
return 0
_g_cdefine_found: int = 0
def is_cdefine_found() -> int:
"""检查上次 lookup_cdefine_constant 是否找到值"""
return _g_cdefine_found
def set_cdefine_found(val: int) -> None:
"""设置 cdefine_found 标志(供跨模块查找函数使用)"""
global _g_cdefine_found
_g_cdefine_found = val
def clear_cdefine_constants() -> None:
@@ -228,6 +350,20 @@ def _parse_type_string(pool: memhub.MemBuddy | t.CPtr,
return ast.Name(pool, type_str, ctx)
# ============================================================
# _parse_type_string_ptr - _parse_type_string 的 t.CPtr 返回类型包装
#
# 旧编译器对 ast.AST | t.CPtr 跨模块返回类型推断有 bug解析为 i32
# 用 t.CPtr 包装绕过,外部模块应调用此函数而非 _parse_type_string
# ============================================================
def _parse_type_string_ptr(pool: memhub.MemBuddy | t.CPtr,
type_str: str,
ctx: t.CInt) -> t.CPtr:
"""_parse_type_string 的 t.CPtr 返回类型包装(绕过旧编译器类型推断 bug"""
result: ast.AST | t.CPtr = _parse_type_string(pool, type_str, ctx)
return result
# ============================================================
# set_current_file - 设置当前编译的文件名
#
@@ -709,7 +845,8 @@ def extract_class_name_from_annotation(node: ast.AST | t.CPtr,
def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
node: ast.AST | t.CPtr,
imported_modules: str,
from_imports: str) -> llvmlite.LLVMType | t.CPtr:
from_imports: str,
trans: HT.Translator | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr:
"""解析类型注解节点为 LLVMType
Args:
@@ -717,6 +854,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
node: 类型注解 AST 节点Name 或 Attribute
imported_modules: 已导入模块名字符串(空格分隔)
from_imports: from-import 映射字符串("name:module name:module" 格式)
trans: 翻译器对象(可选,用于触发泛型特化)
"""
if node is None:
return None
@@ -727,9 +865,9 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
if cn.const_kind == ast.CONST_STR and cn.str_val is not None:
sub_node: ast.AST | t.CPtr = _parse_type_string(pool, cn.str_val, ast.Ctx.Load)
sub_node: ast.AST | t.CPtr = _parse_type_string(pool, cn.str_val, ast.ASTCtx.Load)
if sub_node is not None:
return resolve_annotation_type(pool, sub_node, imported_modules, from_imports)
return resolve_annotation_type(pool, sub_node, imported_modules, from_imports, trans)
return None
# Name 节点: str, int, bytes, from-import 名称, class 名称等
@@ -749,7 +887,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
# 用具体类型名递归解析(支持 BinOp/Attribute 类型实参)
gp_sub_node: ast.AST | t.CPtr = _parse_type_string(pool, gp_ta, nm.ctx)
if gp_sub_node is not None:
return resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports)
return resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans)
# str = bytes = t.CChar | t.CPtr = i8*
if string.strcmp(nm.id, "str") == 0:
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
@@ -817,7 +955,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
if other_is_cvoid != 0:
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
pool, other_node, imported_modules, from_imports)
pool, other_node, imported_modules, from_imports, trans)
if other_ty is None:
# CPtr 单独使用或其他无效类型 → i8*
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
@@ -825,11 +963,11 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
# 无 CPtr 标记:返回第一个非 None装饰器标记如 CExport/CExtern 被忽略)
left_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
pool, bop.left, imported_modules, from_imports)
pool, bop.left, imported_modules, from_imports, trans)
if left_ty is not None:
return left_ty
right_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
pool, bop.right, imported_modules, from_imports)
pool, bop.right, imported_modules, from_imports, trans)
if right_ty is not None:
return right_ty
return None
@@ -891,6 +1029,22 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled)
if gen_spec_ty is not None:
return gen_spec_ty
# 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐)
# 当 trans 可用时,检查是否是泛型模板并触发特化
if trans is not None:
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesExprCall as HandlesExprCall
template_cd_chk: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_nm.id)
if template_cd_chk is not None:
type_args_chk: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(
pool, sub.slice)
if type_args_chk is not None and type_args_chk.__len__() > 0:
spec_name_chk: str = HandlesClassDef._specialize_generic_class(
trans, gen_nm.id, type_args_chk)
if spec_name_chk is not None:
gen_spec_ty = HandlesStruct.get_struct_type(gen_mangled)
if gen_spec_ty is not None:
return gen_spec_ty
# 未特化:返回 None不报错让后续流程处理
return None
# 检查 value 是否是 Attribute(Name('t'), 'CArray')
@@ -912,7 +1066,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
# 相当于 t.CArray[elem_ty, None],表示静态推导长度数组
if sub.slice.kind() != ast.ASTKind.Tuple:
elem_ty_single: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
pool, sub.slice, imported_modules, from_imports)
pool, sub.slice, imported_modules, from_imports, trans)
if elem_ty_single is None:
fatal_type_error(sub.slice, "t.CArray[?] 元素类型解析失败")
return llvmlite.Ptr(pool, elem_ty_single)
@@ -930,7 +1084,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
fatal_type_error(node, "t.CArray Tuple 元素为 None")
# 递归解析元素类型
elem_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
pool, elem_node, imported_modules, from_imports)
pool, elem_node, imported_modules, from_imports, trans)
if elem_ty is None:
fatal_type_error(elem_node, "t.CArray 元素类型解析失败")
# 解析 count必须是整数常量、None 或 CDefine 常量名)
@@ -950,7 +1104,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
if cnt_nm.id is None:
fatal_type_error(count_node, "t.CArray count Name 节点 id 为 None")
looked_up: int = lookup_cdefine_constant(cnt_nm.id)
if looked_up < 0:
if is_cdefine_found() == 0:
fatal_type_error(count_node, "t.CArray count 不是已注册的 CDefine 常量")
count_val = looked_up
else:
@@ -1180,6 +1334,11 @@ def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr)
remain: t.CSizeT = dst_size - dlen
if remain <= 0:
return
for i in range(min(slen, remain - 1)):
# 内联 min(slen, remain - 1) 避免 builtin min 未定义TransPyV 无 builtin min
limit: t.CSizeT = slen
cap: t.CSizeT = remain - 1
if cap < limit:
limit = cap
for i in range(limit):
dst[dlen + i] = src[i]
dst[dlen + i] = '\0'

View File

@@ -36,6 +36,7 @@ class VarEntry:
Alloca: llvmlite.Value | t.CPtr
Used: t.CInt
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名str 别名在结构体字段中触发编译器 bug改用显式联合类型
IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长
# ============================================================
@@ -154,6 +155,25 @@ def set_var_annot_class_name(symtab: SymbolTable | t.CPtr,
return 0
# ============================================================
# set_var_ptr_element — 标记变量为"指针到 str/bytes"类型
#
# 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*
# 但下标访问应按 8 字节步长i8** 语义),而非 1 字节步长i8* 语义)。
# 此标志在 HandlesAnnAssign 中根据注解形式设置。
# ============================================================
def set_var_ptr_element(symtab: SymbolTable | t.CPtr,
name: str) -> int:
"""标记变量为 ptr_element 类型,返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name)
if entry is None:
return 1
entry.IsPtrElement = 1
return 0
# ============================================================
# add_var — 添加变量到变量表
# ============================================================
@@ -175,6 +195,27 @@ def add_var(vars_ptr: VarEntry | t.CPtr,
return 0
# ============================================================
# _alloca_at_entry - 在函数入口块生成 alloca确保支配性
#
# LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成,
# 但在其他分支使用会违反支配性Instruction does not dominate all uses
# 标准做法:所有 alloca 在函数入口块生成。
#
# 临时切换 builder.CurBlock 到入口块,生成 alloca然后恢复。
# ============================================================
def _alloca_at_entry(builder: llvmlite.IRBuilder | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""在函数入口块生成 alloca返回 alloca 值
使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca
确保所有 alloca 在入口块,避免支配性违规。
"""
if builder is None or ty is None:
return None
return llvmlite.build_alloca_at_entry(builder, ty)
# ============================================================
# get_or_create_var — 查找或创建变量 alloca旧版兼容
# ============================================================
@@ -188,7 +229,7 @@ def get_or_create_var(pool: memhub.MemBuddy | t.CPtr,
existing: llvmlite.Value | t.CPtr = find_var(vars_ptr, var_count, name)
if existing is not None:
return existing
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, ty)
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
if alloca is None:
return None
if add_var(vars_ptr, var_count, name, alloca) != 0:
@@ -358,7 +399,7 @@ def get_or_create_sym(symtab: SymbolTable | t.CPtr,
existing: llvmlite.Value | t.CPtr = lookup_current(symtab, name)
if existing is not None:
return existing
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, ty)
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
if alloca is None:
return None
define_var(symtab, name, alloca)