feat(handles): 实现 c.CIf/c.CIfdef/c.CIfndef 编译期宏(对齐 TPC HandlesIf)

- 常量表达式求值: CDefine/跨模块 CDefine/平台宏 + 算术/比较/逻辑/位运算
- 编译期剪枝: 命中分支只编译, elif 递归, 未定义名特判(CIfdef 走 else/CIfndef 走 then, 不报错)
- 求值失败(运行时变量)回退运行时翻译(HandlesExprCall: CIf 真值比较/CIfdef 恒真)
This commit is contained in:
TermiNexus committed 2026-08-09 03:39:18 +08:00
1 parent 57d6ffefad
commit e79b676e51
1 file changed
+392
+392
View File
@@ -10,6 +10,365 @@ import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesImports as HandlesImports
import lib.Projectrans.Config as Config
# ============================================================
# 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
#
# 对齐 TPC HandlesIf.py:编译期求值命中分支并剪枝(不发射运行时 IR)。
# c.CIf(expr) → 常量表达式求值(CDefine/平台宏/算术/比较/逻辑)
# c.CIfdef(NAME) → NAME 已定义?(本地 CDefine / 跨模块 CDefine / 平台宏)
# c.CIfndef(NAME) → NAME 未定义? ← 未定义名特判:返回"未定义"而非报错
#
# 求值失败(如运行时变量 val == 1)→ 回退运行时翻译
# (c.CIf 由 HandlesExprCall.translate_call 特判翻译成运行时真值,
# c.CIfdef/c.CIfndef 运行时恒真,对齐 TPC HandlesExprCall.py L2434-2446)。
# ============================================================
_g_cif_eval_ok: int = 0
def _is_cif_attr(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(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 _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 _is_cif_attr(nm.id) != 0:
return 1
return 0
def _get_platform_macro_value(name: str) -> int:
"""平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。
命中置 _g_cif_eval_ok=1;未命中置 0 返回 0。
"""
global _g_cif_eval_ok
_g_cif_eval_ok = 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: _g_cif_eval_ok = is_win; return 1 if is_win else 0
if string.strcmp(name, "WIN32") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
if string.strcmp(name, "_WIN64") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
if string.strcmp(name, "WIN64") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
if string.strcmp(name, "__linux__") == 0: _g_cif_eval_ok = is_linux; return 1 if is_linux else 0
if string.strcmp(name, "__x86_64__") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "__x86_64") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "_M_X64") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "SIZEOF_VOID_P") == 0: _g_cif_eval_ok = 1; return 8 if is_x64 else 4
if string.strcmp(name, "__SIZEOF_POINTER__") == 0: _g_cif_eval_ok = 1; return 8 if is_x64 else 4
if string.strcmp(name, "NDEBUG") == 0: _g_cif_eval_ok = 1; return 0
return 0
def _cif_name_value(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
name: str) -> int:
"""查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。
命中置 _g_cif_eval_ok=1(值 0 也算命中,如 DISABLED=0);未命中置 0。
"""
global _g_cif_eval_ok
_g_cif_eval_ok = 0
if name is None or trans is None:
return 0
v: int = HandlesType.lookup_cdefine_constant(name)
if HandlesType.is_cdefine_found() != 0:
_g_cif_eval_ok = 1
return v
v2: int = HandlesExpr._lookup_cross_module_cdefine(
pool, name, trans._from_imports, trans._imported_modules)
if HandlesType.is_cdefine_found() != 0:
_g_cif_eval_ok = 1
return v2
pv: int = _get_platform_macro_value(name)
if _g_cif_eval_ok != 0:
return pv
return 0
def _cif_attr_value(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
at: ast.Attribute | t.CPtr) -> int:
"""Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。
命中置 _g_cif_eval_ok=1;未命中置 0。
"""
global _g_cif_eval_ok
_g_cif_eval_ok = 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:
_g_cif_eval_ok = 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:
_g_cif_eval_ok = 1
return v2
return 0
def _cif_eval_node(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 - + ~)。
成功置 _g_cif_eval_ok=1;失败(含运行时变量)置 0 返回 0。
"""
global _g_cif_eval_ok
if node is None:
_g_cif_eval_ok = 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:
_g_cif_eval_ok = 1
return cn.int_val
_g_cif_eval_ok = 0
return 0
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm.id is None:
_g_cif_eval_ok = 0
return 0
return _cif_name_value(pool, trans, nm.id)
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
return _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:
_g_cif_eval_ok = 0
return 0
ov: int = _cif_eval_node(pool, trans, uop.operand)
if _g_cif_eval_ok == 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
_g_cif_eval_ok = 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:
_g_cif_eval_ok = 0
return 0
bn: t.CSizeT = vals.__len__()
if bo.op == ast.OpKind.And:
for bi in range(bn):
rv: int = _cif_eval_node(pool, trans, vals.get(bi))
if _g_cif_eval_ok == 0:
return 0
if rv == 0:
return 0
return 1
if bo.op == ast.OpKind.Or:
for bi in range(bn):
rv: int = _cif_eval_node(pool, trans, vals.get(bi))
if _g_cif_eval_ok == 0:
return 0
if rv != 0:
return 1
return 0
_g_cif_eval_ok = 0
return 0
if k == ast.ASTKind.Compare:
cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
lv: int = _cif_eval_node(pool, trans, cmp.left)
if _g_cif_eval_ok == 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:
_g_cif_eval_ok = 0
return 0
cc: t.CSizeT = comps.__len__()
ci: t.CSizeT
for ci in range(cc):
rv: int = _cif_eval_node(pool, trans, comps.get(ci))
if _g_cif_eval_ok == 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:
_g_cif_eval_ok = 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 = _cif_eval_node(pool, trans, bop.left)
if _g_cif_eval_ok == 0:
return 0
rv: int = _cif_eval_node(pool, trans, bop.right)
if _g_cif_eval_ok == 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:
_g_cif_eval_ok = 0
return 0
return lv // rv
if bop.op == ast.OpKind.Mod:
if rv == 0:
_g_cif_eval_ok = 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
_g_cif_eval_ok = 0
return 0
_g_cif_eval_ok = 0
return 0
def _evaluate_cif_test(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
test: ast.AST | t.CPtr) -> int:
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
成功: 置 _g_cif_eval_ok=1,返回条件值(0/1)
失败(运行时变量/未知结构): 置 _g_cif_eval_ok=0,返回 0
"""
global _g_cif_eval_ok
_g_cif_eval_ok = 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 cargs.__len__() < 1:
return 0
arg0: ast.AST | t.CPtr = cargs.get(0)
if string.strcmp(kind, "CIf") == 0:
v: int = _cif_eval_node(pool, trans, arg0)
if _g_cif_eval_ok == 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
_cif_name_value(pool, trans, nm0.id)
defined = _g_cif_eval_ok
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:
_cif_name_value(pool, trans, cn0.str_val)
defined = _g_cif_eval_ok
else:
return 0
elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute:
at0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
_cif_attr_value(pool, trans, at0)
defined = _g_cif_eval_ok
else:
return 0
# 定义判定本身成功(未定义名特判:不报错,defined=0 走 else)
_g_cif_eval_ok = 1
if string.strcmp(kind, "CIfdef") == 0:
return 1 if defined != 0 else 0
# CIfndef
return 0 if defined != 0 else 1
# ============================================================
@@ -52,6 +411,39 @@ class IfHandle(HandlesBase.Mixin):
if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(node)
# 0. 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
# 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归
# 求值失败(运行时变量等)→ 回退运行时翻译
if _is_cif_call(if_node.test) == 1:
cif_val: int = _evaluate_cif_test(pool, trans, if_node.test)
if _g_cif_eval_ok != 0:
if cif_val != 0:
body_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.children
if body_cif is not None:
bc_cif: t.CSizeT = body_cif.__len__()
bi_cif: t.CSizeT
for bi_cif in range(bc_cif):
stmt_cif: ast.AST | t.CPtr = body_cif.get(bi_cif)
if stmt_cif is not None:
HandlesBody.translate_stmt(trans, stmt_cif)
else:
orelse_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse
if orelse_cif is not None and orelse_cif.__len__() == 1:
sub_cif: ast.AST | t.CPtr = orelse_cif.get(0)
if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If:
# elif: 递归(子 If 的 test 仍会走 CIf 判定或运行时翻译)
self.Handle(sub_cif)
elif sub_cif is not None:
HandlesBody.translate_stmt(trans, sub_cif)
elif orelse_cif is not None:
oc_cif: t.CSizeT = orelse_cif.__len__()
oi_cif: t.CSizeT
for oi_cif in range(oc_cif):
stmt_cif2: ast.AST | t.CPtr = orelse_cif.get(oi_cif)
if stmt_cif2 is not None:
HandlesBody.translate_stmt(trans, stmt_cif2)
return 0
# 1. 求值条件表达式
cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, if_node.test,