TransPyC 编译 translate_with 时,联合类型转换后直接取属性(如 ((ast.Name|CPtr)(ov)).id / ((ast.Call|CPtr)(ce)).func)的属性访问 (GEP+load)被编译器丢弃——编译产物 75904e6cbc83036b.text.ll 显示 store %asname 0 次、load 3 次,asname 恒 null → pool 从未绑定到 SymTab → body 内 pool.alloc 方法调用检测 lookup_var 失败 → 误报 "跨模块调用 'pool.alloc' 找不到模块 SHA1"。同理 cfn 恒 null 导致 cls_name(AnnotClassName)也设置不上。改为先转换到中间变量再取属性 (代码库已验证编译正常的 cmn 模式),修复 3 处(L264/L279/L298)。
1244 lines
55 KiB
Plaintext
1244 lines
55 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesType as HandlesType
|
||
import lib.core.Handles.HandlesVar as HandlesVar
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||
import lib.core.Handles.HandlesImports as HandlesImports
|
||
import lib.core.Handles.HandlesIf as HandlesIf
|
||
import lib.core.Handles.HandlesWhile as HandlesWhile
|
||
import lib.core.Handles.HandlesFor as HandlesFor
|
||
import lib.core.Handles.HandlesReturn as HandlesReturn
|
||
import lib.core.Handles.HandlesMatch as HandlesMatch
|
||
import lib.core.Handles.HandlesEnum as HandlesEnum
|
||
import lib.Projectrans.Config as Config
|
||
|
||
|
||
# ============================================================
|
||
# StmtGenMixin - 语句/流程翻译 Mixin(P6 对象化重构 A 组)
|
||
#
|
||
# 迁移自 HandlesBody/HandlesIf/HandlesWhile/HandlesFor/HandlesReturn/
|
||
# HandlesNonlocal/HandlesMatch/HandlesEnum 的模块级函数(trans 首参
|
||
# 或无状态纯函数 + NewXxxHandle 工厂)→ 类方法;全局状态
|
||
# (_g_cif_eval_ok/_enum_table/_enum_count)→ 本类字段。
|
||
#
|
||
# 迁移原则(与 P1-P5 一致,行为零变化):
|
||
# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的
|
||
# 本模块函数调用改为 self.xxx(...)
|
||
# 2. 外部模块调用(HandlesVar.xxx/HandlesExpr.xxx/HandlesType.xxx
|
||
# 等)保留模块前缀(对应模块保留委托层)
|
||
# 3. trans.XxxH.Handle(...) 子 Handle 分派保留(Handle 类不动,
|
||
# 由 HandlesTranslator._init_state 通过 NewXxxHandle 工厂创建)
|
||
# 4. 原 Handles 模块函数保留为"委托":本地模块级单例 _g_gen
|
||
# (BuildPipeline/main 注入)cast 成 Generator 类型调本类方法
|
||
# 5. HandlesIf._g_cif_eval_ok → self.CifEvalOk;HandlesEnum
|
||
# _enum_table/_enum_count → self.EnumTable/self.EnumCount
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesEnum 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||
# ============================================================
|
||
ENUM_MAX: t.CDefine = 64
|
||
ENUM_MEMBER_MAX: t.CDefine = 128
|
||
|
||
|
||
# ============================================================
|
||
# StmtGenMixin - 语句/流程翻译(P6 方法化)
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class StmtGenMixin:
|
||
"""语句/流程翻译 Mixin(P6 方法化)
|
||
|
||
迁移自 HandlesBody/HandlesIf/HandlesWhile/HandlesFor/HandlesReturn/
|
||
HandlesNonlocal/HandlesMatch/HandlesEnum 的模块级函数
|
||
"""
|
||
|
||
# --- 编译期 CIf 求值状态(原 HandlesIf._g_cif_eval_ok) ---
|
||
CifEvalOk: int
|
||
|
||
# --- 枚举注册表(原 HandlesEnum._enum_table/_enum_count) ---
|
||
EnumTable: HandlesEnum.EnumEntry | t.CPtr
|
||
EnumCount: int
|
||
|
||
# ============================================================
|
||
# 簇 A:语句分派/流程语句(迁移自 HandlesBody.vp)
|
||
# ============================================================
|
||
|
||
def translate_stmt(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译单条语句,返回新增的变量数"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
|
||
if k == ast.ASTKind.Expr:
|
||
return self.translate_expr_stmt(trans, node)
|
||
elif k == ast.ASTKind.Assign:
|
||
return trans.AssignH.Handle(node)
|
||
elif k == ast.ASTKind.AnnAssign:
|
||
return trans.AnnAssignH.Handle(node)
|
||
elif k == ast.ASTKind.FunctionDef:
|
||
# 嵌套函数定义:提升为顶层函数 + 创建闭包
|
||
return HandlesFunctions.translate_nested_function_def(trans, node)
|
||
elif k == ast.ASTKind.Return:
|
||
return trans.ReturnH.Handle(node)
|
||
elif k == ast.ASTKind.If:
|
||
return trans.IfH.Handle(node)
|
||
elif k == ast.ASTKind.While:
|
||
return trans.WhileH.Handle(node)
|
||
elif k == ast.ASTKind.AugAssign:
|
||
return trans.AugAssignH.Handle(node)
|
||
elif k == ast.ASTKind.For:
|
||
return trans.ForH.Handle(node)
|
||
elif k == ast.ASTKind.ClassDef:
|
||
return HandlesClassDef.translate_class_def(trans, node)
|
||
elif k == ast.ASTKind.Import:
|
||
return trans.ImportsH.HandleImport(node)
|
||
elif k == ast.ASTKind.ImportFrom:
|
||
trans.ImportsH.HandleImportFromModule(node)
|
||
return trans.ImportsH.HandleImportFromNames(node)
|
||
elif k == ast.ASTKind.Global:
|
||
return self.translate_global(trans, node)
|
||
elif k == ast.ASTKind.Nonlocal:
|
||
return self.translate_nonlocal(trans, node)
|
||
elif k == ast.ASTKind.Pass:
|
||
return 0
|
||
elif k == ast.ASTKind.Break:
|
||
return self.translate_break(trans)
|
||
elif k == ast.ASTKind.Continue:
|
||
return self.translate_continue(trans)
|
||
elif k == ast.ASTKind.Match:
|
||
return trans.MatchH.Handle(node)
|
||
elif k == ast.ASTKind.Delete:
|
||
return self.translate_delete(trans, node)
|
||
elif k == ast.ASTKind.Raise:
|
||
return self.translate_raise(trans, node)
|
||
elif k == ast.ASTKind.With:
|
||
return self.translate_with(trans, node)
|
||
# 未知语句类型:直接报错终止(fail-fast),暴露上游解析问题
|
||
HandlesType.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError")
|
||
return 0
|
||
|
||
def translate_delete(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 del 语句,返回 0"""
|
||
if trans is None or node is None:
|
||
return 0
|
||
dnode: ast.Delete | t.CPtr = (ast.Delete | t.CPtr)(node)
|
||
if dnode is None or dnode.targets is None:
|
||
return 0
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
if pool is None or mod is None or builder is None:
|
||
return 0
|
||
tn: t.CSizeT = len(dnode.targets)
|
||
for ti in range(tn):
|
||
tgt: ast.AST | t.CPtr = dnode.targets.get(ti)
|
||
if tgt is None:
|
||
continue
|
||
# del obj.attr → property deleter
|
||
if tgt.kind() == ast.ASTKind.Attribute:
|
||
del_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tgt)
|
||
if del_at is not None:
|
||
HandlesExprCall._try_property_deleter(
|
||
pool, builder, mod, del_at, trans)
|
||
return 0
|
||
|
||
def translate_raise(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 raise 语句,返回 0
|
||
|
||
Viper 无异常传播机制:raise 统一按"终止当前函数并返回零值"处理,
|
||
对齐 TPC HandlesRaise 的 StopIteration 语义——迭代器 __next__ 用
|
||
null/0 表示迭代结束(如 dict.__next__ 的 `raise StopIteration`)。
|
||
非 StopIteration 的 raise 同样返回零值(异常消息忽略)。
|
||
"""
|
||
if trans is None or node is None:
|
||
return 0
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
if pool is None or builder is None:
|
||
return 0
|
||
cur_func: llvmlite.Function | t.CPtr = trans._cur_func
|
||
if cur_func is None:
|
||
return 0
|
||
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func)
|
||
if ret_ty is None:
|
||
return 0
|
||
match ret_ty:
|
||
case llvmlite.LLVMType.Void():
|
||
llvmlite.build_ret_void(builder)
|
||
case llvmlite.LLVMType.Ptr(_pe):
|
||
null_v: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
|
||
if null_v is not None:
|
||
llvmlite.build_ret(builder, null_v)
|
||
case llvmlite.LLVMType.Float(_fb):
|
||
zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0)
|
||
if zero_f is not None:
|
||
llvmlite.build_ret(builder, zero_f)
|
||
case _:
|
||
zero_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty)
|
||
if zero_v is not None:
|
||
llvmlite.build_ret(builder, zero_v)
|
||
return 0
|
||
|
||
# ============================================================
|
||
# translate_with - with 语句翻译
|
||
#
|
||
# with expr() as x: body
|
||
# → 1. 构造 context 对象(expr() 调用)
|
||
# 2. 调用 __enter__()(沿继承链 MRO 解析,如 MemPool → MemManager)
|
||
# 3. x 绑定 __enter__ 返回值(缺失时退回 context 对象)
|
||
# 4. 翻译 body
|
||
# 5. 逆序调用 __exit__()(无异常传播,__exit__ 仅做清理如 reset)
|
||
#
|
||
# 实现:context 对象存入临时变量 __with_ctx,方法调用复用
|
||
# translate_call 的 Attribute 分派 + _translate_method_call 的 MRO 回退
|
||
# (与普通 obj.method() 调用一致)。嵌套 with 时保存外层 __with_ctx,
|
||
# 退出后恢复,避免内层覆盖导致外层 __exit__ 解析到错误对象。
|
||
# 对齐 TPC HandlesWith 语义(不含 __provides__ provider 机制)。
|
||
# ============================================================
|
||
def translate_with(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 with 语句,返回 0"""
|
||
if trans is None or node is None:
|
||
return 0
|
||
wt: ast.With | t.CPtr = (ast.With | t.CPtr)(node)
|
||
if wt is None:
|
||
return 0
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
if pool is None or builder is None or mod is None:
|
||
return 0
|
||
items: list[ast.AST | t.CPtr] | t.CPtr = wt.items
|
||
if items is None:
|
||
return 0
|
||
n: t.CSizeT = len(items)
|
||
|
||
# 保存外层 __with_ctx(嵌套 with 时退出后恢复)
|
||
old_ctx_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, "__with_ctx")
|
||
|
||
# 记录每个 item 的类名(__exit__ 调用时设置 __with_ctx 类型用)
|
||
ctx_class_buf: t.CSizeT | t.CPtr = pool.alloc(8 * n)
|
||
if ctx_class_buf is None:
|
||
return 0
|
||
string.memset(ctx_class_buf, 0, 8 * n)
|
||
|
||
# 1. 全部 item:构造 context 对象 + 调用 __enter__ + asname 绑定
|
||
for i in range(n):
|
||
item_node: ast.AST | t.CPtr = items.get(i)
|
||
if item_node is None:
|
||
continue
|
||
if item_node.kind() != ast.ASTKind.WithItem:
|
||
continue
|
||
item: ast.WithItem | t.CPtr = (ast.WithItem | t.CPtr)(item_node)
|
||
if item is None or item.context_expr is None:
|
||
continue
|
||
# 翻译 context_expr(对象构造,如 MemPool(arena, 4096))
|
||
ctx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, item.context_expr,
|
||
trans._funcs, trans._func_count, trans)
|
||
if ctx_val is None:
|
||
continue
|
||
# 提取类名(注解类名,Attribute 时带模块前缀,如 "memhub.MemPool"——
|
||
# 与 AnnAssign 的 extract_class_name_from_annotation 一致,跨模块
|
||
# 方法调用靠 AnnotClassName 回退按模块名查 SHA1)
|
||
cls_name: str = None
|
||
ce: ast.AST | t.CPtr = item.context_expr
|
||
if ce.kind() == ast.ASTKind.Call:
|
||
# 注意:联合类型转换后必须经中间变量再取属性(直接
|
||
# ((ast.Call|CPtr)(ce)).func 会被 TPC 编译损坏丢弃属性访问)
|
||
call_ce: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ce)
|
||
cfn: ast.AST | t.CPtr = call_ce.func
|
||
if cfn is not None:
|
||
if cfn.kind() == ast.ASTKind.Attribute:
|
||
ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cfn)
|
||
if ca.value is not None and ca.value.kind() == ast.ASTKind.Name:
|
||
cmn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value)
|
||
if cmn.id is not None:
|
||
ml2: t.CSizeT = string.strlen(cmn.id) + string.strlen(ca.attr) + 2
|
||
mbuf: str = pool.alloc(ml2)
|
||
if mbuf is not None:
|
||
viperlib.snprintf(mbuf, ml2, "%s.%s", cmn.id, ca.attr)
|
||
cls_name = mbuf
|
||
if cls_name is None:
|
||
cls_name = ca.attr
|
||
elif cfn.kind() == ast.ASTKind.Name:
|
||
nm_cfn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cfn)
|
||
cls_name = nm_cfn.id
|
||
# context 对象存入 __with_ctx(方法调用解析 self 用)
|
||
ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(
|
||
builder, ctx_val.Ty)
|
||
if ctx_alloca is None:
|
||
continue
|
||
llvmlite.build_store(builder, ctx_val, ctx_alloca)
|
||
HandlesVar.define_var(trans.SymTab, "__with_ctx", ctx_alloca)
|
||
if cls_name is not None:
|
||
HandlesVar.set_var_annot_class_name(
|
||
trans.SymTab, "__with_ctx", cls_name)
|
||
ctx_class_buf[i] = t.CSizeT(cls_name)
|
||
# 调用 __enter__()
|
||
enter_val: llvmlite.Value | t.CPtr = self._with_ctx_call(
|
||
trans, pool, builder, mod, "__enter__")
|
||
# asname 绑定(__enter__ 返回值,缺失时退回 context 对象)
|
||
if item.optional_vars is not None:
|
||
ov: ast.AST | t.CPtr = item.optional_vars
|
||
if ov.kind() == ast.ASTKind.Name:
|
||
# 联合类型转换后经中间变量再取属性(同 L264 注释,防 TPC 编译损坏)
|
||
ovn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ov)
|
||
asname: str = ovn.id
|
||
if asname is not None:
|
||
bind_val: llvmlite.Value | t.CPtr = enter_val
|
||
if bind_val is None:
|
||
bind_val = ctx_val
|
||
if bind_val is not None:
|
||
asn_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(
|
||
builder, bind_val.Ty)
|
||
if asn_alloca is not None:
|
||
llvmlite.build_store(builder, bind_val, asn_alloca)
|
||
HandlesVar.define_var(trans.SymTab, asname, asn_alloca)
|
||
if cls_name is not None:
|
||
HandlesVar.set_var_annot_class_name(
|
||
trans.SymTab, asname, cls_name)
|
||
|
||
# 2. 翻译 body
|
||
body: list[ast.AST | t.CPtr] | t.CPtr = wt.children
|
||
if body is not None:
|
||
bn: t.CSizeT = len(body)
|
||
for bi in range(bn):
|
||
st: ast.AST | t.CPtr = body.get(bi)
|
||
if st is not None:
|
||
self.translate_stmt(trans, st)
|
||
|
||
# 3. 逆序调用 __exit__()(Python with 语义:后进先出)
|
||
for i in range(n):
|
||
ci: int = n - 1 - i
|
||
if ctx_class_buf[ci] != 0:
|
||
cls_ci: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[ci], t.CPtr))
|
||
HandlesVar.set_var_annot_class_name(
|
||
trans.SymTab, "__with_ctx", cls_ci)
|
||
self._with_ctx_call(trans, pool, builder, mod, "__exit__")
|
||
|
||
# 4. 恢复外层 __with_ctx
|
||
if old_ctx_alloca is not None:
|
||
HandlesVar.define_var(trans.SymTab, "__with_ctx", old_ctx_alloca)
|
||
return 0
|
||
|
||
def _with_ctx_call(self, trans: HT.Translator | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
method_name: str) -> llvmlite.Value | t.CPtr:
|
||
"""构造并翻译 __with_ctx.<method_name>() 调用(__enter__/__exit__)"""
|
||
if pool is None or method_name is None:
|
||
return None
|
||
name_node: ast.AST | t.CPtr = ast.Name(pool, "__with_ctx", ast.ASTCtx.Load)
|
||
if name_node is None:
|
||
return None
|
||
attr_node: ast.AST | t.CPtr = ast.Attribute(
|
||
pool, name_node, method_name, ast.ASTCtx.Load)
|
||
if attr_node is None:
|
||
return None
|
||
call_node: ast.AST | t.CPtr = ast.Call(pool, attr_node, None, None)
|
||
if call_node is None:
|
||
return None
|
||
return HandlesExpr.translate_value(
|
||
builder, pool, mod, call_node,
|
||
trans._funcs, trans._func_count, trans)
|
||
|
||
def translate_global(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 global 语句:记录 global 变量名"""
|
||
gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node)
|
||
if gn is None:
|
||
return 0
|
||
names: list[ast.AST | t.CPtr] | t.CPtr = gn.names
|
||
if names is None:
|
||
return 0
|
||
n: t.CSizeT = len(names)
|
||
for i in range(n):
|
||
nm_node: ast.AST | t.CPtr = names.get(i)
|
||
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
|
||
if nm.id is not None:
|
||
HT.add_global_name(trans, nm.id)
|
||
return 0
|
||
|
||
def translate_nonlocal(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型
|
||
|
||
类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。
|
||
"""
|
||
nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node)
|
||
if nl is None:
|
||
return 0
|
||
names: list[ast.AST | t.CPtr] | t.CPtr = nl.names
|
||
if names is None:
|
||
return 0
|
||
n: t.CSizeT = len(names)
|
||
for i in range(n):
|
||
nm_node: ast.AST | t.CPtr = names.get(i)
|
||
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
|
||
if nm.id is not None:
|
||
# 查找父作用域中的变量 alloca,获取类型信息
|
||
var_ty: llvmlite.LLVMType | t.CPtr = None
|
||
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, nm.id)
|
||
if var_alloca is not None and var_alloca.Ty is not None:
|
||
var_ty = var_alloca.Ty.Pointee
|
||
# Void 类型视为无效(Pointee 访问异常时可能返回 Void),
|
||
# 类型无效直接报错终止(fail-fast),避免生成
|
||
# "bitcast ... to void*" / "load void, void*" 非法 IR
|
||
if var_ty is not None:
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Void():
|
||
HandlesType.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError")
|
||
case _:
|
||
pass
|
||
HT.add_nonlocal_name(trans, nm.id, var_ty)
|
||
return 0
|
||
|
||
def translate_expr_stmt(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译表达式语句(printf 调用等)"""
|
||
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
|
||
if ex is None:
|
||
return 0
|
||
call_node: ast.AST | t.CPtr = ex.value
|
||
if call_node is None:
|
||
return 0
|
||
ck: int = call_node.kind()
|
||
if ck != ast.ASTKind.Call:
|
||
return 0
|
||
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node)
|
||
func_node: ast.AST | t.CPtr = cl.func
|
||
if func_node is None:
|
||
return 0
|
||
|
||
func_name: str = HandlesExpr.get_func_name(func_node)
|
||
if func_name is None:
|
||
# 函数名解析失败:直接报错终止(fail-fast)
|
||
HandlesType.fatal_error(call_node, "表达式语句的函数名解析失败", "SyntaxError")
|
||
|
||
# printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf)
|
||
if string.strcmp(func_name, "printf") == 0:
|
||
trans.ExprCallH.HandlePrintfCall(cl)
|
||
elif string.strcmp(func_name, "print") == 0:
|
||
trans.ExprCallH.HandlePrintCall(cl)
|
||
else:
|
||
# 通用函数调用(返回值丢弃)
|
||
trans.ExprCallH.HandleCall(call_node)
|
||
return 0
|
||
|
||
def pre_scan_allocas(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""预扫描语句中的 AnnAssign,提前创建 alloca
|
||
|
||
返回新增的变量数
|
||
"""
|
||
if node is None:
|
||
return 0
|
||
return trans.AnnAssignH.PreScan(node)
|
||
|
||
def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""预扫描 Global/Nonlocal 声明,提前注册作用域名称"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Global:
|
||
return self.translate_global(trans, node)
|
||
if k == ast.ASTKind.Nonlocal:
|
||
return self.translate_nonlocal(trans, node)
|
||
return 0
|
||
|
||
def translate_break(self, trans: HT.Translator | t.CPtr) -> int:
|
||
"""翻译 break 语句:跳转到循环 end 块"""
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
|
||
if builder is None or func is None:
|
||
return 0
|
||
|
||
# 发射 br 到 break 目标
|
||
if trans._break_bb is not None:
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, trans._break_bb)
|
||
|
||
# 创建死代码 BB,用于后续语句(break 后面的代码不可达)
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
|
||
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
llvmlite.position_at_end(builder, dead_bb)
|
||
return 0
|
||
|
||
def translate_continue(self, trans: HT.Translator | t.CPtr) -> int:
|
||
"""翻译 continue 语句:跳转到循环 cond/incr 块"""
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
|
||
if builder is None or func is None:
|
||
return 0
|
||
|
||
# 发射 br 到 continue 目标
|
||
if trans._continue_bb is not None:
|
||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||
llvmlite.build_br(builder, trans._continue_bb)
|
||
|
||
# 创建死代码 BB,用于后续语句
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
|
||
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
llvmlite.position_at_end(builder, dead_bb)
|
||
return 0
|
||
|
||
def get_stmt_kind_name(self, node: ast.AST | t.CPtr) -> str:
|
||
"""获取语句类型名"""
|
||
if node is None:
|
||
return None
|
||
return node.type_name()
|
||
|
||
# ============================================================
|
||
# 簇 B:编译期 CIf 宏求值(迁移自 HandlesIf.vp 模块级函数)
|
||
# ============================================================
|
||
|
||
def _is_cif_attr(self, attr: str) -> int:
|
||
"""检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)"""
|
||
if attr is None:
|
||
return 0
|
||
if string.strcmp(attr, "CIf") == 0: return 1
|
||
if string.strcmp(attr, "CIfdef") == 0: return 1
|
||
if string.strcmp(attr, "CIfndef") == 0: return 1
|
||
return 0
|
||
|
||
def _is_cif_call(self, node: ast.AST | t.CPtr) -> int:
|
||
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用"""
|
||
if node is None or node.kind() != ast.ASTKind.Call:
|
||
return 0
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||
if cl.func is None:
|
||
return 0
|
||
fk: int = cl.func.kind()
|
||
if fk == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if at.attr is None:
|
||
return 0
|
||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if vn.id is not None and string.strcmp(vn.id, "c") == 0:
|
||
return self._is_cif_attr(at.attr)
|
||
return 0
|
||
if fk == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
|
||
if nm.id is not None and self._is_cif_attr(nm.id) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _get_platform_macro_value(self, name: str) -> int:
|
||
"""平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。
|
||
|
||
命中置 self.CifEvalOk=1;未命中置 0 返回 0。
|
||
"""
|
||
self.CifEvalOk = 0
|
||
if name is None:
|
||
return 0
|
||
triple: str = Config.TargetTriple
|
||
if triple is None:
|
||
triple = "x86_64-pc-windows-gnu"
|
||
is_win: int = 0
|
||
is_linux: int = 0
|
||
is_x64: int = 0
|
||
if string.strstr(triple, "windows") is not None \
|
||
or string.strstr(triple, "win32") is not None \
|
||
or string.strstr(triple, "mingw") is not None \
|
||
or string.strstr(triple, "msvc") is not None:
|
||
is_win = 1
|
||
if string.strstr(triple, "linux") is not None:
|
||
is_linux = 1
|
||
if string.strstr(triple, "x86_64") is not None:
|
||
is_x64 = 1
|
||
# 简化:本编译目标为 x86_64 Windows(_WIN64/WIN64 恒与 is_win 一致)
|
||
if string.strcmp(name, "_WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
|
||
if string.strcmp(name, "WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
|
||
if string.strcmp(name, "_WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
|
||
if string.strcmp(name, "WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
|
||
if string.strcmp(name, "__linux__") == 0: self.CifEvalOk = is_linux; return 1 if is_linux else 0
|
||
if string.strcmp(name, "__x86_64__") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
|
||
if string.strcmp(name, "__x86_64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
|
||
if string.strcmp(name, "_M_X64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
|
||
if string.strcmp(name, "SIZEOF_VOID_P") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4
|
||
if string.strcmp(name, "__SIZEOF_POINTER__") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4
|
||
if string.strcmp(name, "NDEBUG") == 0: self.CifEvalOk = 1; return 0
|
||
return 0
|
||
|
||
def _cif_name_value(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
name: str) -> int:
|
||
"""查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。
|
||
|
||
命中置 self.CifEvalOk=1(值 0 也算命中,如 DISABLED=0);未命中置 0。
|
||
"""
|
||
self.CifEvalOk = 0
|
||
if name is None or trans is None:
|
||
return 0
|
||
v: int = HandlesType.lookup_cdefine_constant(name)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
self.CifEvalOk = 1
|
||
return v
|
||
v2: int = HandlesExpr._lookup_cross_module_cdefine(
|
||
pool, name, trans._from_imports, trans._imported_modules)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
self.CifEvalOk = 1
|
||
return v2
|
||
pv: int = self._get_platform_macro_value(name)
|
||
if self.CifEvalOk != 0:
|
||
return pv
|
||
return 0
|
||
|
||
def _cif_attr_value(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
at: ast.Attribute | t.CPtr) -> int:
|
||
"""Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。
|
||
|
||
命中置 self.CifEvalOk=1;未命中置 0。
|
||
"""
|
||
self.CifEvalOk = 0
|
||
if at is None or at.attr is None or at.value is None or trans 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
|
||
v: int = HandlesType.lookup_cdefine_constant(at.attr)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
self.CifEvalOk = 1
|
||
return v
|
||
# 跨模块: 确定真实模块名(解析 from_imports 别名)
|
||
real_mod: str = vn.id
|
||
if trans._from_imports is not None:
|
||
resolved: str = HandlesImports.lookup_from_import(
|
||
trans._from_imports, vn.id, 0)
|
||
if resolved is not None:
|
||
rm_len: t.CSizeT = 0
|
||
while resolved[rm_len] != ' ' and resolved[rm_len] != '\0' and resolved[rm_len] != ':':
|
||
rm_len += 1
|
||
rm_buf: str = pool.alloc(rm_len + 1)
|
||
if rm_buf is not None:
|
||
for rm_i in range(rm_len):
|
||
rm_buf[rm_i] = resolved[rm_i]
|
||
rm_buf[rm_len] = '\0'
|
||
real_mod = rm_buf
|
||
fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod) + 2
|
||
fi: str = pool.alloc(fi_len)
|
||
if fi is None:
|
||
return 0
|
||
viperlib.snprintf(fi, fi_len, "%s:%s", at.attr, real_mod)
|
||
v2: int = HandlesExpr._lookup_cross_module_cdefine(pool, at.attr, fi)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
self.CifEvalOk = 1
|
||
return v2
|
||
return 0
|
||
|
||
def _cif_eval_node(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""递归常量求值 CIf 表达式。
|
||
|
||
支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine)
|
||
/ BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=)
|
||
/ BoolOp(and/or) / UnaryOp(not - + ~)。
|
||
成功置 self.CifEvalOk=1;失败(含运行时变量)置 0 返回 0。
|
||
"""
|
||
if node is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||
if cn.const_kind == ast.CONST_INT:
|
||
self.CifEvalOk = 1
|
||
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:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
return self._cif_name_value(pool, trans, nm.id)
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||
return self._cif_attr_value(pool, trans, at)
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||
if uop.operand is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
ov: int = self._cif_eval_node(pool, trans, uop.operand)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
if uop.op == ast.OpKind.Not: return 1 if ov == 0 else 0
|
||
if uop.op == ast.OpKind.USub: return -ov
|
||
if uop.op == ast.OpKind.UAdd: return ov
|
||
if uop.op == ast.OpKind.Invert: return ~ov
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
if k == ast.ASTKind.BoolOp:
|
||
bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
|
||
vals: list[ast.AST | t.CPtr] | t.CPtr = bo.values
|
||
if vals is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
bn: t.CSizeT = len(vals)
|
||
if bo.op == ast.OpKind.And:
|
||
for bi in range(bn):
|
||
rv: int = self._cif_eval_node(pool, trans, vals.get(bi))
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
if rv == 0:
|
||
return 0
|
||
return 1
|
||
if bo.op == ast.OpKind.Or:
|
||
for bi in range(bn):
|
||
rv: int = self._cif_eval_node(pool, trans, vals.get(bi))
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
if rv != 0:
|
||
return 1
|
||
return 0
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
if k == ast.ASTKind.Compare:
|
||
cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
|
||
lv: int = self._cif_eval_node(pool, trans, cmp.left)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops)
|
||
comps: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators
|
||
if ops_list is None or comps is None:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
cc: t.CSizeT = len(comps)
|
||
ci: t.CSizeT
|
||
for ci in range(cc):
|
||
rv: int = self._cif_eval_node(pool, trans, comps.get(ci))
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
op_id: int = ops_list.get(ci)
|
||
ok_cmp: int = 0
|
||
if op_id == ast.OpKind.Eq: ok_cmp = 1 if lv == rv else 0
|
||
elif op_id == ast.OpKind.Ne: ok_cmp = 1 if lv != rv else 0
|
||
elif op_id == ast.OpKind.Lt: ok_cmp = 1 if lv < rv else 0
|
||
elif op_id == ast.OpKind.Le: ok_cmp = 1 if lv <= rv else 0
|
||
elif op_id == ast.OpKind.Gt: ok_cmp = 1 if lv > rv else 0
|
||
elif op_id == ast.OpKind.Ge: ok_cmp = 1 if lv >= rv else 0
|
||
else:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
if ok_cmp == 0:
|
||
return 0
|
||
lv = rv
|
||
return 1
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
lv: int = self._cif_eval_node(pool, trans, bop.left)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
rv: int = self._cif_eval_node(pool, trans, bop.right)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
if bop.op == ast.OpKind.Add: return lv + rv
|
||
if bop.op == ast.OpKind.Sub: return lv - rv
|
||
if bop.op == ast.OpKind.Mult: return lv * rv
|
||
if bop.op == ast.OpKind.FloorDiv:
|
||
if rv == 0:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
return lv // rv
|
||
if bop.op == ast.OpKind.Mod:
|
||
if rv == 0:
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
return lv % rv
|
||
if bop.op == ast.OpKind.BitAnd: return lv & rv
|
||
if bop.op == ast.OpKind.BitOr: return lv | rv
|
||
if bop.op == ast.OpKind.BitXor: return lv ^ rv
|
||
if bop.op == ast.OpKind.LShift: return lv << rv
|
||
if bop.op == ast.OpKind.RShift: return lv >> rv
|
||
self.CifEvalOk = 0
|
||
return 0
|
||
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 len(cargs) < 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:
|
||
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
|
||
|
||
成功: 置 self.CifEvalOk=1,返回条件值(0/1)
|
||
失败(运行时变量/未知结构): 置 self.CifEvalOk=0,返回 0
|
||
"""
|
||
self.CifEvalOk = 0
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(test)
|
||
if cl is None or cl.func is None:
|
||
return 0
|
||
kind: str = None
|
||
fk: int = cl.func.kind()
|
||
if fk == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
kind = at.attr
|
||
elif fk == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
|
||
kind = nm.id
|
||
if kind is None:
|
||
return 0
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or len(cargs) < 1:
|
||
return 0
|
||
arg0: ast.AST | t.CPtr = cargs.get(0)
|
||
if string.strcmp(kind, "CIf") == 0:
|
||
v: int = self._cif_eval_node(pool, trans, arg0)
|
||
if self.CifEvalOk == 0:
|
||
return 0
|
||
return 1 if v != 0 else 0
|
||
# CIfdef / CIfndef: 判定宏名是否已定义
|
||
defined: int = 0
|
||
if arg0 is not None and arg0.kind() == ast.ASTKind.Name:
|
||
nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
|
||
if nm0.id is None:
|
||
return 0
|
||
self._cif_name_value(pool, trans, nm0.id)
|
||
defined = self.CifEvalOk
|
||
elif arg0 is not None and arg0.kind() == ast.ASTKind.Constant:
|
||
cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0)
|
||
if cn0.const_kind == ast.CONST_STR and cn0.str_val is not None:
|
||
self._cif_name_value(pool, trans, cn0.str_val)
|
||
defined = self.CifEvalOk
|
||
else:
|
||
return 0
|
||
elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute:
|
||
at0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
|
||
self._cif_attr_value(pool, trans, at0)
|
||
defined = self.CifEvalOk
|
||
else:
|
||
return 0
|
||
# 定义判定本身成功(未定义名特判:不报错,defined=0 走 else)
|
||
self.CifEvalOk = 1
|
||
if string.strcmp(kind, "CIfdef") == 0:
|
||
return 1 if defined != 0 else 0
|
||
# CIfndef
|
||
return 0 if defined != 0 else 1
|
||
|
||
def NewIfHandle(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> HandlesIf.IfHandle | t.CPtr:
|
||
"""创建 IfHandle 实例(迁移自 HandlesIf.NewIfHandle)"""
|
||
h: HandlesIf.IfHandle | t.CPtr = pool.alloc(HandlesIf.IfHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, HandlesIf.IfHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|
||
|
||
# ============================================================
|
||
# 簇 C:循环/return/match 子 Handle 工厂(迁移自
|
||
# HandlesWhile/HandlesFor/HandlesReturn/HandlesMatch)
|
||
# ============================================================
|
||
|
||
def NewWhileHandle(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> HandlesWhile.WhileHandle | t.CPtr:
|
||
"""创建 WhileHandle 实例(迁移自 HandlesWhile.NewWhileHandle)"""
|
||
h: HandlesWhile.WhileHandle | t.CPtr = pool.alloc(HandlesWhile.WhileHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, HandlesWhile.WhileHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|
||
|
||
def NewForHandle(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> HandlesFor.ForHandle | t.CPtr:
|
||
"""创建 ForHandle 实例(迁移自 HandlesFor.NewForHandle)"""
|
||
h: HandlesFor.ForHandle | t.CPtr = pool.alloc(HandlesFor.ForHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, HandlesFor.ForHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|
||
|
||
def NewReturnHandle(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> HandlesReturn.ReturnHandle | t.CPtr:
|
||
"""创建 ReturnHandle 实例(迁移自 HandlesReturn.NewReturnHandle)"""
|
||
h: HandlesReturn.ReturnHandle | t.CPtr = pool.alloc(HandlesReturn.ReturnHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, HandlesReturn.ReturnHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|
||
|
||
def NewMatchHandle(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> HandlesMatch.MatchHandle | t.CPtr:
|
||
"""创建 MatchHandle 实例(迁移自 HandlesMatch.NewMatchHandle)"""
|
||
h: HandlesMatch.MatchHandle | t.CPtr = pool.alloc(HandlesMatch.MatchHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, HandlesMatch.MatchHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|
||
|
||
# ============================================================
|
||
# 簇 D:nonlocal/闭包 env 访问(迁移自 HandlesNonlocal.vp)
|
||
# ============================================================
|
||
|
||
def _is_void_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""判断是否为 Void 类型,是则返回 1,否则 0"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Void():
|
||
return 1
|
||
case _:
|
||
return 0
|
||
|
||
def get_env_ptr_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
|
||
env_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, "_env_ptr")
|
||
if env_var is not None:
|
||
return env_var
|
||
# 创建 alloca 存储 env
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty)
|
||
if alloca is None:
|
||
return None
|
||
HandlesVar.define_var(trans.SymTab, "_env_ptr", alloca)
|
||
return alloca
|
||
|
||
def _load_raw_var_ptr(self, trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)
|
||
|
||
返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。
|
||
"""
|
||
idx: int = HT.get_nonlocal_index(trans, name)
|
||
if idx < 0:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
|
||
# 1. 加载 env_ptr
|
||
env_alloca: llvmlite.Value | t.CPtr = self.get_env_ptr_var(trans)
|
||
if env_alloca is None:
|
||
return None
|
||
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
|
||
if env_ptr is None:
|
||
return None
|
||
|
||
# 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节
|
||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8)
|
||
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||
if addr is None:
|
||
return None
|
||
|
||
# 3. Bitcast to i8** and load the raw pointer
|
||
ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty)
|
||
if ptr_addr is None:
|
||
return None
|
||
return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr)
|
||
|
||
def load_nonlocal_var(self, trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从闭包 env 加载 nonlocal 变量值
|
||
|
||
通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。
|
||
"""
|
||
raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name)
|
||
if raw_ptr is None:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
|
||
# 获取变量类型(从注册时存储的类型信息)
|
||
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
|
||
if var_ty is None or self._is_void_type(var_ty) != 0:
|
||
# 类型缺失/无效直接报错终止(fail-fast),避免生成 "load void, void*" 非法 IR
|
||
HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
|
||
|
||
# bitcast raw i8* to var_ty*
|
||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|
||
if var_ptr is None:
|
||
return None
|
||
return llvmlite.build_load(builder, var_ty, var_ptr)
|
||
|
||
def get_nonlocal_var_ptr(self, trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作
|
||
|
||
返回的指针指向父函数的 alloca,store 操作对父函数可见。
|
||
"""
|
||
raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name)
|
||
if raw_ptr is None:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
|
||
# 获取变量类型
|
||
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
|
||
if var_ty is None or self._is_void_type(var_ty) != 0:
|
||
# 类型缺失/无效直接报错终止(fail-fast),避免生成 "bitcast ... to void*" 非法 IR
|
||
HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
|
||
|
||
# bitcast raw i8* to var_ty*
|
||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||
return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|
||
|
||
# ============================================================
|
||
# 簇 E:枚举注册表(迁移自 HandlesEnum.vp)
|
||
# ============================================================
|
||
|
||
def init_enum_table(self, pool: memhub.MemBuddy | t.CPtr) -> int:
|
||
"""初始化枚举注册表,返回 1 成功"""
|
||
if self.EnumTable is not None:
|
||
return 1
|
||
|
||
entry_size: t.CSizeT = HandlesEnum.EnumEntry.__sizeof__()
|
||
self.EnumTable = pool.alloc(entry_size * ENUM_MAX)
|
||
if self.EnumTable is None:
|
||
return 0
|
||
string.memset(self.EnumTable, 0, entry_size * ENUM_MAX)
|
||
self.EnumCount = 0
|
||
return 1
|
||
|
||
def _get_enum_entry(self, i: int) -> HandlesEnum.EnumEntry | t.CPtr:
|
||
"""获取第 i 个枚举条目"""
|
||
if self.EnumTable is None or i < 0 or i >= ENUM_MAX:
|
||
return None
|
||
entry_size: t.CSizeT = HandlesEnum.EnumEntry.__sizeof__()
|
||
addr: t.CUInt64T = t.CUInt64T(self.EnumTable) + i * entry_size
|
||
return (HandlesEnum.EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||
|
||
def _get_enum_member(self, enum_entry: HandlesEnum.EnumEntry | t.CPtr,
|
||
i: int) -> HandlesEnum.EnumMember | t.CPtr:
|
||
"""获取枚举中第 i 个成员条目"""
|
||
if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX:
|
||
return None
|
||
member_size: t.CSizeT = HandlesEnum.EnumMember.__sizeof__()
|
||
addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size
|
||
return (HandlesEnum.EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||
|
||
def register_enum(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str,
|
||
base_ty: llvmlite.LLVMType | t.CPtr) -> HandlesEnum.EnumEntry | t.CPtr:
|
||
"""注册枚举类型,返回 EnumEntry 指针"""
|
||
if self.init_enum_table(pool) == 0:
|
||
return None
|
||
|
||
# 检查是否已注册
|
||
existing: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(name)
|
||
if existing is not None:
|
||
return existing
|
||
|
||
if self.EnumCount >= ENUM_MAX:
|
||
fb_et: str = 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: HandlesEnum.EnumEntry | t.CPtr = self._get_enum_entry(self.EnumCount)
|
||
if entry is None:
|
||
return None
|
||
|
||
# 分配成员数组
|
||
member_size: t.CSizeT = HandlesEnum.EnumMember.__sizeof__()
|
||
entry.Members = pool.alloc(member_size * ENUM_MEMBER_MAX)
|
||
if entry.Members is None:
|
||
return None
|
||
string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX)
|
||
|
||
# 复制类名
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
name_buf: str = pool.alloc(name_len + 1)
|
||
if name_buf is not None:
|
||
string.strcpy(name_buf, name)
|
||
entry.Name = name_buf
|
||
|
||
entry.BaseTy = base_ty
|
||
entry.MemberCount = 0
|
||
|
||
self.EnumCount += 1
|
||
return entry
|
||
|
||
def add_enum_member(self, pool: memhub.MemBuddy | t.CPtr,
|
||
enum_entry: HandlesEnum.EnumEntry | t.CPtr,
|
||
member_name: str,
|
||
member_val: t.CInt64T,
|
||
member_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""向枚举添加成员,返回成员索引(-1 失败)"""
|
||
if enum_entry is None or member_name is None or member_ty is None:
|
||
return -1
|
||
|
||
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
|
||
fb_em: str = 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
|
||
me: HandlesEnum.EnumMember | t.CPtr = self._get_enum_member(enum_entry, idx)
|
||
if me is None:
|
||
return -1
|
||
|
||
# 复制成员名
|
||
name_len: t.CSizeT = string.strlen(member_name)
|
||
name_buf: str = pool.alloc(name_len + 1)
|
||
if name_buf is not None:
|
||
string.strcpy(name_buf, member_name)
|
||
me.Name = name_buf
|
||
|
||
me.Value = member_val
|
||
me.Ty = member_ty
|
||
|
||
enum_entry.MemberCount = idx + 1
|
||
return idx
|
||
|
||
def find_enum(self, name: str) -> HandlesEnum.EnumEntry | t.CPtr:
|
||
"""按枚举类名查找,返回 EnumEntry 或 None"""
|
||
if name is None or self.EnumTable is None:
|
||
return None
|
||
for i in range(self.EnumCount):
|
||
entry: HandlesEnum.EnumEntry | t.CPtr = self._get_enum_entry(i)
|
||
if entry is not None and entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
return None
|
||
|
||
def lookup_enum_member(self, enum_name: str,
|
||
member_name: str) -> HandlesEnum.EnumMember | t.CPtr:
|
||
"""按枚举类名和成员名查找,返回 EnumMember 或 None"""
|
||
if enum_name is None or member_name is None:
|
||
return None
|
||
entry: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(enum_name)
|
||
if entry is None:
|
||
return None
|
||
for mi in range(entry.MemberCount):
|
||
me: HandlesEnum.EnumMember | t.CPtr = self._get_enum_member(entry, mi)
|
||
if me is not None and me.Name is not None:
|
||
if string.strcmp(me.Name, member_name) == 0:
|
||
return me
|
||
return None
|
||
|
||
def is_enum_class(self, name: str) -> int:
|
||
"""检查类名是否为已注册枚举,返回 1=是 / 0=否"""
|
||
if name is None:
|
||
return 0
|
||
if self.find_enum(name) is not None:
|
||
return 1
|
||
return 0
|
||
|
||
def get_enum_base_type(self, enum_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""按枚举类名获取基准类型"""
|
||
entry: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(enum_name)
|
||
if entry is not None:
|
||
return entry.BaseTy
|
||
return None
|