feat(vast): 新增自研 Viper/Python 语法解析器取代标准库 ast

TPC 侧取缔对 Python 标准库 ast 模块的依赖,改用 lib/vast 包:
- Nodes: 与 CPython 3.12 ast 完全同构的 131 个节点类(含抽象基类继承)
- Tokenizer: 词法分析(缩进/字符串/f-string/数字/运算符/软关键字)
- ExprParser: 表达式递归下降解析(优先级/lambda/推导式/f-string/切片)
- Parser: 语句解析(def/class/if/for/try/with/match/import/注解)
- Utils/Unparser: walk/dump/unparse/copy_location/literal_eval 等辅助
- 软关键字 fn/fun/func/function 并入解析器, 废除 ExpandSoftKeywords 预处理
- lib/_bootstrap 将 lib 目录加入 sys.path, import vast as ast 零修改替换
- 52 个文件 import ast 替换为 import vast as ast; 94 文件差分测试 0 失败
This commit is contained in:
TermiNexus committed 2026-08-17 09:36:38 +08:00
1 parent a7bbd68507
commit 6fc9e19e24
62 files changed
+19293 -15066

No files matched your search

+652 -652
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import ast
import vast as ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
from lib.core.VLogger import get_logger as _vlog
+59 -59
View File
@@ -1,60 +1,60 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
import ast
import llvmlite.ir as ir
class AssertHandle(BaseHandle):
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
cond_val: ir.Value | None = self.HandleExprLlvm(Node.test)
if not cond_val:
return
if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1:
zero: ir.Constant = ir.Constant(cond_val.type, 0)
cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond")
AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail")
AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok")
Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB)
Gen.builder.position_at_start(AssertFailBB)
exc_code: int = 9
exc_msg: ir.Value | None = None
if Node.msg:
if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str):
exc_msg = self.HandleExprLlvm(Node.msg)
elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name):
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99)
if Node.msg.args:
first_arg: ast.expr = Node.msg.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
exc_msg = self.HandleExprLlvm(first_arg)
elif isinstance(Node.msg, ast.Name):
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99)
else:
exc_msg = self.HandleExprLlvm(Node.msg)
if Gen.eh_except_block_stack:
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code)
if exc_msg:
Gen._store(exc_msg, eh_message)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen._store(null_ptr, eh_message)
Gen.builder.branch(ExceptBB)
else:
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
if exc_msg:
fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string')
Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print")
else:
fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string')
Gen.builder.call(printf_func, [fmt], name="assert_fail_print")
exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)]))
Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit")
Gen.builder.unreachable()
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
import vast as ast
import llvmlite.ir as ir
class AssertHandle(BaseHandle):
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
cond_val: ir.Value | None = self.HandleExprLlvm(Node.test)
if not cond_val:
return
if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1:
zero: ir.Constant = ir.Constant(cond_val.type, 0)
cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond")
AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail")
AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok")
Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB)
Gen.builder.position_at_start(AssertFailBB)
exc_code: int = 9
exc_msg: ir.Value | None = None
if Node.msg:
if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str):
exc_msg = self.HandleExprLlvm(Node.msg)
elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name):
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99)
if Node.msg.args:
first_arg: ast.expr = Node.msg.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
exc_msg = self.HandleExprLlvm(first_arg)
elif isinstance(Node.msg, ast.Name):
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99)
else:
exc_msg = self.HandleExprLlvm(Node.msg)
if Gen.eh_except_block_stack:
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code)
if exc_msg:
Gen._store(exc_msg, eh_message)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen._store(null_ptr, eh_message)
Gen.builder.branch(ExceptBB)
else:
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
if exc_msg:
fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string')
Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print")
else:
fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string')
Gen.builder.call(printf_func, [fmt], name="assert_fail_print")
exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)]))
Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit")
Gen.builder.unreachable()
Gen.builder.position_at_start(AssertOkBB)
File diff suppressed because it is too large. Load diff
+242 -242
View File
@@ -1,243 +1,243 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ast
import sys
import llvmlite.ir as ir
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.VLogger import get_logger as _vlog
from lib.core.Handles.HandlesBase import BaseHandle
class AugAssignHandle(BaseHandle):
_AUGOP_MAP: dict[type, str] = {
ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__',
ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__',
}
_AUGOP_FALLBACK: dict[type, str] = {
ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__',
ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__',
}
def _resolve_global_var_type(self, Gen: "Translator.LlvmGen", VarName: str, fallback: ir.Type) -> ir.Type:
"""解析 global 变量的 LLVM 类型:优先用模块级 AnnAssign 的注解类型。
问题场景:函数内 `_g_alloc_count += 1`(global 声明),模块级注解为
`_g_alloc_count: t.CSizeT`(i64)。若不查模块级注解类型,此处会用 RHS 字面量
类型(i32)自动建 i32 全局,与模块内其他读取/写入(i64)类型不匹配,
产生 "Operands must be the same type, got (i64, i32)" 类错误。
模块级 AnnAssign 已通过 _EmitGlobalAnnAssignLlvm 创建 LLVM 全局,
但注解无初始值(如 `_g_alloc_max: t.CSizeT = 0`)时 initializer 为空、
Gen.module.globals 中无该符号,故需在此兜底解析注解类型。
"""
module_ann: dict = getattr(Gen, '_module_ann_types', None)
if module_ann and VarName in module_ann:
ann_type: ir.Type = module_ann[VarName]
if ann_type is not None:
return ann_type
if isinstance(fallback, ir.IntType):
return fallback
return ir.IntType(64)
def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
if Gen._check_node_unsigned(Node.target):
return True
elif isinstance(Node.target, ast.Attribute):
if Gen._check_node_unsigned(Node.target):
return True
elif isinstance(Node.target, ast.Subscript):
if Gen._check_node_unsigned(Node.target):
return True
if Node.value is not None and Gen._check_node_unsigned(Node.value):
return True
return False
def _HandleAugAssignLlvm(self, Node: ast.AugAssign) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
VarName: str = Node.target.id
if (VarName not in Gen.variables
and VarName not in Gen.global_vars
and VarName not in Gen._reg_values
and VarName not in Gen._direct_values):
src_info: str = Gen._get_node_info()
_vlog().error(f"变量 '{VarName}' 未声明,不能用于增量赋值(需用 global 声明或先声明局部变量){src_info}")
sys.exit(1)
if VarName in Gen.var_const_flags:
src_info: str = Gen._get_node_info()
_vlog().error(f"不能对 const 变量 '{VarName}' 增量赋值{src_info}")
sys.exit(1)
ClassName: str | None = Gen.var_struct_class.get(VarName)
iop_name: str | None = self._AUGOP_MAP.get(type(Node.op))
if ClassName and iop_name:
iFuncName: str = f'{ClassName}.{iop_name}'
FuncName: str = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}'
if iFuncName in Gen.functions or FuncName in Gen.functions:
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
if OldVal and Value:
result: ir.Value | None
if iFuncName in Gen.functions:
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value)
else:
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value)
if result is not None:
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr: ir.Value = Gen.variables[VarName]
if VarPtr.type.pointee == result.type:
Gen._store(result, VarPtr)
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType):
CastedVal: ir.Value = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}")
Gen._store(CastedVal, VarPtr)
else:
NewVar: ir.AllocaInstr = Gen._allocaEntry(result.type, name=VarName)
Gen._store(result, NewVar)
Gen.variables[VarName] = NewVar
else:
Gen._reg_values[VarName] = result
Gen.variables[VarName] = None
return
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
if not Value:
return
is_unsigned: bool = self._is_aug_unsigned(Node, None, Value)
if isinstance(Node.target, ast.Name):
VarName: str = Node.target.id
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if VarName in Gen.global_vars:
# 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局
# (注解无初始值的全局变量),此处自动创建零初始化全局变量
GVar: ir.GlobalVariable
if VarName not in Gen.module.globals:
_gv_type: ir.Type = self._resolve_global_var_type(Gen, VarName, Value.type)
GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName)
GVar.initializer = ir.Constant(_gv_type, 0)
else:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
OldVal: ir.Value = Gen._load(GVar, name=VarName)
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
Gen._store(NewVal, GVar)
return
if VarName in Gen._reg_values:
OldVal: ir.Value = Gen._reg_values[VarName]
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
if VarName in Gen._direct_values:
OldVal: ir.Value = Gen._direct_values.pop(VarName)
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
if Gen.builder.block.is_terminated:
return
if VarName in Gen.variables and Gen.variables[VarName] is not None:
OldVal: ir.Value = Gen._load(Gen.variables[VarName], name=VarName)
store_ptr: ir.Value = Gen.variables[VarName]
if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Value.type.width != 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset")
NewVal: ir.Value
if Op == '-' or Op == '+':
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add")
else:
ptr_val: ir.Value = OldVal
OldVal = Gen._load(OldVal, name="deref_ptr_for_op")
orig_type: ir.Type = OldVal.type
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType):
if NewVal.type.width > orig_type.width:
NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result")
store_ptr = ptr_val
else:
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Op in ('+', '-'):
if Value.type.width < 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug")
NewVal: ir.Value
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_aug")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug")
Gen._store(NewVal, store_ptr)
return
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(store_ptr.type, ir.PointerType):
TargetType: ir.Type = store_ptr.type.pointee
if NewVal.type != TargetType:
Coerced: ir.Value | None = Gen._coerce_value(NewVal, TargetType)
if Coerced is not None:
NewVal = Coerced
Gen._store(NewVal, store_ptr)
elif VarName == 'pos':
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
Gen.variables[VarName] = var
OldVal: ir.Value = Gen._load(var, name=VarName)
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
Gen._store(NewVal, var)
elif isinstance(Node.target, ast.Attribute):
AttrName: str = Node.target.attr
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.target)
if OldVal:
def _deref_if_ptr(val: ir.Value) -> ir.Value:
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)):
return Gen._load(val, name="deref_aug")
return val
OldVal = _deref_if_ptr(OldVal)
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr")
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal)
elif isinstance(Node.target, ast.Subscript):
SubTarget: ast.Subscript = Node.target
ElemPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget)
if ElemPtr:
if isinstance(ElemPtr.type, ir.PointerType):
OldVal: ir.Value = Gen._load(ElemPtr, name="old_subscript_val")
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub")
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Op in ('+', '-'):
if Value.type.width < 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub")
NewVal: ir.Value
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_sub")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub")
Gen._store(NewVal, ElemPtr)
return
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType):
if NewVal.type.width > ElemPtr.type.pointee.width:
NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result")
from __future__ import annotations
from typing import TYPE_CHECKING
import vast as ast
import sys
import llvmlite.ir as ir
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.VLogger import get_logger as _vlog
from lib.core.Handles.HandlesBase import BaseHandle
class AugAssignHandle(BaseHandle):
_AUGOP_MAP: dict[type, str] = {
ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__',
ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__',
}
_AUGOP_FALLBACK: dict[type, str] = {
ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__',
ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__',
}
def _resolve_global_var_type(self, Gen: "Translator.LlvmGen", VarName: str, fallback: ir.Type) -> ir.Type:
"""解析 global 变量的 LLVM 类型:优先用模块级 AnnAssign 的注解类型。
问题场景:函数内 `_g_alloc_count += 1`(global 声明),模块级注解为
`_g_alloc_count: t.CSizeT`(i64)。若不查模块级注解类型,此处会用 RHS 字面量
类型(i32)自动建 i32 全局,与模块内其他读取/写入(i64)类型不匹配,
产生 "Operands must be the same type, got (i64, i32)" 类错误。
模块级 AnnAssign 已通过 _EmitGlobalAnnAssignLlvm 创建 LLVM 全局,
但注解无初始值(如 `_g_alloc_max: t.CSizeT = 0`)时 initializer 为空、
Gen.module.globals 中无该符号,故需在此兜底解析注解类型。
"""
module_ann: dict = getattr(Gen, '_module_ann_types', None)
if module_ann and VarName in module_ann:
ann_type: ir.Type = module_ann[VarName]
if ann_type is not None:
return ann_type
if isinstance(fallback, ir.IntType):
return fallback
return ir.IntType(64)
def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
if Gen._check_node_unsigned(Node.target):
return True
elif isinstance(Node.target, ast.Attribute):
if Gen._check_node_unsigned(Node.target):
return True
elif isinstance(Node.target, ast.Subscript):
if Gen._check_node_unsigned(Node.target):
return True
if Node.value is not None and Gen._check_node_unsigned(Node.value):
return True
return False
def _HandleAugAssignLlvm(self, Node: ast.AugAssign) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(Node.target, ast.Name):
VarName: str = Node.target.id
if (VarName not in Gen.variables
and VarName not in Gen.global_vars
and VarName not in Gen._reg_values
and VarName not in Gen._direct_values):
src_info: str = Gen._get_node_info()
_vlog().error(f"变量 '{VarName}' 未声明,不能用于增量赋值(需用 global 声明或先声明局部变量){src_info}")
sys.exit(1)
if VarName in Gen.var_const_flags:
src_info: str = Gen._get_node_info()
_vlog().error(f"不能对 const 变量 '{VarName}' 增量赋值{src_info}")
sys.exit(1)
ClassName: str | None = Gen.var_struct_class.get(VarName)
iop_name: str | None = self._AUGOP_MAP.get(type(Node.op))
if ClassName and iop_name:
iFuncName: str = f'{ClassName}.{iop_name}'
FuncName: str = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}'
if iFuncName in Gen.functions or FuncName in Gen.functions:
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
if OldVal and Value:
result: ir.Value | None
if iFuncName in Gen.functions:
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value)
else:
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value)
if result is not None:
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr: ir.Value = Gen.variables[VarName]
if VarPtr.type.pointee == result.type:
Gen._store(result, VarPtr)
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType):
CastedVal: ir.Value = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}")
Gen._store(CastedVal, VarPtr)
else:
NewVar: ir.AllocaInstr = Gen._allocaEntry(result.type, name=VarName)
Gen._store(result, NewVar)
Gen.variables[VarName] = NewVar
else:
Gen._reg_values[VarName] = result
Gen.variables[VarName] = None
return
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
if not Value:
return
is_unsigned: bool = self._is_aug_unsigned(Node, None, Value)
if isinstance(Node.target, ast.Name):
VarName: str = Node.target.id
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if VarName in Gen.global_vars:
# 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局
# (注解无初始值的全局变量),此处自动创建零初始化全局变量
GVar: ir.GlobalVariable
if VarName not in Gen.module.globals:
_gv_type: ir.Type = self._resolve_global_var_type(Gen, VarName, Value.type)
GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName)
GVar.initializer = ir.Constant(_gv_type, 0)
else:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
OldVal: ir.Value = Gen._load(GVar, name=VarName)
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
Gen._store(NewVal, GVar)
return
if VarName in Gen._reg_values:
OldVal: ir.Value = Gen._reg_values[VarName]
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
if VarName in Gen._direct_values:
OldVal: ir.Value = Gen._direct_values.pop(VarName)
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.variables[VarName] = var
if Gen.builder.block.is_terminated:
return
if VarName in Gen.variables and Gen.variables[VarName] is not None:
OldVal: ir.Value = Gen._load(Gen.variables[VarName], name=VarName)
store_ptr: ir.Value = Gen.variables[VarName]
if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Value.type.width != 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset")
NewVal: ir.Value
if Op == '-' or Op == '+':
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add")
else:
ptr_val: ir.Value = OldVal
OldVal = Gen._load(OldVal, name="deref_ptr_for_op")
orig_type: ir.Type = OldVal.type
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType):
if NewVal.type.width > orig_type.width:
NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result")
store_ptr = ptr_val
else:
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Op in ('+', '-'):
if Value.type.width < 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug")
NewVal: ir.Value
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_aug")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug")
Gen._store(NewVal, store_ptr)
return
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(store_ptr.type, ir.PointerType):
TargetType: ir.Type = store_ptr.type.pointee
if NewVal.type != TargetType:
Coerced: ir.Value | None = Gen._coerce_value(NewVal, TargetType)
if Coerced is not None:
NewVal = Coerced
Gen._store(NewVal, store_ptr)
elif VarName == 'pos':
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
Gen.variables[VarName] = var
OldVal: ir.Value = Gen._load(var, name=VarName)
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
Gen._store(NewVal, var)
elif isinstance(Node.target, ast.Attribute):
AttrName: str = Node.target.attr
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.target)
if OldVal:
def _deref_if_ptr(val: ir.Value) -> ir.Value:
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)):
return Gen._load(val, name="deref_aug")
return val
OldVal = _deref_if_ptr(OldVal)
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr")
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal)
elif isinstance(Node.target, ast.Subscript):
SubTarget: ast.Subscript = Node.target
ElemPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget)
if ElemPtr:
if isinstance(ElemPtr.type, ir.PointerType):
OldVal: ir.Value = Gen._load(ElemPtr, name="old_subscript_val")
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
if OldVal.type.width < Value.type.width:
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub")
elif OldVal.type.width > Value.type.width:
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub")
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
if Op in ('+', '-'):
if Value.type.width < 64:
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub")
NewVal: ir.Value
if Op == '-':
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_sub")
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub")
else:
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub")
Gen._store(NewVal, ElemPtr)
return
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType):
if NewVal.type.width > ElemPtr.type.pointee.width:
NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result")
Gen._store(NewVal, ElemPtr)
File diff suppressed because it is too large. Load diff
+76 -76
View File
@@ -1,77 +1,77 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class BodyHandle(BaseHandle):
def __init__(self, translator: "Translator") -> None:
super().__init__(translator)
def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for Node in Body:
if Gen.builder and Gen.builder.block.is_terminated:
break
Gen._set_node_info(Node)
try:
if isinstance(Node, ast.Expr):
self.HandleExprLlvm(Node.value)
elif isinstance(Node, ast.Return):
self.Trans.ReturnHandler._HandleReturnLlvm(Node)
elif isinstance(Node, ast.Assign):
self.Trans.AssignHandler._HandleAssignLlvm(Node)
elif isinstance(Node, ast.AugAssign):
self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node)
elif isinstance(Node, ast.AnnAssign):
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node)
elif isinstance(Node, ast.If):
self.Trans.IfHandler._HandleIfLlvm(Node)
elif isinstance(Node, ast.For):
self.Trans.ForHandler._HandleForLlvm(Node)
elif isinstance(Node, ast.While):
self.Trans.WhileHandler._HandleWhileLlvm(Node)
elif isinstance(Node, ast.Break):
if Gen.loop_break_targets:
Gen.builder.branch(Gen.loop_break_targets[-1])
elif isinstance(Node, ast.Continue):
if Gen.loop_continue_targets:
Gen.builder.branch(Gen.loop_continue_targets[-1])
elif isinstance(Node, ast.With):
self.Trans.WithHandler._HandleWithLlvm(Node)
elif isinstance(Node, ast.ClassDef):
pass
elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match):
self.Trans.MatchHandler._HandleMatchLlvm(Node)
elif isinstance(Node, ast.Try):
self.Trans.TryHandler._HandleTryLlvm(Node)
elif isinstance(Node, ast.Raise):
self.Trans.RaiseHandler._HandleRaiseLlvm(Node)
elif isinstance(Node, ast.Assert):
self.Trans.AssertHandler._HandleAssertLlvm(Node)
elif isinstance(Node, ast.Global):
self.Trans.ForHandler._HandleGlobalLlvm(Node)
elif isinstance(Node, ast.FunctionDef):
self.Trans.ForHandler._HandleNestedFunctionLlvm(Node)
elif isinstance(Node, ast.Nonlocal):
self.Trans.ForHandler._HandleNonlocalLlvm(Node)
elif isinstance(Node, ast.Delete):
self.Trans.DeleteHandler._HandleDeleteLlvm(Node)
except Exception as e:
lineno: int = getattr(Node, 'lineno', 0)
source_line: str | None = Gen._get_source_line(lineno)
src_file: str = Gen._current_source_file or ''
src_path: str = src_file if src_file else 'unknown'
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
if source_line:
line_info += ":\n %d | %s" % (lineno, source_line)
self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info))
raise
if Gen.builder and not Gen.builder.block.is_terminated:
Gen._EmitTempFrees()
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import vast as ast
import llvmlite.ir as ir
class BodyHandle(BaseHandle):
def __init__(self, translator: "Translator") -> None:
super().__init__(translator)
def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for Node in Body:
if Gen.builder and Gen.builder.block.is_terminated:
break
Gen._set_node_info(Node)
try:
if isinstance(Node, ast.Expr):
self.HandleExprLlvm(Node.value)
elif isinstance(Node, ast.Return):
self.Trans.ReturnHandler._HandleReturnLlvm(Node)
elif isinstance(Node, ast.Assign):
self.Trans.AssignHandler._HandleAssignLlvm(Node)
elif isinstance(Node, ast.AugAssign):
self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node)
elif isinstance(Node, ast.AnnAssign):
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node)
elif isinstance(Node, ast.If):
self.Trans.IfHandler._HandleIfLlvm(Node)
elif isinstance(Node, ast.For):
self.Trans.ForHandler._HandleForLlvm(Node)
elif isinstance(Node, ast.While):
self.Trans.WhileHandler._HandleWhileLlvm(Node)
elif isinstance(Node, ast.Break):
if Gen.loop_break_targets:
Gen.builder.branch(Gen.loop_break_targets[-1])
elif isinstance(Node, ast.Continue):
if Gen.loop_continue_targets:
Gen.builder.branch(Gen.loop_continue_targets[-1])
elif isinstance(Node, ast.With):
self.Trans.WithHandler._HandleWithLlvm(Node)
elif isinstance(Node, ast.ClassDef):
pass
elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match):
self.Trans.MatchHandler._HandleMatchLlvm(Node)
elif isinstance(Node, ast.Try):
self.Trans.TryHandler._HandleTryLlvm(Node)
elif isinstance(Node, ast.Raise):
self.Trans.RaiseHandler._HandleRaiseLlvm(Node)
elif isinstance(Node, ast.Assert):
self.Trans.AssertHandler._HandleAssertLlvm(Node)
elif isinstance(Node, ast.Global):
self.Trans.ForHandler._HandleGlobalLlvm(Node)
elif isinstance(Node, ast.FunctionDef):
self.Trans.ForHandler._HandleNestedFunctionLlvm(Node)
elif isinstance(Node, ast.Nonlocal):
self.Trans.ForHandler._HandleNonlocalLlvm(Node)
elif isinstance(Node, ast.Delete):
self.Trans.DeleteHandler._HandleDeleteLlvm(Node)
except Exception as e:
lineno: int = getattr(Node, 'lineno', 0)
source_line: str | None = Gen._get_source_line(lineno)
src_file: str = Gen._current_source_file or ''
src_path: str = src_file if src_file else 'unknown'
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
if source_line:
line_info += ":\n %d | %s" % (lineno, source_line)
self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info))
raise
if Gen.builder and not Gen.builder.block.is_terminated:
Gen._EmitTempFrees()
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None:
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
+196 -196
View File
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
import ast
import vast as ast
import copy
import llvmlite.ir as ir
from lib.core.Exportable import EnumMember as ExportEnumMember
@@ -247,125 +247,125 @@ class ClassHandle(BaseHandle):
Gen._struct_sha1_map[spec_name] = self.Trans._module_sha1
return spec_name
def _resolve_base_kind(self, base_name: str, Gen: LlvmGeneratorMixin) -> str | None:
"""解析基类名称的类型种类
查询顺序:
1. _t_type_symbols(from t import CEnum as en)
2. t 模块属性(t.CEnum / t.CUnion / t.CStruct / t.REnum)
3. 返回 None 表示不是已知标记基类
Returns:
'enum' | 'union' | 'renum' | 'struct' | None
"""
# 1) 查 _t_type_symbols(别名导入)
symtab: object = self.Trans.SymbolTable
cls: type | None = symtab._t_type_symbols.get(base_name)
if cls is not None:
if issubclass(cls, (t.CEnum, t.REnum)):
return 'renum' if issubclass(cls, t.REnum) else 'enum'
if issubclass(cls, t.CUnion):
return 'union'
if issubclass(cls, t.CStruct):
return 'struct'
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
# 不应被编译为真实结构体。
if issubclass(cls, t.CType):
return 'ctype_marker'
# 2) 查 t 模块属性(直接引用 t.CEnum 等)
t_cls: type | None = getattr(t, base_name, None)
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
if issubclass(t_cls, (t.CEnum, t.REnum)):
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
if issubclass(t_cls, t.CUnion):
return 'union'
if issubclass(t_cls, t.CStruct):
return 'struct'
# CType 及其子类是"类型强转"标记,不编译为结构体。
return 'ctype_marker'
return None
@staticmethod
def _is_classname_ctype_marker(class_name: str) -> bool:
"""检查类名是否是 t.CType 的"类型强转"标记子类。
只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/
CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等)
才应跳过编译。有 BASE position 的基本类型(CInt/CChar/CSizeT/CLong 等)
有具体大小,应被正常编译。CType 基类本身无 bases,base 检测无法触发,
需要直接按类名检查。
注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault,
所以这里直接用 getattr(t, name) 检查 t 模块属性。
Returns:
True 如果 class_name 是 CType 标记子类名(应跳过编译)
"""
if not class_name:
return False
# 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian)
t_cls: type | None = getattr(t, class_name, None)
if not isinstance(t_cls, type) or not issubclass(t_cls, t.CType):
return False
if issubclass(t_cls, (t.CStruct, t.CEnum, t.REnum, t.CUnion)):
return False
# 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过
# CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过
if t.CType.BASE in t_cls.position:
try:
inst = t_cls()
size_val = getattr(inst, 'Size', None)
if size_val is not None and size_val > 0:
return False
except Exception:
pass
return True
def _resolve_decorator_kind(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> str | None:
"""从装饰器列表中解析结构体类型种类
支持 @t.CStruct, @t.CUnion, @t.CEnum, @t.REnum
也支持 from t import CStruct 等别名形式
Returns:
'enum' | 'union' | 'renum' | 'struct' | None
"""
if not hasattr(Node, 'decorator_list') or not Node.decorator_list:
return None
symtab: object = self.Trans.SymbolTable
for decorator in Node.decorator_list:
attr_name: str | None = None
# @t.CStruct 形式
if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name):
if IsTModule(decorator.value.id, symtab):
attr_name = decorator.attr
# @CStruct 形式 (from t import CStruct)
elif isinstance(decorator, ast.Name):
cls: type | None = getattr(t, decorator.id, None)
if cls is None and hasattr(symtab, '_t_type_symbols'):
cls = symtab._t_type_symbols.get(decorator.id)
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
attr_name = cls.__name__
if attr_name:
# 查 _t_type_symbols 和 t 模块属性以确定种类
resolved_cls: type | None = None
if hasattr(symtab, '_t_type_symbols'):
resolved_cls = symtab._t_type_symbols.get(attr_name)
if resolved_cls is None:
resolved_cls = getattr(t, attr_name, None)
if resolved_cls is not None and isinstance(resolved_cls, type):
if issubclass(resolved_cls, t.REnum):
return 'renum'
if issubclass(resolved_cls, t.CEnum):
return 'enum'
if issubclass(resolved_cls, t.CUnion):
return 'union'
if issubclass(resolved_cls, t.CStruct):
return 'struct'
return None
def _resolve_base_kind(self, base_name: str, Gen: LlvmGeneratorMixin) -> str | None:
"""解析基类名称的类型种类
查询顺序:
1. _t_type_symbols(from t import CEnum as en)
2. t 模块属性(t.CEnum / t.CUnion / t.CStruct / t.REnum)
3. 返回 None 表示不是已知标记基类
Returns:
'enum' | 'union' | 'renum' | 'struct' | None
"""
# 1) 查 _t_type_symbols(别名导入)
symtab: object = self.Trans.SymbolTable
cls: type | None = symtab._t_type_symbols.get(base_name)
if cls is not None:
if issubclass(cls, (t.CEnum, t.REnum)):
return 'renum' if issubclass(cls, t.REnum) else 'enum'
if issubclass(cls, t.CUnion):
return 'union'
if issubclass(cls, t.CStruct):
return 'struct'
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
# 不应被编译为真实结构体。
if issubclass(cls, t.CType):
return 'ctype_marker'
# 2) 查 t 模块属性(直接引用 t.CEnum 等)
t_cls: type | None = getattr(t, base_name, None)
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
if issubclass(t_cls, (t.CEnum, t.REnum)):
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
if issubclass(t_cls, t.CUnion):
return 'union'
if issubclass(t_cls, t.CStruct):
return 'struct'
# CType 及其子类是"类型强转"标记,不编译为结构体。
return 'ctype_marker'
return None
@staticmethod
def _is_classname_ctype_marker(class_name: str) -> bool:
"""检查类名是否是 t.CType 的"类型强转"标记子类。
只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/
CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等)
才应跳过编译。有 BASE position 的基本类型(CInt/CChar/CSizeT/CLong 等)
有具体大小,应被正常编译。CType 基类本身无 bases,base 检测无法触发,
需要直接按类名检查。
注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault,
所以这里直接用 getattr(t, name) 检查 t 模块属性。
Returns:
True 如果 class_name 是 CType 标记子类名(应跳过编译)
"""
if not class_name:
return False
# 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian)
t_cls: type | None = getattr(t, class_name, None)
if not isinstance(t_cls, type) or not issubclass(t_cls, t.CType):
return False
if issubclass(t_cls, (t.CStruct, t.CEnum, t.REnum, t.CUnion)):
return False
# 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过
# CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过
if t.CType.BASE in t_cls.position:
try:
inst = t_cls()
size_val = getattr(inst, 'Size', None)
if size_val is not None and size_val > 0:
return False
except Exception:
pass
return True
def _resolve_decorator_kind(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> str | None:
"""从装饰器列表中解析结构体类型种类
支持 @t.CStruct, @t.CUnion, @t.CEnum, @t.REnum
也支持 from t import CStruct 等别名形式
Returns:
'enum' | 'union' | 'renum' | 'struct' | None
"""
if not hasattr(Node, 'decorator_list') or not Node.decorator_list:
return None
symtab: object = self.Trans.SymbolTable
for decorator in Node.decorator_list:
attr_name: str | None = None
# @t.CStruct 形式
if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name):
if IsTModule(decorator.value.id, symtab):
attr_name = decorator.attr
# @CStruct 形式 (from t import CStruct)
elif isinstance(decorator, ast.Name):
cls: type | None = getattr(t, decorator.id, None)
if cls is None and hasattr(symtab, '_t_type_symbols'):
cls = symtab._t_type_symbols.get(decorator.id)
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
attr_name = cls.__name__
if attr_name:
# 查 _t_type_symbols 和 t 模块属性以确定种类
resolved_cls: type | None = None
if hasattr(symtab, '_t_type_symbols'):
resolved_cls = symtab._t_type_symbols.get(attr_name)
if resolved_cls is None:
resolved_cls = getattr(t, attr_name, None)
if resolved_cls is not None and isinstance(resolved_cls, type):
if issubclass(resolved_cls, t.REnum):
return 'renum'
if issubclass(resolved_cls, t.CEnum):
return 'enum'
if issubclass(resolved_cls, t.CUnion):
return 'union'
if issubclass(resolved_cls, t.CStruct):
return 'struct'
return None
def _resolve_class_flags(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> tuple[bool, bool, str | None, bool]:
"""解析类的 Object/CVTable 标志和父类信息
@@ -467,8 +467,8 @@ class ClassHandle(BaseHandle):
if IsCVTable:
Gen.class_vtable.add(ClassName)
# 沿继承链向上传播,将所有祖先类加入 vtable
visited: set[str] = {ClassName}
ancestor: str | None = ParentClassName
visited: set[str] = {ClassName}
ancestor: str | None = ParentClassName
while ancestor and ancestor not in visited:
visited.add(ancestor)
Gen.class_vtable.add(ancestor)
@@ -550,44 +550,44 @@ class ClassHandle(BaseHandle):
if IsRenum:
self._EmitREnumLlvm(Node, Gen)
return
IsCpythonObject: bool
IsCVTable: bool
ParentClassName: str | None
IsNoVTable: bool
IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable = self._resolve_class_flags(Node, Gen)
# 跟踪正在发射的类,防止递归特化时 _generate_structs 过早为空成员类设置 body
Gen._classes_in_progress.add(ClassName)
# 标记正在收集字段,阻止继承处理(_ResolveGenericSlice → _specialize_generic_class)
# 和 CollectAnnAssignMember 触发的嵌套 _generate_structs 用不完整 class_members 调用 set_body
Gen._collecting_members_set.add(ClassName)
if ClassName not in Gen.class_methods:
Gen.class_methods[ClassName] = []
else:
# 防御性清除:移除导入阶段可能添加的构造函数(__new__/__init__/__before_init__)。
# 构造函数不参与虚分派,放入 vtable 会导致子类与基类 vtable 大小不一致,
# 索引偏移破坏多态分派(如 Module 有 __new__/__init__ 使 vtable=7,而 AST 无它们 vtable=5,
# 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。
Gen.class_methods[ClassName] = [
m for m in Gen.class_methods[ClassName]
if m.split('.')[-1] not in ('__new__', '__init__', '__before_init__')
]
# 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明。
# 关键:如果本地类是 @t.NoVTable 但同名导入类有 vtable(名称冲突),
# 必须清除 vtable 状态,否则 _generate_structs 会错误添加 vtable 指针。
if IsNoVTable:
Gen.class_vtable.discard(ClassName)
Gen._cross_module_vtable_classes.discard(ClassName)
Gen._cross_module_novtable.add(ClassName)
# 清除可能从导入 stub 加载的旧 struct body(含错误 vtable 指针),
# 让 _generate_structs 用本地 class_members 重新生成
_old_st = Gen.structs.get(ClassName)
if isinstance(_old_st, ir.IdentifiedStructType) and _old_st.elements is not None:
_old_st._elements = None
_ih = getattr(Gen, '_import_handler_ref', None)
if _ih is not None:
_ck = (id(Gen), ClassName)
if _ck in _ih._struct_Load_cache:
del _ih._struct_Load_cache[_ck]
IsCpythonObject: bool
IsCVTable: bool
ParentClassName: str | None
IsNoVTable: bool
IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable = self._resolve_class_flags(Node, Gen)
# 跟踪正在发射的类,防止递归特化时 _generate_structs 过早为空成员类设置 body
Gen._classes_in_progress.add(ClassName)
# 标记正在收集字段,阻止继承处理(_ResolveGenericSlice → _specialize_generic_class)
# 和 CollectAnnAssignMember 触发的嵌套 _generate_structs 用不完整 class_members 调用 set_body
Gen._collecting_members_set.add(ClassName)
if ClassName not in Gen.class_methods:
Gen.class_methods[ClassName] = []
else:
# 防御性清除:移除导入阶段可能添加的构造函数(__new__/__init__/__before_init__)。
# 构造函数不参与虚分派,放入 vtable 会导致子类与基类 vtable 大小不一致,
# 索引偏移破坏多态分派(如 Module 有 __new__/__init__ 使 vtable=7,而 AST 无它们 vtable=5,
# 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。
Gen.class_methods[ClassName] = [
m for m in Gen.class_methods[ClassName]
if m.split('.')[-1] not in ('__new__', '__init__', '__before_init__')
]
# 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明。
# 关键:如果本地类是 @t.NoVTable 但同名导入类有 vtable(名称冲突),
# 必须清除 vtable 状态,否则 _generate_structs 会错误添加 vtable 指针。
if IsNoVTable:
Gen.class_vtable.discard(ClassName)
Gen._cross_module_vtable_classes.discard(ClassName)
Gen._cross_module_novtable.add(ClassName)
# 清除可能从导入 stub 加载的旧 struct body(含错误 vtable 指针),
# 让 _generate_structs 用本地 class_members 重新生成
_old_st = Gen.structs.get(ClassName)
if isinstance(_old_st, ir.IdentifiedStructType) and _old_st.elements is not None:
_old_st._elements = None
_ih = getattr(Gen, '_import_handler_ref', None)
if _ih is not None:
_ck = (id(Gen), ClassName)
if _ck in _ih._struct_Load_cache:
del _ih._struct_Load_cache[_ck]
Gen.class_members[ClassName] = []
Gen.class_member_defaults[ClassName] = {}
Gen.class_member_signeds[ClassName] = {}
@@ -707,13 +707,13 @@ class ClassHandle(BaseHandle):
if method_name not in covered_names:
new_methods.append(m)
Gen.class_methods[ClassName] = new_methods
# 提取首个裸字符串字面量作为结构体 __doc__ docstring
if (Node.body and isinstance(Node.body[0], ast.Expr)
and isinstance(Node.body[0].value, ast.Constant)
and isinstance(Node.body[0].value.value, str)):
Gen._create_doc_global(ClassName, Node.body[0].value.value)
else:
Gen._create_doc_global(ClassName, None)
# 提取首个裸字符串字面量作为结构体 __doc__ docstring
if (Node.body and isinstance(Node.body[0], ast.Expr)
and isinstance(Node.body[0].value, ast.Constant)
and isinstance(Node.body[0].value.value, str)):
Gen._create_doc_global(ClassName, Node.body[0].value.value)
else:
Gen._create_doc_global(ClassName, None)
# 解析 __provides__/__requires__/__require_must__ 编译期元数据
for item in Node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
@@ -1081,35 +1081,35 @@ class ClassHandle(BaseHandle):
continue
self._scan_node_for_self_assign(child, ClassName, existing_members, Gen)
def _EmitUnionLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
ClassName: str = Node.name
union_member_types: list[ir.Type] = []
for item in Node.body:
if isinstance(item, ast.ClassDef):
nested_class_name: str = item.name
nested_member_types: list[ir.Type] = []
for nested_item in item.body:
parsed = self.CollectAnnAssignMember(nested_item, Gen)
if parsed:
nested_member_types.append(parsed[1])
if nested_member_types:
nested_struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}")
nested_struct_type.set_body(*nested_member_types)
Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type
union_member_types.append(nested_struct_type)
nested_class_full_name: str = f"{ClassName}_{nested_class_name}"
if nested_class_full_name not in Gen.class_members:
Gen.class_members[nested_class_full_name] = []
if nested_class_full_name not in Gen.class_member_signeds:
Gen.class_member_signeds[nested_class_full_name] = {}
for nested_item in item.body:
parsed = self.CollectAnnAssignMember(nested_item, Gen)
if parsed:
VarName, MemberType, TypeInfo = parsed
Gen.class_members[nested_class_full_name].append((VarName, MemberType))
if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'):
Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned
else:
def _EmitUnionLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
ClassName: str = Node.name
union_member_types: list[ir.Type] = []
for item in Node.body:
if isinstance(item, ast.ClassDef):
nested_class_name: str = item.name
nested_member_types: list[ir.Type] = []
for nested_item in item.body:
parsed = self.CollectAnnAssignMember(nested_item, Gen)
if parsed:
nested_member_types.append(parsed[1])
if nested_member_types:
nested_struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}")
nested_struct_type.set_body(*nested_member_types)
Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type
union_member_types.append(nested_struct_type)
nested_class_full_name: str = f"{ClassName}_{nested_class_name}"
if nested_class_full_name not in Gen.class_members:
Gen.class_members[nested_class_full_name] = []
if nested_class_full_name not in Gen.class_member_signeds:
Gen.class_member_signeds[nested_class_full_name] = {}
for nested_item in item.body:
parsed = self.CollectAnnAssignMember(nested_item, Gen)
if parsed:
VarName, MemberType, TypeInfo = parsed
Gen.class_members[nested_class_full_name].append((VarName, MemberType))
if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'):
Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned
else:
Gen.class_member_signeds[nested_class_full_name][VarName] = None
if union_member_types:
max_size: int = 0
+101 -101
View File
@@ -1,102 +1,102 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
import ast
import llvmlite.ir as ir
class DeleteHandle(BaseHandle):
def _HandleDeleteLlvm(self, Node: ast.Delete) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for target in Node.targets:
if isinstance(target, ast.Subscript):
ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__delitem__'):
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.slice)
if obj_val and idx_val:
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__")
elif isinstance(target, ast.Name):
ClassName: str | None = Gen.var_struct_class.get(target.id)
if ClassName and Gen._has_function(f'{ClassName}.__delete__'):
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
if obj_val:
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__")
elif isinstance(target, ast.Attribute):
# 检查 property deleter
AttrName: str = target.attr
ClassName: str | None = None
obj_val_for_prop: ir.Value | None = None
if isinstance(target.value, ast.Name) and target.value.id == 'self':
# del self.attr — 检查当前类的 property deleter
ClassName = self.Trans._CurrentCpythonObjectClass
if ClassName:
PropKey: str = f'{ClassName}.{AttrName}'
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
if DeleterFunc and SelfPtr:
Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}")
continue
else:
# del obj.attr — 检查 obj 类的 property deleter
ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen)
if ClassName:
PropKey: str = f'{ClassName}.{AttrName}'
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
if obj_val:
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
if DeleterFunc:
Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}")
continue
# 原有的 __del__ 处理逻辑
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
if obj_val:
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType):
obj_val = Gen._load(obj_val, name="Load_del_ptr")
ClassName = None
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
for CN, ST in Gen.structs.items():
if obj_val.type.pointee == ST:
ClassName = CN
break
elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
if isinstance(target.value, ast.Name) and target.value.id == 'self':
AttrName = target.attr
SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass
if SelfClassName and SelfClassName in Gen.class_members:
for member_name, member_type in Gen.class_members[SelfClassName]:
if member_name == AttrName:
for CN in Gen.structs:
if CN == AttrName or Gen._has_function(f'{CN}.__del__'):
ClassName = CN
break
break
if not ClassName:
for CN, ST in Gen.structs.items():
if Gen._has_function(f'{CN}.__del__'):
ClassName = CN
break
if ClassName and Gen._has_function(f'{ClassName}.__del__'):
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
import vast as ast
import llvmlite.ir as ir
class DeleteHandle(BaseHandle):
def _HandleDeleteLlvm(self, Node: ast.Delete) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for target in Node.targets:
if isinstance(target, ast.Subscript):
ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__delitem__'):
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.slice)
if obj_val and idx_val:
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__")
elif isinstance(target, ast.Name):
ClassName: str | None = Gen.var_struct_class.get(target.id)
if ClassName and Gen._has_function(f'{ClassName}.__delete__'):
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
if obj_val:
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__")
elif isinstance(target, ast.Attribute):
# 检查 property deleter
AttrName: str = target.attr
ClassName: str | None = None
obj_val_for_prop: ir.Value | None = None
if isinstance(target.value, ast.Name) and target.value.id == 'self':
# del self.attr — 检查当前类的 property deleter
ClassName = self.Trans._CurrentCpythonObjectClass
if ClassName:
PropKey: str = f'{ClassName}.{AttrName}'
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
if DeleterFunc and SelfPtr:
Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}")
continue
else:
# del obj.attr — 检查 obj 类的 property deleter
ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen)
if ClassName:
PropKey: str = f'{ClassName}.{AttrName}'
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
if obj_val:
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
if DeleterFunc:
Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}")
continue
# 原有的 __del__ 处理逻辑
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
if obj_val:
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType):
obj_val = Gen._load(obj_val, name="Load_del_ptr")
ClassName = None
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
for CN, ST in Gen.structs.items():
if obj_val.type.pointee == ST:
ClassName = CN
break
elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
if isinstance(target.value, ast.Name) and target.value.id == 'self':
AttrName = target.attr
SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass
if SelfClassName and SelfClassName in Gen.class_members:
for member_name, member_type in Gen.class_members[SelfClassName]:
if member_name == AttrName:
for CN in Gen.structs:
if CN == AttrName or Gen._has_function(f'{CN}.__del__'):
ClassName = CN
break
break
if not ClassName:
for CN, ST in Gen.structs.items():
if Gen._has_function(f'{CN}.__del__'):
ClassName = CN
break
if ClassName and Gen._has_function(f'{ClassName}.__del__'):
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Gen.builder.call(Gen._get_function(f'{ClassName}.__del__'), [obj_val], name=f"call_{ClassName}.__del__")
+1 -1
View File
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import ast
import vast as ast
import re
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
+1 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
import ast
import vast as ast
import re
import llvmlite.ir as ir
if TYPE_CHECKING:
+1 -1
View File
@@ -4,7 +4,7 @@ if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
import ast
import vast as ast
import llvmlite.ir as ir
+1 -1
View File
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
import ast
import vast as ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.core.VLogger import get_logger as _vlog
+156 -156
View File
@@ -1,31 +1,31 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
import ast
import os
import re
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.includes import t
from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*(对应 C 的 void* 语义)"""
if isinstance(ty, ir.PointerType):
cur: ir.Type = ty
while isinstance(cur, ir.PointerType):
if isinstance(cur.pointee, ir.VoidType):
return ir.IntType(8).as_pointer()
cur = cur.pointee
return ty
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
import vast as ast
import os
import re
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.includes import t
from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*(对应 C 的 void* 语义)"""
if isinstance(ty, ir.PointerType):
cur: ir.Type = ty
while isinstance(cur, ir.PointerType):
if isinstance(cur.pointee, ir.VoidType):
return ir.IntType(8).as_pointer()
cur = cur.pointee
return ty
class ExprCallHandle(BaseHandle):
def _append_eh_msg_out_arg(self, CallArgs: list[ir.Value], func: ir.Function | None, Gen: LlvmGeneratorMixin) -> None:
if not func:
@@ -929,15 +929,15 @@ class ExprCallHandle(BaseHandle):
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
if (ClassName not in Gen.class_vtable
and ClassName not in Gen._cross_module_vtable_classes
and class_sha1):
self._try_register_vtable_ondemand(ClassName, class_sha1, Gen)
# 跨模块多继承:确保 class_parents 可用(MRO 回退需要)。
# 如 HandlesType 委托调用 Generator 的方法——Generator 定义在
# 另一模块,class_parents 未随 import 填充,需从 vpi 按需加载。
self._EnsureClassParentsLoaded(ClassName, Gen)
if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call:
if (ClassName not in Gen.class_vtable
and ClassName not in Gen._cross_module_vtable_classes
and class_sha1):
self._try_register_vtable_ondemand(ClassName, class_sha1, Gen)
# 跨模块多继承:确保 class_parents 可用(MRO 回退需要)。
# 如 HandlesType 委托调用 Generator 的方法——Generator 定义在
# 另一模块,class_parents 未随 import 填充,需从 vpi 按需加载。
self._EnsureClassParentsLoaded(ClassName, Gen)
if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call:
methods = Gen.class_methods[ClassName]
if class_sha1:
FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}'
@@ -2407,125 +2407,125 @@ class ExprCallHandle(BaseHandle):
# 失败时恢复 declare_only 标记,避免后续调用跳过补发
Gen._generic_class_specializations[spec_key] = (cached_name, True)
def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None:
"""计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。
遍历 struct elements 带对齐累加(与 _get_struct_size/_get_align 一致)。
有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。
返回 None 表示无法计算(struct 未定义 / 字段不存在)。
"""
st = Gen.structs.get(ClassName)
if not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
return None
members: list = Gen.class_members.get(ClassName, [])
has_vtable: bool = (ClassName in Gen.class_vtable
or ClassName in Gen._cross_module_vtable_classes)
base: int = 1 if has_vtable else 0
idx: int | None = None
for i, (name, _) in enumerate(members):
if name == field_name:
idx = base + i
break
if idx is None or idx >= len(st.elements):
return None
# ============================================================
# 修复(2026-08-13):class_members 与 struct.elements 数量不一致时对齐。
# 根因链(NewAstTest ASTCtx 枚举丢失):
# DeclarationGenerator/收集路径生成的 class_members 可能漏部分 Mixin/自动
# 字段(如 Generator 漏 GenericSpecDepth/GenericClassFiles/ISINSTANCE_CLASS_MAX
# 3 个,class_members=88 vs struct=91),导致 this_adjust 用 class_members
# 索引算错字节偏移(Generator 624 vs 真实 644)。StmtGenMixin 方法(find_enum/
# register_enum/is_enum_class)字段访问错位 20 字节 → EnumTable 落在
# ReexportSrcs 内存 → 与 reexport 数据冲突覆盖 → ASTCtx 等枚举丢失。
# 修正:字段真实 struct 索引 = class_members 索引 + (struct 元素数 - members 数)。
# 前提:遗漏字段位于目标字段之前(本 bug 场景成立:漏字段在 StmtGenMixin 前)。
# ============================================================
diff_elems: int = len(st.elements) - len(members)
if diff_elems > 0:
idx += diff_elems
if idx >= len(st.elements):
return None
offset: int = 0
for i in range(idx):
et = st.elements[i]
align: int = Gen._get_align(et)
size: int = Gen._get_struct_size(et)
if align > 1:
offset = ((offset + align - 1) // align) * align
offset += size
align = Gen._get_align(st.elements[idx])
if align > 1:
offset = ((offset + align - 1) // align) * align
return offset
def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value,
ClassName: str, method_anc: str | None) -> ir.Value:
"""多继承 this 调整(与 TPV _translate_method_call 一致):
继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内
GEP(self_B, [0, 1]),字节偏移为 B 布局中 b 的 offset 8)。父类字段区
在子类中的**字节偏移**可能不同(如 AB={i8*,a@8,b@12} 中 b 偏移 12),
self 需按字节差前移,使父类方法内二次 GEP 恰好落到子类字段。
修复(2026-08-10):字段索引法在"父类与子类元素大小不同"时错位
(GEP 索引按元素个数计,非字节等价)。改用字节偏移:
delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移
delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节
GEP 到父类字段区在子类中的等效基址,再 bitcast 成父类指针。
"""
if method_anc is None or method_anc == ClassName:
return ObjVal
anc_members: list = Gen.class_members.get(method_anc, [])
if not anc_members:
return ObjVal
first_field_name: str | None = None
for _fn, _ft in anc_members:
if _fn == '__vtable__':
continue
first_field_name = _fn
break
if first_field_name is None:
return ObjVal
sub_off: int | None = self._compute_field_byte_offset(Gen, ClassName, first_field_name)
if sub_off is None:
return ObjVal
anc_off: int | None = self._compute_field_byte_offset(Gen, method_anc, first_field_name)
if anc_off is None:
return ObjVal
delta: int = sub_off - anc_off
if delta <= 0:
return ObjVal
if method_anc not in Gen.structs:
return ObjVal
obj_i8: ir.Value = Gen.builder.bitcast(ObjVal, ir.PointerType(ir.IntType(8)),
name=f"this_adjust_i8_{method_anc}")
adj: ir.Value = Gen.builder.gep(obj_i8, [ir.Constant(ir.IntType(64), delta)],
name=f"this_adjust_{method_anc}")
return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]),
name=f"this_adjust_cast_{method_anc}")
def _EnsureClassParentsLoaded(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
"""跨模块多继承:class_parents 缺失时从 vpi 按需加载继承信息。
调用方(如 HandlesType 委托)引用的类定义在另一模块,其父类
信息未随 import 填充。_TryLoadClassMembersFromPyi 读取 .vpi 中
的 ClassDef 并经 _EmitExternalClassDeclLlvm 填充 class_parents,
使 _get_mro_chain 能沿 MRO 回退到定义类(如 TypeGenMixin)。
"""
if not ClassName:
return
if Gen.class_parents.get(ClassName):
return
sha1_cls = Gen.ModuleSha1Map.get(ClassName)
if not sha1_cls:
sha1_cls = getattr(Gen, '_struct_sha1_map', {}).get(ClassName)
if not sha1_cls:
return
try:
self.Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, f"{sha1_cls}.stub.ll", Gen)
except Exception:
pass
def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None:
"""计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。
遍历 struct elements 带对齐累加(与 _get_struct_size/_get_align 一致)。
有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。
返回 None 表示无法计算(struct 未定义 / 字段不存在)。
"""
st = Gen.structs.get(ClassName)
if not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
return None
members: list = Gen.class_members.get(ClassName, [])
has_vtable: bool = (ClassName in Gen.class_vtable
or ClassName in Gen._cross_module_vtable_classes)
base: int = 1 if has_vtable else 0
idx: int | None = None
for i, (name, _) in enumerate(members):
if name == field_name:
idx = base + i
break
if idx is None or idx >= len(st.elements):
return None
# ============================================================
# 修复(2026-08-13):class_members 与 struct.elements 数量不一致时对齐。
# 根因链(NewAstTest ASTCtx 枚举丢失):
# DeclarationGenerator/收集路径生成的 class_members 可能漏部分 Mixin/自动
# 字段(如 Generator 漏 GenericSpecDepth/GenericClassFiles/ISINSTANCE_CLASS_MAX
# 3 个,class_members=88 vs struct=91),导致 this_adjust 用 class_members
# 索引算错字节偏移(Generator 624 vs 真实 644)。StmtGenMixin 方法(find_enum/
# register_enum/is_enum_class)字段访问错位 20 字节 → EnumTable 落在
# ReexportSrcs 内存 → 与 reexport 数据冲突覆盖 → ASTCtx 等枚举丢失。
# 修正:字段真实 struct 索引 = class_members 索引 + (struct 元素数 - members 数)。
# 前提:遗漏字段位于目标字段之前(本 bug 场景成立:漏字段在 StmtGenMixin 前)。
# ============================================================
diff_elems: int = len(st.elements) - len(members)
if diff_elems > 0:
idx += diff_elems
if idx >= len(st.elements):
return None
offset: int = 0
for i in range(idx):
et = st.elements[i]
align: int = Gen._get_align(et)
size: int = Gen._get_struct_size(et)
if align > 1:
offset = ((offset + align - 1) // align) * align
offset += size
align = Gen._get_align(st.elements[idx])
if align > 1:
offset = ((offset + align - 1) // align) * align
return offset
def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value,
ClassName: str, method_anc: str | None) -> ir.Value:
"""多继承 this 调整(与 TPV _translate_method_call 一致):
继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内
GEP(self_B, [0, 1]),字节偏移为 B 布局中 b 的 offset 8)。父类字段区
在子类中的**字节偏移**可能不同(如 AB={i8*,a@8,b@12} 中 b 偏移 12),
self 需按字节差前移,使父类方法内二次 GEP 恰好落到子类字段。
修复(2026-08-10):字段索引法在"父类与子类元素大小不同"时错位
(GEP 索引按元素个数计,非字节等价)。改用字节偏移:
delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移
delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节
GEP 到父类字段区在子类中的等效基址,再 bitcast 成父类指针。
"""
if method_anc is None or method_anc == ClassName:
return ObjVal
anc_members: list = Gen.class_members.get(method_anc, [])
if not anc_members:
return ObjVal
first_field_name: str | None = None
for _fn, _ft in anc_members:
if _fn == '__vtable__':
continue
first_field_name = _fn
break
if first_field_name is None:
return ObjVal
sub_off: int | None = self._compute_field_byte_offset(Gen, ClassName, first_field_name)
if sub_off is None:
return ObjVal
anc_off: int | None = self._compute_field_byte_offset(Gen, method_anc, first_field_name)
if anc_off is None:
return ObjVal
delta: int = sub_off - anc_off
if delta <= 0:
return ObjVal
if method_anc not in Gen.structs:
return ObjVal
obj_i8: ir.Value = Gen.builder.bitcast(ObjVal, ir.PointerType(ir.IntType(8)),
name=f"this_adjust_i8_{method_anc}")
adj: ir.Value = Gen.builder.gep(obj_i8, [ir.Constant(ir.IntType(64), delta)],
name=f"this_adjust_{method_anc}")
return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]),
name=f"this_adjust_cast_{method_anc}")
def _EnsureClassParentsLoaded(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
"""跨模块多继承:class_parents 缺失时从 vpi 按需加载继承信息。
调用方(如 HandlesType 委托)引用的类定义在另一模块,其父类
信息未随 import 填充。_TryLoadClassMembersFromPyi 读取 .vpi 中
的 ClassDef 并经 _EmitExternalClassDeclLlvm 填充 class_parents,
使 _get_mro_chain 能沿 MRO 回退到定义类(如 TypeGenMixin)。
"""
if not ClassName:
return
if Gen.class_parents.get(ClassName):
return
sha1_cls = Gen.ModuleSha1Map.get(ClassName)
if not sha1_cls:
sha1_cls = getattr(Gen, '_struct_sha1_map', {}).get(ClassName)
if not sha1_cls:
return
try:
self.Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, f"{sha1_cls}.stub.ll", Gen)
except Exception:
pass
def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value:
Gen = self.Trans.LlvmGen
MethodName = Node.func.attr
+270 -270
View File
@@ -1,271 +1,271 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import re
import llvmlite.ir as ir
class ExprFormatHandle(BaseHandle):
def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return ir.Constant(ir.IntType(8).as_pointer(), None)
format_str: str = ""
cast_args: list[Any] = []
for part in Node.values:
if isinstance(part, ast.Constant) and isinstance(part.value, str):
format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0')
elif isinstance(part, ast.FormattedValue):
fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen)
if fmt_class and Gen._has_function(f'{fmt_class}.__str__'):
obj_val: Any = self.HandleExprLlvm(part.value)
if obj_val:
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
if fmt_class in Gen.structs:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}")
val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__")
Gen._RegisterTempPtr(val)
format_str += "%s"
cast_args.append(val)
else:
format_str += "%s"
cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
continue
val = self.HandleExprLlvm(part.value)
if not val:
format_str += "%d"
cast_args.append(ir.Constant(ir.IntType(32), 0))
continue
# 检查 format_spec(Python f-string 格式说明符)
if part.format_spec is not None:
c_fmt: str | None = self._parse_format_spec(part.format_spec, val)
if c_fmt is not None:
cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value)
format_str += c_fmt
cast_args.append(cast_val)
continue
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, ir.IntType) and pointee.width == 8:
format_str += "%s"
cast_args.append(val)
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int")
trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc")
format_str += "%d"
cast_args.append(trunc_val)
else:
Loaded: Any = Gen._load(val, name="fstr_deref")
if isinstance(Loaded.type, ir.IntType):
if Loaded.type.width == 8:
format_str += "%c"
ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int")
cast_args.append(ext)
else:
format_str += "%d"
cast_args.append(Loaded)
elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)):
format_str += "%f"
cast_args.append(Loaded)
elif isinstance(Loaded.type, ir.PointerType):
format_str += "%s"
cast_args.append(Loaded)
else:
format_str += "%d"
cast_args.append(Loaded)
elif isinstance(val.type, ir.IntType):
if val.type.width == 8:
format_str += "%c"
ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int")
cast_args.append(ext)
elif val.type.width == 1:
zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int")
format_str += "%d"
cast_args.append(zext)
else:
is_u: bool = Gen._check_node_unsigned(part.value)
format_str += "%u" if is_u else "%d"
cast_args.append(val)
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
format_str += "%f"
cast_args.append(val)
else:
format_str += "%d"
cast_args.append(val)
if not format_str:
return Gen.emit_constant("", 'string')
format_ptr: Any = Gen._create_string_global(format_str)
# 统一使用 snprintf 生成字符串,返回 i8*
# __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放)
in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__'))
snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [
ir.PointerType(ir.IntType(8)),
ir.IntType(64),
ir.PointerType(ir.IntType(8))
], var_arg=True)
snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type)
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
# 第一遍:获取所需长度(NULL 缓冲,size=0)
len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len")
# 加 1 用于 null 终止符
size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size")
size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext")
if in_str_method:
# 堆分配(__str__ 返回值需跨函数生命周期)
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type)
buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf")
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
Gen._RegisterTempPtr(buf_ptr)
return buf_ptr
# 栈分配(局部使用,自动释放)
buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val)
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
return buf_ptr
def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None:
"""将 Python f-string format_spec 转换为 C printf 格式说明符。
支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。
返回 None 表示无法解析,调用方应回退到类型推断。
"""
if isinstance(format_spec_node, ast.JoinedStr):
parts: list[str] = []
for v in format_spec_node.values:
if isinstance(v, ast.Constant) and isinstance(v.value, str):
parts.append(v.value)
else:
return None
spec_str: str = ''.join(parts)
elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str):
spec_str = format_spec_node.value
else:
return None
if not spec_str:
return None
m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str)
if not m:
return None
fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups()
c_flags: str = ''
if sign == '+':
c_flags += '+'
elif sign == ' ':
c_flags += ' '
if alt:
c_flags += '#'
if fill_align:
align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0]
if align_char in ('<', '^'):
c_flags += '-'
if zero:
c_flags += '0'
c_width: str = width or ''
c_precision: str = precision or ''
length_mod: str = ''
if isinstance(val.type, ir.IntType):
if val.type.width == 64:
length_mod = 'll'
elif val.type.width == 32:
length_mod = 'l'
elif val.type.width == 16:
length_mod = 'h'
elif val.type.width == 8:
length_mod = 'hh'
c_specifier: str = ''
if fmt_type in ('d', 'n'):
c_specifier = f'{length_mod}d'
elif fmt_type == 'x':
c_specifier = f'{length_mod}x'
elif fmt_type == 'X':
c_specifier = f'{length_mod}X'
elif fmt_type == 'o':
c_specifier = f'{length_mod}o'
elif fmt_type == 'b':
return None
elif fmt_type == 'c':
c_specifier = 'c'
elif fmt_type in ('f', 'F'):
c_specifier = 'f'
elif fmt_type in ('e', 'E', 'g', 'G'):
c_specifier = fmt_type
elif fmt_type == 's':
c_specifier = 's'
elif fmt_type == '%':
c_specifier = 'f%%'
else:
if isinstance(val.type, ir.IntType):
if val.type.width == 8:
c_specifier = 'c'
elif val.type.width == 1:
c_specifier = 'd'
else:
c_specifier = f'{length_mod}d'
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
c_specifier = 'f'
elif isinstance(val.type, ir.PointerType):
c_specifier = 's'
else:
c_specifier = 'd'
return f'%{c_flags}{c_width}{c_precision}{c_specifier}'
def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value:
"""根据 C printf 格式说明符转换值类型。"""
fmt_type_char: str = ''
for ch in reversed(c_fmt):
if ch.isalpha() and ch not in ('l', 'h'):
fmt_type_char = ch
break
elif ch == '%':
break
if fmt_type_char == 's':
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, ir.IntType) and pointee.width == 8:
return val
if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr")
return val
elif fmt_type_char == 'c':
if isinstance(val.type, ir.IntType) and val.type.width < 32:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c")
return val
elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'):
if isinstance(val.type, ir.IntType):
if val.type.width == 8:
is_u: bool = Gen._check_node_unsigned(arg_node)
if is_u:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8")
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8")
elif val.type.width == 16:
is_u = Gen._check_node_unsigned(arg_node)
if is_u:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16")
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16")
elif val.type.width == 1:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool")
return val
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i")
return val
elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'):
if isinstance(val.type, ir.FloatType):
return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext")
elif isinstance(val.type, ir.IntType):
return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f")
return val
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
import vast as ast
import re
import llvmlite.ir as ir
class ExprFormatHandle(BaseHandle):
def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return ir.Constant(ir.IntType(8).as_pointer(), None)
format_str: str = ""
cast_args: list[Any] = []
for part in Node.values:
if isinstance(part, ast.Constant) and isinstance(part.value, str):
format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0')
elif isinstance(part, ast.FormattedValue):
fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen)
if fmt_class and Gen._has_function(f'{fmt_class}.__str__'):
obj_val: Any = self.HandleExprLlvm(part.value)
if obj_val:
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
if fmt_class in Gen.structs:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}")
val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__")
Gen._RegisterTempPtr(val)
format_str += "%s"
cast_args.append(val)
else:
format_str += "%s"
cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
continue
val = self.HandleExprLlvm(part.value)
if not val:
format_str += "%d"
cast_args.append(ir.Constant(ir.IntType(32), 0))
continue
# 检查 format_spec(Python f-string 格式说明符)
if part.format_spec is not None:
c_fmt: str | None = self._parse_format_spec(part.format_spec, val)
if c_fmt is not None:
cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value)
format_str += c_fmt
cast_args.append(cast_val)
continue
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, ir.IntType) and pointee.width == 8:
format_str += "%s"
cast_args.append(val)
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int")
trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc")
format_str += "%d"
cast_args.append(trunc_val)
else:
Loaded: Any = Gen._load(val, name="fstr_deref")
if isinstance(Loaded.type, ir.IntType):
if Loaded.type.width == 8:
format_str += "%c"
ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int")
cast_args.append(ext)
else:
format_str += "%d"
cast_args.append(Loaded)
elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)):
format_str += "%f"
cast_args.append(Loaded)
elif isinstance(Loaded.type, ir.PointerType):
format_str += "%s"
cast_args.append(Loaded)
else:
format_str += "%d"
cast_args.append(Loaded)
elif isinstance(val.type, ir.IntType):
if val.type.width == 8:
format_str += "%c"
ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int")
cast_args.append(ext)
elif val.type.width == 1:
zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int")
format_str += "%d"
cast_args.append(zext)
else:
is_u: bool = Gen._check_node_unsigned(part.value)
format_str += "%u" if is_u else "%d"
cast_args.append(val)
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
format_str += "%f"
cast_args.append(val)
else:
format_str += "%d"
cast_args.append(val)
if not format_str:
return Gen.emit_constant("", 'string')
format_ptr: Any = Gen._create_string_global(format_str)
# 统一使用 snprintf 生成字符串,返回 i8*
# __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放)
in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__'))
snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [
ir.PointerType(ir.IntType(8)),
ir.IntType(64),
ir.PointerType(ir.IntType(8))
], var_arg=True)
snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type)
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
# 第一遍:获取所需长度(NULL 缓冲,size=0)
len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len")
# 加 1 用于 null 终止符
size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size")
size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext")
if in_str_method:
# 堆分配(__str__ 返回值需跨函数生命周期)
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type)
buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf")
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
Gen._RegisterTempPtr(buf_ptr)
return buf_ptr
# 栈分配(局部使用,自动释放)
buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val)
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
return buf_ptr
def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None:
"""将 Python f-string format_spec 转换为 C printf 格式说明符。
支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。
返回 None 表示无法解析,调用方应回退到类型推断。
"""
if isinstance(format_spec_node, ast.JoinedStr):
parts: list[str] = []
for v in format_spec_node.values:
if isinstance(v, ast.Constant) and isinstance(v.value, str):
parts.append(v.value)
else:
return None
spec_str: str = ''.join(parts)
elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str):
spec_str = format_spec_node.value
else:
return None
if not spec_str:
return None
m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str)
if not m:
return None
fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups()
c_flags: str = ''
if sign == '+':
c_flags += '+'
elif sign == ' ':
c_flags += ' '
if alt:
c_flags += '#'
if fill_align:
align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0]
if align_char in ('<', '^'):
c_flags += '-'
if zero:
c_flags += '0'
c_width: str = width or ''
c_precision: str = precision or ''
length_mod: str = ''
if isinstance(val.type, ir.IntType):
if val.type.width == 64:
length_mod = 'll'
elif val.type.width == 32:
length_mod = 'l'
elif val.type.width == 16:
length_mod = 'h'
elif val.type.width == 8:
length_mod = 'hh'
c_specifier: str = ''
if fmt_type in ('d', 'n'):
c_specifier = f'{length_mod}d'
elif fmt_type == 'x':
c_specifier = f'{length_mod}x'
elif fmt_type == 'X':
c_specifier = f'{length_mod}X'
elif fmt_type == 'o':
c_specifier = f'{length_mod}o'
elif fmt_type == 'b':
return None
elif fmt_type == 'c':
c_specifier = 'c'
elif fmt_type in ('f', 'F'):
c_specifier = 'f'
elif fmt_type in ('e', 'E', 'g', 'G'):
c_specifier = fmt_type
elif fmt_type == 's':
c_specifier = 's'
elif fmt_type == '%':
c_specifier = 'f%%'
else:
if isinstance(val.type, ir.IntType):
if val.type.width == 8:
c_specifier = 'c'
elif val.type.width == 1:
c_specifier = 'd'
else:
c_specifier = f'{length_mod}d'
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
c_specifier = 'f'
elif isinstance(val.type, ir.PointerType):
c_specifier = 's'
else:
c_specifier = 'd'
return f'%{c_flags}{c_width}{c_precision}{c_specifier}'
def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value:
"""根据 C printf 格式说明符转换值类型。"""
fmt_type_char: str = ''
for ch in reversed(c_fmt):
if ch.isalpha() and ch not in ('l', 'h'):
fmt_type_char = ch
break
elif ch == '%':
break
if fmt_type_char == 's':
if isinstance(val.type, ir.PointerType):
pointee: ir.Type = val.type.pointee
if isinstance(pointee, ir.IntType) and pointee.width == 8:
return val
if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr")
return val
elif fmt_type_char == 'c':
if isinstance(val.type, ir.IntType) and val.type.width < 32:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c")
return val
elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'):
if isinstance(val.type, ir.IntType):
if val.type.width == 8:
is_u: bool = Gen._check_node_unsigned(arg_node)
if is_u:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8")
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8")
elif val.type.width == 16:
is_u = Gen._check_node_unsigned(arg_node)
if is_u:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16")
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16")
elif val.type.width == 1:
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool")
return val
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i")
return val
elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'):
if isinstance(val.type, ir.FloatType):
return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext")
elif isinstance(val.type, ir.IntType):
return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f")
return val
return val
+248 -248
View File
@@ -1,249 +1,249 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class ExprLambdaHandle(BaseHandle):
def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not getattr(Gen, '_lambda_counter', None):
Gen._lambda_counter = 0
lambda_id: int = Gen._lambda_counter
Gen._lambda_counter += 1
fn_name: str = f"lambda_fn_{lambda_id}"
captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node)
env_types: list[ir.Type] = []
env_var_names: list[str] = []
for var_name, var_val in captured_vars:
env_types.append(var_val.type)
env_var_names.append(var_name)
env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([])
ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body)
param_types: list[ir.Type] = [ir.PointerType(env_struct_type)]
if Node.args:
for arg in Node.args.args:
param_types.append(ir.IntType(32))
fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name)
Gen.functions[fn_name] = fn
entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry")
prev_builder: Any = Gen.builder
prev_func: Any = Gen.func
prev_vars: dict[str, Any] = dict(Gen.variables)
Gen.builder = ir.IRBuilder(entry_block)
Gen.func = fn
Gen.variables = {}
for i, arg in enumerate(fn.args):
arg.name = f"arg_{i}" if i > 0 else "env"
if env_types:
for idx, var_name in enumerate(env_var_names):
env_ptr: Any = fn.args[0]
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}")
Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}")
temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}")
Gen._store(Loaded, temp_alloca)
Gen.variables[var_name] = temp_alloca
if Node.args:
for i, arg in enumerate(Node.args.args):
Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg)
Gen._store(fn.args[i + 1], Gen.variables[arg.arg])
body_val: Any = self.HandleExprLlvm(Node.body)
if body_val:
if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType):
body_val = Gen._load(body_val, name="Load_lambda_ret")
if body_val.type != ret_type:
if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType):
if body_val.type.width < ret_type.width:
body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret")
elif body_val.type.width > ret_type.width:
body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret")
elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType):
body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret")
Gen.builder.ret(body_val)
else:
if isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
else:
Gen.builder.ret(ir.Constant(ret_type, 0))
Gen.builder = prev_builder
Gen.func = prev_func
Gen.variables = prev_vars
closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([
ir.PointerType(ir.IntType(8)),
ir.PointerType(fn_type)
])
closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}")
env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}")
if env_types:
for idx, (var_name, var_val) in enumerate(captured_vars):
zero = ir.Constant(ir.IntType(32), 0)
member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}")
Gen._store(var_val, member_ptr)
zero = ir.Constant(ir.IntType(32), 0)
env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr")
env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr")
Gen._store(env_i8_ptr, env_field_ptr)
fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr")
Gen._store(fn, fn_field_ptr)
return closure_ptr
def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
captured: list[tuple[str, Any]] = []
free_vars: list[str] = self._get_lambda_free_vars(Node)
for var_name in free_vars:
if var_name in Gen.variables:
var_ptr: Any = Gen.variables[var_name]
if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable):
Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}")
captured.append((var_name, Loaded))
return captured
def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]:
bound_vars: set[str] = set()
free_vars: set[str] = set()
# 收集 lambda body 中的 bound 和 free 变量
self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars)
# lambda 参数也是 bound 的
if Node.args:
for arg in Node.args.args:
bound_vars.add(arg.arg)
# free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量
result: list[str] = list(free_vars - bound_vars)
return result
def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
TestVal: Any = self.HandleExprLlvm(Node.test)
if not TestVal:
return None
if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1:
TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond")
ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then")
ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else")
MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end")
Gen.builder.cbranch(TestVal, ThenBB, ElseBB)
# 先在 ThenBB 中生成 BodyVal
Gen.builder.position_at_start(ThenBB)
BodyVal: Any = self.HandleExprLlvm(Node.body)
if not BodyVal:
BodyVal = ir.Constant(ir.IntType(32), 0)
ThenEndBB: ir.Block = Gen.builder.block
# 在 ElseBB 中生成 OrelseVal
Gen.builder.position_at_start(ElseBB)
OrelseVal: Any = self.HandleExprLlvm(Node.orelse)
if not OrelseVal:
OrelseVal = ir.Constant(ir.IntType(32), 0)
ElseEndBB: ir.Block = Gen.builder.block
# 确定 phi 节点的目标类型
result_type: ir.Type = BodyVal.type
if BodyVal.type != OrelseVal.type:
if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType):
result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType):
# 指针类型,使用 BodyVal 的类型
result_type = BodyVal.type
elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType):
# BodyVal 是整数,OrelseVal 是指针(字符串字面量)
# 如果指针指向 i8,将指针转换为 i8(加载字符)
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
result_type = ir.IntType(8)
else:
result_type = OrelseVal.type
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType):
# BodyVal 是指针(字符串字面量),OrelseVal 是整数
# 如果指针指向 i8,将指针转换为 i8(加载字符)
if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8:
result_type = ir.IntType(8)
else:
result_type = BodyVal.type
else:
result_type = OrelseVal.type
# 在 ThenBB 末尾添加类型转换(如果需要)和分支
if not ThenEndBB.is_terminated:
Gen.builder.position_at_end(ThenEndBB)
if BodyVal.type != result_type:
if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
if BodyVal.type.width < result_type.width:
BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext")
else:
BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc")
elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
# 如果 result_type 是 i8*,说明 Else 分支是字符串字面量
# 不应该将整数转换为指针,而应该保持整数类型
# 这里将 result_type 改为 i8
result_type = ir.IntType(8)
# 重新处理 Else 分支的类型转换
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
# 指针转整数
BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int")
Gen.builder.branch(MergeBB)
# 在 ElseBB 末尾添加类型转换(如果需要)和分支
if not ElseEndBB.is_terminated:
Gen.builder.position_at_end(ElseEndBB)
if OrelseVal.type != result_type:
if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
if OrelseVal.type.width < result_type.width:
OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext")
else:
OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc")
elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
# 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量
# 不应该将整数转换为指针,而应该保持整数类型
# 这里将 result_type 改为 i8
result_type = ir.IntType(8)
# 重新处理 BodyVal 分支的类型转换(已经在上面处理过了)
elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
# 如果指针指向 i8,加载字符值
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char")
else:
OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int")
Gen.builder.branch(MergeBB)
Gen.builder.position_at_start(MergeBB)
result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result")
result_phi.add_incoming(BodyVal, ThenEndBB)
result_phi.add_incoming(OrelseVal, ElseEndBB)
return result_phi
def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
ValueVal: Any = self.HandleExprLlvm(Node.value)
if not ValueVal:
return None
TargetName: str = Node.target.id
if TargetName in Gen._reg_values:
del Gen._reg_values[TargetName]
if TargetName in Gen.variables and Gen.variables[TargetName] is not None:
VarPtr: Any = Gen.variables[TargetName]
if VarPtr.type.pointee == ValueVal.type:
Gen._store(ValueVal, VarPtr)
else:
NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName)
Gen._store(ValueVal, NewVar)
Gen.variables[TargetName] = NewVar
else:
NewVar = Gen._alloca(ValueVal.type, name=TargetName)
Gen._store(ValueVal, NewVar)
Gen.variables[TargetName] = NewVar
Gen._reg_values[TargetName] = ValueVal
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
import vast as ast
import llvmlite.ir as ir
class ExprLambdaHandle(BaseHandle):
def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not getattr(Gen, '_lambda_counter', None):
Gen._lambda_counter = 0
lambda_id: int = Gen._lambda_counter
Gen._lambda_counter += 1
fn_name: str = f"lambda_fn_{lambda_id}"
captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node)
env_types: list[ir.Type] = []
env_var_names: list[str] = []
for var_name, var_val in captured_vars:
env_types.append(var_val.type)
env_var_names.append(var_name)
env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([])
ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body)
param_types: list[ir.Type] = [ir.PointerType(env_struct_type)]
if Node.args:
for arg in Node.args.args:
param_types.append(ir.IntType(32))
fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name)
Gen.functions[fn_name] = fn
entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry")
prev_builder: Any = Gen.builder
prev_func: Any = Gen.func
prev_vars: dict[str, Any] = dict(Gen.variables)
Gen.builder = ir.IRBuilder(entry_block)
Gen.func = fn
Gen.variables = {}
for i, arg in enumerate(fn.args):
arg.name = f"arg_{i}" if i > 0 else "env"
if env_types:
for idx, var_name in enumerate(env_var_names):
env_ptr: Any = fn.args[0]
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}")
Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}")
temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}")
Gen._store(Loaded, temp_alloca)
Gen.variables[var_name] = temp_alloca
if Node.args:
for i, arg in enumerate(Node.args.args):
Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg)
Gen._store(fn.args[i + 1], Gen.variables[arg.arg])
body_val: Any = self.HandleExprLlvm(Node.body)
if body_val:
if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType):
body_val = Gen._load(body_val, name="Load_lambda_ret")
if body_val.type != ret_type:
if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType):
if body_val.type.width < ret_type.width:
body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret")
elif body_val.type.width > ret_type.width:
body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret")
elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType):
body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret")
Gen.builder.ret(body_val)
else:
if isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
else:
Gen.builder.ret(ir.Constant(ret_type, 0))
Gen.builder = prev_builder
Gen.func = prev_func
Gen.variables = prev_vars
closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([
ir.PointerType(ir.IntType(8)),
ir.PointerType(fn_type)
])
closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}")
env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}")
if env_types:
for idx, (var_name, var_val) in enumerate(captured_vars):
zero = ir.Constant(ir.IntType(32), 0)
member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}")
Gen._store(var_val, member_ptr)
zero = ir.Constant(ir.IntType(32), 0)
env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr")
env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr")
Gen._store(env_i8_ptr, env_field_ptr)
fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr")
Gen._store(fn, fn_field_ptr)
return closure_ptr
def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
captured: list[tuple[str, Any]] = []
free_vars: list[str] = self._get_lambda_free_vars(Node)
for var_name in free_vars:
if var_name in Gen.variables:
var_ptr: Any = Gen.variables[var_name]
if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable):
Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}")
captured.append((var_name, Loaded))
return captured
def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]:
bound_vars: set[str] = set()
free_vars: set[str] = set()
# 收集 lambda body 中的 bound 和 free 变量
self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars)
# lambda 参数也是 bound 的
if Node.args:
for arg in Node.args.args:
bound_vars.add(arg.arg)
# free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量
result: list[str] = list(free_vars - bound_vars)
return result
def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
TestVal: Any = self.HandleExprLlvm(Node.test)
if not TestVal:
return None
if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1:
TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond")
ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then")
ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else")
MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end")
Gen.builder.cbranch(TestVal, ThenBB, ElseBB)
# 先在 ThenBB 中生成 BodyVal
Gen.builder.position_at_start(ThenBB)
BodyVal: Any = self.HandleExprLlvm(Node.body)
if not BodyVal:
BodyVal = ir.Constant(ir.IntType(32), 0)
ThenEndBB: ir.Block = Gen.builder.block
# 在 ElseBB 中生成 OrelseVal
Gen.builder.position_at_start(ElseBB)
OrelseVal: Any = self.HandleExprLlvm(Node.orelse)
if not OrelseVal:
OrelseVal = ir.Constant(ir.IntType(32), 0)
ElseEndBB: ir.Block = Gen.builder.block
# 确定 phi 节点的目标类型
result_type: ir.Type = BodyVal.type
if BodyVal.type != OrelseVal.type:
if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType):
result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType):
# 指针类型,使用 BodyVal 的类型
result_type = BodyVal.type
elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType):
# BodyVal 是整数,OrelseVal 是指针(字符串字面量)
# 如果指针指向 i8,将指针转换为 i8(加载字符)
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
result_type = ir.IntType(8)
else:
result_type = OrelseVal.type
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType):
# BodyVal 是指针(字符串字面量),OrelseVal 是整数
# 如果指针指向 i8,将指针转换为 i8(加载字符)
if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8:
result_type = ir.IntType(8)
else:
result_type = BodyVal.type
else:
result_type = OrelseVal.type
# 在 ThenBB 末尾添加类型转换(如果需要)和分支
if not ThenEndBB.is_terminated:
Gen.builder.position_at_end(ThenEndBB)
if BodyVal.type != result_type:
if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
if BodyVal.type.width < result_type.width:
BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext")
else:
BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc")
elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
# 如果 result_type 是 i8*,说明 Else 分支是字符串字面量
# 不应该将整数转换为指针,而应该保持整数类型
# 这里将 result_type 改为 i8
result_type = ir.IntType(8)
# 重新处理 Else 分支的类型转换
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
# 指针转整数
BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int")
Gen.builder.branch(MergeBB)
# 在 ElseBB 末尾添加类型转换(如果需要)和分支
if not ElseEndBB.is_terminated:
Gen.builder.position_at_end(ElseEndBB)
if OrelseVal.type != result_type:
if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
if OrelseVal.type.width < result_type.width:
OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext")
else:
OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc")
elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
# 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量
# 不应该将整数转换为指针,而应该保持整数类型
# 这里将 result_type 改为 i8
result_type = ir.IntType(8)
# 重新处理 BodyVal 分支的类型转换(已经在上面处理过了)
elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
# 如果指针指向 i8,加载字符值
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char")
else:
OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int")
Gen.builder.branch(MergeBB)
Gen.builder.position_at_start(MergeBB)
result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result")
result_phi.add_incoming(BodyVal, ThenEndBB)
result_phi.add_incoming(OrelseVal, ElseEndBB)
return result_phi
def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
ValueVal: Any = self.HandleExprLlvm(Node.value)
if not ValueVal:
return None
TargetName: str = Node.target.id
if TargetName in Gen._reg_values:
del Gen._reg_values[TargetName]
if TargetName in Gen.variables and Gen.variables[TargetName] is not None:
VarPtr: Any = Gen.variables[TargetName]
if VarPtr.type.pointee == ValueVal.type:
Gen._store(ValueVal, VarPtr)
else:
NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName)
Gen._store(ValueVal, NewVar)
Gen.variables[TargetName] = NewVar
else:
NewVar = Gen._alloca(ValueVal.type, name=TargetName)
Gen._store(ValueVal, NewVar)
Gen.variables[TargetName] = NewVar
Gen._reg_values[TargetName] = ValueVal
return ValueVal
+486 -486
View File
@@ -1,487 +1,487 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class ExprOpsHandle(BaseHandle):
def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
Gen._set_node_info(Node, "BinOp")
LeftVal: Any = self.HandleExprLlvm(Node.left, VarType)
if not LeftVal:
return None
RightVal: Any = self.HandleExprLlvm(Node.right, VarType)
if not RightVal:
return None
Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if not Op:
return None
OP_OVERLOAD_MAP: dict[str, list[str]] = {
'+': ['__add__'], '-': ['__sub__'], '*': ['__mul__'],
'/': ['__truediv__', '__div__'], '//': ['__floordiv__'], '%': ['__mod__'],
'**': ['__pow__'],
'&': ['__and__'], '|': ['__or__'], '^': ['__xor__'],
'<<': ['__lshift__'], '>>': ['__rshift__'],
}
if Op in OP_OVERLOAD_MAP:
LeftClassName: str | None = None
if isinstance(LeftVal.type, ir.PointerType):
pointee: ir.Type = LeftVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
LeftClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
if LeftClassName and LeftClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName is None and isinstance(Node.left, ast.Name):
LeftClassName = Gen.var_struct_class.get(Node.left.id)
if LeftClassName and LeftClassName in Gen.structs:
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName:
op_names: list[str] = OP_OVERLOAD_MAP[Op]
for op_name in op_names:
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
if result is not None:
return result
if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1:
CharVal: Any = Gen._load(LeftVal, name="Load_char_const")
CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
return TruncResult
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType):
LeftVal = Gen._load(LeftVal, name="deref_ptr_binop")
if LeftVal.type.width < RightVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left")
elif LeftVal.type.width > RightVal.type.width:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType):
RightVal = Gen._load(RightVal, name="deref_ptr_binop_r")
if RightVal.type.width < LeftVal.type.width:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
elif RightVal.type.width > LeftVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
vname: str = Node.left.id
if vname in Gen.var_signedness and Gen.var_signedness[vname]:
is_unsigned = True
result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned)
return result
def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
def _to_bool(val: Any, name: str) -> Any:
if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name)
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name)
return val
values: list[ast.expr] = Node.values
if len(values) < 2:
return self.HandleExprLlvm(values[0]) if values else None
if isinstance(Node.op, ast.And):
phi_incomings: list[tuple[ir.Constant, ir.Block]] = []
end_bb: ir.Block = Gen.func.append_basic_block(name="and.end")
for idx in range(len(values) - 1):
val: Any = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block: ir.Block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"andcond{idx}")
cur_bb: ir.Block = Gen.builder.block
next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}")
Gen.builder.cbranch(val, next_bb, end_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val: Any = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 0)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "andcond_last")
last_bb: ir.Block = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
elif isinstance(Node.op, ast.Or):
phi_incomings = []
end_bb = Gen.func.append_basic_block(name="or.end")
for idx in range(len(values) - 1):
val = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"orcond{idx}")
cur_bb = Gen.builder.block
next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
Gen.builder.cbranch(val, end_bb, next_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 1)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "orcond_last")
last_bb = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
return None
def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
OperandVal: Any = self.HandleExprLlvm(Node.operand)
if not OperandVal:
return None
OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
if not OpSymbol:
return None
UNARY_OVERLOAD_MAP: dict[str, str] = {
'-': '__neg__',
'+': '__pos__',
'~': '__invert__',
}
if OpSymbol in UNARY_OVERLOAD_MAP:
ClassName: str | None = None
if isinstance(OperandVal.type, ir.PointerType):
pointee: ir.Type = OperandVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
ClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
if ClassName and ClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName is None and isinstance(Node.operand, ast.Name):
ClassName = Gen.var_struct_class.get(Node.operand.id)
if ClassName and ClassName in Gen.structs:
if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName:
op_name: str = UNARY_OVERLOAD_MAP[OpSymbol]
result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
if result is not None:
return result
if OpSymbol == 'not':
if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
return Gen.builder.not_(OperandVal, name="not_result")
if isinstance(OperandVal.type, ir.PointerType):
null_val: ir.Constant = ir.Constant(OperandVal.type, None)
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
zero: ir.Constant = ir.Constant(OperandVal.type, 0)
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
elif OpSymbol == '~':
if isinstance(OperandVal.type, ir.IntType):
mask: int = (1 << OperandVal.type.width) - 1
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
elif OpSymbol == '+':
return OperandVal
elif OpSymbol == '-':
if isinstance(OperandVal.type, ir.IntType):
return Gen.builder.neg(OperandVal, name="neg_result")
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fneg(OperandVal, name="fneg_result")
return None
def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
LeftVal: Any = self.HandleExprLlvm(Node.left)
if not LeftVal:
return None
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
if len(Node.ops) == 1:
Op: ast.cmpop = Node.ops[0]
# in/not in: 调用 __contains__
if isinstance(Op, (ast.In, ast.NotIn)):
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
if RightVal:
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen)
if ClassName and Gen._has_function(f'{ClassName}.__contains__'):
# 处理 RightVal 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8:
RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__')
result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__")
# 归一化为 i1
if isinstance(result.type, ir.IntType) and result.type.width > 1:
zero: ir.Constant = ir.Constant(result.type, 0)
result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool")
if isinstance(Op, ast.NotIn):
result = Gen.builder.not_(result, name="not_in_result")
return result
return ir.Constant(ir.IntType(1), 0)
ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
return None
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
if not RightVal:
return None
# 比较运算符重载检测:当左侧是结构体指针时,尝试调用 __eq__/__ne__/__lt__/__le__/__gt__/__ge__
CMP_OVERLOAD_MAP: dict[str, str] = {
'==': '__eq__', '!=': '__ne__', '<': '__lt__',
'<=': '__le__', '>': '__gt__', '>=': '__ge__',
}
if ComparatorSymbol in CMP_OVERLOAD_MAP:
LeftClassName: str | None = None
if isinstance(LeftVal.type, ir.PointerType):
pointee: ir.Type = LeftVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
LeftClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
if LeftClassName and LeftClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName is None and isinstance(Node.left, ast.Name):
LeftClassName = Gen.var_struct_class.get(Node.left.id)
if LeftClassName and LeftClassName in Gen.structs:
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName:
op_name: str = CMP_OVERLOAD_MAP[ComparatorSymbol]
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
if result is not None:
return result
if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
lv: int = LeftVal.constant
rv: int = RightVal.constant
lw: int = LeftVal.type.width
rw: int = RightVal.type.width
if lw < rw:
lv = lv if lv >= 0 else lv + (1 << lw)
elif rw < lw:
rv = rv if rv >= 0 else rv + (1 << rw)
if is_unsigned:
mask_l: int = (1 << max(lw, rw)) - 1
lv = lv & mask_l
rv = rv & mask_l
cmp_map: dict[str, bool] = {
'==': lv == rv, '!=': lv != rv,
'<': lv < rv, '>': lv > rv,
'<=': lv <= rv, '>=': lv >= rv,
}
result: bool = cmp_map.get(ComparatorSymbol, False)
return ir.Constant(ir.IntType(1), 1 if result else 0)
# is / is not: 值类型(IntType)与 None(空指针常量)比较
# 值类型(如 i8/i32)永远不可能为 None,因此:
# - 值类型 is None → 恒为 false (i1 0)
# - 值类型 is not None → 恒为 true (i1 1)
# 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load(空指针解引用)导致崩溃
if ComparatorSymbol in ('is', 'is not'):
LeftIsNullPtr: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None and isinstance(LeftVal.type, ir.PointerType)
RightIsNullPtr: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None and isinstance(RightVal.type, ir.PointerType)
LeftIsValueType: bool = isinstance(LeftVal.type, ir.IntType)
RightIsValueType: bool = isinstance(RightVal.type, ir.IntType)
if (LeftIsValueType and RightIsNullPtr) or (RightIsValueType and LeftIsNullPtr):
IsNotResult: int = 1 if ComparatorSymbol == 'is not' else 0
return ir.Constant(ir.IntType(1), IsNotResult)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
# 如果宽类型常量值超出窄类型有符号范围,则必须用zext
# i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节)
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
else:
if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
RightVal = ir.Constant(LeftVal.type, None)
else:
# 指针 vs 非零整数: 将指针转为整数走正常 ==(地址值比较)
LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
else:
if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
LeftVal = ir.Constant(RightVal.type, None)
else:
# 非零整数 vs 指针: 将指针转为整数走正常 ==(地址值比较)
RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp")
# is / is not: 地址比较(指针)或值比较(int)
if ComparatorSymbol in ('is', 'is not'):
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp")
if ComparatorSymbol == 'is not':
addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result")
return addr_cmp
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp")
if ComparatorSymbol == 'is not':
val_cmp = Gen.builder.not_(val_cmp, name="is_not_result")
return val_cmp
# == / !=: 指针间做地址比较(C-Like 语义,不隐式调用 strcmp)
# 如需字符串内容比较,应显式调用 string.strcmp()
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif is_unsigned:
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
else:
result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
return result
EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end")
phi_incomings: list[tuple[ir.Value, ir.Block]] = []
for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
continue
RightVal = self.HandleExprLlvm(Comparator)
if not RightVal:
continue
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
if is_unsigned:
cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
else:
cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
if i < len(Node.ops) - 1:
NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}")
cur_bb: ir.Block = Gen.builder.block
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(NextBB)
LeftVal = RightVal
else:
cur_bb = Gen.builder.block
Gen.builder.branch(EndBB)
phi_incomings.append((cmp_result, cur_bb))
Gen.builder.position_at_start(EndBB)
final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp")
for val, bb in phi_incomings:
final_result.add_incoming(val, bb)
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
import vast as ast
import llvmlite.ir as ir
class ExprOpsHandle(BaseHandle):
def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
Gen._set_node_info(Node, "BinOp")
LeftVal: Any = self.HandleExprLlvm(Node.left, VarType)
if not LeftVal:
return None
RightVal: Any = self.HandleExprLlvm(Node.right, VarType)
if not RightVal:
return None
Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if not Op:
return None
OP_OVERLOAD_MAP: dict[str, list[str]] = {
'+': ['__add__'], '-': ['__sub__'], '*': ['__mul__'],
'/': ['__truediv__', '__div__'], '//': ['__floordiv__'], '%': ['__mod__'],
'**': ['__pow__'],
'&': ['__and__'], '|': ['__or__'], '^': ['__xor__'],
'<<': ['__lshift__'], '>>': ['__rshift__'],
}
if Op in OP_OVERLOAD_MAP:
LeftClassName: str | None = None
if isinstance(LeftVal.type, ir.PointerType):
pointee: ir.Type = LeftVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
LeftClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
if LeftClassName and LeftClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName is None and isinstance(Node.left, ast.Name):
LeftClassName = Gen.var_struct_class.get(Node.left.id)
if LeftClassName and LeftClassName in Gen.structs:
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName:
op_names: list[str] = OP_OVERLOAD_MAP[Op]
for op_name in op_names:
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
if result is not None:
return result
if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1:
CharVal: Any = Gen._load(LeftVal, name="Load_char_const")
CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
return TruncResult
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType):
LeftVal = Gen._load(LeftVal, name="deref_ptr_binop")
if LeftVal.type.width < RightVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left")
elif LeftVal.type.width > RightVal.type.width:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType):
RightVal = Gen._load(RightVal, name="deref_ptr_binop_r")
if RightVal.type.width < LeftVal.type.width:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
elif RightVal.type.width > LeftVal.type.width:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
vname: str = Node.left.id
if vname in Gen.var_signedness and Gen.var_signedness[vname]:
is_unsigned = True
result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned)
return result
def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
def _to_bool(val: Any, name: str) -> Any:
if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name)
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name)
return val
values: list[ast.expr] = Node.values
if len(values) < 2:
return self.HandleExprLlvm(values[0]) if values else None
if isinstance(Node.op, ast.And):
phi_incomings: list[tuple[ir.Constant, ir.Block]] = []
end_bb: ir.Block = Gen.func.append_basic_block(name="and.end")
for idx in range(len(values) - 1):
val: Any = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block: ir.Block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"andcond{idx}")
cur_bb: ir.Block = Gen.builder.block
next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}")
Gen.builder.cbranch(val, next_bb, end_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val: Any = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 0)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "andcond_last")
last_bb: ir.Block = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
elif isinstance(Node.op, ast.Or):
phi_incomings = []
end_bb = Gen.func.append_basic_block(name="or.end")
for idx in range(len(values) - 1):
val = self.HandleExprLlvm(values[idx])
if not val:
if not end_bb.is_terminated:
saved_block = Gen.builder.block
Gen.builder.position_at_start(end_bb)
Gen.builder.unreachable()
Gen.builder.position_at_end(saved_block)
return None
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
val = _to_bool(val, f"orcond{idx}")
cur_bb = Gen.builder.block
next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
Gen.builder.cbranch(val, end_bb, next_bb)
phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
Gen.builder.position_at_start(next_bb)
last_val = self.HandleExprLlvm(values[-1])
if not last_val:
last_val = ir.Constant(ir.IntType(1), 1)
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
last_val = _to_bool(last_val, "orcond_last")
last_bb = Gen.builder.block
Gen.builder.branch(end_bb)
Gen.builder.position_at_start(end_bb)
result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
for const_val, bb in phi_incomings:
result_phi.add_incoming(const_val, bb)
result_phi.add_incoming(last_val, last_bb)
return result_phi
return None
def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
OperandVal: Any = self.HandleExprLlvm(Node.operand)
if not OperandVal:
return None
OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
if not OpSymbol:
return None
UNARY_OVERLOAD_MAP: dict[str, str] = {
'-': '__neg__',
'+': '__pos__',
'~': '__invert__',
}
if OpSymbol in UNARY_OVERLOAD_MAP:
ClassName: str | None = None
if isinstance(OperandVal.type, ir.PointerType):
pointee: ir.Type = OperandVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
ClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
if ClassName and ClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName is None and isinstance(Node.operand, ast.Name):
ClassName = Gen.var_struct_class.get(Node.operand.id)
if ClassName and ClassName in Gen.structs:
if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
if ClassName:
op_name: str = UNARY_OVERLOAD_MAP[OpSymbol]
result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
if result is not None:
return result
if OpSymbol == 'not':
if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
return Gen.builder.not_(OperandVal, name="not_result")
if isinstance(OperandVal.type, ir.PointerType):
null_val: ir.Constant = ir.Constant(OperandVal.type, None)
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
zero: ir.Constant = ir.Constant(OperandVal.type, 0)
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
elif OpSymbol == '~':
if isinstance(OperandVal.type, ir.IntType):
mask: int = (1 << OperandVal.type.width) - 1
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
elif OpSymbol == '+':
return OperandVal
elif OpSymbol == '-':
if isinstance(OperandVal.type, ir.IntType):
return Gen.builder.neg(OperandVal, name="neg_result")
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
return Gen.builder.fneg(OperandVal, name="fneg_result")
return None
def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
LeftVal: Any = self.HandleExprLlvm(Node.left)
if not LeftVal:
return None
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
if len(Node.ops) == 1:
Op: ast.cmpop = Node.ops[0]
# in/not in: 调用 __contains__
if isinstance(Op, (ast.In, ast.NotIn)):
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
if RightVal:
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen)
if ClassName and Gen._has_function(f'{ClassName}.__contains__'):
# 处理 RightVal 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8:
RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__')
result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__")
# 归一化为 i1
if isinstance(result.type, ir.IntType) and result.type.width > 1:
zero: ir.Constant = ir.Constant(result.type, 0)
result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool")
if isinstance(Op, ast.NotIn):
result = Gen.builder.not_(result, name="not_in_result")
return result
return ir.Constant(ir.IntType(1), 0)
ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
return None
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
if not RightVal:
return None
# 比较运算符重载检测:当左侧是结构体指针时,尝试调用 __eq__/__ne__/__lt__/__le__/__gt__/__ge__
CMP_OVERLOAD_MAP: dict[str, str] = {
'==': '__eq__', '!=': '__ne__', '<': '__lt__',
'<=': '__le__', '>': '__gt__', '>=': '__ge__',
}
if ComparatorSymbol in CMP_OVERLOAD_MAP:
LeftClassName: str | None = None
if isinstance(LeftVal.type, ir.PointerType):
pointee: ir.Type = LeftVal.type.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
for CN, ST in Gen.structs.items():
if pointee == ST:
LeftClassName = CN
break
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
if LeftClassName and LeftClassName in Gen.structs:
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName is None and isinstance(Node.left, ast.Name):
LeftClassName = Gen.var_struct_class.get(Node.left.id)
if LeftClassName and LeftClassName in Gen.structs:
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
if LeftClassName:
op_name: str = CMP_OVERLOAD_MAP[ComparatorSymbol]
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
if result is not None:
return result
if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
lv: int = LeftVal.constant
rv: int = RightVal.constant
lw: int = LeftVal.type.width
rw: int = RightVal.type.width
if lw < rw:
lv = lv if lv >= 0 else lv + (1 << lw)
elif rw < lw:
rv = rv if rv >= 0 else rv + (1 << rw)
if is_unsigned:
mask_l: int = (1 << max(lw, rw)) - 1
lv = lv & mask_l
rv = rv & mask_l
cmp_map: dict[str, bool] = {
'==': lv == rv, '!=': lv != rv,
'<': lv < rv, '>': lv > rv,
'<=': lv <= rv, '>=': lv >= rv,
}
result: bool = cmp_map.get(ComparatorSymbol, False)
return ir.Constant(ir.IntType(1), 1 if result else 0)
# is / is not: 值类型(IntType)与 None(空指针常量)比较
# 值类型(如 i8/i32)永远不可能为 None,因此:
# - 值类型 is None → 恒为 false (i1 0)
# - 值类型 is not None → 恒为 true (i1 1)
# 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load(空指针解引用)导致崩溃
if ComparatorSymbol in ('is', 'is not'):
LeftIsNullPtr: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None and isinstance(LeftVal.type, ir.PointerType)
RightIsNullPtr: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None and isinstance(RightVal.type, ir.PointerType)
LeftIsValueType: bool = isinstance(LeftVal.type, ir.IntType)
RightIsValueType: bool = isinstance(RightVal.type, ir.IntType)
if (LeftIsValueType and RightIsNullPtr) or (RightIsValueType and LeftIsNullPtr):
IsNotResult: int = 1 if ComparatorSymbol == 'is not' else 0
return ir.Constant(ir.IntType(1), IsNotResult)
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
# 如果宽类型常量值超出窄类型有符号范围,则必须用zext
# i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节)
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
else:
if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
RightVal = ir.Constant(LeftVal.type, None)
else:
# 指针 vs 非零整数: 将指针转为整数走正常 ==(地址值比较)
LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp")
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
else:
if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
LeftVal = ir.Constant(RightVal.type, None)
else:
# 非零整数 vs 指针: 将指针转为整数走正常 ==(地址值比较)
RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp")
# is / is not: 地址比较(指针)或值比较(int)
if ComparatorSymbol in ('is', 'is not'):
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp")
if ComparatorSymbol == 'is not':
addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result")
return addr_cmp
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp")
if ComparatorSymbol == 'is not':
val_cmp = Gen.builder.not_(val_cmp, name="is_not_result")
return val_cmp
# == / !=: 指针间做地址比较(C-Like 语义,不隐式调用 strcmp)
# 如需字符串内容比较,应显式调用 string.strcmp()
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
elif is_unsigned:
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
else:
result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
return result
EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end")
phi_incomings: list[tuple[ir.Value, ir.Block]] = []
for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
if not ComparatorSymbol:
continue
RightVal = self.HandleExprLlvm(Comparator)
if not RightVal:
continue
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
if LeftVal.type.width < RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
if not need_zext and isinstance(RightVal, ir.Constant):
signed_max = (1 << (LeftVal.type.width - 1)) - 1
try:
if RightVal.constant > signed_max or RightVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
else:
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
elif LeftVal.type.width > RightVal.type.width:
need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1
if not need_zext and isinstance(LeftVal, ir.Constant):
signed_max = (1 << (RightVal.type.width - 1)) - 1
try:
if LeftVal.constant > signed_max or LeftVal.constant < 0:
need_zext = True
except (TypeError, ValueError):
pass
if need_zext:
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
else:
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
if is_unsigned:
cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
else:
cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
if i < len(Node.ops) - 1:
NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}")
cur_bb: ir.Block = Gen.builder.block
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
Gen.builder.position_at_start(NextBB)
LeftVal = RightVal
else:
cur_bb = Gen.builder.block
Gen.builder.branch(EndBB)
phi_incomings.append((cmp_result, cur_bb))
Gen.builder.position_at_start(EndBB)
final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp")
for val, bb in phi_incomings:
final_result.add_incoming(val, bb)
return final_result
+304 -304
View File
@@ -1,305 +1,305 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import ast
import llvmlite.ir as ir
from lib.core.SymbolUtils import IsTModule
class ExprUtils:
def __init__(self, translator: "Translator") -> None:
self.Trans: Translator = translator
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
OpMap: dict[type, str] = {
ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/',
ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&',
ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>',
ast.MatMult: '@',
}
return OpMap.get(type(Op), None)
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'}
return OpMap.get(type(Op), None)
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
OpMap: dict[type, str] = {
ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=',
ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not',
ast.In: 'in', ast.NotIn: 'not in',
}
return OpMap.get(type(Op), None)
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
if isinstance(node, ast.Name):
VarName: str = node.id
return Gen.var_struct_class.get(VarName)
if isinstance(node, ast.Attribute):
AttrName: str = node.attr
# 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable)
# 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派
# (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST')
BaseClass: str | None = self._get_var_class(node.value, Gen)
if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self':
BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
if BaseClass and BaseClass in Gen.class_members:
for m_name, m_type in Gen.class_members[BaseClass]:
if m_name == AttrName:
if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found = Gen.find_struct_by_pointee(m_type.pointee)
if found:
return found[0]
# 联合类型(如 GSList[Param] | t.CPtr)降级为 i8* 时,
# 从 class_member_element_class 查找泛型特化类名
element_class_map = getattr(Gen, 'class_member_element_class', {})
element_class = element_class_map.get(BaseClass, {}).get(AttrName)
if element_class:
return element_class
break
# Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后,
# 避免字段名和变量名冲突导致错误分派)
cls: str | None = Gen.var_struct_class.get(AttrName)
if cls:
return cls
return None
return None
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
FullMethodName: str = f'{ClassName}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{ClassName}.{op_name}__'
if not Gen._has_function(FullMethodName):
# 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 TPV 一致)
for anc in Gen._get_mro_chain(ClassName)[1:]:
anc_method: str = f'{anc}.{op_name}'
if Gen._has_function(anc_method):
FullMethodName = anc_method
break
anc_method_ss = f'{anc}.{op_name}__'
if Gen._has_function(anc_method_ss):
FullMethodName = anc_method_ss
break
if not Gen._has_function(FullMethodName):
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且
# 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
# (如 'ndarray[double]')。注解 'numpy.ndarray | t.CPtr' 未指定类型参数时,
# var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。
# 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。
if '[' not in ClassName:
SpecClass: str | None = None
for CN in Gen.structs.keys():
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'):
SpecClass = CN
break
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'):
SpecClass = CN
break
if SpecClass:
FullMethodName = f'{SpecClass}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{SpecClass}.{op_name}__'
if Gen._has_function(FullMethodName):
func: Any = Gen._get_function(FullMethodName)
# 多继承 this 调整:运算符重载方法定义在"无 vtable 父类"且字段区偏移 > 0 时,
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
method_anc: str | None = None
_fm_short: str = FullMethodName.split('.')[-1] if '.' in FullMethodName else FullMethodName
if '.' in FullMethodName:
_fm_cls: str = FullMethodName.split('.')[0]
if _fm_cls != ClassName:
method_anc = _fm_cls
_call_self: Any = self.Trans.ExprCallHandle._adjust_this_for_inherited_method(Gen, obj_val, ClassName, method_anc)
call_args: list[Any] = [_call_self]
if other_val is not None:
call_args.append(other_val)
if len(func.ftype.args) == len(call_args):
for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)):
if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType):
if expected_type != actual_val.type:
if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}")
result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
return result
return None
def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]:
info: dict[str, Any] = {
'name': "unknown",
'size': 0,
'signed': False,
'ptr': False
}
if isinstance(llvm_type, ir.IntType):
info['size'] = llvm_type.width // 8
info['signed'] = True
if llvm_type.width == 8:
info['name'] = "char"
elif llvm_type.width == 16:
info['name'] = "short"
elif llvm_type.width == 32:
info['name'] = "int"
elif llvm_type.width == 64:
info['name'] = "long long"
else:
info['name'] = f"int{llvm_type.width}"
elif isinstance(llvm_type, ir.DoubleType):
info['size'] = 8
info['signed'] = True
info['name'] = "double"
elif isinstance(llvm_type, ir.FloatType):
info['size'] = 4
info['signed'] = True
info['name'] = "float"
elif isinstance(llvm_type, ir.PointerType):
info['size'] = 8
info['signed'] = False
info['ptr'] = True
pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee)
info['name'] = f"{pointee_info['name']}*"
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
size: int = 0
for elem in llvm_type.elements:
elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem)
size += elem_info['size']
info['size'] = size
info['signed'] = False
if isinstance(llvm_type, ir.IdentifiedStructType):
info['name'] = llvm_type.name
else:
info['name'] = "struct"
elif isinstance(llvm_type, ir.ArrayType):
elem_info = self._llvm_type_to_detailed_string(llvm_type.element)
info['size'] = elem_info['size'] * llvm_type.count
info['signed'] = elem_info['signed']
info['name'] = f"{elem_info['name']}[]"
elif isinstance(llvm_type, ir.VoidType):
info['size'] = 0
info['signed'] = False
info['name'] = "void"
else:
info['size'] = 0
info['signed'] = False
info['name'] = str(llvm_type)
return info
def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return ir.IntType(32)
elif isinstance(node.value, int):
return ir.IntType(32)
elif isinstance(node.value, float):
return ir.DoubleType()
elif isinstance(node.value, str):
if getattr(node, 'kind', None) == 'u':
return ir.PointerType(ir.IntType(16))
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Name):
if node.id in Gen.variables:
var_ptr: Any = Gen.variables[node.id]
if isinstance(var_ptr.type, ir.PointerType):
return var_ptr.type.pointee
return var_ptr.type
if node.id in Gen._reg_values:
return Gen._reg_values[node.id].type
return ir.IntType(32)
elif isinstance(node, ast.Attribute):
attr_name: str = node.attr
AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name)
if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None):
return ir.IntType(32)
return ir.IntType(32)
elif isinstance(node, ast.BinOp):
left_type: ir.Type = self._infer_expr_llvm_type_full(node.left)
right_type: ir.Type = self._infer_expr_llvm_type_full(node.right)
if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)):
return ir.DoubleType()
if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.UnaryOp):
return self._infer_expr_llvm_type_full(node.operand)
elif isinstance(node, ast.Subscript):
val_type: ir.Type = self._infer_expr_llvm_type_full(node.value)
if isinstance(val_type, ir.PointerType):
if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8:
return ir.IntType(8)
if isinstance(val_type.pointee, ir.ArrayType):
return ir.PointerType(val_type.pointee.element)
return val_type.pointee
if isinstance(val_type, ir.ArrayType):
return val_type.element
if isinstance(val_type, ir.IntType):
return ir.IntType(8)
return ir.IntType(32)
elif isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
func_name: str = node.func.id
if Gen._has_function(func_name):
fn: Any = Gen._get_function(func_name)
return fn.function_type.return_type
if func_name == 'len':
return ir.IntType(32)
if func_name == 'sizeof':
return ir.IntType(32)
if func_name == 'ord':
return ir.IntType(32)
if func_name == 'chr':
return ir.IntType(8)
if func_name == 'int':
return ir.IntType(32)
if func_name == 'float' or func_name == 'double':
return ir.DoubleType()
elif isinstance(node.func, ast.Attribute):
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
if node.func.attr == 'Deref':
return ir.IntType(64)
if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable):
if node.func.attr == 'CChar':
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Compare):
return ir.IntType(1)
elif isinstance(node, ast.BoolOp):
return ir.IntType(1)
elif isinstance(node, ast.IfExp):
return self._infer_expr_llvm_type_full(node.body)
elif isinstance(node, ast.Attribute):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None:
"""收集 AST 节点中的绑定变量和自由变量
Args:
node: AST 节点
bound: 集合,收集绑定变量(ast.Store 上下文)
free: 集合,收集自由变量(ast.Load 上下文),可为 None
"""
if free is None:
free = set()
if isinstance(node, ast.Name):
if isinstance(node.ctx, ast.Store):
bound.add(node.id)
elif isinstance(node.ctx, ast.Load):
free.add(node.id)
elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)):
# 这些节点有自己的作用域,不递归进入
# 但需要收集参数名作为 bound
if hasattr(node, 'args') and node.args:
for arg in node.args.args:
bound.add(arg.arg)
elif getattr(node, '_fields', None):
for field in node._fields:
value: Any = getattr(node, field, None)
if isinstance(value, list):
for item in value:
if isinstance(item, (ast.stmt, ast.expr)):
self._collect_names(item, bound, free)
elif isinstance(value, (ast.stmt, ast.expr)):
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import vast as ast
import llvmlite.ir as ir
from lib.core.SymbolUtils import IsTModule
class ExprUtils:
def __init__(self, translator: "Translator") -> None:
self.Trans: Translator = translator
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
OpMap: dict[type, str] = {
ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/',
ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&',
ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>',
ast.MatMult: '@',
}
return OpMap.get(type(Op), None)
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'}
return OpMap.get(type(Op), None)
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
OpMap: dict[type, str] = {
ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=',
ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not',
ast.In: 'in', ast.NotIn: 'not in',
}
return OpMap.get(type(Op), None)
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
if isinstance(node, ast.Name):
VarName: str = node.id
return Gen.var_struct_class.get(VarName)
if isinstance(node, ast.Attribute):
AttrName: str = node.attr
# 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable)
# 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派
# (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST')
BaseClass: str | None = self._get_var_class(node.value, Gen)
if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self':
BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
if BaseClass and BaseClass in Gen.class_members:
for m_name, m_type in Gen.class_members[BaseClass]:
if m_name == AttrName:
if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found = Gen.find_struct_by_pointee(m_type.pointee)
if found:
return found[0]
# 联合类型(如 GSList[Param] | t.CPtr)降级为 i8* 时,
# 从 class_member_element_class 查找泛型特化类名
element_class_map = getattr(Gen, 'class_member_element_class', {})
element_class = element_class_map.get(BaseClass, {}).get(AttrName)
if element_class:
return element_class
break
# Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后,
# 避免字段名和变量名冲突导致错误分派)
cls: str | None = Gen.var_struct_class.get(AttrName)
if cls:
return cls
return None
return None
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
FullMethodName: str = f'{ClassName}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{ClassName}.{op_name}__'
if not Gen._has_function(FullMethodName):
# 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 TPV 一致)
for anc in Gen._get_mro_chain(ClassName)[1:]:
anc_method: str = f'{anc}.{op_name}'
if Gen._has_function(anc_method):
FullMethodName = anc_method
break
anc_method_ss = f'{anc}.{op_name}__'
if Gen._has_function(anc_method_ss):
FullMethodName = anc_method_ss
break
if not Gen._has_function(FullMethodName):
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且
# 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
# (如 'ndarray[double]')。注解 'numpy.ndarray | t.CPtr' 未指定类型参数时,
# var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。
# 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。
if '[' not in ClassName:
SpecClass: str | None = None
for CN in Gen.structs.keys():
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'):
SpecClass = CN
break
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'):
SpecClass = CN
break
if SpecClass:
FullMethodName = f'{SpecClass}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{SpecClass}.{op_name}__'
if Gen._has_function(FullMethodName):
func: Any = Gen._get_function(FullMethodName)
# 多继承 this 调整:运算符重载方法定义在"无 vtable 父类"且字段区偏移 > 0 时,
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
method_anc: str | None = None
_fm_short: str = FullMethodName.split('.')[-1] if '.' in FullMethodName else FullMethodName
if '.' in FullMethodName:
_fm_cls: str = FullMethodName.split('.')[0]
if _fm_cls != ClassName:
method_anc = _fm_cls
_call_self: Any = self.Trans.ExprCallHandle._adjust_this_for_inherited_method(Gen, obj_val, ClassName, method_anc)
call_args: list[Any] = [_call_self]
if other_val is not None:
call_args.append(other_val)
if len(func.ftype.args) == len(call_args):
for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)):
if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType):
if expected_type != actual_val.type:
if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}")
result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
return result
return None
def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]:
info: dict[str, Any] = {
'name': "unknown",
'size': 0,
'signed': False,
'ptr': False
}
if isinstance(llvm_type, ir.IntType):
info['size'] = llvm_type.width // 8
info['signed'] = True
if llvm_type.width == 8:
info['name'] = "char"
elif llvm_type.width == 16:
info['name'] = "short"
elif llvm_type.width == 32:
info['name'] = "int"
elif llvm_type.width == 64:
info['name'] = "long long"
else:
info['name'] = f"int{llvm_type.width}"
elif isinstance(llvm_type, ir.DoubleType):
info['size'] = 8
info['signed'] = True
info['name'] = "double"
elif isinstance(llvm_type, ir.FloatType):
info['size'] = 4
info['signed'] = True
info['name'] = "float"
elif isinstance(llvm_type, ir.PointerType):
info['size'] = 8
info['signed'] = False
info['ptr'] = True
pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee)
info['name'] = f"{pointee_info['name']}*"
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
size: int = 0
for elem in llvm_type.elements:
elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem)
size += elem_info['size']
info['size'] = size
info['signed'] = False
if isinstance(llvm_type, ir.IdentifiedStructType):
info['name'] = llvm_type.name
else:
info['name'] = "struct"
elif isinstance(llvm_type, ir.ArrayType):
elem_info = self._llvm_type_to_detailed_string(llvm_type.element)
info['size'] = elem_info['size'] * llvm_type.count
info['signed'] = elem_info['signed']
info['name'] = f"{elem_info['name']}[]"
elif isinstance(llvm_type, ir.VoidType):
info['size'] = 0
info['signed'] = False
info['name'] = "void"
else:
info['size'] = 0
info['signed'] = False
info['name'] = str(llvm_type)
return info
def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return ir.IntType(32)
elif isinstance(node.value, int):
return ir.IntType(32)
elif isinstance(node.value, float):
return ir.DoubleType()
elif isinstance(node.value, str):
if getattr(node, 'kind', None) == 'u':
return ir.PointerType(ir.IntType(16))
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Name):
if node.id in Gen.variables:
var_ptr: Any = Gen.variables[node.id]
if isinstance(var_ptr.type, ir.PointerType):
return var_ptr.type.pointee
return var_ptr.type
if node.id in Gen._reg_values:
return Gen._reg_values[node.id].type
return ir.IntType(32)
elif isinstance(node, ast.Attribute):
attr_name: str = node.attr
AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name)
if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None):
return ir.IntType(32)
return ir.IntType(32)
elif isinstance(node, ast.BinOp):
left_type: ir.Type = self._infer_expr_llvm_type_full(node.left)
right_type: ir.Type = self._infer_expr_llvm_type_full(node.right)
if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)):
return ir.DoubleType()
if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.UnaryOp):
return self._infer_expr_llvm_type_full(node.operand)
elif isinstance(node, ast.Subscript):
val_type: ir.Type = self._infer_expr_llvm_type_full(node.value)
if isinstance(val_type, ir.PointerType):
if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8:
return ir.IntType(8)
if isinstance(val_type.pointee, ir.ArrayType):
return ir.PointerType(val_type.pointee.element)
return val_type.pointee
if isinstance(val_type, ir.ArrayType):
return val_type.element
if isinstance(val_type, ir.IntType):
return ir.IntType(8)
return ir.IntType(32)
elif isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
func_name: str = node.func.id
if Gen._has_function(func_name):
fn: Any = Gen._get_function(func_name)
return fn.function_type.return_type
if func_name == 'len':
return ir.IntType(32)
if func_name == 'sizeof':
return ir.IntType(32)
if func_name == 'ord':
return ir.IntType(32)
if func_name == 'chr':
return ir.IntType(8)
if func_name == 'int':
return ir.IntType(32)
if func_name == 'float' or func_name == 'double':
return ir.DoubleType()
elif isinstance(node.func, ast.Attribute):
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
if node.func.attr == 'Deref':
return ir.IntType(64)
if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable):
if node.func.attr == 'CChar':
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Compare):
return ir.IntType(1)
elif isinstance(node, ast.BoolOp):
return ir.IntType(1)
elif isinstance(node, ast.IfExp):
return self._infer_expr_llvm_type_full(node.body)
elif isinstance(node, ast.Attribute):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None:
"""收集 AST 节点中的绑定变量和自由变量
Args:
node: AST 节点
bound: 集合,收集绑定变量(ast.Store 上下文)
free: 集合,收集自由变量(ast.Load 上下文),可为 None
"""
if free is None:
free = set()
if isinstance(node, ast.Name):
if isinstance(node.ctx, ast.Store):
bound.add(node.id)
elif isinstance(node.ctx, ast.Load):
free.add(node.id)
elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)):
# 这些节点有自己的作用域,不递归进入
# 但需要收集参数名作为 bound
if hasattr(node, 'args') and node.args:
for arg in node.args.args:
bound.add(arg.arg)
elif getattr(node, '_fields', None):
for field in node._fields:
value: Any = getattr(node, field, None)
if isinstance(value, list):
for item in value:
if isinstance(item, (ast.stmt, ast.expr)):
self._collect_names(item, bound, free)
elif isinstance(value, (ast.stmt, ast.expr)):
self._collect_names(value, bound, free)
File diff suppressed because it is too large. Load diff
+15 -15
View File
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import ast
import vast as ast
import copy
import traceback
import llvmlite.ir as ir
@@ -1757,8 +1757,8 @@ class FunctionHandle(BaseHandle):
Gen.builder.store(last_param_ptr, last_param_alloc)
Gen.emit_va_start(va_list_ptr)
Gen._variadic_info['va_start_called'] = True
# 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*),
# 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节)
# 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*),
# 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节)
Gen._direct_values[vararg_name] = va_list_ptr
# @t.TLS 一次性初始化检查:首次调用执行函数体,后续调用直接返回
if is_tls_func:
@@ -1790,18 +1790,18 @@ class FunctionHandle(BaseHandle):
Gen.builder.ret(ir.Constant(ActualReturnType, None))
Gen.builder.position_at_end(cont_bb)
Gen.builder.store(ir.Constant(ir.IntType(1), 1), flag_global)
_saved_class_name = getattr(Gen, '_current_class_name', None)
Gen._current_class_name = ClassName
# 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码
func_body: list[ast.stmt] = Node.body
doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name
if (func_body and isinstance(func_body[0], ast.Expr)
and isinstance(func_body[0].value, ast.Constant)
and isinstance(func_body[0].value.value, str)):
Gen._create_doc_global(doc_symbol, func_body[0].value.value)
func_body = func_body[1:]
else:
Gen._create_doc_global(doc_symbol, None)
_saved_class_name = getattr(Gen, '_current_class_name', None)
Gen._current_class_name = ClassName
# 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码
func_body: list[ast.stmt] = Node.body
doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name
if (func_body and isinstance(func_body[0], ast.Expr)
and isinstance(func_body[0].value, ast.Constant)
and isinstance(func_body[0].value.value, str)):
Gen._create_doc_global(doc_symbol, func_body[0].value.value)
func_body = func_body[1:]
else:
Gen._create_doc_global(doc_symbol, None)
try:
self.Trans.BodyHandler.HandleBodyLlvm(func_body)
except Exception as _body_exc:
+213 -213
View File
@@ -1,214 +1,214 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
import ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
class IfHandle(BaseHandle):
def _get_attr_full_name(self, node: ast.expr) -> str | None:
if isinstance(node, ast.Attribute):
parts: list[str] = []
cur: ast.expr = node
while isinstance(cur, ast.Attribute):
parts.append(cur.attr)
cur = cur.value
if isinstance(cur, ast.Name):
parts.append(cur.id)
parts.reverse()
return '.'.join(parts)
return None
def _is_cif_call(self, node: ast.expr) -> bool:
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
return node.func.attr in ('CIf', 'CIfdef', 'CIfndef')
if isinstance(node.func, ast.Name):
return node.func.id in ('CIf', 'CIfdef', 'CIfndef')
return False
def _resolve_macro_name(self, arg: ast.expr) -> str | None:
if isinstance(arg, ast.Name):
return arg.id
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
return arg.value
if isinstance(arg, ast.Attribute):
full_name: str | None = self._get_attr_full_name(arg)
if full_name:
return full_name
return None
def _evaluate_cif_condition(self, node: ast.Call) -> int | None:
if not isinstance(node, ast.Call):
return None
args: list[ast.expr] = node.args
if not args:
return 0
kind: str | None = None
if isinstance(node.func, ast.Attribute):
kind = node.func.attr
elif isinstance(node.func, ast.Name):
kind = node.func.id
else:
return None
if kind == 'CIfdef':
name: str | None = self._resolve_macro_name(args[0])
if name is None:
return 0
return 1 if self._is_macro_defined(name) else 0
elif kind == 'CIfndef':
name: str | None = self._resolve_macro_name(args[0])
if name is None:
return 1
return 0 if self._is_macro_defined(name) else 1
elif kind == 'CIf':
return self._eval_const_expr(args[0])
return None
def _is_macro_defined(self, name: str) -> bool:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
return True
if self.Trans.SymbolTable.is_define(name):
return True
platform_macros: dict[str, int] = self._get_platform_macros()
return name in platform_macros
def _get_macro_value(self, name: str) -> int | float | None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
val: int | float | None = Gen._define_constants[name]
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖
try:
if hasattr(Gen, 'module') and name in Gen.module.globals:
_gv: Any = Gen.module.globals[name]
if getattr(_gv, 'initializer', None) is not None:
_iv: Any = _gv.initializer
if hasattr(_iv, 'constant') and isinstance(_iv.constant, (int, float)):
val = _iv.constant
except Exception:
pass
if isinstance(val, (int, float)):
return val
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name)
if info:
if info.IsDefine:
val: int | float | None = info.DefineValue
if isinstance(val, (int, float)):
return val
platform_macros: dict[str, int] = self._get_platform_macros()
if name in platform_macros:
return platform_macros[name]
return None
def _get_platform_macros(self) -> dict[str, int]:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
macros: dict[str, int] = {}
pi: dict[str, object] = Gen._platform_info
ptr_size: int = getattr(Gen, 'ptr_size', 8)
# 根据目标平台设置宏(从三元组推导)
if pi.get('is_windows'):
macros['_WIN32'] = 1
if not pi.get('is_32bit'):
macros['_WIN64'] = 1
macros['WIN64'] = 1
macros['WIN32'] = 1
if pi.get('is_linux'):
macros['__linux__'] = 1
if pi.get('is_macos'):
macros['__APPLE__'] = 1
macros['__MACH__'] = 1
if pi.get('is_x86_64'):
macros['__x86_64__'] = 1
macros['__x86_64'] = 1
macros['_M_X64'] = 1
elif pi.get('is_arm64'):
macros['__aarch64__'] = 1
macros['_M_ARM64'] = 1
if not pi.get('is_32bit') and pi.get('is_linux'):
macros['__LP64__'] = 1
elif pi.get('is_32bit'):
macros['_ILP32'] = 1
macros['SIZEOF_VOID_P'] = ptr_size
macros['__SIZEOF_POINTER__'] = ptr_size
macros['NDEBUG'] = 0
return macros
def _eval_const_expr(self, node: ast.expr) -> int | None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx)
if result is None:
# 保留 CIf 嵌套调用处理(HandlesIf 特有逻辑)
if isinstance(node, ast.Call) and self._is_cif_call(node):
return self._evaluate_cif_condition(node)
return None
# HandlesIf 需要 bool/float → int 转换(#if 条件编译语义)
if isinstance(result, bool):
return 1 if result else 0
if isinstance(result, float):
return 1 if result != 0.0 else 0
return result
def _HandleIfLlvm(self, Node: ast.If) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if self._is_cif_call(Node.test):
compile_time_val: int | None = self._evaluate_cif_condition(Node.test)
if compile_time_val is not None:
if compile_time_val:
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
elif Node.orelse:
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
self._HandleIfLlvm(Node.orelse[0])
else:
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
return
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
if not Cond:
return
is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1
if is_const:
if Cond.constant:
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
elif Node.orelse:
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
self._HandleIfLlvm(Node.orelse[0])
else:
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
return
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
obj_val: ir.Value = Cond
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__")
if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result")
else:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond")
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond")
ThenBB: ir.Block = Gen.func.append_basic_block(name="then")
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None
MergeBB: ir.Block = Gen.func.append_basic_block(name="endif")
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
Gen.builder.position_at_start(ThenBB)
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if not MergeBB.is_terminated:
Gen.builder.position_at_start(MergeBB)
else:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
import vast as ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
class IfHandle(BaseHandle):
def _get_attr_full_name(self, node: ast.expr) -> str | None:
if isinstance(node, ast.Attribute):
parts: list[str] = []
cur: ast.expr = node
while isinstance(cur, ast.Attribute):
parts.append(cur.attr)
cur = cur.value
if isinstance(cur, ast.Name):
parts.append(cur.id)
parts.reverse()
return '.'.join(parts)
return None
def _is_cif_call(self, node: ast.expr) -> bool:
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
return node.func.attr in ('CIf', 'CIfdef', 'CIfndef')
if isinstance(node.func, ast.Name):
return node.func.id in ('CIf', 'CIfdef', 'CIfndef')
return False
def _resolve_macro_name(self, arg: ast.expr) -> str | None:
if isinstance(arg, ast.Name):
return arg.id
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
return arg.value
if isinstance(arg, ast.Attribute):
full_name: str | None = self._get_attr_full_name(arg)
if full_name:
return full_name
return None
def _evaluate_cif_condition(self, node: ast.Call) -> int | None:
if not isinstance(node, ast.Call):
return None
args: list[ast.expr] = node.args
if not args:
return 0
kind: str | None = None
if isinstance(node.func, ast.Attribute):
kind = node.func.attr
elif isinstance(node.func, ast.Name):
kind = node.func.id
else:
return None
if kind == 'CIfdef':
name: str | None = self._resolve_macro_name(args[0])
if name is None:
return 0
return 1 if self._is_macro_defined(name) else 0
elif kind == 'CIfndef':
name: str | None = self._resolve_macro_name(args[0])
if name is None:
return 1
return 0 if self._is_macro_defined(name) else 1
elif kind == 'CIf':
return self._eval_const_expr(args[0])
return None
def _is_macro_defined(self, name: str) -> bool:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
return True
if self.Trans.SymbolTable.is_define(name):
return True
platform_macros: dict[str, int] = self._get_platform_macros()
return name in platform_macros
def _get_macro_value(self, name: str) -> int | float | None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
val: int | float | None = Gen._define_constants[name]
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖
try:
if hasattr(Gen, 'module') and name in Gen.module.globals:
_gv: Any = Gen.module.globals[name]
if getattr(_gv, 'initializer', None) is not None:
_iv: Any = _gv.initializer
if hasattr(_iv, 'constant') and isinstance(_iv.constant, (int, float)):
val = _iv.constant
except Exception:
pass
if isinstance(val, (int, float)):
return val
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name)
if info:
if info.IsDefine:
val: int | float | None = info.DefineValue
if isinstance(val, (int, float)):
return val
platform_macros: dict[str, int] = self._get_platform_macros()
if name in platform_macros:
return platform_macros[name]
return None
def _get_platform_macros(self) -> dict[str, int]:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
macros: dict[str, int] = {}
pi: dict[str, object] = Gen._platform_info
ptr_size: int = getattr(Gen, 'ptr_size', 8)
# 根据目标平台设置宏(从三元组推导)
if pi.get('is_windows'):
macros['_WIN32'] = 1
if not pi.get('is_32bit'):
macros['_WIN64'] = 1
macros['WIN64'] = 1
macros['WIN32'] = 1
if pi.get('is_linux'):
macros['__linux__'] = 1
if pi.get('is_macos'):
macros['__APPLE__'] = 1
macros['__MACH__'] = 1
if pi.get('is_x86_64'):
macros['__x86_64__'] = 1
macros['__x86_64'] = 1
macros['_M_X64'] = 1
elif pi.get('is_arm64'):
macros['__aarch64__'] = 1
macros['_M_ARM64'] = 1
if not pi.get('is_32bit') and pi.get('is_linux'):
macros['__LP64__'] = 1
elif pi.get('is_32bit'):
macros['_ILP32'] = 1
macros['SIZEOF_VOID_P'] = ptr_size
macros['__SIZEOF_POINTER__'] = ptr_size
macros['NDEBUG'] = 0
return macros
def _eval_const_expr(self, node: ast.expr) -> int | None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx)
if result is None:
# 保留 CIf 嵌套调用处理(HandlesIf 特有逻辑)
if isinstance(node, ast.Call) and self._is_cif_call(node):
return self._evaluate_cif_condition(node)
return None
# HandlesIf 需要 bool/float → int 转换(#if 条件编译语义)
if isinstance(result, bool):
return 1 if result else 0
if isinstance(result, float):
return 1 if result != 0.0 else 0
return result
def _HandleIfLlvm(self, Node: ast.If) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if self._is_cif_call(Node.test):
compile_time_val: int | None = self._evaluate_cif_condition(Node.test)
if compile_time_val is not None:
if compile_time_val:
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
elif Node.orelse:
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
self._HandleIfLlvm(Node.orelse[0])
else:
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
return
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
if not Cond:
return
is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1
if is_const:
if Cond.constant:
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
elif Node.orelse:
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
self._HandleIfLlvm(Node.orelse[0])
else:
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
return
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen)
if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
obj_val: ir.Value = Cond
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__")
if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result")
else:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond")
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond")
ThenBB: ir.Block = Gen.func.append_basic_block(name="then")
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None
MergeBB: ir.Block = Gen.func.append_basic_block(name="endif")
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
Gen.builder.position_at_start(ThenBB)
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(MergeBB)
if not MergeBB.is_terminated:
Gen.builder.position_at_start(MergeBB)
else:
Gen.builder.position_at_end(MergeBB)
+2 -2
View File
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
import ast
import vast as ast
import inspect
import os
import re
@@ -381,7 +381,7 @@ class ImportHandle(BaseHandle):
# 治本修复:使用 file_module_name(源模块名)而非 module_name(可能是别名/类名)。
# 这样 _EmitExternalClassDeclLlvm 内的 ModuleSha1Map 查找才能命中,
# _EmitExternalFuncDeclLlvm 才能拿到正确的 source_module_name → 正确的 struct sha1。
# 注意:actual_module_name 保持原值(可能为 None),不回退到 module_name(可能是别名)
# 注意:actual_module_name 保持原值(可能为 None),不回退到 module_name(可能是别名)
self._EmitExternalClassDeclLlvm(node, Gen, module_name=file_module_name, actual_module_name=actual_module_name)
elif isinstance(node, ast.ImportFrom):
if node.level > 0:
+419 -419
View File
@@ -1,420 +1,420 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class MatchHandle(BaseHandle):
def _HandleMatchLlvm(self, Node: ast.Match) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject)
if not SubjectVal:
return
IsRenumMatch: bool = False
RenumName: str | None = None
SubjectPtr: ir.Value | None = None
if isinstance(Node.subject, ast.Name):
VarName: str = Node.subject.id
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName)
if TypeInfo and TypeInfo.IsRenum:
IsRenumMatch = True
RenumName = TypeInfo.Name
SubjectPtr = Gen._Load_var(VarName)
if not IsRenumMatch:
for case in Node.cases:
if isinstance(case.pattern, ast.MatchClass):
cls_node: ast.expr = case.pattern.cls
VariantName: str | None = None
QualifiedName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
# Extract enum name for qualified lookup to avoid collision
# with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr)
if isinstance(cls_node.value, ast.Attribute):
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
elif isinstance(cls_node.value, ast.Name):
QualifiedName = f"{cls_node.value.id}.{VariantName}"
if VariantName:
# Try qualified name first (e.g., "LLVMType.Ptr") to avoid
# collision with same-name functions (e.g., def Ptr(...))
SymInfo: "SymbolTable.SymbolInfo" = None
if QualifiedName:
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
if not (SymInfo and SymInfo.IsEnumMember):
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName:
EnumName: str = SymInfo.EnumName
EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName)
if EnumInfo and EnumInfo.IsRenum:
IsRenumMatch = True
RenumName = EnumName
if SubjectPtr is None:
SubjectPtr = self.HandleExprLlvm(Node.subject)
break
if IsRenumMatch and SubjectPtr:
self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr)
return
if not isinstance(SubjectVal.type, ir.IntType):
try:
SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj")
SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32")
except Exception: # 回退:ptrtoint 失败时直接返回
return
SwitchIntType: ir.IntType = SubjectVal.type
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
CaseBBs: list[ir.Block] = []
CaseValues: list[ir.Value] = []
HasDefault: bool = False
HasNoBreak: list[bool] = []
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchOr):
for j, SubPattern in enumerate(pattern.patterns):
if isinstance(SubPattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}"))
elif isinstance(pattern, ast.MatchSingleton):
if pattern.value is None:
CaseValues.append(ir.Constant(SwitchIntType, 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
elif isinstance(pattern, ast.MatchClass):
# 兜底处理:REnum 检测失败但 case 是 MatchClass(REnum 变体模式)
# 尝试从变体名查找 tag 值,按整数值处理
cls_node_mc: ast.expr = pattern.cls
VariantName_mc: str | None = None
QualifiedName_mc: str | None = None
if isinstance(cls_node_mc, ast.Name):
VariantName_mc = cls_node_mc.id
elif isinstance(cls_node_mc, ast.Attribute):
VariantName_mc = cls_node_mc.attr
if isinstance(cls_node_mc.value, ast.Attribute):
QualifiedName_mc = f"{cls_node_mc.value.attr}.{VariantName_mc}"
elif isinstance(cls_node_mc.value, ast.Name):
QualifiedName_mc = f"{cls_node_mc.value.id}.{VariantName_mc}"
TagValue_mc: int | None = None
SymInfo_mc: "SymbolTable.SymbolInfo" = None
if QualifiedName_mc:
SymInfo_mc = self.Trans.SymbolTable.lookup(QualifiedName_mc)
if not (SymInfo_mc and SymInfo_mc.IsEnumMember):
SymInfo_mc = self.Trans.SymbolTable.lookup(VariantName_mc)
if SymInfo_mc and SymInfo_mc.IsEnumMember:
TagValue_mc = SymInfo_mc.value
if TagValue_mc is not None:
CaseValues.append(ir.Constant(SwitchIntType, TagValue_mc))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{VariantName_mc}"))
else:
# 变体名未找到,跳过此 case(fast-fail 已在外层处理)
pass
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
for stmt in stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Attribute):
if (isinstance(stmt.value.func.value, ast.Name) and
stmt.value.func.value.id == 'c' and
stmt.value.func.attr == 'NoBreak'):
return True
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
if _HasNoBreak(stmt.body):
return True
if getattr(stmt, 'orelse', None):
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
return True
return False
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx: int = 0
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchOr):
NumSubCases: int = len(pattern.patterns)
for j in range(NumSubCases):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchClass):
# 兜底处理:MatchClass 在非 REnum 路径的 case body 生成
# case 收集阶段已创建 CaseBB,此处生成 body
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj")
# Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。
# 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store
# 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast
NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType)
NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and
not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)))
if NeedAlloca or NeedBitcast:
RenumStructType: Any = Gen.structs.get(RenumName)
if RenumStructType is None:
# 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册
# (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。
# 使用 _get_or_create_struct 按需创建(可能为 opaque)。
RenumStructType = Gen._get_or_create_struct(RenumName)
if NeedAlloca:
AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca")
CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast")
Gen._store(SubjectPtr, CastedPtr)
SubjectPtr = AllocaPtr
else:
SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast")
# REnum 布局为 { i32 __tag, <payload> },tag 在偏移 0。
# 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体
# (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。
tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr")
TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val")
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
CaseBBs: list[ir.Block] = []
CaseValues: list[ir.Value] = []
CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = []
HasDefault: bool = False
HasNoBreak: list[bool] = []
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
bindings: list[tuple[str, str, ir.Type, int]] = []
if isinstance(pattern, ast.MatchClass):
cls_node: ast.expr = pattern.cls
VariantName: str | None = None
QualifiedName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if isinstance(cls_node.value, ast.Attribute):
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
elif isinstance(cls_node.value, ast.Name):
QualifiedName = f"{cls_node.value.id}.{VariantName}"
if VariantName:
TagValue: int | None = None
SymInfo: "SymbolTable.SymbolInfo" = None
if QualifiedName:
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
if not (SymInfo and SymInfo.IsEnumMember):
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
if SymInfo and SymInfo.IsEnumMember:
TagValue = SymInfo.value
if TagValue is not None:
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
CaseBBs.append(CaseBB)
NestedStructName: str = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
for j, sub_pat in enumerate(pattern.patterns):
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
CaseBindings.append(bindings)
else:
CaseValues.append(ir.Constant(ir.IntType(32), 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(ir.IntType(32), 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
for stmt in stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Attribute):
if (isinstance(stmt.value.func.value, ast.Name) and
stmt.value.func.value.id == 'c' and
stmt.value.func.attr == 'NoBreak'):
return True
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
if _HasNoBreak(stmt.body):
return True
if getattr(stmt, 'orelse', None):
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
return True
return False
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx: int = 0
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchClass):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
cls_node: ast.expr = pattern.cls
VariantName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName:
NestedStructName: str = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
NestedStructType: ir.Type = Gen.structs[NestedStructName]
NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType)
variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
for bind_name, member_name, member_type, member_idx in bindings:
elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
# REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与
# 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast")
Gen.variables[bind_name] = elem_ptr
self.HandleBodyLlvm(case.body)
for bind_name, _, _, _ in bindings:
if bind_name in Gen.variables:
del Gen.variables[bind_name]
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchValue):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import vast as ast
import llvmlite.ir as ir
class MatchHandle(BaseHandle):
def _HandleMatchLlvm(self, Node: ast.Match) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject)
if not SubjectVal:
return
IsRenumMatch: bool = False
RenumName: str | None = None
SubjectPtr: ir.Value | None = None
if isinstance(Node.subject, ast.Name):
VarName: str = Node.subject.id
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName)
if TypeInfo and TypeInfo.IsRenum:
IsRenumMatch = True
RenumName = TypeInfo.Name
SubjectPtr = Gen._Load_var(VarName)
if not IsRenumMatch:
for case in Node.cases:
if isinstance(case.pattern, ast.MatchClass):
cls_node: ast.expr = case.pattern.cls
VariantName: str | None = None
QualifiedName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
# Extract enum name for qualified lookup to avoid collision
# with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr)
if isinstance(cls_node.value, ast.Attribute):
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
elif isinstance(cls_node.value, ast.Name):
QualifiedName = f"{cls_node.value.id}.{VariantName}"
if VariantName:
# Try qualified name first (e.g., "LLVMType.Ptr") to avoid
# collision with same-name functions (e.g., def Ptr(...))
SymInfo: "SymbolTable.SymbolInfo" = None
if QualifiedName:
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
if not (SymInfo and SymInfo.IsEnumMember):
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName:
EnumName: str = SymInfo.EnumName
EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName)
if EnumInfo and EnumInfo.IsRenum:
IsRenumMatch = True
RenumName = EnumName
if SubjectPtr is None:
SubjectPtr = self.HandleExprLlvm(Node.subject)
break
if IsRenumMatch and SubjectPtr:
self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr)
return
if not isinstance(SubjectVal.type, ir.IntType):
try:
SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj")
SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32")
except Exception: # 回退:ptrtoint 失败时直接返回
return
SwitchIntType: ir.IntType = SubjectVal.type
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
CaseBBs: list[ir.Block] = []
CaseValues: list[ir.Value] = []
HasDefault: bool = False
HasNoBreak: list[bool] = []
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchOr):
for j, SubPattern in enumerate(pattern.patterns):
if isinstance(SubPattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
if Val.type != SwitchIntType:
if Val.type.width > SwitchIntType.width:
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
else:
CaseVal = ir.Constant(SwitchIntType, Val.constant)
else:
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(SwitchIntType, 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}"))
elif isinstance(pattern, ast.MatchSingleton):
if pattern.value is None:
CaseValues.append(ir.Constant(SwitchIntType, 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
elif isinstance(pattern, ast.MatchClass):
# 兜底处理:REnum 检测失败但 case 是 MatchClass(REnum 变体模式)
# 尝试从变体名查找 tag 值,按整数值处理
cls_node_mc: ast.expr = pattern.cls
VariantName_mc: str | None = None
QualifiedName_mc: str | None = None
if isinstance(cls_node_mc, ast.Name):
VariantName_mc = cls_node_mc.id
elif isinstance(cls_node_mc, ast.Attribute):
VariantName_mc = cls_node_mc.attr
if isinstance(cls_node_mc.value, ast.Attribute):
QualifiedName_mc = f"{cls_node_mc.value.attr}.{VariantName_mc}"
elif isinstance(cls_node_mc.value, ast.Name):
QualifiedName_mc = f"{cls_node_mc.value.id}.{VariantName_mc}"
TagValue_mc: int | None = None
SymInfo_mc: "SymbolTable.SymbolInfo" = None
if QualifiedName_mc:
SymInfo_mc = self.Trans.SymbolTable.lookup(QualifiedName_mc)
if not (SymInfo_mc and SymInfo_mc.IsEnumMember):
SymInfo_mc = self.Trans.SymbolTable.lookup(VariantName_mc)
if SymInfo_mc and SymInfo_mc.IsEnumMember:
TagValue_mc = SymInfo_mc.value
if TagValue_mc is not None:
CaseValues.append(ir.Constant(SwitchIntType, TagValue_mc))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{VariantName_mc}"))
else:
# 变体名未找到,跳过此 case(fast-fail 已在外层处理)
pass
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
for stmt in stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Attribute):
if (isinstance(stmt.value.func.value, ast.Name) and
stmt.value.func.value.id == 'c' and
stmt.value.func.attr == 'NoBreak'):
return True
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
if _HasNoBreak(stmt.body):
return True
if getattr(stmt, 'orelse', None):
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
return True
return False
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx: int = 0
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchOr):
NumSubCases: int = len(pattern.patterns)
for j in range(NumSubCases):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchClass):
# 兜底处理:MatchClass 在非 REnum 路径的 case body 生成
# case 收集阶段已创建 CaseBB,此处生成 body
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj")
# Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。
# 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store
# 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast
NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType)
NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and
not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)))
if NeedAlloca or NeedBitcast:
RenumStructType: Any = Gen.structs.get(RenumName)
if RenumStructType is None:
# 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册
# (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。
# 使用 _get_or_create_struct 按需创建(可能为 opaque)。
RenumStructType = Gen._get_or_create_struct(RenumName)
if NeedAlloca:
AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca")
CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast")
Gen._store(SubjectPtr, CastedPtr)
SubjectPtr = AllocaPtr
else:
SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast")
# REnum 布局为 { i32 __tag, <payload> },tag 在偏移 0。
# 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体
# (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。
tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr")
TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val")
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
CaseBBs: list[ir.Block] = []
CaseValues: list[ir.Value] = []
CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = []
HasDefault: bool = False
HasNoBreak: list[bool] = []
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
bindings: list[tuple[str, str, ir.Type, int]] = []
if isinstance(pattern, ast.MatchClass):
cls_node: ast.expr = pattern.cls
VariantName: str | None = None
QualifiedName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if isinstance(cls_node.value, ast.Attribute):
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
elif isinstance(cls_node.value, ast.Name):
QualifiedName = f"{cls_node.value.id}.{VariantName}"
if VariantName:
TagValue: int | None = None
SymInfo: "SymbolTable.SymbolInfo" = None
if QualifiedName:
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
if not (SymInfo and SymInfo.IsEnumMember):
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
if SymInfo and SymInfo.IsEnumMember:
TagValue = SymInfo.value
if TagValue is not None:
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
CaseBBs.append(CaseBB)
NestedStructName: str = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
for j, sub_pat in enumerate(pattern.patterns):
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
CaseBindings.append(bindings)
else:
CaseValues.append(ir.Constant(ir.IntType(32), 0))
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchValue):
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
if Val:
CaseVal: ir.Value
if isinstance(Val.type, ir.IntType):
CaseVal = Val
else:
try:
CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}")
except Exception: # 回退:ptrtoint 失败时设默认值 0
CaseVal = ir.Constant(ir.IntType(32), 0)
CaseValues.append(CaseVal)
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
CaseBindings.append([])
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
elif isinstance(pattern, ast.MatchSequence):
HasDefault = True
CaseBBs.append(DefaultBB)
CaseBindings.append([])
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
for stmt in stmts:
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
if isinstance(stmt.value.func, ast.Attribute):
if (isinstance(stmt.value.func.value, ast.Name) and
stmt.value.func.value.id == 'c' and
stmt.value.func.attr == 'NoBreak'):
return True
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
if _HasNoBreak(stmt.body):
return True
if getattr(stmt, 'orelse', None):
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
return True
return False
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
if not HasDefault:
CaseBBs.append(DefaultBB)
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB)
for val, bb in SwitchCases:
switch_instr.add_case(val, bb)
CaseIdx: int = 0
for i, case in enumerate(Node.cases):
pattern: ast.pattern = case.pattern
if isinstance(pattern, ast.MatchClass):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
cls_node: ast.expr = pattern.cls
VariantName: str | None = None
if isinstance(cls_node, ast.Name):
VariantName = cls_node.id
elif isinstance(cls_node, ast.Attribute):
VariantName = cls_node.attr
if VariantName:
NestedStructName: str = f"{RenumName}_{VariantName}"
if NestedStructName in Gen.structs:
NestedStructType: ir.Type = Gen.structs[NestedStructName]
NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType)
variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
for bind_name, member_name, member_type, member_idx in bindings:
elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
# REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与
# 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast")
Gen.variables[bind_name] = elem_ptr
self.HandleBodyLlvm(case.body)
for bind_name, _, _, _ in bindings:
if bind_name in Gen.variables:
del Gen.variables[bind_name]
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchValue):
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
Gen.builder.position_at_start(CaseBBs[CaseIdx])
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchAs):
if pattern.pattern is None:
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
elif isinstance(pattern, ast.MatchSequence):
Gen.builder.position_at_start(DefaultBB)
self.HandleBodyLlvm(case.body)
if not Gen.builder.block.is_terminated:
if not HasNoBreak[i]:
Gen.builder.branch(AfterBB)
CaseIdx += 1
if not HasDefault:
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
Gen.builder.position_at_start(DefaultBB)
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
+154 -154
View File
@@ -1,155 +1,155 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
import ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
from lib.constants.config import mode as _config_mode
class RaiseHandle(BaseHandle):
def _get_exception_code(self, ExcName: str) -> int:
if ExcName in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[ExcName]
if ExcName in self.Trans.exception_registry:
return self.Trans.exception_registry[ExcName]
return 1
def _HandleRaiseLlvm(self, Node: ast.Raise) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1)
exc_msg: ir.Value | None = None
IsStopIteration: bool = False
if Node.exc:
if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int):
exc_val = ir.Constant(ir.IntType(32), Node.exc.value)
elif isinstance(Node.exc, ast.Name):
ExcName: str = Node.exc.id
if ExcName == 'StopIteration':
IsStopIteration = True
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name):
ExcName: str = Node.exc.func.id
if ExcName == 'StopIteration':
IsStopIteration = True
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
if Node.exc.args:
first_arg: ast.expr = Node.exc.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
exc_msg = self.HandleExprLlvm(first_arg)
elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)):
arg_val: ir.Value | None = self.HandleExprLlvm(first_arg)
if arg_val:
if isinstance(arg_val.type, ir.PointerType):
if self._is_char_pointer(arg_val):
exc_msg = arg_val
else:
try:
exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast")
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
else:
try:
exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr")
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
else:
val: ir.Value | None = self.HandleExprLlvm(Node.exc)
if val:
if isinstance(val.type, ir.IntType):
if val.type.width != 32:
try:
val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc")
except Exception: # 回退:trunc 失败时设默认值 1
val = ir.Constant(ir.IntType(32), 1)
exc_val = val
else:
try:
val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int")
exc_val = val
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
if IsStopIteration:
if Gen._stop_iter_flag_param is not None:
Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param)
if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType():
ret_type: ir.Type = Gen.func.type.pointee.return_type
if isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
else:
Gen.builder.ret(ir.Constant(ret_type, 0))
else:
Gen.builder.ret_void()
return
if Gen.eh_except_block_stack:
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
Gen._store(exc_val, exception_code)
if exc_msg:
Gen._store(exc_msg, eh_message)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen._store(null_ptr, eh_message)
if Gen.func and ExceptBB and ExceptBB.function is Gen.func:
Gen.builder.branch(ExceptBB)
else:
eh_msg_arg: ir.Argument | None = None
eh_code_arg: ir.Argument | None = None
if Gen.func:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_arg = arg
if eh_msg_arg is not None:
if exc_msg:
Gen.builder.store(exc_msg, eh_msg_arg)
else:
null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen.builder.store(null_ptr, eh_msg_arg)
if eh_code_arg is not None:
Gen.builder.store(exc_val, eh_code_arg)
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
Gen.builder.ret_void()
else:
eh_msg_arg: ir.Argument | None = None
eh_code_arg: ir.Argument | None = None
if Gen.func:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_arg = arg
if eh_msg_arg is not None:
if exc_msg:
Gen.builder.store(exc_msg, eh_msg_arg)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen.builder.store(null_ptr, eh_msg_arg)
if eh_code_arg is not None:
Gen.builder.store(exc_val, eh_code_arg)
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
import vast as ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
from lib.constants.config import mode as _config_mode
class RaiseHandle(BaseHandle):
def _get_exception_code(self, ExcName: str) -> int:
if ExcName in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[ExcName]
if ExcName in self.Trans.exception_registry:
return self.Trans.exception_registry[ExcName]
return 1
def _HandleRaiseLlvm(self, Node: ast.Raise) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1)
exc_msg: ir.Value | None = None
IsStopIteration: bool = False
if Node.exc:
if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int):
exc_val = ir.Constant(ir.IntType(32), Node.exc.value)
elif isinstance(Node.exc, ast.Name):
ExcName: str = Node.exc.id
if ExcName == 'StopIteration':
IsStopIteration = True
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name):
ExcName: str = Node.exc.func.id
if ExcName == 'StopIteration':
IsStopIteration = True
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
if Node.exc.args:
first_arg: ast.expr = Node.exc.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
exc_msg = self.HandleExprLlvm(first_arg)
elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)):
arg_val: ir.Value | None = self.HandleExprLlvm(first_arg)
if arg_val:
if isinstance(arg_val.type, ir.PointerType):
if self._is_char_pointer(arg_val):
exc_msg = arg_val
else:
try:
exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast")
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
else:
try:
exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr")
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
else:
val: ir.Value | None = self.HandleExprLlvm(Node.exc)
if val:
if isinstance(val.type, ir.IntType):
if val.type.width != 32:
try:
val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc")
except Exception: # 回退:trunc 失败时设默认值 1
val = ir.Constant(ir.IntType(32), 1)
exc_val = val
else:
try:
val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int")
exc_val = val
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
if IsStopIteration:
if Gen._stop_iter_flag_param is not None:
Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param)
if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType():
ret_type: ir.Type = Gen.func.type.pointee.return_type
if isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
else:
Gen.builder.ret(ir.Constant(ret_type, 0))
else:
Gen.builder.ret_void()
return
if Gen.eh_except_block_stack:
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
Gen._store(exc_val, exception_code)
if exc_msg:
Gen._store(exc_msg, eh_message)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen._store(null_ptr, eh_message)
if Gen.func and ExceptBB and ExceptBB.function is Gen.func:
Gen.builder.branch(ExceptBB)
else:
eh_msg_arg: ir.Argument | None = None
eh_code_arg: ir.Argument | None = None
if Gen.func:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_arg = arg
if eh_msg_arg is not None:
if exc_msg:
Gen.builder.store(exc_msg, eh_msg_arg)
else:
null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen.builder.store(null_ptr, eh_msg_arg)
if eh_code_arg is not None:
Gen.builder.store(exc_val, eh_code_arg)
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
Gen.builder.ret_void()
else:
eh_msg_arg: ir.Argument | None = None
eh_code_arg: ir.Argument | None = None
if Gen.func:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_arg = arg
if eh_msg_arg is not None:
if exc_msg:
Gen.builder.store(exc_msg, eh_msg_arg)
else:
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
Gen.builder.store(null_ptr, eh_msg_arg)
if eh_code_arg is not None:
Gen.builder.store(exc_val, eh_code_arg)
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
Gen.builder.ret_void()
+227 -227
View File
@@ -1,228 +1,228 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
import ast
import llvmlite.ir as ir
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*"""
if isinstance(ty, ir.PointerType):
cur: ir.Type = ty
while isinstance(cur, ir.PointerType):
if isinstance(cur.pointee, ir.VoidType):
return ir.IntType(8).as_pointer()
cur = cur.pointee
return ty
class ReturnHandle(BaseHandle):
def _find_active_finally(self, Gen: "Translator.LlvmGen") -> tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None:
for item in reversed(Gen.eh_finally_stack):
if item is not None and item[0] is not None:
return item
return None
def _HandleReturnLlvm(self, Node: ast.Return) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
# 闭包返回检测:当返回值是带 nonlocal 参数的嵌套函数时,创建闭包结构体
# 闭包结构体 {i8* env, i8* fn} 在堆上分配,env 指向 nonlocal 变量的堆存储
if Node.value and isinstance(Node.value, ast.Name):
ret_name: str = Node.value.id
if ret_name in Gen.nonlocal_params and ret_name in Gen.functions:
nested_fn: ir.Function = Gen.functions[ret_name]
nonlocal_params: list[tuple[str, ir.Type]] = Gen.nonlocal_params[ret_name]
fn_return_type: ir.Type = nested_fn.function_type.return_type
nonlocal_types: list[ir.Type] = [_safe_ptr_type(t) for _, t in nonlocal_params]
# 构建 env:收集所有 nonlocal 变量指针
env_ptrs: list[ir.Value] = []
for var_name, _ in nonlocal_params:
vp: ir.Value | None = Gen.variables.get(var_name)
if vp is not None:
env_ptrs.append(vp)
if env_ptrs:
# env 值:单个指针直接用,多个指针打包成结构体
i8_ptr_type: ir.PointerType = ir.IntType(8).as_pointer()
if len(env_ptrs) == 1:
env_val: ir.Value = Gen.builder.bitcast(env_ptrs[0], i8_ptr_type, name="closure_env")
else:
env_struct_type: ir.LiteralStructType = ir.LiteralStructType([p.type for p in env_ptrs])
env_size: int = len(env_ptrs) * 8
malloc_type: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)])
malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type)
env_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), env_size)], name="env_struct_raw")
env_struct_ptr: ir.Value = Gen.builder.bitcast(env_raw, ir.PointerType(env_struct_type), name="env_struct_ptr")
for i, ptr in enumerate(env_ptrs):
gep: ir.Value = Gen.builder.gep(env_struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"env_field_{i}")
Gen._store(ptr, gep)
env_val = Gen.builder.bitcast(env_struct_ptr, i8_ptr_type, name="closure_env")
# fn 指针
fn_ptr: ir.Value = Gen.builder.bitcast(nested_fn, i8_ptr_type, name="closure_fn")
# 创建闭包结构体 {i8* env, i8* fn}
closure_type: ir.LiteralStructType = ir.LiteralStructType([i8_ptr_type, i8_ptr_type])
malloc_type2: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)])
malloc_func2: ir.Function = Gen._get_or_declare_func('malloc', malloc_type2)
closure_raw: ir.Value = Gen.builder.call(malloc_func2, [ir.Constant(ir.IntType(64), 16)], name="closure_raw")
closure_ptr: ir.Value = Gen.builder.bitcast(closure_raw, ir.PointerType(closure_type), name="closure_ptr")
# 填充闭包结构体
env_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="closure_env_slot")
Gen._store(env_val, env_gep)
fn_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name="closure_fn_slot")
Gen._store(fn_ptr, fn_gep)
# 记录闭包返回类型
current_name: str = Gen.func.name if Gen.func else ''
short_name: str = current_name.split('.', 1)[1] if '.' in current_name else current_name
Gen._closure_return_types[short_name] = (fn_return_type, nonlocal_types)
# 返回闭包结构体指针(bitcast 到 i8*)
closure_ret: ir.Value = Gen.builder.bitcast(closure_ptr, i8_ptr_type, name="closure_ret")
Gen.emit_return(closure_ret)
return
active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen)
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value:
return_values: list[ast.expr] = []
if isinstance(Node.value, ast.Tuple):
return_values = Node.value.elts
else:
return_values = [Node.value]
if len(return_values) == len(self.Trans.CurrentCReturnTypes):
llvm_vals: list[ir.Value] = []
expected_types: list[ir.Type] = []
for i, val in enumerate(return_values):
ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable)
IsRetPtr: bool = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'):
IsRetPtr = True
ExpectedType: ir.Type = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr)
expected_types.append(ExpectedType)
Val: ir.Value | None = self.HandleExprLlvm(val)
if Val is None:
if isinstance(ExpectedType, ir.PointerType):
Val = ir.Constant(ExpectedType, None)
elif isinstance(ExpectedType, ir.IntType):
Val = ir.Constant(ExpectedType, 0)
else:
Val = ir.Constant(ExpectedType, ir.Undefined)
else:
if Val.type != ExpectedType:
if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType):
if Val.type.width < ExpectedType.width:
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
elif Val.type.width > ExpectedType.width:
Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}")
elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType):
Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}")
llvm_vals.append(Val)
if llvm_vals:
struct_type: ir.LiteralStructType = ir.LiteralStructType(expected_types)
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
for i, val in enumerate(llvm_vals):
result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}")
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(result, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(result)
return
if Node.value:
Val: ir.Value | None = self.HandleExprLlvm(Node.value)
if Val:
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None:
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(zero_val, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(zero_val)
return
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes:
struct_type: ir.Type = Gen.func.ftype.return_type
if isinstance(struct_type, ir.LiteralStructType):
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType):
result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0")
for j in range(1, len(struct_type.elements)):
elem_type: ir.Type = struct_type.elements[j]
zero_val: ir.Constant = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
else:
for j, elem_type in enumerate(struct_type.elements):
if j == 0:
if Val.type == elem_type:
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType):
if Val.type.width < elem_type.width:
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
elif Val.type.width > elem_type.width:
Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}")
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
else:
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
else:
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(result, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(result)
return
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(Val, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(Val)
else:
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
elif isinstance(ret_type, ir.ArrayType):
Gen.builder.ret(ir.Constant(ret_type, None))
else:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
import vast as ast
import llvmlite.ir as ir
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*"""
if isinstance(ty, ir.PointerType):
cur: ir.Type = ty
while isinstance(cur, ir.PointerType):
if isinstance(cur.pointee, ir.VoidType):
return ir.IntType(8).as_pointer()
cur = cur.pointee
return ty
class ReturnHandle(BaseHandle):
def _find_active_finally(self, Gen: "Translator.LlvmGen") -> tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None:
for item in reversed(Gen.eh_finally_stack):
if item is not None and item[0] is not None:
return item
return None
def _HandleReturnLlvm(self, Node: ast.Return) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
# 闭包返回检测:当返回值是带 nonlocal 参数的嵌套函数时,创建闭包结构体
# 闭包结构体 {i8* env, i8* fn} 在堆上分配,env 指向 nonlocal 变量的堆存储
if Node.value and isinstance(Node.value, ast.Name):
ret_name: str = Node.value.id
if ret_name in Gen.nonlocal_params and ret_name in Gen.functions:
nested_fn: ir.Function = Gen.functions[ret_name]
nonlocal_params: list[tuple[str, ir.Type]] = Gen.nonlocal_params[ret_name]
fn_return_type: ir.Type = nested_fn.function_type.return_type
nonlocal_types: list[ir.Type] = [_safe_ptr_type(t) for _, t in nonlocal_params]
# 构建 env:收集所有 nonlocal 变量指针
env_ptrs: list[ir.Value] = []
for var_name, _ in nonlocal_params:
vp: ir.Value | None = Gen.variables.get(var_name)
if vp is not None:
env_ptrs.append(vp)
if env_ptrs:
# env 值:单个指针直接用,多个指针打包成结构体
i8_ptr_type: ir.PointerType = ir.IntType(8).as_pointer()
if len(env_ptrs) == 1:
env_val: ir.Value = Gen.builder.bitcast(env_ptrs[0], i8_ptr_type, name="closure_env")
else:
env_struct_type: ir.LiteralStructType = ir.LiteralStructType([p.type for p in env_ptrs])
env_size: int = len(env_ptrs) * 8
malloc_type: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)])
malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type)
env_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), env_size)], name="env_struct_raw")
env_struct_ptr: ir.Value = Gen.builder.bitcast(env_raw, ir.PointerType(env_struct_type), name="env_struct_ptr")
for i, ptr in enumerate(env_ptrs):
gep: ir.Value = Gen.builder.gep(env_struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"env_field_{i}")
Gen._store(ptr, gep)
env_val = Gen.builder.bitcast(env_struct_ptr, i8_ptr_type, name="closure_env")
# fn 指针
fn_ptr: ir.Value = Gen.builder.bitcast(nested_fn, i8_ptr_type, name="closure_fn")
# 创建闭包结构体 {i8* env, i8* fn}
closure_type: ir.LiteralStructType = ir.LiteralStructType([i8_ptr_type, i8_ptr_type])
malloc_type2: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)])
malloc_func2: ir.Function = Gen._get_or_declare_func('malloc', malloc_type2)
closure_raw: ir.Value = Gen.builder.call(malloc_func2, [ir.Constant(ir.IntType(64), 16)], name="closure_raw")
closure_ptr: ir.Value = Gen.builder.bitcast(closure_raw, ir.PointerType(closure_type), name="closure_ptr")
# 填充闭包结构体
env_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="closure_env_slot")
Gen._store(env_val, env_gep)
fn_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name="closure_fn_slot")
Gen._store(fn_ptr, fn_gep)
# 记录闭包返回类型
current_name: str = Gen.func.name if Gen.func else ''
short_name: str = current_name.split('.', 1)[1] if '.' in current_name else current_name
Gen._closure_return_types[short_name] = (fn_return_type, nonlocal_types)
# 返回闭包结构体指针(bitcast 到 i8*)
closure_ret: ir.Value = Gen.builder.bitcast(closure_ptr, i8_ptr_type, name="closure_ret")
Gen.emit_return(closure_ret)
return
active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen)
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value:
return_values: list[ast.expr] = []
if isinstance(Node.value, ast.Tuple):
return_values = Node.value.elts
else:
return_values = [Node.value]
if len(return_values) == len(self.Trans.CurrentCReturnTypes):
llvm_vals: list[ir.Value] = []
expected_types: list[ir.Type] = []
for i, val in enumerate(return_values):
ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable)
IsRetPtr: bool = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'):
IsRetPtr = True
ExpectedType: ir.Type = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr)
expected_types.append(ExpectedType)
Val: ir.Value | None = self.HandleExprLlvm(val)
if Val is None:
if isinstance(ExpectedType, ir.PointerType):
Val = ir.Constant(ExpectedType, None)
elif isinstance(ExpectedType, ir.IntType):
Val = ir.Constant(ExpectedType, 0)
else:
Val = ir.Constant(ExpectedType, ir.Undefined)
else:
if Val.type != ExpectedType:
if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType):
if Val.type.width < ExpectedType.width:
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
elif Val.type.width > ExpectedType.width:
Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}")
elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType):
Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}")
llvm_vals.append(Val)
if llvm_vals:
struct_type: ir.LiteralStructType = ir.LiteralStructType(expected_types)
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
for i, val in enumerate(llvm_vals):
result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}")
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(result, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(result)
return
if Node.value:
Val: ir.Value | None = self.HandleExprLlvm(Node.value)
if Val:
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None:
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(zero_val, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(zero_val)
return
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes:
struct_type: ir.Type = Gen.func.ftype.return_type
if isinstance(struct_type, ir.LiteralStructType):
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType):
result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0")
for j in range(1, len(struct_type.elements)):
elem_type: ir.Type = struct_type.elements[j]
zero_val: ir.Constant = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
else:
for j, elem_type in enumerate(struct_type.elements):
if j == 0:
if Val.type == elem_type:
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType):
if Val.type.width < elem_type.width:
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
elif Val.type.width > elem_type.width:
Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}")
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
else:
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
else:
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(result, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(result)
return
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
if pending_ret_val:
Gen._store(Val, pending_ret_val)
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
Gen.emit_return(Val)
else:
if active_finally:
FinallyBB: ir.Block = active_finally[0]
pending_ret_flag: ir.AllocaInstr = active_finally[1]
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
Gen.builder.branch(FinallyBB)
else:
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 0))
elif isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.BaseStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
elif isinstance(ret_type, ir.ArrayType):
Gen.builder.ret(ir.Constant(ret_type, None))
else:
Gen.emit_return()
+1 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
from typing import TYPE_CHECKING
import ast
import vast as ast
import llvmlite.ir as ir
if TYPE_CHECKING:
from lib.core.translator import Translator
+213 -213
View File
@@ -1,214 +1,214 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
import ast
import llvmlite.ir as ir
class TryHandle(BaseHandle):
def _get_exception_type_code(self, type_node: ast.expr) -> int:
if isinstance(type_node, ast.Name):
name: str = type_node.id
if name in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[name]
if name in self.Trans.exception_registry:
return self.Trans.exception_registry[name]
return 1
if isinstance(type_node, ast.Attribute):
name: str = type_node.attr
if name in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[name]
if name in self.Trans.exception_registry:
return self.Trans.exception_registry[name]
return 1
if isinstance(type_node, ast.Tuple):
for elt in type_node.elts:
code: int = self._get_exception_type_code(elt)
if code != 1:
return code
return 1
return 1
def _get_exception_name(self, type_node: ast.expr) -> str | None:
if isinstance(type_node, ast.Name):
return type_node.id
if isinstance(type_node, ast.Attribute):
return type_node.attr
return None
def _get_all_match_codes(self, type_node: ast.expr) -> list[int]:
name: str | None = self._get_exception_name(type_node)
if name is None:
return [self._get_exception_type_code(type_node)]
if name not in self.Trans.exception_registry:
return [self._get_exception_type_code(type_node)]
codes: list[int] = [self.Trans.exception_registry[name]]
self._collect_descendant_codes(name, codes)
return codes
def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None:
for child_name, parent in self.Trans.exception_parents.items():
if parent == parent_name:
child_code: int | None = self.Trans.exception_registry.get(child_name)
if child_code is not None and child_code not in codes:
codes.append(child_code)
self._collect_descendant_codes(child_name, codes)
def _HandleTryLlvm(self, Node: ast.Try) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if not Gen.func:
return
exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code")
eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message")
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message)
HasFinally: bool = bool(Node.finalbody)
if HasFinally:
Gen.eh_finally_stack.append((None, None, None))
else:
Gen.eh_finally_stack.append(None)
DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch")
AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after")
except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = []
for i, handler in enumerate(Node.handlers):
ExcTypeCodes: list[int] = [1]
if handler.type:
ExcTypeCodes = self._get_all_match_codes(handler.type)
ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}")
Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message))
except_blocks.append((ExceptBB, ExcTypeCodes, handler))
TryBB: ir.Block = Gen.func.append_basic_block(name="try.body")
ElseBB: ir.Block | None = None
if Node.orelse:
ElseBB = Gen.func.append_basic_block(name="try.else")
Gen.builder.branch(TryBB)
Gen.builder.position_at_start(TryBB)
self.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
if ElseBB:
Gen.builder.branch(ElseBB)
else:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(DispatchBB)
eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code")
next_check_bb: ir.Block | None = None
handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {}
UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled")
for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}")
if i > 0 and next_check_bb is not None:
Gen.builder.position_at_start(next_check_bb)
eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}")
if handler.type is None:
Gen.builder.branch(MatchBB)
else:
match_cond: ir.Value | None = None
for code in ExcTypeCodes:
is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}")
if match_cond is None:
match_cond = is_code_match
else:
match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}")
if i < len(except_blocks) - 1:
next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}")
else:
next_check_bb = UnhandledBB
Gen.builder.cbranch(match_cond, MatchBB, next_check_bb)
Gen.builder.position_at_start(MatchBB)
if handler.name:
var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name)
eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}")
Gen._store(eh_msg_val, var_alloca)
handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name))
Gen.builder.branch(ExceptBB)
Gen.builder.position_at_start(UnhandledBB)
eh_msg_out_arg: ir.Argument | None = None
eh_code_out_arg: ir.Argument | None = None
if Gen.func and len(Gen.func.args) > 0:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_out_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_out_arg = arg
if eh_msg_out_arg is not None and eh_code_out_arg is not None:
eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate")
eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate")
Gen._store(eh_msg_val, eh_msg_out_arg)
Gen._store(eh_code_val_prop, eh_code_out_arg)
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IdentifiedStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
elif isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 1))
elif isinstance(ret_type, ir.VoidType):
Gen.builder.ret_void()
else:
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
Gen.builder.branch(AfterBB)
for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
Gen.builder.position_at_start(ExceptBB)
old_var: ir.Value | None = None
if idx in handler_var_map:
hname: str = handler_var_map[idx][0]
var_alloca: ir.AllocaInstr = handler_var_map[idx][1]
old_var = handler_var_map[idx][2]
Gen.variables[hname] = var_alloca
self.HandleBodyLlvm(handler.body)
if idx in handler_var_map:
hname = handler_var_map[idx][0]
old_var = handler_var_map[idx][2]
if old_var is not None:
Gen.variables[hname] = old_var
elif hname in Gen.variables:
del Gen.variables[hname]
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.eh_except_block_stack.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
if HasFinally:
Gen.eh_finally_stack.pop()
if Node.finalbody:
FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally")
pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag")
pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None
Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val))
Gen.builder.branch(FinallyBB)
Gen.builder.position_at_start(FinallyBB)
Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag)
self.HandleBodyLlvm(Node.finalbody)
if Gen.eh_finally_stack:
_, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1]
Gen.eh_finally_stack.pop()
ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag")
ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag")
RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret")
ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue")
Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB)
Gen.builder.position_at_start(RetBB)
if pending_ret_val:
ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val")
Gen.builder.ret(ret_val)
else:
Gen.builder.ret_void()
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
import vast as ast
import llvmlite.ir as ir
class TryHandle(BaseHandle):
def _get_exception_type_code(self, type_node: ast.expr) -> int:
if isinstance(type_node, ast.Name):
name: str = type_node.id
if name in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[name]
if name in self.Trans.exception_registry:
return self.Trans.exception_registry[name]
return 1
if isinstance(type_node, ast.Attribute):
name: str = type_node.attr
if name in EXCEPTION_CODE_MAP:
return EXCEPTION_CODE_MAP[name]
if name in self.Trans.exception_registry:
return self.Trans.exception_registry[name]
return 1
if isinstance(type_node, ast.Tuple):
for elt in type_node.elts:
code: int = self._get_exception_type_code(elt)
if code != 1:
return code
return 1
return 1
def _get_exception_name(self, type_node: ast.expr) -> str | None:
if isinstance(type_node, ast.Name):
return type_node.id
if isinstance(type_node, ast.Attribute):
return type_node.attr
return None
def _get_all_match_codes(self, type_node: ast.expr) -> list[int]:
name: str | None = self._get_exception_name(type_node)
if name is None:
return [self._get_exception_type_code(type_node)]
if name not in self.Trans.exception_registry:
return [self._get_exception_type_code(type_node)]
codes: list[int] = [self.Trans.exception_registry[name]]
self._collect_descendant_codes(name, codes)
return codes
def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None:
for child_name, parent in self.Trans.exception_parents.items():
if parent == parent_name:
child_code: int | None = self.Trans.exception_registry.get(child_name)
if child_code is not None and child_code not in codes:
codes.append(child_code)
self._collect_descendant_codes(child_name, codes)
def _HandleTryLlvm(self, Node: ast.Try) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if not Gen.func:
return
exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code")
eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message")
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message)
HasFinally: bool = bool(Node.finalbody)
if HasFinally:
Gen.eh_finally_stack.append((None, None, None))
else:
Gen.eh_finally_stack.append(None)
DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch")
AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after")
except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = []
for i, handler in enumerate(Node.handlers):
ExcTypeCodes: list[int] = [1]
if handler.type:
ExcTypeCodes = self._get_all_match_codes(handler.type)
ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}")
Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message))
except_blocks.append((ExceptBB, ExcTypeCodes, handler))
TryBB: ir.Block = Gen.func.append_basic_block(name="try.body")
ElseBB: ir.Block | None = None
if Node.orelse:
ElseBB = Gen.func.append_basic_block(name="try.else")
Gen.builder.branch(TryBB)
Gen.builder.position_at_start(TryBB)
self.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
if ElseBB:
Gen.builder.branch(ElseBB)
else:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(DispatchBB)
eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code")
next_check_bb: ir.Block | None = None
handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {}
UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled")
for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}")
if i > 0 and next_check_bb is not None:
Gen.builder.position_at_start(next_check_bb)
eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}")
if handler.type is None:
Gen.builder.branch(MatchBB)
else:
match_cond: ir.Value | None = None
for code in ExcTypeCodes:
is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}")
if match_cond is None:
match_cond = is_code_match
else:
match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}")
if i < len(except_blocks) - 1:
next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}")
else:
next_check_bb = UnhandledBB
Gen.builder.cbranch(match_cond, MatchBB, next_check_bb)
Gen.builder.position_at_start(MatchBB)
if handler.name:
var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name)
eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}")
Gen._store(eh_msg_val, var_alloca)
handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name))
Gen.builder.branch(ExceptBB)
Gen.builder.position_at_start(UnhandledBB)
eh_msg_out_arg: ir.Argument | None = None
eh_code_out_arg: ir.Argument | None = None
if Gen.func and len(Gen.func.args) > 0:
for arg in Gen.func.args:
if arg.name == '__eh_msg_out__':
eh_msg_out_arg = arg
elif arg.name == '__eh_code_out__':
eh_code_out_arg = arg
if eh_msg_out_arg is not None and eh_code_out_arg is not None:
eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate")
eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate")
Gen._store(eh_msg_val, eh_msg_out_arg)
Gen._store(eh_code_val_prop, eh_code_out_arg)
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
if isinstance(ret_type, ir.IdentifiedStructType):
if ret_type.elements:
zero_val: ir.Constant = ir.Constant(ret_type, [
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
else:
zero_val = ir.Constant(ret_type, None)
Gen.builder.ret(zero_val)
elif isinstance(ret_type, ir.PointerType):
Gen.builder.ret(ir.Constant(ret_type, None))
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
Gen.builder.ret(ir.Constant(ret_type, 0.0))
elif isinstance(ret_type, ir.IntType):
Gen.builder.ret(ir.Constant(ret_type, 1))
elif isinstance(ret_type, ir.VoidType):
Gen.builder.ret_void()
else:
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
else:
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
Gen.builder.branch(AfterBB)
for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
Gen.builder.position_at_start(ExceptBB)
old_var: ir.Value | None = None
if idx in handler_var_map:
hname: str = handler_var_map[idx][0]
var_alloca: ir.AllocaInstr = handler_var_map[idx][1]
old_var = handler_var_map[idx][2]
Gen.variables[hname] = var_alloca
self.HandleBodyLlvm(handler.body)
if idx in handler_var_map:
hname = handler_var_map[idx][0]
old_var = handler_var_map[idx][2]
if old_var is not None:
Gen.variables[hname] = old_var
elif hname in Gen.variables:
del Gen.variables[hname]
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.eh_except_block_stack.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
if HasFinally:
Gen.eh_finally_stack.pop()
if Node.finalbody:
FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally")
pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag")
pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None
Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val))
Gen.builder.branch(FinallyBB)
Gen.builder.position_at_start(FinallyBB)
Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag)
self.HandleBodyLlvm(Node.finalbody)
if Gen.eh_finally_stack:
_, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1]
Gen.eh_finally_stack.pop()
ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag")
ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag")
RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret")
ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue")
Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB)
Gen.builder.position_at_start(RetBB)
if pending_ret_val:
ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val")
Gen.builder.ret(ret_val)
else:
Gen.builder.ret_void()
Gen.builder.position_at_start(ContinueBB)
+1 -1
View File
@@ -7,7 +7,7 @@ from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
from lib.includes import t
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
import ast
import vast as ast
class HandlesTypeMerge(BaseHandle):
+211 -211
View File
@@ -1,212 +1,212 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir
class WithHandle(BaseHandle):
def _ResolveInheritedMethod(self, ClassName: str, MethodName: str, Gen: "Translator.LlvmGen") -> tuple[str | None, "ir.Function | None"]:
"""沿继承链查找方法,返回 (定义方法的类名, 函数对象)
当子类未覆写 __enter__/__exit__ 等方法时,沿 Gen.class_parent 链查找父类实现。
_generate_inherited_method_wrappers 只为 class_methods[ClassName] 中的方法生成包装,
不包括父类独有方法,因此 with 语句需要单独处理继承查找。
"""
# 先检查子类自身:必须有函数体(define)才算真方法。
# 子类继承方法的 stub declare(如 MemPool.__enter__,Phase1 生成的继承
# 包装声明)无函数体且 TPC 不生成对应定义,直接调用会链接 undefined,
# 必须跳过并沿 MRO 找父类实现。
FullName: str = f'{ClassName}.{MethodName}'
func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName)
if func and len(list(func.blocks)) > 0:
return (ClassName, func)
# 沿 MRO 继承链查找(多继承:先声明父类优先)。
# 祖先的 stub declare(无函数体)是真实定义的声明(定义在其模块 obj 中),
# 可直接调用——与 _HandleMethodCallLlvm 的 MRO 回退语义一致。
for anc in Gen._get_mro_chain(ClassName)[1:]:
parent_full: str = f'{anc}.{MethodName}'
parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full)
if parent_func:
return (anc, parent_func)
return (None, None)
def _HandleWithLlvm(self, Node: ast.With) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for item in Node.items:
context_expr: ast.expr = item.context_expr
asname: str | None = None
target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None)))
if target and isinstance(target, ast.Name):
asname = target.id
ClassName: str | None = None
if isinstance(context_expr, ast.Call):
if isinstance(context_expr.func, ast.Name):
ClassName = context_expr.func.id
elif isinstance(context_expr.func, ast.Attribute):
ClassName = context_expr.func.attr
if ClassName and ClassName not in Gen.structs:
SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName)
if SymInfo:
if SymInfo.IsStruct or SymInfo.IsRenum:
pass
else:
ClassName = None
else:
ClassName = None
elif isinstance(context_expr, ast.Name):
VarName: str = context_expr.id
if VarName in Gen.var_struct_class:
ClassName = Gen.var_struct_class[VarName]
ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr)
if not ctx_val:
continue
original_ctx_val: ir.Value = ctx_val
if ClassName and isinstance(ctx_val.type, ir.PointerType):
pointee: ir.Type = ctx_val.type.pointee
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee)
if found:
CN: str = found[0]
ST: ir.Type = found[1]
ClassName = CN
StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None
if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName):
ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx")
ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx")
Gen._store(ctx_val, ctx_alloca)
Gen._UnregisterTempPtr(ctx_val)
if ClassName:
Gen.var_struct_class['__with_ctx'] = ClassName
Gen._var_to_heap_ptr['__with_ctx'] = ctx_val
original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None
ctx_is_var_ref: bool = isinstance(context_expr, ast.Name)
enter_result: ir.Value | None = None
if ClassName:
# 沿继承链查找 __enter__(子类可能未覆写,使用父类实现)
enter_class, enter_func = self._ResolveInheritedMethod(ClassName, '__enter__', Gen)
if enter_func is not None:
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
# 父类方法需要 self 为父类指针类型,bitcast 子类指针。
# bitcast 目标用 enter_func 签名参数类型(args[0] 本身即
# MemManager* 指针),避免 Gen.structs 查找返回 opaque/异
# sha1 占位对象导致 llvmlite 类型不匹配。
if enter_class != ClassName:
parent_ptr_type: ir.Type = enter_func.function_type.args[0]
if ctx_Loaded.type != parent_ptr_type:
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_enter_self")
enter_call: ir.CallInstr = Gen.builder.call(enter_func, [ctx_Loaded], name="call_enter")
enter_result = enter_call
if isinstance(enter_call.type, ir.PointerType):
pointee: ir.Type = enter_call.type.pointee
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
enter_result = Gen._load(enter_call, name="enter_deref")
elif self._is_char_pointer(enter_call) and StructPtrType:
enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter")
if asname and enter_result:
if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee)
if found:
CN: str = found[0]
ST: ir.Type = found[1]
Gen.var_struct_class[asname] = CN
Gen._var_to_heap_ptr[asname] = enter_result
Gen._register_local_heap_ptr(enter_result, VarName=asname)
if asname in Gen._reg_values:
OldVal: ir.Value = Gen._reg_values[asname]
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname)
Gen._store(OldVal, var)
Gen.variables[asname] = var
del Gen._reg_values[asname]
if asname in Gen.variables and Gen.variables[asname] is not None:
VarPtr: ir.Value = Gen.variables[asname]
if VarPtr.type.pointee == enter_result.type:
Gen._store(enter_result, VarPtr)
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}")
Gen._store(CastedVal, VarPtr)
else:
NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname)
Gen._store(enter_result, NewVar)
Gen.variables[asname] = NewVar
else:
Gen._reg_values[asname] = enter_result
Gen.variables[asname] = None
# 如果类有 __provides__,自动生成 push 代码
if ClassName and ClassName in Gen.class_provides:
# 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32)
# _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈
current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack)
new_fields: int = len(Gen.class_provides[ClassName])
if current_depth + new_fields > 32:
raise SyntaxError(
f"[TransPyC] with provider stack overflow at line {Node.lineno}: "
f"current depth {current_depth} + new {new_fields} fields > max 32. "
f"Class '{ClassName}' provides too many fields or with nesting too deep."
)
# 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查
Gen._with_provides_stack.append(Gen.class_provides[ClassName])
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
ctx_i8: ir.Value = ctx_Loaded
if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)):
ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8")
for field_name in Gen.class_provides[ClassName]:
field_str: ir.Value = Gen._create_string_global(field_name)
push_func = Gen.functions.get('_push_provider')
if push_func:
Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider")
self.Trans.VarScopes.append({})
if asname:
self.Trans.VarScopes[-1][asname] = True
self.HandleBodyLlvm(Node.body)
if self.Trans.VarScopes:
self.Trans.VarScopes.pop()
# 如果类有 __provides__,自动生成 pop 代码
if ClassName and ClassName in Gen.class_provides:
for _ in Gen.class_provides[ClassName]:
pop_func = Gen.functions.get('_pop_provider')
if pop_func:
Gen.builder.call(pop_func, [], name="call_pop_provider")
# 编译期弹栈
if Gen._with_provides_stack:
Gen._with_provides_stack.pop()
if ClassName:
# 沿继承链查找 __exit__(子类可能未覆写,使用父类实现)
exit_class, exit_func = self._ResolveInheritedMethod(ClassName, '__exit__', Gen)
if exit_func is not None:
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
# 父类方法需要 self 为父类指针类型,bitcast 子类指针(同上)
if exit_class != ClassName:
parent_ptr_type: ir.Type = exit_func.function_type.args[0]
if ctx_Loaded.type != parent_ptr_type:
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_exit_self")
Gen.builder.call(exit_func, [ctx_Loaded], name="call_exit")
Gen._unregister_local_heap_ptr(original_ctx_val)
if ctx_val is not original_ctx_val:
Gen._unregister_local_heap_ptr(ctx_val)
if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val:
Gen._unregister_local_heap_ptr(original_asname_heap_ptr)
if '__with_ctx' in Gen._var_to_heap_ptr:
del Gen._var_to_heap_ptr['__with_ctx']
if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int")
enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int")
same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check")
with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx")
with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free")
Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb)
Gen.builder.position_at_start(with_free_bb)
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
Gen.builder.call(free_func, [raw])
Gen.builder.branch(with_skip_bb)
Gen.builder.position_at_start(with_skip_bb)
Gen._unregister_local_heap_ptr(enter_result)
Gen._unregister_local_heap_ptr(original_ctx_val)
elif isinstance(ctx_val.type, ir.PointerType):
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
Gen.builder.call(free_func, [raw])
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import vast as ast
import llvmlite.ir as ir
class WithHandle(BaseHandle):
def _ResolveInheritedMethod(self, ClassName: str, MethodName: str, Gen: "Translator.LlvmGen") -> tuple[str | None, "ir.Function | None"]:
"""沿继承链查找方法,返回 (定义方法的类名, 函数对象)
当子类未覆写 __enter__/__exit__ 等方法时,沿 Gen.class_parent 链查找父类实现。
_generate_inherited_method_wrappers 只为 class_methods[ClassName] 中的方法生成包装,
不包括父类独有方法,因此 with 语句需要单独处理继承查找。
"""
# 先检查子类自身:必须有函数体(define)才算真方法。
# 子类继承方法的 stub declare(如 MemPool.__enter__,Phase1 生成的继承
# 包装声明)无函数体且 TPC 不生成对应定义,直接调用会链接 undefined,
# 必须跳过并沿 MRO 找父类实现。
FullName: str = f'{ClassName}.{MethodName}'
func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName)
if func and len(list(func.blocks)) > 0:
return (ClassName, func)
# 沿 MRO 继承链查找(多继承:先声明父类优先)。
# 祖先的 stub declare(无函数体)是真实定义的声明(定义在其模块 obj 中),
# 可直接调用——与 _HandleMethodCallLlvm 的 MRO 回退语义一致。
for anc in Gen._get_mro_chain(ClassName)[1:]:
parent_full: str = f'{anc}.{MethodName}'
parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full)
if parent_func:
return (anc, parent_func)
return (None, None)
def _HandleWithLlvm(self, Node: ast.With) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
for item in Node.items:
context_expr: ast.expr = item.context_expr
asname: str | None = None
target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None)))
if target and isinstance(target, ast.Name):
asname = target.id
ClassName: str | None = None
if isinstance(context_expr, ast.Call):
if isinstance(context_expr.func, ast.Name):
ClassName = context_expr.func.id
elif isinstance(context_expr.func, ast.Attribute):
ClassName = context_expr.func.attr
if ClassName and ClassName not in Gen.structs:
SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName)
if SymInfo:
if SymInfo.IsStruct or SymInfo.IsRenum:
pass
else:
ClassName = None
else:
ClassName = None
elif isinstance(context_expr, ast.Name):
VarName: str = context_expr.id
if VarName in Gen.var_struct_class:
ClassName = Gen.var_struct_class[VarName]
ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr)
if not ctx_val:
continue
original_ctx_val: ir.Value = ctx_val
if ClassName and isinstance(ctx_val.type, ir.PointerType):
pointee: ir.Type = ctx_val.type.pointee
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee)
if found:
CN: str = found[0]
ST: ir.Type = found[1]
ClassName = CN
StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None
if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName):
ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx")
ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx")
Gen._store(ctx_val, ctx_alloca)
Gen._UnregisterTempPtr(ctx_val)
if ClassName:
Gen.var_struct_class['__with_ctx'] = ClassName
Gen._var_to_heap_ptr['__with_ctx'] = ctx_val
original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None
ctx_is_var_ref: bool = isinstance(context_expr, ast.Name)
enter_result: ir.Value | None = None
if ClassName:
# 沿继承链查找 __enter__(子类可能未覆写,使用父类实现)
enter_class, enter_func = self._ResolveInheritedMethod(ClassName, '__enter__', Gen)
if enter_func is not None:
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
# 父类方法需要 self 为父类指针类型,bitcast 子类指针。
# bitcast 目标用 enter_func 签名参数类型(args[0] 本身即
# MemManager* 指针),避免 Gen.structs 查找返回 opaque/异
# sha1 占位对象导致 llvmlite 类型不匹配。
if enter_class != ClassName:
parent_ptr_type: ir.Type = enter_func.function_type.args[0]
if ctx_Loaded.type != parent_ptr_type:
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_enter_self")
enter_call: ir.CallInstr = Gen.builder.call(enter_func, [ctx_Loaded], name="call_enter")
enter_result = enter_call
if isinstance(enter_call.type, ir.PointerType):
pointee: ir.Type = enter_call.type.pointee
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
enter_result = Gen._load(enter_call, name="enter_deref")
elif self._is_char_pointer(enter_call) and StructPtrType:
enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter")
if asname and enter_result:
if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee)
if found:
CN: str = found[0]
ST: ir.Type = found[1]
Gen.var_struct_class[asname] = CN
Gen._var_to_heap_ptr[asname] = enter_result
Gen._register_local_heap_ptr(enter_result, VarName=asname)
if asname in Gen._reg_values:
OldVal: ir.Value = Gen._reg_values[asname]
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname)
Gen._store(OldVal, var)
Gen.variables[asname] = var
del Gen._reg_values[asname]
if asname in Gen.variables and Gen.variables[asname] is not None:
VarPtr: ir.Value = Gen.variables[asname]
if VarPtr.type.pointee == enter_result.type:
Gen._store(enter_result, VarPtr)
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}")
Gen._store(CastedVal, VarPtr)
else:
NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname)
Gen._store(enter_result, NewVar)
Gen.variables[asname] = NewVar
else:
Gen._reg_values[asname] = enter_result
Gen.variables[asname] = None
# 如果类有 __provides__,自动生成 push 代码
if ClassName and ClassName in Gen.class_provides:
# 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32)
# _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈
current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack)
new_fields: int = len(Gen.class_provides[ClassName])
if current_depth + new_fields > 32:
raise SyntaxError(
f"[TransPyC] with provider stack overflow at line {Node.lineno}: "
f"current depth {current_depth} + new {new_fields} fields > max 32. "
f"Class '{ClassName}' provides too many fields or with nesting too deep."
)
# 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查
Gen._with_provides_stack.append(Gen.class_provides[ClassName])
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
ctx_i8: ir.Value = ctx_Loaded
if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)):
ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8")
for field_name in Gen.class_provides[ClassName]:
field_str: ir.Value = Gen._create_string_global(field_name)
push_func = Gen.functions.get('_push_provider')
if push_func:
Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider")
self.Trans.VarScopes.append({})
if asname:
self.Trans.VarScopes[-1][asname] = True
self.HandleBodyLlvm(Node.body)
if self.Trans.VarScopes:
self.Trans.VarScopes.pop()
# 如果类有 __provides__,自动生成 pop 代码
if ClassName and ClassName in Gen.class_provides:
for _ in Gen.class_provides[ClassName]:
pop_func = Gen.functions.get('_pop_provider')
if pop_func:
Gen.builder.call(pop_func, [], name="call_pop_provider")
# 编译期弹栈
if Gen._with_provides_stack:
Gen._with_provides_stack.pop()
if ClassName:
# 沿继承链查找 __exit__(子类可能未覆写,使用父类实现)
exit_class, exit_func = self._ResolveInheritedMethod(ClassName, '__exit__', Gen)
if exit_func is not None:
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
# 父类方法需要 self 为父类指针类型,bitcast 子类指针(同上)
if exit_class != ClassName:
parent_ptr_type: ir.Type = exit_func.function_type.args[0]
if ctx_Loaded.type != parent_ptr_type:
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_exit_self")
Gen.builder.call(exit_func, [ctx_Loaded], name="call_exit")
Gen._unregister_local_heap_ptr(original_ctx_val)
if ctx_val is not original_ctx_val:
Gen._unregister_local_heap_ptr(ctx_val)
if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val:
Gen._unregister_local_heap_ptr(original_asname_heap_ptr)
if '__with_ctx' in Gen._var_to_heap_ptr:
del Gen._var_to_heap_ptr['__with_ctx']
if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int")
enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int")
same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check")
with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx")
with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free")
Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb)
Gen.builder.position_at_start(with_free_bb)
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
Gen.builder.call(free_func, [raw])
Gen.builder.branch(with_skip_bb)
Gen.builder.position_at_start(with_skip_bb)
Gen._unregister_local_heap_ptr(enter_result)
Gen._unregister_local_heap_ptr(original_ctx_val)
elif isinstance(ctx_val.type, ir.PointerType):
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
Gen.builder.call(free_func, [raw])
Gen._unregister_local_heap_ptr(original_ctx_val)
+842 -842
View File
File diff suppressed because it is too large. Load diff
+557 -557
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+301 -301
View File
@@ -1,301 +1,301 @@
"""LLVMTypeMapper — AST 注解节点到 LLVM IR 类型字符串的映射器
从 SymbolTable 中提取的类型解析逻辑,职责单一:
将 Python AST 注解节点翻译为 LLVM IR 类型字符串(如 'i32', 'i8*', '{ i32, i8* }')。
原 SymbolTable 上的 4 个方法:
- _GetLLVMTypeStr → LLVMTypeMapper.get_llvm_type_str
- _GetFuncRetTypeStr → LLVMTypeMapper.get_func_ret_type_str
- _GetFuncParamTypeStr → LLVMTypeMapper.get_func_param_type_str
- _ResolveTypedefValueType → LLVMTypeMapper.resolve_typedef_value_type
"""
from __future__ import annotations
import ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
from lib.includes import t as _t
from lib.includes.t import CTypeRegistry
class LLVMTypeMapper:
"""AST 注解节点 → LLVM IR 类型字符串 映射器"""
def __init__(self, symtab: SymbolTable):
self._symtab = symtab
# ==================================================================
# 公共 API
# ==================================================================
def get_llvm_type_str(self, node: ast.AST | None) -> str:
"""将 AST 注解节点转换为 LLVM IR 类型字符串"""
if node is None:
self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32")
return 'i32'
if isinstance(node, ast.Name):
return self._resolve_name(node)
elif isinstance(node, ast.Attribute):
return self._resolve_attribute(node)
elif isinstance(node, ast.Subscript):
return self._resolve_subscript(node)
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
return self._resolve_bitor(node)
elif isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return 'i8'
return 'i32'
elif isinstance(node, ast.Call):
return self._resolve_call(node)
self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32")
return 'i32'
def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str:
"""提取函数返回类型的 LLVM 字符串"""
if returns_node is None:
return 'i32'
if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr):
left_str: str = self.get_llvm_type_str(returns_node.left)
right_str: str = self.get_llvm_type_str(returns_node.right)
if right_str and right_str.endswith('*'):
return right_str
if left_str and left_str.endswith('*'):
return left_str
if left_str and left_str not in ('i32', 'void', 'i64'):
return left_str
if right_str and right_str not in ('i32', 'void', 'i64'):
return right_str
return left_str
result: str = self.get_llvm_type_str(returns_node)
return result if result else 'i32'
def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str:
"""提取函数参数类型的 LLVM 字符串"""
if annotation_node is None:
return 'i8*'
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
left_str: str = self.get_llvm_type_str(annotation_node.left)
right_str: str = self.get_llvm_type_str(annotation_node.right)
if right_str and right_str.endswith('*'):
return right_str
if left_str and left_str.endswith('*'):
return left_str
if right_str and right_str not in ('i32', 'void', 'i64'):
return right_str
if left_str and left_str not in ('i32', 'void', 'i64'):
return left_str
return right_str if right_str else left_str
result: str = self.get_llvm_type_str(annotation_node)
return result if result else 'i8*'
def resolve_typedef_value_type(self, node: ast.AST | None) -> str:
"""解析 typedef 值表达式的 C 类型字符串"""
if node is None:
return ''
if isinstance(node, ast.Name):
if node.id in self._symtab:
Entry: CTypeInfo = self._symtab[node.id]
if Entry.IsTypedef and Entry.OriginalType:
return Entry.OriginalType
return ''
if isinstance(node, ast.Attribute):
if isinstance(node.value, ast.Name) and IsTModule(node.value.id):
# 直接判断属性名是否为 CPtr(消除对 CName=='*' 的依赖)
if node.attr == 'CPtr':
return 'ptr'
CName: str | None = CTypeHelper.GetCName(node.attr)
if CName == 'CPtr':
return 'ptr'
if CName:
return CName
return ''
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_str: str = self.resolve_typedef_value_type(node.left)
right_str: str = self.resolve_typedef_value_type(node.right)
if right_str == 'ptr' or (right_str and right_str.endswith('*')):
base: str = left_str if left_str and left_str != 'ptr' else ''
return base + ' *' if base else 'void *'
if left_str == 'ptr' or (left_str and left_str.endswith('*')):
base: str = right_str if right_str and right_str != 'ptr' else ''
return base + ' *' if base else 'void *'
if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'):
return right_str
if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'):
return left_str
return left_str if left_str else right_str
return ''
# ==================================================================
# 内部解析方法
# ==================================================================
def _ctype_to_llvm_str(self, info: CTypeInfo) -> str:
"""从 CTypeInfo 的 BaseType+PtrCount 生成归一化的 LLVM 类型字符串。
void* 在 LLVM IR 中归一化为 i8*;struct/enum/union 等非基础类型返回空字符串。
"""
if not info or not info.BaseType:
return ''
base_type = info.BaseType
base_llvm: str = ''
if isinstance(base_type, type) and issubclass(base_type, _t.CType):
base_llvm = CTypeRegistry.CTypeToLLVM(base_type)
elif isinstance(base_type, _t.CType):
base_llvm = CTypeRegistry.CTypeToLLVM(type(base_type))
if not base_llvm:
return ''
if info.PtrCount > 0:
if base_llvm == 'void':
return 'i8*'
return base_llvm + '*' * info.PtrCount
return base_llvm
def _ctype_str_to_llvm(self, type_str: str) -> str:
"""将 C 类型名字符串(如 'CUnsignedInt *')转换为 LLVM 类型字符串(如 'i32*')
支持:
- C 类名:'CUnsignedInt' → 'i32','CChar' → 'i8'
- 指针:'CUnsignedInt *' → 'i32*','void *' → 'i8*'
- 已是 LLVM 类型:'i32' → 'i32','i8*' → 'i8*'
无法识别返回空字符串。
"""
s: str = type_str.strip()
ptr_count: int = 0
while s.endswith('*'):
ptr_count += 1
s = s[:-1].strip()
base_llvm: str = ''
if s in ('void', 'CVoid'):
base_llvm = 'void'
else:
base_llvm = CTypeRegistry.NameToLLVM(s)
if not base_llvm and s in ('i8', 'i16', 'i32', 'i64', 'float', 'double', 'half', 'fp128', 'void'):
base_llvm = s
if not base_llvm:
return ''
if ptr_count > 0:
if base_llvm == 'void':
return 'i8*'
return base_llvm + '*' * ptr_count
return base_llvm
def _resolve_name(self, node: ast.Name) -> str:
"""解析 ast.Name 节点"""
id_map: dict[str, str] = {
'str': 'i8*', 'int': 'i32', 'bool': 'i8',
'float': 'double', 'None': 'void',
'UINT8PTR': 'i8*', 'INT8PTR': 'i8*', 'BYTEPTR': 'i8*',
'UINT16PTR': 'i16*', 'INT16PTR': 'i16*',
'UINT32PTR': 'i32*', 'INT32PTR': 'i32*',
'UINT64PTR': 'i64*', 'INT64PTR': 'i64*',
}
if node.id in id_map:
return id_map[node.id]
# 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名
builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id)
if builtin_entry:
TypeClass: type
base_ptr: int
TypeClass, base_ptr = builtin_entry
base_llvm: str = CTypeRegistry.CTypeToLLVM(TypeClass)
if base_ptr > 0:
if base_llvm == 'void':
return 'i8*'
return base_llvm + '*' * base_ptr
return base_llvm if base_llvm else 'i32'
# 查找 SymbolTable 中的 typedef
if node.id in self._symtab:
entry: CTypeInfo = self._symtab[node.id]
if entry and entry.IsTypedef:
# 优先用 OriginalType 解析
if entry.OriginalType:
if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr:
return 'i8*'
elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType:
# 用 CTypeRegistry 生成归一化 LLVM 字符串(void*→i8*),struct/enum 回退 ToString()
resolved: str = self._ctype_to_llvm_str(entry.OriginalType)
if resolved:
return resolved
return entry.OriginalType.ToString()
elif isinstance(entry.OriginalType, str):
# 字符串形式的 OriginalType(如 'CUnsignedInt *')需转换为 LLVM 类型字符串
llvm_str: str = self._ctype_str_to_llvm(entry.OriginalType)
if llvm_str:
return llvm_str
# OriginalType 为空或字符串无法转换时,回退到 BaseType
if entry.BaseType and (not isinstance(entry.BaseType, (_t._CTypedef,)) or entry.PtrCount > 0):
resolved = self._ctype_to_llvm_str(entry)
if resolved:
return resolved
self._symtab.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}',回退到 i32")
return 'i32'
def _resolve_attribute(self, node: ast.Attribute) -> str:
"""解析 ast.Attribute 节点"""
attr_name: str = node.attr if hasattr(node, 'attr') else ''
llvm_str: str | None = CTypeRegistry.NameToLLVM(attr_name)
if llvm_str is not None:
return llvm_str
if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'):
return ''
if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'):
return 'i8*'
if attr_name == 'CVoidPtr':
return 'i8*'
if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class:
return f'%struct.{attr_name}*'
if attr_name and attr_name not in CTypeRegistry._name_to_class:
return f'%struct.{attr_name}*'
self._symtab.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}',回退到 i32")
return 'i32'
def _resolve_subscript(self, node: ast.Subscript) -> str:
"""解析 ast.Subscript 节点"""
if isinstance(node.value, ast.Name) and node.value.id == 'tuple':
slice_node: ast.AST = node.slice
elem_types: list[str] = []
if isinstance(slice_node, ast.Tuple):
elt: ast.AST
for elt in slice_node.elts:
elem_types.append(self.get_llvm_type_str(elt))
else:
elem_types.append(self.get_llvm_type_str(slice_node))
if elem_types:
return '{ ' + ', '.join(elem_types) + ' }'
if IsListAnnotation(node):
slice_node: ast.AST = node.slice
elem_type: str
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
elem_type = self.get_llvm_type_str(slice_node.elts[0])
else:
elem_type = self.get_llvm_type_str(slice_node)
return elem_type + '*'
self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32")
return 'i32'
def _resolve_bitor(self, node: ast.BinOp) -> str:
"""解析 ast.BinOp(BitOr) 节点"""
left: str = self.get_llvm_type_str(node.left)
right: str = self.get_llvm_type_str(node.right)
if right and right.endswith('*'):
return right
if left and left.endswith('*'):
return left
if left and left not in ('i32', 'void', 'i64'):
return left
if right and right not in ('i32', 'void', 'i64'):
return right
return left if left else right
def _resolve_call(self, node: ast.Call) -> str:
"""解析 ast.Call 节点"""
if isinstance(node.func, ast.Attribute):
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id):
return self.get_llvm_type_str(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr))
self._symtab.diagnostics.warn('', 0, "无法解析 Call 类型,回退到 i32")
return 'i32'
"""LLVMTypeMapper — AST 注解节点到 LLVM IR 类型字符串的映射器
从 SymbolTable 中提取的类型解析逻辑,职责单一:
将 Python AST 注解节点翻译为 LLVM IR 类型字符串(如 'i32', 'i8*', '{ i32, i8* }')。
原 SymbolTable 上的 4 个方法:
- _GetLLVMTypeStr → LLVMTypeMapper.get_llvm_type_str
- _GetFuncRetTypeStr → LLVMTypeMapper.get_func_ret_type_str
- _GetFuncParamTypeStr → LLVMTypeMapper.get_func_param_type_str
- _ResolveTypedefValueType → LLVMTypeMapper.resolve_typedef_value_type
"""
from __future__ import annotations
import vast as ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
from lib.includes import t as _t
from lib.includes.t import CTypeRegistry
class LLVMTypeMapper:
"""AST 注解节点 → LLVM IR 类型字符串 映射器"""
def __init__(self, symtab: SymbolTable):
self._symtab = symtab
# ==================================================================
# 公共 API
# ==================================================================
def get_llvm_type_str(self, node: ast.AST | None) -> str:
"""将 AST 注解节点转换为 LLVM IR 类型字符串"""
if node is None:
self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32")
return 'i32'
if isinstance(node, ast.Name):
return self._resolve_name(node)
elif isinstance(node, ast.Attribute):
return self._resolve_attribute(node)
elif isinstance(node, ast.Subscript):
return self._resolve_subscript(node)
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
return self._resolve_bitor(node)
elif isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return 'i8'
return 'i32'
elif isinstance(node, ast.Call):
return self._resolve_call(node)
self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32")
return 'i32'
def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str:
"""提取函数返回类型的 LLVM 字符串"""
if returns_node is None:
return 'i32'
if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr):
left_str: str = self.get_llvm_type_str(returns_node.left)
right_str: str = self.get_llvm_type_str(returns_node.right)
if right_str and right_str.endswith('*'):
return right_str
if left_str and left_str.endswith('*'):
return left_str
if left_str and left_str not in ('i32', 'void', 'i64'):
return left_str
if right_str and right_str not in ('i32', 'void', 'i64'):
return right_str
return left_str
result: str = self.get_llvm_type_str(returns_node)
return result if result else 'i32'
def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str:
"""提取函数参数类型的 LLVM 字符串"""
if annotation_node is None:
return 'i8*'
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
left_str: str = self.get_llvm_type_str(annotation_node.left)
right_str: str = self.get_llvm_type_str(annotation_node.right)
if right_str and right_str.endswith('*'):
return right_str
if left_str and left_str.endswith('*'):
return left_str
if right_str and right_str not in ('i32', 'void', 'i64'):
return right_str
if left_str and left_str not in ('i32', 'void', 'i64'):
return left_str
return right_str if right_str else left_str
result: str = self.get_llvm_type_str(annotation_node)
return result if result else 'i8*'
def resolve_typedef_value_type(self, node: ast.AST | None) -> str:
"""解析 typedef 值表达式的 C 类型字符串"""
if node is None:
return ''
if isinstance(node, ast.Name):
if node.id in self._symtab:
Entry: CTypeInfo = self._symtab[node.id]
if Entry.IsTypedef and Entry.OriginalType:
return Entry.OriginalType
return ''
if isinstance(node, ast.Attribute):
if isinstance(node.value, ast.Name) and IsTModule(node.value.id):
# 直接判断属性名是否为 CPtr(消除对 CName=='*' 的依赖)
if node.attr == 'CPtr':
return 'ptr'
CName: str | None = CTypeHelper.GetCName(node.attr)
if CName == 'CPtr':
return 'ptr'
if CName:
return CName
return ''
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_str: str = self.resolve_typedef_value_type(node.left)
right_str: str = self.resolve_typedef_value_type(node.right)
if right_str == 'ptr' or (right_str and right_str.endswith('*')):
base: str = left_str if left_str and left_str != 'ptr' else ''
return base + ' *' if base else 'void *'
if left_str == 'ptr' or (left_str and left_str.endswith('*')):
base: str = right_str if right_str and right_str != 'ptr' else ''
return base + ' *' if base else 'void *'
if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'):
return right_str
if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'):
return left_str
return left_str if left_str else right_str
return ''
# ==================================================================
# 内部解析方法
# ==================================================================
def _ctype_to_llvm_str(self, info: CTypeInfo) -> str:
"""从 CTypeInfo 的 BaseType+PtrCount 生成归一化的 LLVM 类型字符串。
void* 在 LLVM IR 中归一化为 i8*;struct/enum/union 等非基础类型返回空字符串。
"""
if not info or not info.BaseType:
return ''
base_type = info.BaseType
base_llvm: str = ''
if isinstance(base_type, type) and issubclass(base_type, _t.CType):
base_llvm = CTypeRegistry.CTypeToLLVM(base_type)
elif isinstance(base_type, _t.CType):
base_llvm = CTypeRegistry.CTypeToLLVM(type(base_type))
if not base_llvm:
return ''
if info.PtrCount > 0:
if base_llvm == 'void':
return 'i8*'
return base_llvm + '*' * info.PtrCount
return base_llvm
def _ctype_str_to_llvm(self, type_str: str) -> str:
"""将 C 类型名字符串(如 'CUnsignedInt *')转换为 LLVM 类型字符串(如 'i32*')
支持:
- C 类名:'CUnsignedInt' → 'i32','CChar' → 'i8'
- 指针:'CUnsignedInt *' → 'i32*','void *' → 'i8*'
- 已是 LLVM 类型:'i32' → 'i32','i8*' → 'i8*'
无法识别返回空字符串。
"""
s: str = type_str.strip()
ptr_count: int = 0
while s.endswith('*'):
ptr_count += 1
s = s[:-1].strip()
base_llvm: str = ''
if s in ('void', 'CVoid'):
base_llvm = 'void'
else:
base_llvm = CTypeRegistry.NameToLLVM(s)
if not base_llvm and s in ('i8', 'i16', 'i32', 'i64', 'float', 'double', 'half', 'fp128', 'void'):
base_llvm = s
if not base_llvm:
return ''
if ptr_count > 0:
if base_llvm == 'void':
return 'i8*'
return base_llvm + '*' * ptr_count
return base_llvm
def _resolve_name(self, node: ast.Name) -> str:
"""解析 ast.Name 节点"""
id_map: dict[str, str] = {
'str': 'i8*', 'int': 'i32', 'bool': 'i8',
'float': 'double', 'None': 'void',
'UINT8PTR': 'i8*', 'INT8PTR': 'i8*', 'BYTEPTR': 'i8*',
'UINT16PTR': 'i16*', 'INT16PTR': 'i16*',
'UINT32PTR': 'i32*', 'INT32PTR': 'i32*',
'UINT64PTR': 'i64*', 'INT64PTR': 'i64*',
}
if node.id in id_map:
return id_map[node.id]
# 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名
builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id)
if builtin_entry:
TypeClass: type
base_ptr: int
TypeClass, base_ptr = builtin_entry
base_llvm: str = CTypeRegistry.CTypeToLLVM(TypeClass)
if base_ptr > 0:
if base_llvm == 'void':
return 'i8*'
return base_llvm + '*' * base_ptr
return base_llvm if base_llvm else 'i32'
# 查找 SymbolTable 中的 typedef
if node.id in self._symtab:
entry: CTypeInfo = self._symtab[node.id]
if entry and entry.IsTypedef:
# 优先用 OriginalType 解析
if entry.OriginalType:
if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr:
return 'i8*'
elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType:
# 用 CTypeRegistry 生成归一化 LLVM 字符串(void*→i8*),struct/enum 回退 ToString()
resolved: str = self._ctype_to_llvm_str(entry.OriginalType)
if resolved:
return resolved
return entry.OriginalType.ToString()
elif isinstance(entry.OriginalType, str):
# 字符串形式的 OriginalType(如 'CUnsignedInt *')需转换为 LLVM 类型字符串
llvm_str: str = self._ctype_str_to_llvm(entry.OriginalType)
if llvm_str:
return llvm_str
# OriginalType 为空或字符串无法转换时,回退到 BaseType
if entry.BaseType and (not isinstance(entry.BaseType, (_t._CTypedef,)) or entry.PtrCount > 0):
resolved = self._ctype_to_llvm_str(entry)
if resolved:
return resolved
self._symtab.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}',回退到 i32")
return 'i32'
def _resolve_attribute(self, node: ast.Attribute) -> str:
"""解析 ast.Attribute 节点"""
attr_name: str = node.attr if hasattr(node, 'attr') else ''
llvm_str: str | None = CTypeRegistry.NameToLLVM(attr_name)
if llvm_str is not None:
return llvm_str
if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'):
return ''
if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'):
return 'i8*'
if attr_name == 'CVoidPtr':
return 'i8*'
if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class:
return f'%struct.{attr_name}*'
if attr_name and attr_name not in CTypeRegistry._name_to_class:
return f'%struct.{attr_name}*'
self._symtab.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}',回退到 i32")
return 'i32'
def _resolve_subscript(self, node: ast.Subscript) -> str:
"""解析 ast.Subscript 节点"""
if isinstance(node.value, ast.Name) and node.value.id == 'tuple':
slice_node: ast.AST = node.slice
elem_types: list[str] = []
if isinstance(slice_node, ast.Tuple):
elt: ast.AST
for elt in slice_node.elts:
elem_types.append(self.get_llvm_type_str(elt))
else:
elem_types.append(self.get_llvm_type_str(slice_node))
if elem_types:
return '{ ' + ', '.join(elem_types) + ' }'
if IsListAnnotation(node):
slice_node: ast.AST = node.slice
elem_type: str
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
elem_type = self.get_llvm_type_str(slice_node.elts[0])
else:
elem_type = self.get_llvm_type_str(slice_node)
return elem_type + '*'
self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32")
return 'i32'
def _resolve_bitor(self, node: ast.BinOp) -> str:
"""解析 ast.BinOp(BitOr) 节点"""
left: str = self.get_llvm_type_str(node.left)
right: str = self.get_llvm_type_str(node.right)
if right and right.endswith('*'):
return right
if left and left.endswith('*'):
return left
if left and left not in ('i32', 'void', 'i64'):
return left
if right and right not in ('i32', 'void', 'i64'):
return right
return left if left else right
def _resolve_call(self, node: ast.Call) -> str:
"""解析 ast.Call 节点"""
if isinstance(node.func, ast.Attribute):
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id):
return self.get_llvm_type_str(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr))
self._symtab.diagnostics.warn('', 0, "无法解析 Call 类型,回退到 i32")
return 'i32'
+85 -85
View File
@@ -1,85 +1,85 @@
"""符号表处理的数据结构:四阶段管线中传递的中间数据"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Tuple, TYPE_CHECKING
import ast
if TYPE_CHECKING:
from lib.core.Handles.HandlesBase import CTypeInfo
@dataclass
class ClassSymbolData:
"""从 AST 提取的类符号数据"""
name: str
type_kind: str # 'struct', 'union', 'enum', 'exception'
lineno: int
members: Dict[str, CTypeInfo]
is_cpython_object: bool = False
is_packed: bool = False
enum_members: List[Tuple[str, int, int]] = field(default_factory=list) # (name, value, lineno)
@dataclass
class TypedefSymbolData:
"""Typedef 符号数据(含原始注解和解析结果)"""
name: str
lineno: int
# 原始注解数据(由 Extractor 设置,Resolver 使用)
annotation: ast.expr | None = None
value: ast.expr | int | str | float | None = None
has_cdefine: bool = False
has_postdef: bool = False
has_ctypedef: bool = False
# 解析结果(由 Resolver 设置,Inserter 使用)
original_type_kind: Optional[str] = None
original_class: type | None = None
members: Optional[Dict] = None
@dataclass
class FuncSymbolData:
"""函数符号数据(含原始注解和解析结果)"""
name: str
lineno: int
# 原始数据(由 Extractor 设置)
returns_node: ast.expr | None = None
params: List = field(default_factory=list) # [(name, annotation_node), ...]
is_variadic: bool = False
is_inline: bool = False
# 解析结果(由 Resolver 设置)
ret_type: str | None = None
param_types: List = field(default_factory=list) # [str, ...]
# 解析结果(CTypeInfo,保留符号性,由 Resolver 设置)
ret_ctype: Optional[CTypeInfo] = None
@dataclass
class DefineSymbolData:
"""Define 符号数据(含原始值和解析结果)"""
name: str
lineno: int
# 原始数据(由 Extractor 设置)
value_node: ast.expr | None = None
# 解析结果(由 Resolver 设置)
value: int | str | float | None = None
@dataclass
class AnonymousTypeData:
"""匿名类型数据"""
name: str
is_union: bool
members: Dict[str, CTypeInfo]
lineno: int
@dataclass
class ModuleSymbols:
"""从模块提取的完整符号数据,在四阶段管线中传递"""
file_path: str
classes: List[ClassSymbolData] = field(default_factory=list)
typedefs: List[TypedefSymbolData] = field(default_factory=list)
functions: List[FuncSymbolData] = field(default_factory=list)
defines: List[DefineSymbolData] = field(default_factory=list)
anonymous_types: Dict[str, AnonymousTypeData] = field(default_factory=dict)
"""符号表处理的数据结构:四阶段管线中传递的中间数据"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Tuple, TYPE_CHECKING
import vast as ast
if TYPE_CHECKING:
from lib.core.Handles.HandlesBase import CTypeInfo
@dataclass
class ClassSymbolData:
"""从 AST 提取的类符号数据"""
name: str
type_kind: str # 'struct', 'union', 'enum', 'exception'
lineno: int
members: Dict[str, CTypeInfo]
is_cpython_object: bool = False
is_packed: bool = False
enum_members: List[Tuple[str, int, int]] = field(default_factory=list) # (name, value, lineno)
@dataclass
class TypedefSymbolData:
"""Typedef 符号数据(含原始注解和解析结果)"""
name: str
lineno: int
# 原始注解数据(由 Extractor 设置,Resolver 使用)
annotation: ast.expr | None = None
value: ast.expr | int | str | float | None = None
has_cdefine: bool = False
has_postdef: bool = False
has_ctypedef: bool = False
# 解析结果(由 Resolver 设置,Inserter 使用)
original_type_kind: Optional[str] = None
original_class: type | None = None
members: Optional[Dict] = None
@dataclass
class FuncSymbolData:
"""函数符号数据(含原始注解和解析结果)"""
name: str
lineno: int
# 原始数据(由 Extractor 设置)
returns_node: ast.expr | None = None
params: List = field(default_factory=list) # [(name, annotation_node), ...]
is_variadic: bool = False
is_inline: bool = False
# 解析结果(由 Resolver 设置)
ret_type: str | None = None
param_types: List = field(default_factory=list) # [str, ...]
# 解析结果(CTypeInfo,保留符号性,由 Resolver 设置)
ret_ctype: Optional[CTypeInfo] = None
@dataclass
class DefineSymbolData:
"""Define 符号数据(含原始值和解析结果)"""
name: str
lineno: int
# 原始数据(由 Extractor 设置)
value_node: ast.expr | None = None
# 解析结果(由 Resolver 设置)
value: int | str | float | None = None
@dataclass
class AnonymousTypeData:
"""匿名类型数据"""
name: str
is_union: bool
members: Dict[str, CTypeInfo]
lineno: int
@dataclass
class ModuleSymbols:
"""从模块提取的完整符号数据,在四阶段管线中传递"""
file_path: str
classes: List[ClassSymbolData] = field(default_factory=list)
typedefs: List[TypedefSymbolData] = field(default_factory=list)
functions: List[FuncSymbolData] = field(default_factory=list)
defines: List[DefineSymbolData] = field(default_factory=list)
anonymous_types: Dict[str, AnonymousTypeData] = field(default_factory=dict)
+307 -307
View File
@@ -1,307 +1,307 @@
"""Pass 1: ASTSymbolExtractor — 从 AST 提取原始符号信息"""
from __future__ import annotations
import ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolData import (
ModuleSymbols, ClassSymbolData, TypedefSymbolData,
FuncSymbolData, DefineSymbolData, AnonymousTypeData
)
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline, IsTModule, AnnotationContainsName
from lib.includes import t
class ASTSymbolExtractor:
"""从 Python 源文件的 AST 中提取所有符号信息"""
def __init__(self, symbol_table: SymbolTable) -> None:
self._symtab: SymbolTable = symbol_table
def extract(self, file_path: str) -> ModuleSymbols:
"""提取文件中的所有符号信息"""
with open(file_path, 'r', encoding='utf-8') as f:
code: str = f.read()
tree: ast.Module = ast.parse(code)
result: ModuleSymbols = ModuleSymbols(file_path=file_path)
# 第一步:收集所有类的成员和匿名类型
class_members: dict[str, dict[str, CTypeInfo]] = {}
for node in tree.body:
if isinstance(node, ast.ClassDef):
members: dict[str, CTypeInfo] = {}
self._collect_members(node, members, result.anonymous_types)
class_members[node.name] = members
# 第二步:从每个顶层节点提取符号信息
for node in tree.body:
if isinstance(node, ast.ClassDef):
members_info: dict[str, CTypeInfo] = class_members.get(node.name, {})
result.classes.append(self._extract_class(node, members_info))
elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
self._extract_ann_assign(node, result)
elif isinstance(node, ast.FunctionDef):
result.functions.append(self._extract_function(node))
return result
# ------------------------------------------------------------------
# 成员收集(递归处理嵌套匿名类)
# ------------------------------------------------------------------
def _collect_members(self, class_node: ast.ClassDef, members: dict[str, CTypeInfo], anonymous_types: dict[str, AnonymousTypeData], prefix: str = '') -> None:
"""递归收集类成员,包括嵌套匿名类型"""
for item in class_node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
member_name: str = item.target.id
full_name: str = f'{prefix}{member_name}' if prefix else member_name
member_type: CTypeInfo | None = CTypeInfo.FromNode(item.annotation, self._symtab)
if member_type is None:
member_type = CTypeInfo()
member_type.BaseType = t.CInt()
is_ptr: bool = member_type.IsPtr
if isinstance(item.annotation, ast.BinOp):
if AnnotationContainsName(item.annotation, 'CPtr'):
is_ptr = True
members[full_name] = member_type.Copy()
elif isinstance(item, ast.ClassDef):
is_anonymous: bool = any(
any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases)
) if item.bases else False
if is_anonymous:
is_union: bool = any(
any(AnnotationContainsTType(base, 'CUnion') for base in item.bases)
)
# 也检查装饰器形式 @t.CUnion
if not is_union and hasattr(item, 'decorator_list') and item.decorator_list:
for deco in item.decorator_list:
if isinstance(deco, ast.Attribute) and hasattr(deco.value, 'id') and IsTModule(deco.value.id, self._symtab) and deco.attr == 'CUnion':
is_union = True
break
elif isinstance(deco, ast.Name):
cls2: type | None = getattr(t, deco.id, None)
if cls2 is None and hasattr(self._symtab, '_t_type_symbols'):
cls2 = self._symtab._t_type_symbols.get(deco.id)
if cls2 is not None and isinstance(cls2, type) and issubclass(cls2, t.CUnion):
is_union = True
break
nested_name: str = f'{prefix}{item.name}' if prefix else item.name
members[nested_name] = CTypeInfo()
members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}'
members[nested_name].PtrCount = 0
members[nested_name].ArrayDims = []
new_prefix: str = f'{prefix}{item.name}.' if prefix else f'{item.name}.'
self._collect_members(item, members, anonymous_types, new_prefix)
anonymous_members: dict[str, CTypeInfo] = {}
for full_name, member_info in members.items():
if full_name.startswith(f"{nested_name}."):
member_name: str = full_name[len(nested_name) + 1:]
anonymous_members[member_name] = member_info
if item.name not in anonymous_types:
anonymous_types[item.name] = AnonymousTypeData(
name=item.name,
is_union=is_union,
members=anonymous_members,
lineno=item.lineno
)
# ------------------------------------------------------------------
# 类符号提取
# ------------------------------------------------------------------
def _extract_class(self, node: ast.ClassDef, members_info: dict[str, CTypeInfo]) -> ClassSymbolData:
"""从 ClassDef 节点提取类符号数据"""
type_kind: str = 'struct'
is_cpython_object: bool = False
is_packed: bool = False
# 检查装饰器
if hasattr(node, 'decorator_list') and node.decorator_list:
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute):
if (hasattr(decorator.value, 'id') and
IsTModule(decorator.value.id, self._symtab)):
if decorator.attr == 'Object':
is_cpython_object = True
elif decorator.attr == 'CUnion':
type_kind = 'union'
elif decorator.attr == 'CEnum':
type_kind = 'enum'
elif decorator.attr == 'REnum':
type_kind = 'renum'
elif decorator.attr == 'CStruct':
type_kind = 'struct'
elif isinstance(decorator, ast.Name):
# from t import CStruct / CUnion / CEnum / REnum
cls: type | None = getattr(t, decorator.id, None)
if cls is None and hasattr(self._symtab, '_t_type_symbols'):
cls = self._symtab._t_type_symbols.get(decorator.id)
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
if issubclass(cls, t.CUnion):
type_kind = 'union'
elif issubclass(cls, t.REnum):
type_kind = 'renum'
elif issubclass(cls, t.CEnum):
type_kind = 'enum'
elif issubclass(cls, t.CStruct):
type_kind = 'struct'
elif decorator.id == 'Object':
is_cpython_object = True
elif isinstance(decorator, ast.Call):
if isinstance(decorator.func, ast.Attribute):
if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute':
for arg in decorator.args:
if isinstance(arg, ast.Attribute):
if isinstance(arg.value, ast.Attribute):
if hasattr(arg.value.value, 'id') and IsTModule(arg.value.value.id, self._symtab) and arg.value.attr == 'attr' and arg.attr == 'packed':
is_packed = True
# 检查基类
for base in node.bases:
if AnnotationContainsTType(base, 'CUnion'):
type_kind = 'union'
break
elif AnnotationContainsTType(base, 'CEnum'):
type_kind = 'enum'
break
elif AnnotationContainsTType(base, 'REnum'):
type_kind = 'renum'
break
elif AnnotationContainsTType(base, 'CStruct'):
type_kind = 'struct'
break
elif AnnotationContainsTType(base, 'Object'):
is_cpython_object = True
type_kind = 'struct'
break
elif isinstance(base, ast.Name) and base.id == 'Exception':
type_kind = 'exception'
break
elif isinstance(base, ast.Name):
base_entry: CTypeInfo | None = self._symtab.get(base.id)
if base_entry and base_entry.IsExceptionClass:
type_kind = 'exception'
break
# 提取枚举成员
enum_members: list[tuple[str, int, int]] = []
if type_kind == 'enum':
next_enum_value: int = 0
for item in node.body:
if isinstance(item, ast.Assign):
if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name):
member_name: str = item.targets[0].id
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
next_enum_value = item.value.value + 1
else:
next_enum_value += 1
enum_members.append((member_name, next_enum_value - 1, item.lineno))
elif isinstance(item, ast.AnnAssign):
if isinstance(item.target, ast.Name):
member_name: str = item.target.id
if item.value:
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
next_enum_value = item.value.value + 1
else:
next_enum_value += 1
else:
next_enum_value += 1
enum_members.append((member_name, next_enum_value - 1, item.lineno))
# REnum 变体提取(嵌套 ClassDef + Assign 显式值)
# 与 HandlesClassDef._EmitREnumLlvm 的 tag 分配逻辑对齐:
# - 先收集 Assign 显式值
# - ClassDef 变体从 max(explicit)+1 开始顺序编号
# - Assign 无显式值时用独立计数器 variant_index
if type_kind == 'renum':
explicit_values: dict[str, int] = {}
for item in node.body:
if isinstance(item, ast.Assign):
for target in item.targets:
if isinstance(target, ast.Name):
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
explicit_values[target.id] = item.value.value
next_class_tag: int = max(explicit_values.values()) + 1 if explicit_values else 0
variant_index: int = 0
for item in node.body:
if isinstance(item, ast.ClassDef):
variant_name_r: str = item.name
tag: int = next_class_tag
next_class_tag += 1
enum_members.append((variant_name_r, tag, item.lineno))
elif isinstance(item, ast.Assign):
for target in item.targets:
if isinstance(target, ast.Name):
var_name: str = target.id
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
value: int = item.value.value
else:
value = variant_index
variant_index += 1
enum_members.append((var_name, value, item.lineno))
return ClassSymbolData(
name=node.name,
type_kind=type_kind,
lineno=node.lineno,
members=members_info,
is_cpython_object=is_cpython_object,
is_packed=is_packed,
enum_members=enum_members,
)
# ------------------------------------------------------------------
# AnnAssign 提取(typedef / define)
# ------------------------------------------------------------------
def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None:
"""从 AnnAssign 节点提取 typedef 或 define 数据"""
var_name: str = node.target.id
has_cdefine: bool = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False
has_postdef: bool = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False
has_ctypedef: bool = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False
if has_cdefine:
result.defines.append(DefineSymbolData(
name=var_name,
lineno=node.lineno,
value_node=node.value,
))
else:
result.typedefs.append(TypedefSymbolData(
name=var_name,
lineno=node.lineno,
annotation=node.annotation,
value=node.value,
has_cdefine=has_cdefine,
has_postdef=has_postdef,
has_ctypedef=has_ctypedef,
))
# ------------------------------------------------------------------
# 函数提取
# ------------------------------------------------------------------
def _extract_function(self, node: ast.FunctionDef) -> FuncSymbolData:
"""从 FunctionDef 节点提取函数符号数据"""
params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args]
is_variadic: bool = node.args.vararg is not None
is_inline: bool = CheckAnnotationHasCInline(node.returns)
return FuncSymbolData(
name=node.name,
lineno=node.lineno,
returns_node=node.returns,
params=params,
is_variadic=is_variadic,
is_inline=is_inline,
)
"""Pass 1: ASTSymbolExtractor — 从 AST 提取原始符号信息"""
from __future__ import annotations
import vast as ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolData import (
ModuleSymbols, ClassSymbolData, TypedefSymbolData,
FuncSymbolData, DefineSymbolData, AnonymousTypeData
)
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline, IsTModule, AnnotationContainsName
from lib.includes import t
class ASTSymbolExtractor:
"""从 Python 源文件的 AST 中提取所有符号信息"""
def __init__(self, symbol_table: SymbolTable) -> None:
self._symtab: SymbolTable = symbol_table
def extract(self, file_path: str) -> ModuleSymbols:
"""提取文件中的所有符号信息"""
with open(file_path, 'r', encoding='utf-8') as f:
code: str = f.read()
tree: ast.Module = ast.parse(code)
result: ModuleSymbols = ModuleSymbols(file_path=file_path)
# 第一步:收集所有类的成员和匿名类型
class_members: dict[str, dict[str, CTypeInfo]] = {}
for node in tree.body:
if isinstance(node, ast.ClassDef):
members: dict[str, CTypeInfo] = {}
self._collect_members(node, members, result.anonymous_types)
class_members[node.name] = members
# 第二步:从每个顶层节点提取符号信息
for node in tree.body:
if isinstance(node, ast.ClassDef):
members_info: dict[str, CTypeInfo] = class_members.get(node.name, {})
result.classes.append(self._extract_class(node, members_info))
elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
self._extract_ann_assign(node, result)
elif isinstance(node, ast.FunctionDef):
result.functions.append(self._extract_function(node))
return result
# ------------------------------------------------------------------
# 成员收集(递归处理嵌套匿名类)
# ------------------------------------------------------------------
def _collect_members(self, class_node: ast.ClassDef, members: dict[str, CTypeInfo], anonymous_types: dict[str, AnonymousTypeData], prefix: str = '') -> None:
"""递归收集类成员,包括嵌套匿名类型"""
for item in class_node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
member_name: str = item.target.id
full_name: str = f'{prefix}{member_name}' if prefix else member_name
member_type: CTypeInfo | None = CTypeInfo.FromNode(item.annotation, self._symtab)
if member_type is None:
member_type = CTypeInfo()
member_type.BaseType = t.CInt()
is_ptr: bool = member_type.IsPtr
if isinstance(item.annotation, ast.BinOp):
if AnnotationContainsName(item.annotation, 'CPtr'):
is_ptr = True
members[full_name] = member_type.Copy()
elif isinstance(item, ast.ClassDef):
is_anonymous: bool = any(
any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases)
) if item.bases else False
if is_anonymous:
is_union: bool = any(
any(AnnotationContainsTType(base, 'CUnion') for base in item.bases)
)
# 也检查装饰器形式 @t.CUnion
if not is_union and hasattr(item, 'decorator_list') and item.decorator_list:
for deco in item.decorator_list:
if isinstance(deco, ast.Attribute) and hasattr(deco.value, 'id') and IsTModule(deco.value.id, self._symtab) and deco.attr == 'CUnion':
is_union = True
break
elif isinstance(deco, ast.Name):
cls2: type | None = getattr(t, deco.id, None)
if cls2 is None and hasattr(self._symtab, '_t_type_symbols'):
cls2 = self._symtab._t_type_symbols.get(deco.id)
if cls2 is not None and isinstance(cls2, type) and issubclass(cls2, t.CUnion):
is_union = True
break
nested_name: str = f'{prefix}{item.name}' if prefix else item.name
members[nested_name] = CTypeInfo()
members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}'
members[nested_name].PtrCount = 0
members[nested_name].ArrayDims = []
new_prefix: str = f'{prefix}{item.name}.' if prefix else f'{item.name}.'
self._collect_members(item, members, anonymous_types, new_prefix)
anonymous_members: dict[str, CTypeInfo] = {}
for full_name, member_info in members.items():
if full_name.startswith(f"{nested_name}."):
member_name: str = full_name[len(nested_name) + 1:]
anonymous_members[member_name] = member_info
if item.name not in anonymous_types:
anonymous_types[item.name] = AnonymousTypeData(
name=item.name,
is_union=is_union,
members=anonymous_members,
lineno=item.lineno
)
# ------------------------------------------------------------------
# 类符号提取
# ------------------------------------------------------------------
def _extract_class(self, node: ast.ClassDef, members_info: dict[str, CTypeInfo]) -> ClassSymbolData:
"""从 ClassDef 节点提取类符号数据"""
type_kind: str = 'struct'
is_cpython_object: bool = False
is_packed: bool = False
# 检查装饰器
if hasattr(node, 'decorator_list') and node.decorator_list:
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute):
if (hasattr(decorator.value, 'id') and
IsTModule(decorator.value.id, self._symtab)):
if decorator.attr == 'Object':
is_cpython_object = True
elif decorator.attr == 'CUnion':
type_kind = 'union'
elif decorator.attr == 'CEnum':
type_kind = 'enum'
elif decorator.attr == 'REnum':
type_kind = 'renum'
elif decorator.attr == 'CStruct':
type_kind = 'struct'
elif isinstance(decorator, ast.Name):
# from t import CStruct / CUnion / CEnum / REnum
cls: type | None = getattr(t, decorator.id, None)
if cls is None and hasattr(self._symtab, '_t_type_symbols'):
cls = self._symtab._t_type_symbols.get(decorator.id)
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
if issubclass(cls, t.CUnion):
type_kind = 'union'
elif issubclass(cls, t.REnum):
type_kind = 'renum'
elif issubclass(cls, t.CEnum):
type_kind = 'enum'
elif issubclass(cls, t.CStruct):
type_kind = 'struct'
elif decorator.id == 'Object':
is_cpython_object = True
elif isinstance(decorator, ast.Call):
if isinstance(decorator.func, ast.Attribute):
if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute':
for arg in decorator.args:
if isinstance(arg, ast.Attribute):
if isinstance(arg.value, ast.Attribute):
if hasattr(arg.value.value, 'id') and IsTModule(arg.value.value.id, self._symtab) and arg.value.attr == 'attr' and arg.attr == 'packed':
is_packed = True
# 检查基类
for base in node.bases:
if AnnotationContainsTType(base, 'CUnion'):
type_kind = 'union'
break
elif AnnotationContainsTType(base, 'CEnum'):
type_kind = 'enum'
break
elif AnnotationContainsTType(base, 'REnum'):
type_kind = 'renum'
break
elif AnnotationContainsTType(base, 'CStruct'):
type_kind = 'struct'
break
elif AnnotationContainsTType(base, 'Object'):
is_cpython_object = True
type_kind = 'struct'
break
elif isinstance(base, ast.Name) and base.id == 'Exception':
type_kind = 'exception'
break
elif isinstance(base, ast.Name):
base_entry: CTypeInfo | None = self._symtab.get(base.id)
if base_entry and base_entry.IsExceptionClass:
type_kind = 'exception'
break
# 提取枚举成员
enum_members: list[tuple[str, int, int]] = []
if type_kind == 'enum':
next_enum_value: int = 0
for item in node.body:
if isinstance(item, ast.Assign):
if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name):
member_name: str = item.targets[0].id
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
next_enum_value = item.value.value + 1
else:
next_enum_value += 1
enum_members.append((member_name, next_enum_value - 1, item.lineno))
elif isinstance(item, ast.AnnAssign):
if isinstance(item.target, ast.Name):
member_name: str = item.target.id
if item.value:
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
next_enum_value = item.value.value + 1
else:
next_enum_value += 1
else:
next_enum_value += 1
enum_members.append((member_name, next_enum_value - 1, item.lineno))
# REnum 变体提取(嵌套 ClassDef + Assign 显式值)
# 与 HandlesClassDef._EmitREnumLlvm 的 tag 分配逻辑对齐:
# - 先收集 Assign 显式值
# - ClassDef 变体从 max(explicit)+1 开始顺序编号
# - Assign 无显式值时用独立计数器 variant_index
if type_kind == 'renum':
explicit_values: dict[str, int] = {}
for item in node.body:
if isinstance(item, ast.Assign):
for target in item.targets:
if isinstance(target, ast.Name):
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
explicit_values[target.id] = item.value.value
next_class_tag: int = max(explicit_values.values()) + 1 if explicit_values else 0
variant_index: int = 0
for item in node.body:
if isinstance(item, ast.ClassDef):
variant_name_r: str = item.name
tag: int = next_class_tag
next_class_tag += 1
enum_members.append((variant_name_r, tag, item.lineno))
elif isinstance(item, ast.Assign):
for target in item.targets:
if isinstance(target, ast.Name):
var_name: str = target.id
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
value: int = item.value.value
else:
value = variant_index
variant_index += 1
enum_members.append((var_name, value, item.lineno))
return ClassSymbolData(
name=node.name,
type_kind=type_kind,
lineno=node.lineno,
members=members_info,
is_cpython_object=is_cpython_object,
is_packed=is_packed,
enum_members=enum_members,
)
# ------------------------------------------------------------------
# AnnAssign 提取(typedef / define)
# ------------------------------------------------------------------
def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None:
"""从 AnnAssign 节点提取 typedef 或 define 数据"""
var_name: str = node.target.id
has_cdefine: bool = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False
has_postdef: bool = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False
has_ctypedef: bool = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False
if has_cdefine:
result.defines.append(DefineSymbolData(
name=var_name,
lineno=node.lineno,
value_node=node.value,
))
else:
result.typedefs.append(TypedefSymbolData(
name=var_name,
lineno=node.lineno,
annotation=node.annotation,
value=node.value,
has_cdefine=has_cdefine,
has_postdef=has_postdef,
has_ctypedef=has_ctypedef,
))
# ------------------------------------------------------------------
# 函数提取
# ------------------------------------------------------------------
def _extract_function(self, node: ast.FunctionDef) -> FuncSymbolData:
"""从 FunctionDef 节点提取函数符号数据"""
params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args]
is_variadic: bool = node.args.vararg is not None
is_inline: bool = CheckAnnotationHasCInline(node.returns)
return FuncSymbolData(
name=node.name,
lineno=node.lineno,
returns_node=node.returns,
params=params,
is_variadic=is_variadic,
is_inline=is_inline,
)
+531 -531
View File
File diff suppressed because it is too large. Load diff
+272 -272
View File
@@ -1,272 +1,272 @@
"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值"""
from __future__ import annotations
import ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolData import (
ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData
)
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
from lib.core.LLVMTypeMapper import LLVMTypeMapper
from lib.core.SymbolUtils import IsTModule
from lib.includes import t
class TypeResolver:
"""解析从 AST 提取的原始符号中的类型信息"""
def __init__(self, symbol_table: SymbolTable):
self._symtab = symbol_table
self._type_mapper = LLVMTypeMapper(symbol_table)
# 本模块内已解析的 typedef: name → original_class(供同模块 typedef 间引用解析)
self._resolved_typedefs: dict[str, str | None] = {}
def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols:
"""解析所有类型信息,就地更新 ModuleSymbols"""
# 构建 class_members 查找表(typedef Postdefinition 需要)
class_members: dict[str, dict[str, CTypeInfo]] = {cls.name: cls.members for cls in module_symbols.classes}
# 解析 typedef(按顺序记录,供后续 typedef 引用同模块已解析的 typedef)
td: TypedefSymbolData
for td in module_symbols.typedefs:
self._resolve_typedef(td, class_members)
self._resolved_typedefs[td.name] = td.original_class
# 解析函数签名
func: FuncSymbolData
for func in module_symbols.functions:
self._resolve_function(func)
# 解析 define 值
define: DefineSymbolData
for define in module_symbols.defines:
self._resolve_define(define)
return module_symbols
# ------------------------------------------------------------------
# Typedef 解析
# ------------------------------------------------------------------
def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
"""解析单个 typedef 的类型信息"""
is_postdef_with_typedef: bool = td.has_postdef and td.has_ctypedef
if is_postdef_with_typedef:
self._resolve_postdef_typedef(td, class_members)
elif td.has_ctypedef:
self._resolve_ctypedef_typedef(td)
else:
# 无特殊注解的 typedef
td.original_type_kind = None
td.original_class = None
def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
"""解析 Postdefinition + CTypedef 组合注解"""
original_class: str | None = self._find_postdef_arg(td.annotation)
if original_class and original_class in class_members:
members_info: dict[str, CTypeInfo] = class_members[original_class]
original_type_kind: str = 'struct'
if original_class in self._symtab:
orig_type_info: CTypeInfo = self._symtab[original_class]
if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion):
if orig_type_info.type_cls is t.CStruct:
original_type_kind = 'struct'
elif orig_type_info.type_cls is t.CEnum:
original_type_kind = 'enum'
elif orig_type_info.type_cls is t.CUnion:
original_type_kind = 'union'
td.original_type_kind = original_type_kind
td.original_class = original_class
td.members = members_info
else:
td.original_type_kind = None
td.original_class = None
def _resolve_ctypedef_typedef(self, td: TypedefSymbolData):
"""解析 CTypedef 注解"""
base_type_name: str | None = self._find_base_type(td.annotation)
_TYPE_QUALIFIERS: frozenset[str] = frozenset({'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'})
if base_type_name == 'Callable':
original_type: CTypeInfo = CTypeInfo()
original_type.IsFuncPtr = True
original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
original_type.FuncPtrParams = []
td.original_type_kind = 'typedef'
td.original_class = original_type
elif base_type_name and base_type_name not in _TYPE_QUALIFIERS:
cname: str | None = CTypeHelper.GetCName(base_type_name)
if cname:
td.original_class = cname
else:
td.original_class = base_type_name
td.original_type_kind = 'typedef'
else:
# 尝试从值表达式解析
self._resolve_typedef_from_value(td)
def _resolve_typedef_from_value(self, td: TypedefSymbolData):
"""从值表达式解析 typedef 类型
BinOp(如 UINT | t.CPtr)优先于 _find_base_type 处理,
因为 _find_base_type 是静态方法无法解析 Name 引用(如 UINT)。
"""
if not td.value:
td.original_type_kind = None
td.original_class = None
return
# 优先处理 BinOp(_find_base_type 无法解析 Name 引用)
if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr):
left_type: str = self._resolve_type_expr(td.value.left)
right_type: str = self._resolve_type_expr(td.value.right)
is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr'
if is_ptr_type:
base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '')
original_type: str = (base_name + ' *') if base_name else 'void *'
td.original_class = original_type
td.original_type_kind = 'typedef'
elif left_type:
td.original_class = left_type
td.original_type_kind = 'typedef'
elif right_type:
td.original_class = right_type
td.original_type_kind = 'typedef'
else:
td.original_type_kind = None
td.original_class = None
return
# 非 BinOp:使用 _find_base_type
value_base_type: str | None = self._find_base_type(td.value)
_PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'})
if value_base_type and value_base_type not in _PTR_MODIFIERS:
cname: str | None = CTypeHelper.GetCName(value_base_type)
if cname:
td.original_class = cname
else:
td.original_class = value_base_type
td.original_type_kind = 'typedef'
return
if isinstance(td.value, ast.Name):
ref_name: str = td.value.id
# 先查本模块已解析的 typedef
if ref_name in self._resolved_typedefs:
ref_class: str | None = self._resolved_typedefs[ref_name]
if ref_class:
td.original_class = ref_class
td.original_type_kind = 'typedef'
return
# 再查 symtab(跨模块)
if ref_name in self._symtab:
ref_info: CTypeInfo = self._symtab[ref_name]
if ref_info and ref_info.IsTypedef and ref_info.OriginalType:
td.original_class = ref_info.OriginalType
td.original_type_kind = 'typedef'
return
td.original_type_kind = None
td.original_class = None
def _resolve_type_expr(self, node: ast.AST) -> str:
"""解析类型表达式为 C 类型名字符串,优先查本模块已解析的 typedef
解决同模块 typedef 间引用(如 UINTPTR = UINT | t.CPtr 中的 UINT)
在 TypeResolver 阶段尚未插入 symtab 的问题。
"""
if isinstance(node, ast.Name):
if node.id in self._resolved_typedefs:
return self._resolved_typedefs[node.id] or ''
return self._type_mapper.resolve_typedef_value_type(node)
# ------------------------------------------------------------------
# 函数签名解析
# ------------------------------------------------------------------
def _resolve_function(self, func: FuncSymbolData):
"""解析函数的返回类型和参数类型"""
func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node)
# 同时解析为 CTypeInfo,保留符号性(LLVM 类型字符串 'i64' 不区分有无符号)
if func.returns_node is not None:
try:
func.ret_ctype = CTypeInfo.FromNode(func.returns_node, self._symtab)
except Exception:
func.ret_ctype = None
func.param_types = []
_arg_name: str
annotation: ast.expr | None
for _arg_name, annotation in func.params:
if annotation:
func.param_types.append(self._type_mapper.get_func_param_type_str(annotation))
else:
func.param_types.append('i8*')
# ------------------------------------------------------------------
# Define 值解析
# ------------------------------------------------------------------
def _resolve_define(self, define: DefineSymbolData):
"""解析 define 常量值"""
if define.value_node:
define.value = self._symtab._eval_const_expr(define.value_node)
# ------------------------------------------------------------------
# 静态工具方法(原 _LoadSymbolsFromFile 中的闭包)
# ------------------------------------------------------------------
@staticmethod
def _find_base_type(node: ast.AST | None) -> str | None:
"""从注解 AST 节点中查找基础类型名称"""
if isinstance(node, ast.Attribute):
if hasattr(node.value, 'id') and IsTModule(node.value.id):
if node.attr == 'CPtr':
return 'ptr'
return node.attr
elif isinstance(node, ast.Subscript):
if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and IsTModule(node.value.value.id) and node.value.attr == 'Callable':
return 'Callable'
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_result: str | None = TypeResolver._find_base_type(node.left)
if left_result == 'ptr':
right_result: str | None = TypeResolver._find_base_type(node.right)
return (right_result if right_result and right_result != 'ptr' else 'void') + ' *'
if left_result == 'Callable':
return 'Callable'
right_result: str | None = TypeResolver._find_base_type(node.right)
if right_result == 'ptr':
return (left_result if left_result and left_result != 'ptr' else 'void') + ' *'
if right_result == 'Callable':
return 'Callable'
# 类型拼接语义:CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong
long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'})
if left_result in long_types and right_result in long_types:
if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong':
return 'CUnsignedLongLong'
return 'CLongLong'
if left_result:
return left_result
if right_result:
return right_result
return None
@staticmethod
def _find_postdef_arg(node: ast.AST | None) -> str | None:
"""从注解 AST 节点中查找 Postdefinition 参数"""
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id) and node.func.attr == 'Postdefinition':
if node.args and isinstance(node.args[0], ast.Name):
return node.args[0].id
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_result: str | None = TypeResolver._find_postdef_arg(node.left)
if left_result:
return left_result
right_result: str | None = TypeResolver._find_postdef_arg(node.right)
if right_result:
return right_result
return None
"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值"""
from __future__ import annotations
import vast as ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolData import (
ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData
)
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
from lib.core.LLVMTypeMapper import LLVMTypeMapper
from lib.core.SymbolUtils import IsTModule
from lib.includes import t
class TypeResolver:
"""解析从 AST 提取的原始符号中的类型信息"""
def __init__(self, symbol_table: SymbolTable):
self._symtab = symbol_table
self._type_mapper = LLVMTypeMapper(symbol_table)
# 本模块内已解析的 typedef: name → original_class(供同模块 typedef 间引用解析)
self._resolved_typedefs: dict[str, str | None] = {}
def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols:
"""解析所有类型信息,就地更新 ModuleSymbols"""
# 构建 class_members 查找表(typedef Postdefinition 需要)
class_members: dict[str, dict[str, CTypeInfo]] = {cls.name: cls.members for cls in module_symbols.classes}
# 解析 typedef(按顺序记录,供后续 typedef 引用同模块已解析的 typedef)
td: TypedefSymbolData
for td in module_symbols.typedefs:
self._resolve_typedef(td, class_members)
self._resolved_typedefs[td.name] = td.original_class
# 解析函数签名
func: FuncSymbolData
for func in module_symbols.functions:
self._resolve_function(func)
# 解析 define 值
define: DefineSymbolData
for define in module_symbols.defines:
self._resolve_define(define)
return module_symbols
# ------------------------------------------------------------------
# Typedef 解析
# ------------------------------------------------------------------
def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
"""解析单个 typedef 的类型信息"""
is_postdef_with_typedef: bool = td.has_postdef and td.has_ctypedef
if is_postdef_with_typedef:
self._resolve_postdef_typedef(td, class_members)
elif td.has_ctypedef:
self._resolve_ctypedef_typedef(td)
else:
# 无特殊注解的 typedef
td.original_type_kind = None
td.original_class = None
def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
"""解析 Postdefinition + CTypedef 组合注解"""
original_class: str | None = self._find_postdef_arg(td.annotation)
if original_class and original_class in class_members:
members_info: dict[str, CTypeInfo] = class_members[original_class]
original_type_kind: str = 'struct'
if original_class in self._symtab:
orig_type_info: CTypeInfo = self._symtab[original_class]
if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion):
if orig_type_info.type_cls is t.CStruct:
original_type_kind = 'struct'
elif orig_type_info.type_cls is t.CEnum:
original_type_kind = 'enum'
elif orig_type_info.type_cls is t.CUnion:
original_type_kind = 'union'
td.original_type_kind = original_type_kind
td.original_class = original_class
td.members = members_info
else:
td.original_type_kind = None
td.original_class = None
def _resolve_ctypedef_typedef(self, td: TypedefSymbolData):
"""解析 CTypedef 注解"""
base_type_name: str | None = self._find_base_type(td.annotation)
_TYPE_QUALIFIERS: frozenset[str] = frozenset({'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'})
if base_type_name == 'Callable':
original_type: CTypeInfo = CTypeInfo()
original_type.IsFuncPtr = True
original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
original_type.FuncPtrParams = []
td.original_type_kind = 'typedef'
td.original_class = original_type
elif base_type_name and base_type_name not in _TYPE_QUALIFIERS:
cname: str | None = CTypeHelper.GetCName(base_type_name)
if cname:
td.original_class = cname
else:
td.original_class = base_type_name
td.original_type_kind = 'typedef'
else:
# 尝试从值表达式解析
self._resolve_typedef_from_value(td)
def _resolve_typedef_from_value(self, td: TypedefSymbolData):
"""从值表达式解析 typedef 类型
BinOp(如 UINT | t.CPtr)优先于 _find_base_type 处理,
因为 _find_base_type 是静态方法无法解析 Name 引用(如 UINT)。
"""
if not td.value:
td.original_type_kind = None
td.original_class = None
return
# 优先处理 BinOp(_find_base_type 无法解析 Name 引用)
if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr):
left_type: str = self._resolve_type_expr(td.value.left)
right_type: str = self._resolve_type_expr(td.value.right)
is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr'
if is_ptr_type:
base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '')
original_type: str = (base_name + ' *') if base_name else 'void *'
td.original_class = original_type
td.original_type_kind = 'typedef'
elif left_type:
td.original_class = left_type
td.original_type_kind = 'typedef'
elif right_type:
td.original_class = right_type
td.original_type_kind = 'typedef'
else:
td.original_type_kind = None
td.original_class = None
return
# 非 BinOp:使用 _find_base_type
value_base_type: str | None = self._find_base_type(td.value)
_PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'})
if value_base_type and value_base_type not in _PTR_MODIFIERS:
cname: str | None = CTypeHelper.GetCName(value_base_type)
if cname:
td.original_class = cname
else:
td.original_class = value_base_type
td.original_type_kind = 'typedef'
return
if isinstance(td.value, ast.Name):
ref_name: str = td.value.id
# 先查本模块已解析的 typedef
if ref_name in self._resolved_typedefs:
ref_class: str | None = self._resolved_typedefs[ref_name]
if ref_class:
td.original_class = ref_class
td.original_type_kind = 'typedef'
return
# 再查 symtab(跨模块)
if ref_name in self._symtab:
ref_info: CTypeInfo = self._symtab[ref_name]
if ref_info and ref_info.IsTypedef and ref_info.OriginalType:
td.original_class = ref_info.OriginalType
td.original_type_kind = 'typedef'
return
td.original_type_kind = None
td.original_class = None
def _resolve_type_expr(self, node: ast.AST) -> str:
"""解析类型表达式为 C 类型名字符串,优先查本模块已解析的 typedef
解决同模块 typedef 间引用(如 UINTPTR = UINT | t.CPtr 中的 UINT)
在 TypeResolver 阶段尚未插入 symtab 的问题。
"""
if isinstance(node, ast.Name):
if node.id in self._resolved_typedefs:
return self._resolved_typedefs[node.id] or ''
return self._type_mapper.resolve_typedef_value_type(node)
# ------------------------------------------------------------------
# 函数签名解析
# ------------------------------------------------------------------
def _resolve_function(self, func: FuncSymbolData):
"""解析函数的返回类型和参数类型"""
func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node)
# 同时解析为 CTypeInfo,保留符号性(LLVM 类型字符串 'i64' 不区分有无符号)
if func.returns_node is not None:
try:
func.ret_ctype = CTypeInfo.FromNode(func.returns_node, self._symtab)
except Exception:
func.ret_ctype = None
func.param_types = []
_arg_name: str
annotation: ast.expr | None
for _arg_name, annotation in func.params:
if annotation:
func.param_types.append(self._type_mapper.get_func_param_type_str(annotation))
else:
func.param_types.append('i8*')
# ------------------------------------------------------------------
# Define 值解析
# ------------------------------------------------------------------
def _resolve_define(self, define: DefineSymbolData):
"""解析 define 常量值"""
if define.value_node:
define.value = self._symtab._eval_const_expr(define.value_node)
# ------------------------------------------------------------------
# 静态工具方法(原 _LoadSymbolsFromFile 中的闭包)
# ------------------------------------------------------------------
@staticmethod
def _find_base_type(node: ast.AST | None) -> str | None:
"""从注解 AST 节点中查找基础类型名称"""
if isinstance(node, ast.Attribute):
if hasattr(node.value, 'id') and IsTModule(node.value.id):
if node.attr == 'CPtr':
return 'ptr'
return node.attr
elif isinstance(node, ast.Subscript):
if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and IsTModule(node.value.value.id) and node.value.attr == 'Callable':
return 'Callable'
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_result: str | None = TypeResolver._find_base_type(node.left)
if left_result == 'ptr':
right_result: str | None = TypeResolver._find_base_type(node.right)
return (right_result if right_result and right_result != 'ptr' else 'void') + ' *'
if left_result == 'Callable':
return 'Callable'
right_result: str | None = TypeResolver._find_base_type(node.right)
if right_result == 'ptr':
return (left_result if left_result and left_result != 'ptr' else 'void') + ' *'
if right_result == 'Callable':
return 'Callable'
# 类型拼接语义:CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong
long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'})
if left_result in long_types and right_result in long_types:
if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong':
return 'CUnsignedLongLong'
return 'CLongLong'
if left_result:
return left_result
if right_result:
return right_result
return None
@staticmethod
def _find_postdef_arg(node: ast.AST | None) -> str | None:
"""从注解 AST 节点中查找 Postdefinition 参数"""
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id) and node.func.attr == 'Postdefinition':
if node.args and isinstance(node.args[0], ast.Name):
return node.args[0].id
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_result: str | None = TypeResolver._find_postdef_arg(node.left)
if left_result:
return left_result
right_result: str | None = TypeResolver._find_postdef_arg(node.right)
if right_result:
return right_result
return None
+233 -233
View File
@@ -1,233 +1,233 @@
"""共享工具函数:符号表处理中使用的 AST 分析工具"""
from __future__ import annotations
import ast
import re
from lib.includes import t
_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__})
# Viper 软关键字 fn/fun/func/function 是 def 的别名(行首 + 空白 + 标识符才算函数定义,
# 变量名/调用/注解中的 fn 不受影响)。展开为 def 后行号不变,供 ast.parse 使用。
_SOFT_KEYWORD_RE: re.Pattern[str] = re.compile(
r'^(\s*)(function|func|fun|fn)(\s+)(?=[A-Za-z_])', re.MULTILINE
)
def ExpandSoftKeywords(Code: str) -> str:
"""将 Viper 软关键字 fn/fun/func/function 展开为 def(函数定义行)。
仅在"行首缩进 + 关键字 + 空白 + 标识符"的函数定义形态匹配,
变量名(fn = 5)、调用(fn(x))、注解(x: fn)与字符串内容不受影响。
展开为 def 与关键字等宽或更短,行号不变,AST 行号映射保持有效。
"""
if not Code:
return Code
return _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code)
def IsTModule(module_id: str, symtable: object | None = None) -> bool:
"""检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)"""
if module_id in _T_MODULE_NAMES:
return True
if symtable is not None and hasattr(symtable, 'import_aliases'):
resolved: str = symtable.import_aliases.get(module_id, module_id)
if resolved in _T_MODULE_NAMES:
return True
return False
def IsTModulePath(module_path: str) -> bool:
"""检查模块路径是否指向 t 类型模块"""
if module_path in _T_MODULE_NAMES:
return True
if module_path:
t_name: str
for t_name in _T_MODULE_NAMES:
if module_path == t_name or module_path.startswith(t_name + '.'):
return True
return False
def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool:
"""检测 AST 节点中是否包含指定名称的 t 模块类型"""
if isinstance(node, ast.Attribute):
if (hasattr(node.value, 'id') and IsTModule(node.value.id) and
node.attr == TypeName):
return True
elif isinstance(node, ast.BinOp):
return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName)
elif isinstance(node, ast.Call):
if AnnotationContainsTType(node.func, TypeName):
return True
for arg in node.args:
if AnnotationContainsTType(arg, TypeName):
return True
elif isinstance(node, ast.Subscript):
if AnnotationContainsTType(node.value, TypeName):
return True
if AnnotationContainsTType(node.slice, TypeName):
return True
return False
def IsListAnnotation(annotation: ast.expr) -> bool:
"""检查注解是否为栈上固定数组类型(t.CArray[...] 或 list[type, count])"""
if not isinstance(annotation, ast.Subscript):
return False
value = annotation.value
# t.CArray[...]
if (isinstance(value, ast.Attribute)
and isinstance(value.value, ast.Name)
and value.value.id == 't'
and value.attr == 'CArray'):
return True
# list[type, count] — 仅匹配双参数 Tuple 切片(固定数组),
# 单参数 list[type] 不匹配(走泛型类 list[T] 路径)
if (isinstance(value, ast.Name)
and value.id == 'list'
and isinstance(annotation.slice, ast.Tuple)
and len(annotation.slice.elts) == 2):
return True
return False
def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None:
"""从 BinOp(BitOr) 注解中提取 list[...] 部分,如 list[i32] | t.CPtr"""
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
for side in (annotation.left, annotation.right):
if IsListAnnotation(side):
return side
return None
class ListAnnotationParseResult:
"""list[...] 注解解析结果。
is_pointer=True 表示单参数 list[type] → 指针模式;
is_pointer=False 表示 Tuple(2) 模式 list[type, count]。
"""
__slots__ = ('elem_type_node', 'count_node', 'is_pointer')
def __init__(self, elem_type_node: ast.expr, count_node: ast.expr | None, is_pointer: bool) -> None:
self.elem_type_node: ast.expr = elem_type_node
self.count_node: ast.expr | None = count_node
self.is_pointer: bool = is_pointer
def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None:
"""解析 list[...] 注解,统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。
自动处理 BinOp(BitOr) 包裹(如 list[i32, N] | t.CPtr)。
返回 None 表示不是 list 注解。
"""
list_node: ast.expr = annotation
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
extracted: ast.Subscript | None = ExtractListFromBinOp(annotation)
if extracted is None:
return None
list_node = extracted
if not IsListAnnotation(list_node):
return None
slice_node: ast.AST = list_node.slice
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False)
# 单参数 list[type] → 指针模式
return ListAnnotationParseResult(slice_node, None, is_pointer=True)
def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool:
"""检测注解节点中是否包含 CInline"""
if annotation_node is None:
return False
if isinstance(annotation_node, ast.Attribute):
if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline':
return True
if isinstance(annotation_node, ast.Name):
if annotation_node.id == 'CInline':
return True
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right)
return False
def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None:
"""从 BinOp(BitOr) 注解左侧提取类型名(如 TypeA | TypeB → TypeA)。
返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。
"""
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
left: ast.expr = annotation.left
if isinstance(left, ast.Name):
return left.id
if isinstance(left, ast.Attribute):
return left.attr
return None
def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None:
"""递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。
检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。
支持泛型特化类型(如 GSList[Param]),构造特化名后检查是否在 struct_names 中。
"""
if isinstance(node, ast.Name) and node.id in struct_names:
return node.id
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names:
return node.value
if isinstance(node, ast.Attribute) and node.attr in struct_names:
return node.attr
if isinstance(node, ast.Subscript):
base_name: str | None = None
if isinstance(node.value, ast.Name):
base_name = node.value.id
elif isinstance(node.value, ast.Attribute):
base_name = node.value.attr
if base_name:
slice_node: ast.AST = node.slice
if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index):
slice_node = slice_node.value
type_args: list[str] = []
if isinstance(slice_node, ast.Name):
type_args.append(slice_node.id)
elif isinstance(slice_node, ast.Attribute):
type_args.append(slice_node.attr)
elif isinstance(slice_node, ast.Tuple):
for elt in slice_node.elts:
if isinstance(elt, ast.Name):
type_args.append(elt.id)
elif isinstance(elt, ast.Attribute):
type_args.append(elt.attr)
if type_args:
spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
if spec_name in struct_names:
return spec_name
if base_name in struct_names:
return base_name
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
result: str | None = FindStructNameInAnnotation(node.left, struct_names)
if result:
return result
return FindStructNameInAnnotation(node.right, struct_names)
return None
def AnnotationContainsName(annotation: ast.AST, name: str) -> bool:
"""检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。
同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。
"""
if isinstance(annotation, ast.Attribute):
return annotation.attr == name
if isinstance(annotation, ast.Name):
return annotation.id == name
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name)
return False
def IsCPtrNode(node: ast.AST) -> bool:
"""检查节点是否为 t.CPtr 属性引用。"""
return (isinstance(node, ast.Attribute)
and isinstance(node.value, ast.Name)
and node.value.id == 't'
and node.attr == 'CPtr')
"""共享工具函数:符号表处理中使用的 AST 分析工具"""
from __future__ import annotations
import vast as ast
import re
from lib.includes import t
_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__})
# Viper 软关键字 fn/fun/func/function 是 def 的别名(行首 + 空白 + 标识符才算函数定义,
# 变量名/调用/注解中的 fn 不受影响)。展开为 def 后行号不变,供 ast.parse 使用。
_SOFT_KEYWORD_RE: re.Pattern[str] = re.compile(
r'^(\s*)(function|func|fun|fn)(\s+)(?=[A-Za-z_])', re.MULTILINE
)
def ExpandSoftKeywords(Code: str) -> str:
"""将 Viper 软关键字 fn/fun/func/function 展开为 def(函数定义行)。
仅在"行首缩进 + 关键字 + 空白 + 标识符"的函数定义形态匹配,
变量名(fn = 5)、调用(fn(x))、注解(x: fn)与字符串内容不受影响。
展开为 def 与关键字等宽或更短,行号不变,AST 行号映射保持有效。
"""
if not Code:
return Code
return _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code)
def IsTModule(module_id: str, symtable: object | None = None) -> bool:
"""检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)"""
if module_id in _T_MODULE_NAMES:
return True
if symtable is not None and hasattr(symtable, 'import_aliases'):
resolved: str = symtable.import_aliases.get(module_id, module_id)
if resolved in _T_MODULE_NAMES:
return True
return False
def IsTModulePath(module_path: str) -> bool:
"""检查模块路径是否指向 t 类型模块"""
if module_path in _T_MODULE_NAMES:
return True
if module_path:
t_name: str
for t_name in _T_MODULE_NAMES:
if module_path == t_name or module_path.startswith(t_name + '.'):
return True
return False
def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool:
"""检测 AST 节点中是否包含指定名称的 t 模块类型"""
if isinstance(node, ast.Attribute):
if (hasattr(node.value, 'id') and IsTModule(node.value.id) and
node.attr == TypeName):
return True
elif isinstance(node, ast.BinOp):
return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName)
elif isinstance(node, ast.Call):
if AnnotationContainsTType(node.func, TypeName):
return True
for arg in node.args:
if AnnotationContainsTType(arg, TypeName):
return True
elif isinstance(node, ast.Subscript):
if AnnotationContainsTType(node.value, TypeName):
return True
if AnnotationContainsTType(node.slice, TypeName):
return True
return False
def IsListAnnotation(annotation: ast.expr) -> bool:
"""检查注解是否为栈上固定数组类型(t.CArray[...] 或 list[type, count])"""
if not isinstance(annotation, ast.Subscript):
return False
value = annotation.value
# t.CArray[...]
if (isinstance(value, ast.Attribute)
and isinstance(value.value, ast.Name)
and value.value.id == 't'
and value.attr == 'CArray'):
return True
# list[type, count] — 仅匹配双参数 Tuple 切片(固定数组),
# 单参数 list[type] 不匹配(走泛型类 list[T] 路径)
if (isinstance(value, ast.Name)
and value.id == 'list'
and isinstance(annotation.slice, ast.Tuple)
and len(annotation.slice.elts) == 2):
return True
return False
def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None:
"""从 BinOp(BitOr) 注解中提取 list[...] 部分,如 list[i32] | t.CPtr"""
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
for side in (annotation.left, annotation.right):
if IsListAnnotation(side):
return side
return None
class ListAnnotationParseResult:
"""list[...] 注解解析结果。
is_pointer=True 表示单参数 list[type] → 指针模式;
is_pointer=False 表示 Tuple(2) 模式 list[type, count]。
"""
__slots__ = ('elem_type_node', 'count_node', 'is_pointer')
def __init__(self, elem_type_node: ast.expr, count_node: ast.expr | None, is_pointer: bool) -> None:
self.elem_type_node: ast.expr = elem_type_node
self.count_node: ast.expr | None = count_node
self.is_pointer: bool = is_pointer
def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None:
"""解析 list[...] 注解,统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。
自动处理 BinOp(BitOr) 包裹(如 list[i32, N] | t.CPtr)。
返回 None 表示不是 list 注解。
"""
list_node: ast.expr = annotation
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
extracted: ast.Subscript | None = ExtractListFromBinOp(annotation)
if extracted is None:
return None
list_node = extracted
if not IsListAnnotation(list_node):
return None
slice_node: ast.AST = list_node.slice
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False)
# 单参数 list[type] → 指针模式
return ListAnnotationParseResult(slice_node, None, is_pointer=True)
def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool:
"""检测注解节点中是否包含 CInline"""
if annotation_node is None:
return False
if isinstance(annotation_node, ast.Attribute):
if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline':
return True
if isinstance(annotation_node, ast.Name):
if annotation_node.id == 'CInline':
return True
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right)
return False
def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None:
"""从 BinOp(BitOr) 注解左侧提取类型名(如 TypeA | TypeB → TypeA)。
返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。
"""
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
left: ast.expr = annotation.left
if isinstance(left, ast.Name):
return left.id
if isinstance(left, ast.Attribute):
return left.attr
return None
def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None:
"""递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。
检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。
支持泛型特化类型(如 GSList[Param]),构造特化名后检查是否在 struct_names 中。
"""
if isinstance(node, ast.Name) and node.id in struct_names:
return node.id
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names:
return node.value
if isinstance(node, ast.Attribute) and node.attr in struct_names:
return node.attr
if isinstance(node, ast.Subscript):
base_name: str | None = None
if isinstance(node.value, ast.Name):
base_name = node.value.id
elif isinstance(node.value, ast.Attribute):
base_name = node.value.attr
if base_name:
slice_node: ast.AST = node.slice
if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index):
slice_node = slice_node.value
type_args: list[str] = []
if isinstance(slice_node, ast.Name):
type_args.append(slice_node.id)
elif isinstance(slice_node, ast.Attribute):
type_args.append(slice_node.attr)
elif isinstance(slice_node, ast.Tuple):
for elt in slice_node.elts:
if isinstance(elt, ast.Name):
type_args.append(elt.id)
elif isinstance(elt, ast.Attribute):
type_args.append(elt.attr)
if type_args:
spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
if spec_name in struct_names:
return spec_name
if base_name in struct_names:
return base_name
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
result: str | None = FindStructNameInAnnotation(node.left, struct_names)
if result:
return result
return FindStructNameInAnnotation(node.right, struct_names)
return None
def AnnotationContainsName(annotation: ast.AST, name: str) -> bool:
"""检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。
同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。
"""
if isinstance(annotation, ast.Attribute):
return annotation.attr == name
if isinstance(annotation, ast.Name):
return annotation.id == name
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name)
return False
def IsCPtrNode(node: ast.AST) -> bool:
"""检查节点是否为 t.CPtr 属性引用。"""
return (isinstance(node, ast.Attribute)
and isinstance(node.value, ast.Name)
and node.value.id == 't'
and node.attr == 'CPtr')
+1 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
import ast
import vast as ast
import os
import importlib
import types
+9 -9
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
import ast
import vast as ast
from typing import Any, Callable, Dict, TYPE_CHECKING
from lib.core.Exportable import Exportable
@@ -25,9 +25,9 @@ from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolNode import SymbolNode
from lib.constants.config import mode as _ConfigMode
from lib.core.VLogger import get_logger as _vlog
from lib.core.VLogger import get_logger as _vlog
def _StrictLog(logger: Callable[[str], None], msg: str) -> None:
"""在 strict 模式下记录异常日志"""
if _ConfigMode == "strict":
@@ -66,14 +66,14 @@ class BaseTranslatorMixin:
self.InClass: bool = False # 是否正在处理 class 定义
self._UserTypeModules: dict = {}
self._source_module_sig_files: dict = {}
self._global_function_default_args: dict = {}
self._global_function_default_args: dict = {}
self._global_function_param_names: dict = {}
self.exception_registry: dict = {}
self.exception_parents: dict = {}
self._next_exception_code: int = 100
# 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射
self.config: Any = None
self._ImportedModules: set[str] | None = None
self._next_exception_code: int = 100
# 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射
self.config: Any = None
self._ImportedModules: set[str] | None = None
self._t_c_imported_names: dict = {}
# 导出表
+1 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
import ast
import vast as ast
from typing import TYPE_CHECKING
import llvmlite.ir as ir
+1 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
import ast
import vast as ast
import re
import llvmlite.ir as ir
+1 -1
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
import ast
import vast as ast
import json
import struct
File diff suppressed because it is too large. Load diff