Some simple information syncing

This commit is contained in:
2026-07-28 21:08:58 +08:00
parent 1837339f69
commit 3633be1995
65 changed files with 1132 additions and 368581 deletions

View File

@@ -23,7 +23,18 @@ from StubGen import PythonToStubConverter
def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object]) -> None:
"""从 .pyi 文件中提取 CDefine 常量到 all_dc。文件不存在时静默跳过。"""
"""从 .pyi 文件中提取 CDefine 常量到 all_dc。文件不存在时静默跳过。
治本修复:原实现只支持 ast.Constant 和 float() 调用,
无法处理 t.CUnsignedLong(-11)ast.Call
FOREGROUND_GREEN | FOREGROUND_INTENSITYast.BinOp等复杂表达式。
现使用 ConstEvaluator.eval_full 统一求值,支持:
- ast.Constant: 简单常量 (0x0002)
- ast.Call: 类型构造 (t.CUnsignedLong(-11))
- ast.BinOp: 位运算 (FOREGROUND_RED | FOREGROUND_GREEN)
- ast.UnaryOp: 一元运算 (-11)
- ast.Name: 引用其他 CDefine 常量
"""
if not os.path.exists(pyi_path):
return
try:
@@ -31,16 +42,25 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object]) ->
_, tree = parse_python_file(pyi_path)
if tree is None:
return
# 治本修复:使用 ConstEvaluator 处理复杂表达式
# 创建 mock Gen 对象,其 _define_constants 指向 all_dc
# 使 ConstEvaluator 能查找同文件中已提取的常量(如 FOREGROUND_RED 引用 FOREGROUND_BLUE
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
class _MockGen:
"""轻量 mock仅提供 _define_constants 供 ConstEvaluator 查找"""
def __init__(self) -> None:
self._define_constants: dict[str, object] = all_dc
mock_gen: _MockGen = _MockGen()
ctx: EvalContext = EvalContext(Gen=mock_gen)
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
if AnnotationContainsName(node.annotation, 'CDefine') and node.value:
val = None
if isinstance(node.value, ast.Constant):
val = node.value.value
elif isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name) and node.value.func.id == 'float' and node.value.args and isinstance(node.value.args[0], ast.Constant):
val = node.value.args[0].value
if val is not None:
all_dc[f"{node.target.id}"] = val
val: object = ConstEvaluator.eval_full(node.value, ctx)
if val is not None and isinstance(val, (int, float, str)):
all_dc[node.target.id] = val
except Exception as e:
_vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e)

View File

@@ -477,16 +477,34 @@ class PythonToStubConverter:
lines.append(f'{IndentStr}@{DecoratorStr}')
# 构建参数列表
# 治本修复:原实现只遍历 node.args.args完全忽略 node.args.defaults
# 导致带默认值的参数(如 category: str = "")在 .pyi 中丢失默认值。
# 下游 DeclarationGenerator 据此生成 stub.ll 时,会因缺少默认参数而
# 生成参数数量不足的 declare进而造成调用方 ABI 不匹配崩溃。
# 修复:按 Python AST 语义defaults 从右向左对应 args 末尾的参数,
# 对有默认值的参数附加 '= <default_value>'。
params: list[str] = []
NumDefaults: int = len(node.args.defaults) if node.args.defaults else 0
DefaultsStart: int = len(node.args.args) - NumDefaults
for arg_idx, arg in enumerate(node.args.args):
ArgName: str = arg.arg
if arg.annotation:
TypeStr: str = PythonToStubConverter._GetTypeString(arg.annotation)
params.append(f'{ArgName}: {TypeStr}')
ParamPart: str = f'{ArgName}: {TypeStr}'
elif class_name and arg_idx == 0 and ArgName == 'self':
params.append(f'self: {class_name}')
ParamPart = f'self: {class_name}'
else:
params.append(ArgName)
ParamPart = ArgName
# 附加默认值defaults[i] 对应 args[DefaultsStart + i]
if NumDefaults > 0 and arg_idx >= DefaultsStart:
DefaultIdx: int = arg_idx - DefaultsStart
try:
DefaultStr: str = ast.unparse(node.args.defaults[DefaultIdx])
ParamPart = f'{ParamPart} = {DefaultStr}'
except Exception:
# unparse 失败时保留无默认值形式,避免阻塞生成
pass
params.append(ParamPart)
# 处理 *args
if node.args.vararg:

View File

@@ -20,6 +20,9 @@ from typing import Any, Callable, Optional, TYPE_CHECKING
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import CTypeInfo
# 治本修复:导入 t 模块和 CType 基类,用于类型构造调用求值(如 t.CUnsignedLong(-11)
from lib.includes import t as _t_module
from lib.includes.t import CType as _CType_base
if TYPE_CHECKING:
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
@@ -36,7 +39,7 @@ class ConstEvaluator:
def eval_with_symtab(node: ast.AST, symtab: Any) -> Optional[Any]:
"""求值常量表达式,支持从 SymbolTable 查找 define 值。
支持: Constant, BinOp, UnaryOp, Name(define), Attribute(define)
支持: Constant, BinOp, UnaryOp, Name(define), Attribute(define), Call(类型构造)
"""
if isinstance(node, ast.Constant):
return node.value
@@ -52,8 +55,68 @@ class ConstEvaluator:
if size_val is not None:
return size_val
return ConstEvaluator._eval_attribute_define(node, symtab)
# 治本修复:支持 t.CUnsignedLong(-11) 等类型构造调用
if isinstance(node, ast.Call):
return ConstEvaluator._eval_ctype_ctor_call(node, symtab)
return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_with_symtab(n, symtab))
@staticmethod
def _eval_ctype_ctor_call(node: ast.Call, symtab: Any) -> Optional[Any]:
"""求值类型构造调用,如 t.CUnsignedLong(-11)、CInt(42)。
在无 ctxEvalContext的场景下通过 symtab 和 t 模块直接求值。
按类型的 Size 和 IsSigned 应用位掩码。
"""
func: ast.expr = node.func
func_name: str | None = None
module_name: str | None = None
if isinstance(func, ast.Attribute):
if isinstance(func.value, ast.Name):
module_name = func.value.id
func_name = func.attr
elif isinstance(func, ast.Name):
func_name = func.id
ctype_cls: Any = None
if module_name == 't' and func_name:
ctype_cls = getattr(_t_module, func_name, None)
elif func_name and not module_name:
ctype_cls = getattr(_t_module, func_name, None)
if ctype_cls is None and symtab:
t_type_syms = getattr(symtab, '_t_type_symbols', {})
cls_candidate = t_type_syms.get(func_name)
if cls_candidate is not None:
ctype_cls = cls_candidate
if ctype_cls is None or not (isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base)):
return None
if not node.args:
return None
arg_val: Any = ConstEvaluator.eval_with_symtab(node.args[0], symtab)
if arg_val is None:
return None
size: int | None = None
is_signed: bool | None = None
try:
tmp_inst = ctype_cls()
size = getattr(tmp_inst, 'Size', None)
is_signed = getattr(tmp_inst, 'IsSigned', None)
except Exception:
pass
if isinstance(arg_val, int) and size and size > 0:
mask: int = (1 << size) - 1
if is_signed:
masked: int = arg_val & mask
if masked >= (1 << (size - 1)):
masked -= (1 << size)
return masked
else:
return arg_val & mask
return arg_val
# ==================================================================
# Level 3: + Gen._define_constants / _all_define_constants / 平台宏
# ==================================================================
@@ -147,7 +210,7 @@ class ConstEvaluator:
@staticmethod
def _eval_compile_time_call(node: ast.Call, ctx: 'EvalContext') -> Optional[Any]:
"""处理编译时函数调用,如 ctraits.isptr(x)"""
"""处理编译时函数调用,如 ctraits.isptr(x)、t.CUnsignedLong(-11)"""
func: ast.expr = node.func
func_name: str | None = None
module_name: str | None = None
@@ -200,6 +263,60 @@ class ConstEvaluator:
return None
except Exception:
return None
# 治本修复:支持 t.CUnsignedLong(-11) 等类型构造调用
# 当 t.CUnsignedLong(value) / CUnsignedInt(value) / CInt(value) 等被用作常量表达式时,
# 求值参数并返回(按类型的无符号/有符号语义应用位掩码)。
# 这修复了 stdint.py 中 INFINITE = t.CUnsignedLong(-1) 等常量无法被求值的问题。
is_ctype_ctor: bool = False
ctype_cls: Any = None
if module_name == 't' and func_name:
ctype_cls = getattr(_t_module, func_name, None)
if ctype_cls is not None and isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base):
is_ctype_ctor = True
elif func_name and not module_name:
# from t import CUnsignedLong 形式
ctype_cls = getattr(_t_module, func_name, None)
if ctype_cls is not None and isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base):
is_ctype_ctor = True
# 也检查 _t_type_symbols符号表中的 t 模块类型符号)
if not is_ctype_ctor and ctx.symtab:
t_type_syms = getattr(ctx.symtab, '_t_type_symbols', {})
cls_candidate = t_type_syms.get(func_name)
if cls_candidate is not None and isinstance(cls_candidate, type) and issubclass(cls_candidate, _CType_base):
ctype_cls = cls_candidate
is_ctype_ctor = True
if is_ctype_ctor and node.args:
try:
arg_node: ast.expr = node.args[0]
arg_val: Any = ConstEvaluator.eval_full(arg_node, ctx)
if arg_val is None:
return None
# 按类型的 Size 和 IsSigned 应用位掩码
size: int | None = getattr(ctype_cls, '_Size', None)
is_signed: bool | None = getattr(ctype_cls, '_IsSigned', None)
# 尝试创建临时实例获取 Size/IsSigned
try:
tmp_inst = ctype_cls()
size = getattr(tmp_inst, 'Size', size)
is_signed = getattr(tmp_inst, 'IsSigned', is_signed)
except Exception:
pass
if isinstance(arg_val, int) and size and size > 0:
mask: int = (1 << size) - 1
if is_signed:
# 有符号类型:解释为补码
masked: int = arg_val & mask
if masked >= (1 << (size - 1)):
masked -= (1 << size)
return masked
else:
# 无符号类型:直接掩码
return arg_val & mask
return arg_val
except Exception:
return None
return None
@staticmethod

View File

@@ -328,9 +328,14 @@ class ExprHandle(BaseHandle):
def _HandleNameLlvm(self, Node: ast.Name, VarType: ir.Type | str | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
VarName: str = Node.id
# [CD] 诊断仅对关键常量输出FOREGROUND_*, BACKGROUND_*, STD_*, *HANDLE*
import sys as _sys
_is_cd_key: bool = isinstance(VarName, str) and (VarName.startswith('FOREGROUND_') or VarName.startswith('BACKGROUND_') or 'STD_' in VarName or 'HANDLE' in VarName)
define_constants: dict[str, Any] = getattr(Gen, '_define_constants', {})
if VarName in define_constants:
val: Any = define_constants[VarName]
if _is_cd_key:
print(f"[CD] lookup: '{VarName}' found in _define_constants val={val}", file=_sys.stderr, flush=True)
if isinstance(val, int):
# Use VarType hint if available to avoid unnecessary type mismatch
if VarType is not None and isinstance(VarType, ir.IntType):
@@ -347,11 +352,13 @@ class ExprHandle(BaseHandle):
elif isinstance(val, str):
return Gen._create_string_global(val)
# 如果 _define_constants 中没有,尝试从符号表查找
if VarName not in getattr(Gen, '_define_constants', {}):
if VarName not in define_constants:
try:
sym_info: Any = self.translator.SymbolTable.lookup(VarName)
sym_info: Any = self.Trans.SymbolTable.lookup(VarName)
if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None:
val = sym_info.DefineValue
if _is_cd_key:
print(f"[CD] lookup: '{VarName}' found in SymbolTable val={val}", file=_sys.stderr, flush=True)
if isinstance(val, int):
# Use VarType hint if available
if VarType is not None and isinstance(VarType, ir.IntType):
@@ -363,9 +370,32 @@ class ExprHandle(BaseHandle):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
elif _is_cd_key:
print(f"[CD] lookup: '{VarName}' NOT in SymbolTable", file=_sys.stderr, flush=True)
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
# 治本修复:如果符号表也没有,回退查询 _all_define_constants
# _all_define_constants 由 Phase2Translator 从所有 .pyi 文件预提取,
# 包含跨模块导入的 CDefine 常量(如 FOREGROUND_GREEN、STD_OUTPUT_HANDLE
if VarName not in define_constants:
all_dc: dict[str, Any] = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
if VarName in all_dc:
val: Any = all_dc[VarName]
if _is_cd_key:
print(f"[CD] lookup: '{VarName}' found in _all_define_constants val={val}", file=_sys.stderr, flush=True)
if isinstance(val, int):
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
elif _is_cd_key:
print(f"[CD] lookup: '{VarName}' NOT found in ANY CDefine table", file=_sys.stderr, flush=True)
# 优先检查 variablesalloca因为变量可能已被 += 等操作迁移到 variables
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr: Any = Gen.variables[VarName]
@@ -410,7 +440,18 @@ class ExprHandle(BaseHandle):
return GVar
return Gen._load(GVar, name=VarName)
if VarName == 'self':
return Gen.GetVarPtr('self')
# 治本修复:方法名为 _get_var_ptr小写原 GetVarPtr 不存在会抛 AttributeError。
# 当 self 未注册到 variables 时(如 opaque struct 参数走了 else 分支),
# 通过 _get_var_ptr 兜底返回 None由调用方处理。
SelfPtr: ir.Value | None = Gen._get_var_ptr('self')
if SelfPtr is not None:
return SelfPtr
# 最终兜底:若 _get_var_ptr 返回 Noneself 既不在 _reg_values 也不在 variables
# 直接返回函数参数本身LLVM Argument。这避免了 AttributeError 导致的异常路径。
for arg in getattr(Gen.func, 'args', []):
if getattr(arg, 'name', None) == 'self':
return arg
return ir.Constant(ir.IntType(32), 0)
if Gen._has_function(VarName):
func: Any = Gen._get_function(VarName)
if func:

View File

@@ -2045,6 +2045,21 @@ class ExprCallHandle(BaseHandle):
arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{FuncName}")
else:
arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{FuncName}")
elif isinstance(arg.type, (ir.LiteralStructType, ir.IdentifiedStructType)):
# 治本修复:变参函数(如 printf不支持 struct by value 传递。
# 当 self 等 struct 值被错误地 load 为值(而非指针)传入变参时,
# ABI 不匹配会导致崩溃。修复:将 struct 值通过 alloca + bitcast
# 转换为 i8* 指针传递,确保与 %p / %s 等格式说明符兼容。
try:
alloca_tmp = Gen.builder.alloca(arg.type, name=f"vararg_struct_{FuncName}_{i}")
Gen.builder.store(arg, alloca_tmp)
arg = Gen.builder.bitcast(alloca_tmp, ir.IntType(8).as_pointer(), name=f"vararg_struct_ptr_{FuncName}_{i}")
except Exception:
# 回退alloca/store 失败时,尝试 ptrtoint 为 i64
try:
arg = Gen.builder.ptrtoint(arg, ir.IntType(64), name=f"vararg_struct_i64_{FuncName}_{i}")
except Exception:
pass # 最终回退:保留原值(可能仍会导致崩溃,但至少不阻塞编译)
adjusted.append(arg)
result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}")
else:
@@ -2851,15 +2866,33 @@ class ExprCallHandle(BaseHandle):
if class_sha1 and ClassName in Gen.structs:
struct_type = Gen.structs[ClassName]
self_ptr_type = ir.PointerType(struct_type)
param_types = [self_ptr_type] + [a.type for a in CallArgs]
func_type = ir.FunctionType(ir.IntType(32), param_types)
# 修复 Bug 4: 从符号表获取完整参数列表(含默认参数)和正确返回类型,
# 而非仅使用 CallArgs漏掉默认参数和硬编码 i32 返回类型。
# 这避免了 main.py 中 declare Logger.info(...,i8*) 2参数
# 与 VLogger 中 define Logger.info(...,i8*,i8*) 3参数的签名冲突。
ret_type: Any = ir.IntType(32)
param_types: list[Any] = [self_ptr_type] + [a.type for a in CallArgs]
SymInfoFallback = self.LookupFunctionSymbol(MethodName, module_path=ClassName)
if SymInfoFallback and SymInfoFallback.IsFunction:
sig = self.BuildLLVMFuncTypeFromSig(SymInfoFallback, Gen)
if sig is not None:
sig_ret, sig_params, _ = sig
ret_type = sig_ret
is_static_fb = FuncMeta.STATIC_METHOD in SymInfoFallback.MetaList
if not is_static_fb:
sig_params = [self_ptr_type] + sig_params
param_types = sig_params
func_type = ir.FunctionType(ret_type, param_types)
func = ir.Function(Gen.module, func_type, name=FullMethodName)
Gen.functions[FullMethodName] = func
if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == struct_type:
call_self = ObjVal
else:
call_self = Gen.builder.bitcast(ObjVal, self_ptr_type, name=f"method_self_{ClassName}")
adjusted = Gen._adjust_args([call_self] + CallArgs, func)
call_args_fb = [call_self] + CallArgs
self._fill_default_args(call_args_fb, func, FullMethodName)
self._append_eh_msg_out_arg(call_args_fb, func, Gen)
adjusted = Gen._adjust_args(call_args_fb, func)
result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}")
return result
raise Exception(f"Undefined method '{MethodName}' in class '{ClassName}' (no function declaration found for '{FullMethodName}')")

View File

@@ -112,20 +112,26 @@ class ImportHandle(BaseHandle):
# For 'from X import Y' (no asname), register CDefine constants
# into _define_constants so they can be found by _HandleNameLlvm
if not asname or asname == name:
define_constants = vars(Gen).setdefault('_define_constants', {})
# Check if this name is a CDefine constant in SymbolTable
sym_info = self.Trans.SymbolTable.lookup(name)
if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None:
define_constants = vars(Gen).setdefault('_define_constants', {})
if name not in define_constants:
define_constants[name] = sym_info.DefineValue
# Also check with module prefix
for prefix_key in [f"{module}.{name}", name]:
sym_info2 = self.Trans.SymbolTable.lookup(prefix_key)
if sym_info2 and sym_info2.IsDefine and sym_info2.DefineValue is not None:
define_constants = vars(Gen).setdefault('_define_constants', {})
if name not in define_constants:
define_constants[name] = sym_info2.DefineValue
break
# 治本修复:如果符号表中没有,回退查询 _all_define_constants
# _all_define_constants 由 Phase2Translator 从所有 .pyi 文件预提取,
# 包含跨模块导入的 CDefine 常量(如 FOREGROUND_GREEN、STD_OUTPUT_HANDLE
if name not in define_constants:
all_dc: dict = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
if name in all_dc:
define_constants[name] = all_dc[name]
continue
if not hasattr(self.Trans, '_t_c_imported_names'):
self.Trans._t_c_imported_names = {}

View File

@@ -211,6 +211,11 @@ class HandlesTypeMerge(BaseHandle):
elif TypeClass:
Info = CTypeInfo()
Info.BaseType = TypeClass
# 治本修复t.CDefine 注解必须设置 IsDefine=True
# 否则预扫描 (LlvmGenerator.py) 和主处理 (HandlesAnnAssign.py)
# 都无法识别 CDefine 常量,导致 FOREGROUND_GREEN 等解析为 0
if isinstance(TypeClass, type) and issubclass(TypeClass, t.CDefine):
Info.IsDefine = True
return Info
elif CTypeHelper.GetCName(TypeName):
return self._MakeCTypeInfoFromName(CTypeHelper.GetCName(TypeName))

View File

@@ -12,6 +12,8 @@ from lib.constants.config import mode as _config_mode
from lib.core.VLogger import get_logger as _vlog
from lib.core.DecoratorPass import run as _run_decorator_pass
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
# 治本修复:导入 ConstEvaluator 用于预扫描 CDefine 常量的复杂表达式求值
from lib.core.ConstEvaluator import ConstEvaluator
class LlvmGeneratorMixin:
@@ -59,26 +61,31 @@ class LlvmGeneratorMixin:
Gen.known_return_types[Node.name] = ir.PointerType(ir.IntType(8))
# 首先收集所有 CDefine 常量,确保类定义中可以引用
def _extract_call_const_val(node: ast.AST) -> int | str | float | None:
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if getattr(node.func.value, 'id', None) == 't':
if node.args and isinstance(node.args[0], ast.Constant):
return node.args[0].value
elif isinstance(node.func, ast.Name):
if node.args and isinstance(node.args[0], ast.Constant):
return node.args[0].value
return None
def _extract_const_value(node: ast.AST) -> int | str | float | None:
"""求值 CDefine 常量表达式,支持 Constant、BinOp、UnaryOp、Name(引用其他 define)、Call(类型构造)。
治本修复:原 _extract_call_const_val 只支持 t.XxxType(Constant) 形式,
无法处理 FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
等引用其他 CDefine 的 BinOp 表达式,导致依赖常量无法被预扫描。
现使用 ConstEvaluator.eval_with_symtab 统一求值。
"""
if isinstance(node, ast.Constant):
return node.value
# 使用 ConstEvaluator 处理 BinOp/UnaryOp/Name/Attribute/Call
return ConstEvaluator.eval_with_symtab(node, self.SymbolTable)
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value:
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine)):
val: int | str | float | None = None
if isinstance(Node.value, ast.Constant):
val = Node.value.value
else:
val = _extract_call_const_val(Node.value)
# 治本修复:检查 BaseType 是否为 t.CDefine 实例/子类,或 IsDefine 标志
# IsDefine 由 GetCTypeInfo 对 t.CDefine 注解自动设置
if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine) or TypeInfo.IsDefine):
val: int | str | float | None = _extract_const_value(Node.value)
import sys as _sys
_nm = Node.target.id
# [CD] 仅输出关键常量FOREGROUND_*, STD_OUTPUT_HANDLE, BACKGROUND_*
if isinstance(_nm, str) and (_nm.startswith('FOREGROUND_') or _nm.startswith('BACKGROUND_') or 'STD_' in _nm or 'HANDLE' in _nm):
print(f"[CD] extract: '{_nm}' IsDefine={TypeInfo.IsDefine} val={val}", file=_sys.stderr, flush=True)
if val is not None:
if not hasattr(Gen, '_define_constants'):
Gen._define_constants: dict[str, int | str | float | bool] = {}
@@ -89,6 +96,8 @@ class LlvmGeneratorMixin:
sym_info.IsDefine = True
sym_info.DefineValue = val
self.SymbolTable.insert(Node.target.id, sym_info)
else:
print(f"[CD] extract: WARN val is None for '{_nm}'", file=_sys.stderr, flush=True)
elif isinstance(Node, ast.Assign):
for target in Node.targets:
if isinstance(target, ast.Name):
@@ -102,11 +111,7 @@ class LlvmGeneratorMixin:
raise
_vlog().warning(f"解析类型注释失败: {_e}", "Exception")
if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine)):
val: int | str | float | None = None
if isinstance(Node.value, ast.Constant):
val = Node.value.value
else:
val = _extract_call_const_val(Node.value)
val: int | str | float | None = _extract_const_value(Node.value)
if val is not None:
if not hasattr(Gen, '_define_constants'):
Gen._define_constants: dict[str, int | str | float | bool] = {}

View File

@@ -711,19 +711,45 @@ class TypeAnnotationResolver:
if FullName in SymbolTable:
Info: CTypeInfo = SymbolTable[FullName]
if Info and Info.IsTypedef:
OriginalType: str = Info.get('OriginalType', '')
if OriginalType and 'typedef' in OriginalType:
parts: list[str] = OriginalType.split()
if len(parts) >= 2:
BaseType_name: str = parts[1]
if not BaseType_name.startswith('C'):
BaseType_name = 'C' + BaseType_name
CNAME: str | None = CTypeHelper.GetCName(BaseType_name)
if CNAME:
return TypeAnnotationResolver.from_type_name(CNAME)
# 优先用 BaseType 解析(如 VOIDPTR 已解析为 BaseType=CVoid, PtrCount=1
if Info.BaseType and (not isinstance(Info.BaseType, (t._CTypedef,)) or Info.PtrCount > 0):
Result = Info.Copy()
Result.IsTypedef = True
Result.Name = FullName
return Result
# 再用 OriginalType 解析(字符串如 'void *',或 CTypeInfo
if Info.OriginalType:
if isinstance(Info.OriginalType, CTypeInfo) and Info.OriginalType.IsFuncPtr:
Result = CTypeInfo()
Result.IsFuncPtr = True
Result.FuncPtrReturn = Info.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
Result.FuncPtrParams = list(Info.OriginalType.FuncPtrParams) if Info.OriginalType.FuncPtrParams else []
Result.IsTypedef = True
Result.Name = FullName
return Result
elif isinstance(Info.OriginalType, CTypeInfo):
Resolved: CTypeInfo = Info.OriginalType.Copy()
elif isinstance(Info.OriginalType, str) and Info.OriginalType == 'Callable':
Result = CTypeInfo()
Result.IsFuncPtr = True
Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
Result.FuncPtrParams = []
Result.IsTypedef = True
Result.Name = FullName
return Result
elif isinstance(Info.OriginalType, str):
Resolved = TypeAnnotationResolver.from_type_name(Info.OriginalType)
else:
Resolved = Info.OriginalType
if Resolved and Resolved.BaseType:
Resolved.IsTypedef = True
Resolved.Name = FullName
return Resolved
# 回退:保持原逻辑但设置 Name = FullName供后续 TypeConvert 查找)
Result: CTypeInfo = CTypeInfo()
Result.BaseType = t._CTypedef(TypeName)
Result.IsTypedef = True
Result.Name = FullName
return Result
if Info:
Result: CTypeInfo = Info.Copy()