fix(gen): 类字段单参CArray静态数组推断+列表默认值深拷贝;G3泛型循环防护与before_init去重;f-string/ctraits支持
This commit is contained in:
1 parent
a649e4807d
commit
4fd331dc08
9 files changed
+791
-2
No files matched your search
@@ -22,6 +22,7 @@ import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -1918,6 +1919,21 @@ class CallGenMixin:
|
||||
continue
|
||||
if fe.DefaultVal is None:
|
||||
continue # 合理跳过:无默认值的字段
|
||||
# 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store
|
||||
# (与 _generate_before_init 一致;translate_value 会把列表字面量
|
||||
# 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。
|
||||
# Mixin 静态绑定:跨 Mixin 方法必须走 HandlesAnnAssign 模块级委托。
|
||||
if fe.Ty is not None and HandlesExpr.is_array_type(fe.Ty) != 0 \
|
||||
and fe.DefaultVal.kind() == ast.ASTKind.List:
|
||||
field_ptr_arr2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||||
if field_ptr_arr2 is not None:
|
||||
zero_arr2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty)
|
||||
if zero_arr2 is not None:
|
||||
llvmlite.build_store(builder, zero_arr2, field_ptr_arr2)
|
||||
HandlesAnnAssign._init_global_array_from_list(
|
||||
builder, pool, mod, field_ptr_arr2, fe.DefaultVal, trans)
|
||||
continue
|
||||
default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, fe.DefaultVal, None, 0, trans)
|
||||
if default_val is None:
|
||||
@@ -4803,6 +4819,26 @@ class CallGenMixin:
|
||||
if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0:
|
||||
return self._translate_super_call(
|
||||
pool, builder, mod, cl, func_name, trans)
|
||||
|
||||
# ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用,
|
||||
# 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底,
|
||||
# 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错)
|
||||
if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
ct_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name:
|
||||
ct_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_at.value)
|
||||
if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \
|
||||
and string.strcmp(func_name, "isptr") == 0:
|
||||
ct_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
if ct_args is not None and ct_args.__len__() >= 1:
|
||||
ct_arg0: ast.AST | t.CPtr = ct_args.get(0)
|
||||
if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name:
|
||||
ct_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_arg0)
|
||||
if ct_nm0.id is not None and trans is not None:
|
||||
ct_r: int = HandlesType.eval_ctraits_isptr(trans.SymTab, ct_nm0.id)
|
||||
if ct_r > 0:
|
||||
return llvmlite.const_int32(pool, 1)
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
if func_name is None:
|
||||
# 检查是否是 list[int](pool) 形式的泛型实例化调用
|
||||
# Subscript 节点作为 Call func: 泛型类构造函数
|
||||
|
||||
@@ -13,6 +13,7 @@ import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesEnum as HandlesEnum
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
import lib.core.StubMerger as StubMerger
|
||||
|
||||
|
||||
@@ -56,6 +57,10 @@ META_KEY_LEN: t.CDefine = 128
|
||||
# 泛型特化缓存容量上限(与 HandlesClassDef.SPEC_CACHE_MAX 一致)
|
||||
SPEC_CACHE_MAX: t.CDefine = 512
|
||||
|
||||
# 泛型特化递归深度上限(泛型循环套用防护)
|
||||
# 正常嵌套特化深度 ≤ 3(如 list[list[str]]);64 远超合理值,命中即循环
|
||||
GENERIC_SPEC_MAX_DEPTH: t.CDefine = 64
|
||||
|
||||
# vtable 方法最大数量(与 HandlesClassDef.VTBL_METHOD_MAX 一致)
|
||||
VTBL_METHOD_MAX: t.CDefine = 32
|
||||
|
||||
@@ -92,6 +97,11 @@ class ClassGenMixin:
|
||||
SpecNames: t.CSizeT | t.CPtr
|
||||
SpecCount: int
|
||||
|
||||
# --- 泛型特化递归深度(泛型循环套用防护) ---
|
||||
# _specialize_generic_class 进入时 +1、退出时 -1;超过上限立即报错终止
|
||||
# (防止 F-bounded 等循环特化把编译变成死循环)
|
||||
GenericSpecDepth: int
|
||||
|
||||
# --- 泛型模板表(原 HandlesClassDef._generic_class_names/
|
||||
# _generic_class_nodes/_generic_class_sha1s) ---
|
||||
GenericClassNames: list[str] | t.CPtr
|
||||
@@ -2031,6 +2041,17 @@ class ClassGenMixin:
|
||||
"""
|
||||
if trans is None or class_name is None or type_args is None:
|
||||
return None
|
||||
# 泛型循环套用防护:递归深度 +1,超过上限立即报错终止(防 F-bounded
|
||||
# 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。
|
||||
self.GenericSpecDepth += 1
|
||||
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH:
|
||||
err_spec: t.CChar | t.CPtr = trans.Pool.alloc(256)
|
||||
if err_spec is not None:
|
||||
viperlib.snprintf(err_spec, 256,
|
||||
"泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d",
|
||||
class_name, self.GenericSpecDepth)
|
||||
HandlesType.fatal_error(None, err_spec, "InternalCompilerError")
|
||||
HandlesType.fatal_error(None, "泛型特化递归过深(疑似泛型循环套用)", "InternalCompilerError")
|
||||
# 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"),
|
||||
# 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。
|
||||
# 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。
|
||||
@@ -2069,11 +2090,13 @@ class ClassGenMixin:
|
||||
if template_cd is None:
|
||||
if string.strcmp(class_name, "GSListNode") == 0:
|
||||
VLogger.debug("template NOT FOUND, return None", "SPEC")
|
||||
self.GenericSpecDepth -= 1
|
||||
return None
|
||||
|
||||
# 2. 生成特化名
|
||||
spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args)
|
||||
if spec_name is None:
|
||||
self.GenericSpecDepth -= 1
|
||||
return None
|
||||
|
||||
# 治本修复:Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前)
|
||||
@@ -2122,6 +2145,7 @@ class ClassGenMixin:
|
||||
sk_total += 1 # NUL
|
||||
spec_key: str = pool.alloc(sk_total)
|
||||
if spec_key is None:
|
||||
self.GenericSpecDepth -= 1
|
||||
return None
|
||||
spec_key[0] = '\0'
|
||||
string.strcat(spec_key, class_name)
|
||||
@@ -2140,6 +2164,7 @@ class ClassGenMixin:
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "CACHE HIT, return cached=%s", cached)
|
||||
VLogger.debug(fb, "SPEC")
|
||||
self.GenericSpecDepth -= 1
|
||||
return cached
|
||||
|
||||
# 4. 检查是否已注册(Phase B 重复特化)
|
||||
@@ -2152,6 +2177,7 @@ class ClassGenMixin:
|
||||
spec_name, existing.FieldCount)
|
||||
VLogger.debug(fb, "SPEC")
|
||||
self._cache_spec(pool, spec_key, spec_name)
|
||||
self.GenericSpecDepth -= 1
|
||||
return spec_name
|
||||
|
||||
# 预注册缓存(防止递归)
|
||||
@@ -2162,6 +2188,7 @@ class ClassGenMixin:
|
||||
spec_cd: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec(
|
||||
pool, template_cd, spec_name, tp_names, type_args)
|
||||
if spec_cd is None:
|
||||
self.GenericSpecDepth -= 1
|
||||
return None
|
||||
|
||||
# 6. 设置 type_map 上下文(用于方法体中的 T 替换)
|
||||
@@ -2216,6 +2243,7 @@ class ClassGenMixin:
|
||||
else:
|
||||
VLogger.debug("DONE but result NOT FOUND in struct table!", "SPEC")
|
||||
|
||||
self.GenericSpecDepth -= 1
|
||||
return spec_name
|
||||
|
||||
# ============================================================
|
||||
@@ -2469,6 +2497,14 @@ class ClassGenMixin:
|
||||
# 解析字段类型
|
||||
field_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
|
||||
# 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem]
|
||||
# (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义):
|
||||
# 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**),
|
||||
# for x in self.field 会误走指针迭代(元素非整数 → null 终止符
|
||||
# 检查失败报错)。推断为静态数组后走数组迭代(按长度 N)。
|
||||
if field_ty is not None:
|
||||
field_ty = HandlesAnnAssign._infer_static_array_ty_from_literal(
|
||||
pool, aa.annotation, aa.value, field_ty)
|
||||
if field_ty is None:
|
||||
# BUG 5 方案1修改点1:消除 i32 静默回退
|
||||
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,延迟到下一遍
|
||||
@@ -3257,6 +3293,14 @@ class ClassGenMixin:
|
||||
self._collect_vtable_methods(trans, cd, class_name)
|
||||
return 0
|
||||
|
||||
# 防重复生成:MethodsEmitted==1 说明方法体/__before_init__ 已生成过。
|
||||
# 场景:_specialize_generic_class 的 Phase B 补译分支(MethodsEmitted==0
|
||||
# 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量
|
||||
# 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。
|
||||
# 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。
|
||||
if oop_entry is not None and oop_entry.MethodsEmitted == 1:
|
||||
return 0
|
||||
|
||||
# 防重入:方法体翻译前先标记 MethodsEmitted=1。
|
||||
# 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]|t.CPtr)时,
|
||||
# 返回类型注解会再次触发 _specialize_generic_class,此时 MethodsEmitted
|
||||
@@ -3775,6 +3819,25 @@ class ClassGenMixin:
|
||||
bi_entry, fi)
|
||||
if fe is None or fe.DefaultVal is None:
|
||||
continue
|
||||
# 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store
|
||||
# (与局部 AnnAssign 数组初始化一致;translate_value 会把列表字面量
|
||||
# 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。
|
||||
# 单参 CArray 字段(如 t.CArray[str] = ["py", ...])经类体字段收集
|
||||
# 推断为静态数组,此处保证 __before_init__ 填充真实字符串指针。
|
||||
if fe.Ty is not None and HandlesExpr.is_array_type(fe.Ty) != 0 \
|
||||
and fe.DefaultVal.kind() == ast.ASTKind.List:
|
||||
field_ptr_arr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
func_builder, struct_ty, fe.Ty, self_val, fe.Index)
|
||||
if field_ptr_arr is not None:
|
||||
zero_arr_f: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty)
|
||||
if zero_arr_f is not None:
|
||||
llvmlite.build_store(func_builder, zero_arr_f, field_ptr_arr)
|
||||
# Mixin 静态绑定:self._xxx 只沿本类查找,跨 Mixin 方法
|
||||
# (AssignGenMixin._init_global_array_from_list)会生成不存在
|
||||
# 符号 → 必须走 HandlesAnnAssign 模块级委托(延迟 import Gen)。
|
||||
HandlesAnnAssign._init_global_array_from_list(
|
||||
func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans)
|
||||
continue
|
||||
# 翻译默认值表达式
|
||||
default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
func_builder, pool, mod, fe.DefaultVal, None, 0, trans)
|
||||
|
||||
@@ -38,6 +38,17 @@ DOC_MAX: t.CDefine = 512
|
||||
DOC_KEY_SZ: t.CDefine = 192
|
||||
DOC_VAL_SZ: t.CDefine = 4096
|
||||
|
||||
# ============================================================
|
||||
# f-string 翻译常量(对齐 TPC HandlesExprFormat)
|
||||
#
|
||||
# FSTR_BUF_SIZE: 运行时栈缓冲大小(snprintf 结果缓冲)
|
||||
# FSTR_SPEC_MAX: 编译期 format_spec 解析缓冲宽度
|
||||
# FSTR_FMT_MAX: 编译期 C printf 格式串缓冲宽度
|
||||
# ============================================================
|
||||
FSTR_BUF_SIZE: t.CDefine = 1024
|
||||
FSTR_SPEC_MAX: t.CDefine = 64
|
||||
FSTR_FMT_MAX: t.CDefine = 64
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenMixin - 表达式处理 Mixin(对象化 P3,wiki/14-oo-refactor.md)
|
||||
@@ -925,8 +936,473 @@ class ExprGenMixin:
|
||||
# 模块级委托:translate_lambda 定义在 FuncGenMixin(跨 Mixin
|
||||
# 方法不能 self. 直接调用,见 HandlesExpr.translate_lambda)
|
||||
return HandlesExpr.translate_lambda(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.JoinedStr:
|
||||
return self.translate_joined_str(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.FormattedValue:
|
||||
# 解析器对 f"{expr:spec}"(单 FormattedValue 无字面量)返回裸 FormattedValue
|
||||
# 而非 JoinedStr(见 ast/parser.vp _parse_fstring),需单独翻译
|
||||
return self.translate_formatted_value(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# translate_joined_str - f-string 翻译(对齐 TPC _HandleJoinedStrLlvm)
|
||||
#
|
||||
# f"..."(JoinedStr)→ 拼接字面量与格式说明符 → snprintf 生成 i8*
|
||||
# 栈缓冲。之前 f-string 未翻译导致 print/赋值拿到 NULL 指针
|
||||
# ("(null)"输出 + printf("%s", 垃圾) 崩溃 0xC0000005)。
|
||||
# ============================================================
|
||||
def translate_joined_str(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""f-string → snprintf 生成 i8* 栈缓冲"""
|
||||
if node is None or builder is None or trans is None:
|
||||
return None
|
||||
js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(node)
|
||||
if js is None or js.values is None:
|
||||
return None
|
||||
|
||||
# 编译期格式串缓冲(pool 分配)
|
||||
fmt_buf: t.CChar | t.CPtr = pool.alloc(FSTR_BUF_SIZE)
|
||||
if fmt_buf is None:
|
||||
return None
|
||||
fmt_buf[0] = '\0'
|
||||
|
||||
# 运行时参数链表(Value.Next 链接,与 printf 调用一致)
|
||||
arg_head: llvmlite.Value | t.CPtr = None
|
||||
arg_tail: llvmlite.Value | t.CPtr = None
|
||||
arg_count: int = 0
|
||||
|
||||
parts: list[ast.AST | t.CPtr] | t.CPtr = js.values
|
||||
pn: t.CSizeT = parts.__len__()
|
||||
for pi in range(pn):
|
||||
part: ast.AST | t.CPtr = parts.get(pi)
|
||||
if part is None:
|
||||
continue
|
||||
if part.kind() == ast.ASTKind.Constant:
|
||||
pcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part)
|
||||
if pcn.const_kind == ast.CONST_STR and pcn.str_val is not None:
|
||||
self._fstr_append_literal(fmt_buf, pcn.str_val)
|
||||
continue
|
||||
if part.kind() != ast.ASTKind.FormattedValue:
|
||||
continue
|
||||
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part)
|
||||
if fv.value is None:
|
||||
continue
|
||||
val: llvmlite.Value | t.CPtr = self.translate_value(
|
||||
builder, pool, mod, fv.value, None, 0, trans)
|
||||
if val is None:
|
||||
self._fstr_append_raw(fmt_buf, "(null)")
|
||||
continue
|
||||
# 确定 C 格式说明符(format_spec 优先,否则按值类型推断)
|
||||
c_fmt: str = None
|
||||
if fv.format_spec is not None:
|
||||
c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value)
|
||||
if c_fmt is None:
|
||||
c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
|
||||
if c_fmt is None:
|
||||
c_fmt = "%d"
|
||||
# 追加格式说明符
|
||||
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1:
|
||||
string.strcat(fmt_buf, c_fmt)
|
||||
# 转换参数类型(i8/i16→i32、bool→i32、f32→f64)
|
||||
cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value(
|
||||
builder, pool, val, c_fmt, fv.value, trans)
|
||||
if cast_val is None:
|
||||
cast_val = val
|
||||
cast_val.Next = None
|
||||
if arg_head is None:
|
||||
arg_head = cast_val
|
||||
else:
|
||||
arg_tail.Next = cast_val
|
||||
arg_tail = cast_val
|
||||
arg_count += 1
|
||||
|
||||
return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
||||
|
||||
def translate_formatted_value(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译裸 FormattedValue(f"{expr:spec}" 无字面量时解析器返回 FormattedValue 而非 JoinedStr)"""
|
||||
if node is None or builder is None or trans is None:
|
||||
return None
|
||||
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node)
|
||||
if fv is None or fv.value is None:
|
||||
return None
|
||||
fmt_buf: t.CChar | t.CPtr = pool.alloc(FSTR_BUF_SIZE)
|
||||
if fmt_buf is None:
|
||||
return None
|
||||
fmt_buf[0] = '\0'
|
||||
arg_head: llvmlite.Value | t.CPtr = None
|
||||
arg_tail: llvmlite.Value | t.CPtr = None
|
||||
arg_count: int = 0
|
||||
val: llvmlite.Value | t.CPtr = self.translate_value(
|
||||
builder, pool, mod, fv.value, None, 0, trans)
|
||||
if val is None:
|
||||
self._fstr_append_raw(fmt_buf, "(null)")
|
||||
else:
|
||||
c_fmt: str = None
|
||||
if fv.format_spec is not None:
|
||||
c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value)
|
||||
if c_fmt is None:
|
||||
c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
|
||||
if c_fmt is None:
|
||||
c_fmt = "%d"
|
||||
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1:
|
||||
string.strcat(fmt_buf, c_fmt)
|
||||
cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value(
|
||||
builder, pool, val, c_fmt, fv.value, trans)
|
||||
if cast_val is None:
|
||||
cast_val = val
|
||||
cast_val.Next = None
|
||||
arg_head = cast_val
|
||||
arg_tail = cast_val
|
||||
arg_count = 1
|
||||
return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
||||
|
||||
def _fstr_finalize(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
fmt_buf: t.CChar | t.CPtr,
|
||||
arg_head: llvmlite.Value | t.CPtr,
|
||||
arg_tail: llvmlite.Value | t.CPtr,
|
||||
arg_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""f-string 尾部:全局格式串 + 固定栈缓冲 + snprintf,返回 i8*"""
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
if fmt_buf is None or fmt_buf[0] == '\0':
|
||||
# 空 f-string(f"")→ 空字符串常量
|
||||
return HandlesExpr.create_global_string(builder, pool, mod, "", trans)
|
||||
# 格式串 → 全局字符串常量(i8*)
|
||||
fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string(
|
||||
builder, pool, mod, fmt_buf, trans)
|
||||
if fmt_ptr is None:
|
||||
return None
|
||||
# 固定栈缓冲 [FSTR_BUF_SIZE x i8],GEP(0,0) 取 i8*
|
||||
buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE)
|
||||
buf_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, buf_ty)
|
||||
if buf_alloca is None:
|
||||
return None
|
||||
zero_i32: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
buf_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||||
builder, buf_ty, i8_ty, buf_alloca, zero_i32)
|
||||
if buf_ptr is None:
|
||||
return None
|
||||
# snprintf(buf, FSTR_BUF_SIZE, fmt, args...)
|
||||
size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, FSTR_BUF_SIZE)
|
||||
buf_ptr.Next = size_val
|
||||
size_val.Next = fmt_ptr
|
||||
fmt_ptr.Next = arg_head
|
||||
if arg_tail is not None:
|
||||
arg_tail.Next = None
|
||||
llvmlite.build_call(builder, "snprintf", buf_ptr, 3 + arg_count, i32_ty, 1)
|
||||
return buf_ptr
|
||||
|
||||
def _fstr_append_literal(self, fmt_buf: t.CChar | t.CPtr,
|
||||
lit: str) -> None:
|
||||
"""追加字面量到格式串(% 转义为 %%)"""
|
||||
if fmt_buf is None or lit is None:
|
||||
return
|
||||
cur_len: t.CSizeT = string.strlen(fmt_buf)
|
||||
rem: t.CSizeT = FSTR_BUF_SIZE - 1 - cur_len
|
||||
if rem == 0:
|
||||
return
|
||||
src_len: t.CSizeT = string.strlen(lit)
|
||||
si: t.CSizeT = 0
|
||||
while si < src_len and rem > 0:
|
||||
ch: t.CChar = lit[si]
|
||||
if ch == '%':
|
||||
if rem < 2:
|
||||
break
|
||||
fmt_buf[cur_len] = '%'
|
||||
fmt_buf[cur_len + 1] = '%'
|
||||
cur_len += 2
|
||||
rem -= 2
|
||||
else:
|
||||
fmt_buf[cur_len] = ch
|
||||
cur_len += 1
|
||||
rem -= 1
|
||||
si += 1
|
||||
fmt_buf[cur_len] = '\0'
|
||||
|
||||
def _fstr_append_raw(self, fmt_buf: t.CChar | t.CPtr, s: str) -> None:
|
||||
"""追加原始字符串(不做 % 转义)"""
|
||||
if fmt_buf is None or s is None:
|
||||
return
|
||||
cur_len: t.CSizeT = string.strlen(fmt_buf)
|
||||
src_len: t.CSizeT = string.strlen(s)
|
||||
if cur_len + src_len < FSTR_BUF_SIZE:
|
||||
string.strcpy(fmt_buf + cur_len, s)
|
||||
|
||||
def _fstr_parse_format_spec(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
spec_node: ast.AST | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
arg_node: ast.AST | t.CPtr) -> str:
|
||||
"""Python format_spec → C printf 格式串(pool 分配),无法解析返回 None"""
|
||||
if spec_node is None or pool is None or val is None:
|
||||
return None
|
||||
# 1. 提取 spec 字符串(JoinedStr 仅常量拼接)
|
||||
spec: t.CChar | t.CPtr = pool.alloc(FSTR_SPEC_MAX)
|
||||
if spec is None:
|
||||
return None
|
||||
spec[0] = '\0'
|
||||
sk: int = spec_node.kind()
|
||||
if sk == ast.ASTKind.JoinedStr:
|
||||
jss: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(spec_node)
|
||||
if jss.values is None:
|
||||
return None
|
||||
vn: t.CSizeT = jss.values.__len__()
|
||||
for vi in range(vn):
|
||||
vpart: ast.AST | t.CPtr = jss.values.get(vi)
|
||||
if vpart is None:
|
||||
continue
|
||||
if vpart.kind() != ast.ASTKind.Constant:
|
||||
return None
|
||||
vcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(vpart)
|
||||
if vcn.const_kind != ast.CONST_STR or vcn.str_val is None:
|
||||
return None
|
||||
if string.strlen(spec) + string.strlen(vcn.str_val) < FSTR_SPEC_MAX - 1:
|
||||
string.strcat(spec, vcn.str_val)
|
||||
elif sk == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(spec_node)
|
||||
if cn.const_kind != ast.CONST_STR or cn.str_val is None:
|
||||
return None
|
||||
string.strncpy(spec, cn.str_val, FSTR_SPEC_MAX - 1)
|
||||
else:
|
||||
return None
|
||||
slen: t.CSizeT = string.strlen(spec)
|
||||
if slen == 0:
|
||||
return None
|
||||
|
||||
# 2. 逐段解析: [fill]align / sign / # / 0 / width / , / .precision / type
|
||||
pos: t.CSizeT = 0
|
||||
align_char: t.CChar = 0
|
||||
if pos < slen:
|
||||
ch0: t.CChar = spec[pos]
|
||||
if ch0 == '<' or ch0 == '>' or ch0 == '^' or ch0 == '=':
|
||||
align_char = ch0
|
||||
pos += 1
|
||||
elif pos + 1 < slen:
|
||||
ch1: t.CChar = spec[pos + 1]
|
||||
if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=':
|
||||
align_char = ch1
|
||||
pos += 2
|
||||
c_flags: t.CChar | t.CPtr = pool.alloc(FSTR_FMT_MAX)
|
||||
c_width: t.CChar | t.CPtr = pool.alloc(32)
|
||||
c_prec: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if c_flags is None or c_width is None or c_prec is None:
|
||||
return None
|
||||
c_flags[0] = '\0'
|
||||
c_width[0] = '\0'
|
||||
c_prec[0] = '\0'
|
||||
# sign
|
||||
if pos < slen and (spec[pos] == '+' or spec[pos] == '-' or spec[pos] == ' '):
|
||||
if spec[pos] == '+':
|
||||
string.strcat(c_flags, "+")
|
||||
elif spec[pos] == ' ':
|
||||
string.strcat(c_flags, " ")
|
||||
pos += 1
|
||||
# alt '#'
|
||||
if pos < slen and spec[pos] == '#':
|
||||
string.strcat(c_flags, "#")
|
||||
pos += 1
|
||||
# zero '0'
|
||||
if pos < slen and spec[pos] == '0':
|
||||
string.strcat(c_flags, "0")
|
||||
pos += 1
|
||||
# 左对齐 '<'/'^' → '-'(与 0 同时存在时 C 语义 '-' 优先)
|
||||
if align_char == '<' or align_char == '^':
|
||||
string.strcat(c_flags, "-")
|
||||
# width digits
|
||||
while pos < slen and spec[pos] >= '0' and spec[pos] <= '9':
|
||||
wl: t.CSizeT = string.strlen(c_width)
|
||||
if wl < 30:
|
||||
c_width[wl] = spec[pos]
|
||||
c_width[wl + 1] = '\0'
|
||||
pos += 1
|
||||
# comma ',' → C printf 不支持千分位,忽略
|
||||
if pos < slen and spec[pos] == ',':
|
||||
pos += 1
|
||||
# .precision
|
||||
if pos < slen and spec[pos] == '.':
|
||||
string.strcat(c_prec, ".")
|
||||
pos += 1
|
||||
while pos < slen and spec[pos] >= '0' and spec[pos] <= '9':
|
||||
pl: t.CSizeT = string.strlen(c_prec)
|
||||
if pl < 30:
|
||||
c_prec[pl] = spec[pos]
|
||||
c_prec[pl + 1] = '\0'
|
||||
pos += 1
|
||||
if string.strlen(c_prec) == 1:
|
||||
return None # 只有 '.' 无效
|
||||
# type char
|
||||
fmt_type: t.CChar = 0
|
||||
if pos < slen:
|
||||
fmt_type = spec[pos]
|
||||
pos += 1
|
||||
if pos != slen:
|
||||
return None # 多余字符无法解析
|
||||
|
||||
# 3. 长度修饰(按值类型位宽)
|
||||
len_mod: t.CChar | t.CPtr = pool.alloc(4)
|
||||
if len_mod is None:
|
||||
return None
|
||||
len_mod[0] = '\0'
|
||||
ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
|
||||
if ibits == 64:
|
||||
string.strcpy(len_mod, "ll")
|
||||
elif ibits == 32:
|
||||
string.strcpy(len_mod, "l")
|
||||
elif ibits == 16:
|
||||
string.strcpy(len_mod, "h")
|
||||
elif ibits == 8:
|
||||
string.strcpy(len_mod, "hh")
|
||||
|
||||
# 4. 组装 C 格式串
|
||||
out: t.CChar | t.CPtr = pool.alloc(FSTR_FMT_MAX)
|
||||
if out is None:
|
||||
return None
|
||||
out[0] = '\0'
|
||||
string.strcat(out, "%")
|
||||
string.strcat(out, c_flags)
|
||||
string.strcat(out, c_width)
|
||||
string.strcat(out, c_prec)
|
||||
if fmt_type == 0:
|
||||
# 无 type:按值类型推断
|
||||
fbits2: int = HandlesExpr.get_llvm_float_bits(val.Ty)
|
||||
if ibits != 0:
|
||||
if ibits == 8:
|
||||
string.strcat(out, "c")
|
||||
elif ibits == 1:
|
||||
string.strcat(out, "d")
|
||||
else:
|
||||
string.strcat(out, len_mod)
|
||||
string.strcat(out, "d")
|
||||
elif fbits2 != 0:
|
||||
string.strcat(out, "f")
|
||||
elif HandlesExpr.is_ptr_type(val.Ty) != 0:
|
||||
string.strcat(out, "s")
|
||||
else:
|
||||
string.strcat(out, "d")
|
||||
elif fmt_type == 'c':
|
||||
string.strcat(out, "c")
|
||||
elif fmt_type == 'f' or fmt_type == 'F':
|
||||
string.strcat(out, "f")
|
||||
elif fmt_type == 'e' or fmt_type == 'E' or fmt_type == 'g' or fmt_type == 'G':
|
||||
tmp_ch: t.CChar | t.CPtr = pool.alloc(2)
|
||||
if tmp_ch is None:
|
||||
return None
|
||||
tmp_ch[0] = fmt_type
|
||||
tmp_ch[1] = '\0'
|
||||
string.strcat(out, tmp_ch)
|
||||
elif fmt_type == 's':
|
||||
string.strcat(out, "s")
|
||||
elif fmt_type == '%':
|
||||
string.strcat(out, "%")
|
||||
elif fmt_type == 'b':
|
||||
return None # 二进制不支持
|
||||
elif fmt_type == 'd' or fmt_type == 'i':
|
||||
string.strcat(out, len_mod)
|
||||
string.strcat(out, "d")
|
||||
elif fmt_type == 'x' or fmt_type == 'X' or fmt_type == 'o' or fmt_type == 'u':
|
||||
string.strcat(out, len_mod)
|
||||
tmp_ch2: t.CChar | t.CPtr = pool.alloc(2)
|
||||
if tmp_ch2 is None:
|
||||
return None
|
||||
tmp_ch2[0] = fmt_type
|
||||
tmp_ch2[1] = '\0'
|
||||
string.strcat(out, tmp_ch2)
|
||||
else:
|
||||
return None
|
||||
return out
|
||||
|
||||
def _fstr_infer_c_fmt(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
arg_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> str:
|
||||
"""无 format_spec 时按值类型推断 C printf 格式(对齐 TPC 无 spec 分支,带 % 前缀)"""
|
||||
if val is None or pool is None:
|
||||
return None
|
||||
out: t.CChar | t.CPtr = pool.alloc(16)
|
||||
if out is None:
|
||||
return None
|
||||
out[0] = '\0'
|
||||
ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
|
||||
fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty)
|
||||
if ibits == 1:
|
||||
return "%d" # bool
|
||||
if ibits == 8:
|
||||
return "%c" # 字符
|
||||
if ibits != 0:
|
||||
if self._node_type_unsigned(pool, arg_node, trans) != 0:
|
||||
if ibits == 64:
|
||||
string.strcpy(out, "%llu")
|
||||
else:
|
||||
string.strcpy(out, "%u")
|
||||
else:
|
||||
if ibits == 64:
|
||||
string.strcpy(out, "%lld")
|
||||
else:
|
||||
string.strcpy(out, "%d")
|
||||
return out
|
||||
if fbits != 0:
|
||||
return "%f"
|
||||
if HandlesExpr.is_ptr_type(val.Ty) != 0:
|
||||
return "%s"
|
||||
return "%d"
|
||||
|
||||
def _fstr_cast_value(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
c_fmt: str,
|
||||
arg_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)"""
|
||||
if val is None or c_fmt is None:
|
||||
return None
|
||||
# 找格式类型字符(最后一个字母,忽略 l/h 长度修饰)
|
||||
fmt_char: t.CChar = 0
|
||||
flen: t.CSizeT = string.strlen(c_fmt)
|
||||
fi: t.CSizeT = flen
|
||||
while fi > 0:
|
||||
fi -= 1
|
||||
ch: t.CChar = c_fmt[fi]
|
||||
if ch == '%':
|
||||
break
|
||||
if (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z'):
|
||||
if ch != 'l' and ch != 'h':
|
||||
fmt_char = ch
|
||||
break
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if fmt_char == 's':
|
||||
return val
|
||||
if fmt_char == 'c':
|
||||
ibits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
|
||||
if ibits != 0 and ibits < 32:
|
||||
return llvmlite.build_zext(builder, val, i32_ty)
|
||||
return val
|
||||
if fmt_char == 'd' or fmt_char == 'i' or fmt_char == 'x' \
|
||||
or fmt_char == 'X' or fmt_char == 'o' or fmt_char == 'u':
|
||||
ibits = HandlesExpr.get_llvm_type_bits(val.Ty)
|
||||
if ibits == 1:
|
||||
return llvmlite.build_zext(builder, val, i32_ty)
|
||||
if ibits == 8 or ibits == 16:
|
||||
if self._node_type_unsigned(pool, arg_node, trans) != 0:
|
||||
return llvmlite.build_zext(builder, val, i32_ty)
|
||||
return llvmlite.build_sext(builder, val, i32_ty)
|
||||
return val
|
||||
if fmt_char == 'f' or fmt_char == 'e' or fmt_char == 'E' \
|
||||
or fmt_char == 'g' or fmt_char == 'G':
|
||||
fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty)
|
||||
if fbits == 32:
|
||||
return llvmlite.build_fpext(builder, val, llvmlite.Double(pool))
|
||||
return val
|
||||
return val
|
||||
|
||||
# ============================================================
|
||||
# 翻译三元表达式 IfExp(test, body, orelse)
|
||||
#
|
||||
|
||||
@@ -602,7 +602,8 @@ class ImportsGenMixin:
|
||||
if mod_name is None:
|
||||
return 1
|
||||
# t/c 是内部库,不参与 includes 扫描,豁免检查
|
||||
if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0:
|
||||
# ctraits 是纯编译期宏库(.vpi 后缀,IncludesScanner 不扫描 .vpi),豁免检查
|
||||
if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0 or string.strcmp(mod_name, "ctraits") == 0:
|
||||
return 1
|
||||
mod_sha1: str = StubMerger.LookupSha1ByModName(mod_name)
|
||||
if mod_sha1 is None:
|
||||
|
||||
@@ -474,6 +474,8 @@ class StmtGenMixin:
|
||||
return cn.int_val
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
if k == ast.ASTKind.Call:
|
||||
return self._cif_eval_call(pool, trans, node)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm.id is None:
|
||||
@@ -584,6 +586,69 @@ class StmtGenMixin:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
|
||||
def _eval_ctraits_isptr(self, symtab: HandlesVar.SymbolTable | t.CPtr,
|
||||
name: str) -> int:
|
||||
"""ctraits.isptr(name) 编译期求值。
|
||||
|
||||
按变量实际存储类型判断是否指针:alloca 的 pointee 为 Ptr 即指针
|
||||
(与 TPC ConstEvaluator._eval_compile_time_call 的 LLVM 类型判断一致)。
|
||||
返回: 1=指针 0=非指针 -1=无法求值(变量不存在/无类型信息)。
|
||||
"""
|
||||
if name is None or symtab is None:
|
||||
return -1
|
||||
v: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(symtab, name)
|
||||
if v is None or v.Ty is None:
|
||||
return -1
|
||||
pointee: llvmlite.LLVMType | t.CPtr = v.Ty.Pointee
|
||||
if pointee is not None and HandlesExpr.is_ptr_type(pointee) != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _cif_eval_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""编译期函数调用求值:ctraits.isptr(x)。
|
||||
|
||||
命中置 self.CifEvalOk=1 返回 1/0;未识别调用置 0 返回 0。
|
||||
"""
|
||||
self.CifEvalOk = 0
|
||||
if node is None or trans is None:
|
||||
return 0
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl is None or cl.func is None:
|
||||
return 0
|
||||
fk: int = cl.func.kind()
|
||||
if fk != ast.ASTKind.Attribute:
|
||||
return 0
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if at.value is None or at.attr is None:
|
||||
return 0
|
||||
if at.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if vn.id is None:
|
||||
return 0
|
||||
if string.strcmp(vn.id, "ctraits") != 0 or string.strcmp(at.attr, "isptr") != 0:
|
||||
return 0
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
if cargs is None or cargs.__len__() < 1:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
arg0: ast.AST | t.CPtr = cargs.get(0)
|
||||
if arg0 is None or arg0.kind() != ast.ASTKind.Name:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
|
||||
if nm0.id is None:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
r: int = self._eval_ctraits_isptr(trans.SymTab, nm0.id)
|
||||
if r < 0:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
self.CifEvalOk = 1
|
||||
return r
|
||||
|
||||
def _evaluate_cif_test(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
test: ast.AST | t.CPtr) -> int:
|
||||
|
||||
@@ -317,12 +317,15 @@ class StructGenMixin:
|
||||
字段默认值(fe.DefaultVal)除定义文件内 _generate_before_init 使用外,
|
||||
跨文件结构体构造(_translate_struct_ctor → _apply_struct_defaults)会在
|
||||
调用方文件翻译时读取——原 pool AST 已 reset 回收必须深拷贝。
|
||||
非常量默认值(Name/BinOp 等引用表达式)无法安全深拷贝:返回 None
|
||||
支持 Constant(标量)与 List(列表字面量,如 t.CArray[str] = ["py", "pyw"])。
|
||||
其他非常量默认值(Name/BinOp 等引用表达式)无法安全深拷贝:返回 None
|
||||
(调用方 fe.DefaultVal 保持 None,仅定义文件内 _generate_before_init
|
||||
仍持有原始 pool 指针,不受影响)。
|
||||
"""
|
||||
if default_val is None:
|
||||
return None
|
||||
if default_val.kind() == ast.ASTKind.List:
|
||||
return self._deep_copy_list_ast(default_val)
|
||||
if default_val.kind() != ast.ASTKind.Constant:
|
||||
return None
|
||||
src_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(default_val)
|
||||
@@ -352,6 +355,57 @@ class StructGenMixin:
|
||||
dst_c.str_val = s_copy
|
||||
return (ast.AST | t.CPtr)(dst_c)
|
||||
|
||||
def _deep_copy_list_ast(self, default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
|
||||
"""深拷贝 List 节点(列表字面量默认值)到 stdlib,跨 1b reset 存活。
|
||||
|
||||
elts 容器手动在 stdlib 构造(list 的 __pool__ 置 None:深拷贝的 elts
|
||||
只被只读访问 get/__len__/迭代,不 append,不会触发 pool 扩容)。
|
||||
元素递归调用 _deep_copy_default_ast(支持 Constant 与嵌套 List)。
|
||||
"""
|
||||
src_l: ast.List | t.CPtr = (ast.List | t.CPtr)(default_val)
|
||||
dst_l: ast.List | t.CPtr = (ast.List | t.CPtr)(
|
||||
stdlib.malloc(ast.List.__sizeof__()))
|
||||
if dst_l is None:
|
||||
return None
|
||||
string.memset(dst_l, 0, ast.List.__sizeof__())
|
||||
# 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr)
|
||||
vt_l: t.CVoid | t.CPtr = t.CVoid(
|
||||
c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr)
|
||||
c.DerefAs(dst_l, vt_l)
|
||||
# 拷贝位置字段与 ctx
|
||||
dst_l.lineno = src_l.lineno
|
||||
dst_l.col_offset = src_l.col_offset
|
||||
dst_l.end_lineno = src_l.end_lineno
|
||||
dst_l.end_col_offset = src_l.end_col_offset
|
||||
dst_l.ctx = src_l.ctx
|
||||
# 深拷贝 elts:stdlib 手动构造 list[AST | t.CPtr] 容器
|
||||
src_elts_l: list[ast.AST | t.CPtr] | t.CPtr = src_l.elts
|
||||
if src_elts_l is not None:
|
||||
cnt_l: t.CSizeT = src_elts_l.__len__()
|
||||
lst_copy_l: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(
|
||||
stdlib.malloc(list[ast.AST | t.CPtr].__sizeof__()))
|
||||
if lst_copy_l is not None:
|
||||
string.memset(lst_copy_l, 0, list[ast.AST | t.CPtr].__sizeof__())
|
||||
lst_copy_l.__count__ = cnt_l
|
||||
lst_copy_l.__capacity__ = cnt_l
|
||||
lst_copy_l.__elem_size__ = 8
|
||||
lst_copy_l.__pool__ = None
|
||||
data_l: t.CVoid | t.CPtr = stdlib.malloc(cnt_l * 8)
|
||||
if data_l is not None:
|
||||
string.memset(data_l, 0, cnt_l * 8)
|
||||
lst_copy_l.__data__ = data_l
|
||||
li_l: t.CSizeT
|
||||
for li_l in range(cnt_l):
|
||||
elem_src_l: ast.AST | t.CPtr = src_elts_l.get(li_l)
|
||||
if elem_src_l is not None:
|
||||
elem_dst_l: ast.AST | t.CPtr = self._deep_copy_default_ast(elem_src_l)
|
||||
if elem_dst_l is not None:
|
||||
slot_l: ast.AST | t.CPtr = (ast.AST | t.CPtr)(
|
||||
t.CVoid(t.CUInt64T(data_l) + li_l * 8, t.CPtr))
|
||||
slot_l[0] = elem_dst_l
|
||||
dst_l.elts = lst_copy_l
|
||||
return (ast.AST | t.CPtr)(dst_l)
|
||||
|
||||
def get_struct_count(self) -> int:
|
||||
"""返回当前已注册的结构体数量"""
|
||||
return self.StructCount
|
||||
|
||||
@@ -1608,6 +1608,11 @@ class TypeGenMixin:
|
||||
if gp_tpn is not None and string.strcmp(nm.id, gp_tpn) == 0:
|
||||
gp_ta: str = self.GenericTypeArgs.get(gp_i)
|
||||
if gp_ta is not None:
|
||||
# 自映射防护(泛型循环套用):实参与参数名相同(T→T)
|
||||
# 时 _parse_type_string 会重新解析回同一个 Name → 无条件
|
||||
# 自递归无退出条件 → 编译卡死。直接返回 None 让上层回落。
|
||||
if string.strcmp(gp_ta, gp_tpn) == 0:
|
||||
return None
|
||||
# 用具体类型名递归解析(支持 BinOp/Attribute 类型实参)
|
||||
gp_sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, gp_ta, nm.ctx)
|
||||
if gp_sub_node is not None:
|
||||
|
||||
@@ -162,6 +162,72 @@ def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _is_single_param_carray_annot - 检查注解是否为单参 t.CArray[elem_ty]
|
||||
#
|
||||
# 单参形式(t.CArray[elem_ty])与 count=None 形式(t.CArray[elem_ty, None])
|
||||
# 都解析为 Ptr(elem_ty)。当 RHS 是列表字面量时,按 TPC 语义应推断为
|
||||
# 静态数组 [len x elem_ty](对齐 TPC ParseListAnnotation 的 is_pointer 分支:
|
||||
# "单参数 list[type] → 指针,但如果有列表字面量初始化值则按数组 list[type, N] 处理")。
|
||||
# ============================================================
|
||||
def _is_single_param_carray_annot(annot: ast.AST | t.CPtr) -> int:
|
||||
"""检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否"""
|
||||
if annot is None or annot.kind() != ast.ASTKind.Subscript:
|
||||
return 0
|
||||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
|
||||
if sub.value is None or sub.slice is None:
|
||||
return 0
|
||||
if sub.value.kind() != ast.ASTKind.Attribute:
|
||||
return 0
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value)
|
||||
if at.attr is None or string.strcmp(at.attr, "CArray") != 0:
|
||||
return 0
|
||||
if at.value is None or at.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if mv.id is None or string.strcmp(mv.id, "t") != 0:
|
||||
return 0
|
||||
# 单参形式:slice 非 Tuple(如 t.CArray[u64])
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||
return 1
|
||||
# 双参形式:count=None(t.CArray[u64, None])→ 等价单参
|
||||
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice)
|
||||
if tup.elts is None or tup.elts.__len__() < 2:
|
||||
return 0
|
||||
cnt_node: ast.AST | t.CPtr = tup.elts.get(1)
|
||||
if cnt_node is not None and cnt_node.kind() == ast.ASTKind.Constant:
|
||||
cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(cnt_node)
|
||||
if cn0.const_kind == ast.CONST_NONE:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组
|
||||
#
|
||||
# 单参 t.CArray[elem_ty] 解析为 Ptr(elem_ty),但当 RHS 是列表字面量时,
|
||||
# 按 TPC 语义应推断为 [len x elem_ty](对齐 TPC ParseListAnnotation):
|
||||
# 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期
|
||||
# undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须
|
||||
# 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。
|
||||
# ============================================================
|
||||
def _infer_static_array_ty_from_literal(pool: memhub.MemBuddy | t.CPtr,
|
||||
annot: ast.AST | t.CPtr,
|
||||
value: ast.AST | t.CPtr,
|
||||
resolved_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型"""
|
||||
if value is not None and value.kind() == ast.ASTKind.List and resolved_ty is not None:
|
||||
if _is_single_param_carray_annot(annot) != 0:
|
||||
elem_ty_arr: llvmlite.LLVMType | t.CPtr = resolved_ty.Pointee
|
||||
lst_arr: ast.List | t.CPtr = (ast.List | t.CPtr)(value)
|
||||
cnt_arr: int = 0
|
||||
if lst_arr.elts is not None:
|
||||
cnt_arr = lst_arr.elts.__len__()
|
||||
if elem_ty_arr is not None and cnt_arr > 0:
|
||||
return llvmlite.Array(pool, elem_ty_arr, cnt_arr)
|
||||
return resolved_ty
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _init_global_array_from_list — 从列表字面量初始化全局数组
|
||||
#
|
||||
@@ -279,6 +345,10 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
||||
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
|
||||
if resolved is not None:
|
||||
var_ty = resolved
|
||||
# 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。
|
||||
# PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的
|
||||
# get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。
|
||||
var_ty = _infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||||
else:
|
||||
# fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32)
|
||||
HandlesType.fatal_error(
|
||||
@@ -440,6 +510,11 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
||||
llvmlite.build_store(builder, rhs_val_mg, mod_glob)
|
||||
return 0
|
||||
|
||||
# 单参 t.CArray[elem_ty] + 列表字面量 → 按静态数组处理(count 从字面量长度推断)
|
||||
# 与 PreScan 推断一致:get_or_create_sym 复用 PreScan 创建的 alloca,
|
||||
# 类型一致才能命中局部数组快路径,避免 _find_pool_var 兜底引用 @_mbuddy。
|
||||
var_ty = _infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||||
|
||||
# 普通局部变量
|
||||
# 创建 alloca
|
||||
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
|
||||
|
||||
@@ -13,6 +13,7 @@ import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -174,6 +175,19 @@ def lookup_cdefine_double(name: str) -> double:
|
||||
return 0.0
|
||||
|
||||
|
||||
def eval_ctraits_isptr(symtab: HandlesVar.SymbolTable | t.CPtr,
|
||||
name: str) -> int:
|
||||
"""ctraits.isptr(name) 编译期求值(委托到 gen._eval_ctraits_isptr)。
|
||||
|
||||
返回: 1=指针 0=非指针 -1=无法求值。
|
||||
"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._eval_ctraits_isptr(symtab, name)
|
||||
return -1
|
||||
|
||||
|
||||
def is_cdefine_double() -> int:
|
||||
"""检查最近一次 CDefine 查找命中的是否是浮点常量(委托到 gen.is_cdefine_double)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
|
||||
Reference in new issue
Block a user