diff --git a/Test/CPythonTest/temp/_shared_sym.pkl b/Test/CPythonTest/temp/_shared_sym.pkl index 59d9977..918d337 100644 Binary files a/Test/CPythonTest/temp/_shared_sym.pkl and b/Test/CPythonTest/temp/_shared_sym.pkl differ diff --git a/Test/TestProject/temp/_shared_sym.pkl b/Test/TestProject/temp/_shared_sym.pkl index 72361f0..4229ca0 100644 Binary files a/Test/TestProject/temp/_shared_sym.pkl and b/Test/TestProject/temp/_shared_sym.pkl differ diff --git a/Test/TestProject2/temp/_shared_sym.pkl b/Test/TestProject2/temp/_shared_sym.pkl index 0d372ae..13f33f4 100644 Binary files a/Test/TestProject2/temp/_shared_sym.pkl and b/Test/TestProject2/temp/_shared_sym.pkl differ diff --git a/Test/TestProject3/temp/_shared_sym.pkl b/Test/TestProject3/temp/_shared_sym.pkl index 92438b1..ff508e2 100644 Binary files a/Test/TestProject3/temp/_shared_sym.pkl and b/Test/TestProject3/temp/_shared_sym.pkl differ diff --git a/Test/ZlibTest/temp/_shared_sym.pkl b/Test/ZlibTest/temp/_shared_sym.pkl index d42f8d0..236dd93 100644 Binary files a/Test/ZlibTest/temp/_shared_sym.pkl and b/Test/ZlibTest/temp/_shared_sym.pkl differ diff --git a/lib/core/ConstEvaluator.py b/lib/core/ConstEvaluator.py new file mode 100644 index 0000000..4a4486a --- /dev/null +++ b/lib/core/ConstEvaluator.py @@ -0,0 +1,404 @@ +"""统一常量表达式求值器 + +整合了原先分散在 5 处的常量求值逻辑: + - SymbolTable._eval_const_expr + - CTypeInfo.TryEvalConstExpr + - ConstEvalMixin._try_eval_const_expr + - HandlesAssign._eval_const_expr + - HandlesIf._eval_const_expr + +ConstEvaluator 提供三个级别的求值: + 1. eval_basic(node) — 纯 AST 常量 + 算术(无外部依赖) + 2. eval_with_symtab(node) — + SymbolTable 中的 define 查找 + 3. eval_full(node, ctx) — + Gen._define_constants / _all_define_constants / 平台宏 +""" +from __future__ import annotations + +import ast +from typing import Any, Optional + + +class ConstEvaluator: + """统一常量表达式求值器""" + + # ================================================================== + # Level 1: 纯 AST 常量 + 算术(无外部依赖) + # ================================================================== + + @staticmethod + def eval_basic(node: ast.AST) -> Optional[Any]: + """求值纯常量表达式,不依赖任何外部符号表。 + + 支持: Constant, BinOp, UnaryOp + """ + if isinstance(node, ast.Constant): + return node.value + return ConstEvaluator._eval_arith(node, ConstEvaluator.eval_basic) + + # ================================================================== + # Level 2: + SymbolTable define 查找 + # ================================================================== + + @staticmethod + def eval_with_symtab(node: ast.AST, symtab) -> Optional[Any]: + """求值常量表达式,支持从 SymbolTable 查找 define 值。 + + 支持: Constant, BinOp, UnaryOp, Name(define), Attribute(define) + """ + if isinstance(node, ast.Constant): + return node.value + if isinstance(node, ast.Name): + if hasattr(symtab, '__contains__') and node.id in symtab: + info = symtab[node.id] + if info.IsDefine and isinstance(info.DefineValue, int): + return info.DefineValue + return None + if isinstance(node, ast.Attribute): + return ConstEvaluator._eval_attribute_define(node, symtab) + return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_with_symtab(n, symtab)) + + # ================================================================== + # Level 3: + Gen._define_constants / _all_define_constants / 平台宏 + # ================================================================== + + @staticmethod + def eval_full(node: ast.AST, ctx: 'EvalContext') -> Optional[Any]: + """完整求值,支持 define_constants、平台宏、BoolOp、Compare。 + + ctx: EvalContext 实例,封装了 Gen、SymbolTable 等上下文。 + """ + # BoolOp (HandlesIf 逻辑) + if isinstance(node, ast.BoolOp): + if isinstance(node.op, ast.And): + for val in node.values: + result = ConstEvaluator.eval_full(val, ctx) + if result is None: + return None + if not result: + return 0 + return 1 + elif isinstance(node.op, ast.Or): + for val in node.values: + result = ConstEvaluator.eval_full(val, ctx) + if result is None: + return None + if result: + return 1 + return 0 + return None + + # Compare (HandlesIf 逻辑) + if isinstance(node, ast.Compare): + left = ConstEvaluator.eval_full(node.left, ctx) + if left is None: + return None + for op, comparator in zip(node.ops, node.comparators): + right = ConstEvaluator.eval_full(comparator, ctx) + if right is None: + return None + result = ConstEvaluator._eval_compare_op(op, left, right) + if result is None: + return None + if not result: + return 0 + left = right + return 1 + + # Constant — 直接返回原始值,bool→0/1 转换由 HandlesIf 自行处理 + if isinstance(node, ast.Constant): + return node.value + + # Name — 查 define_constants / SymbolTable / 平台宏 + if isinstance(node, ast.Name): + return ctx.lookup_name(node.id) + + # Attribute — 查 define_constants / SymbolTable / 平台宏 + if isinstance(node, ast.Attribute): + return ctx.lookup_attribute(node) + + # UnaryOp + if isinstance(node, ast.UnaryOp): + operand = ConstEvaluator.eval_full(node.operand, ctx) + if operand is None: + return None + if isinstance(node.op, ast.Not): + return 1 if not operand else 0 + if isinstance(node.op, ast.USub): + return -operand + if isinstance(node.op, ast.UAdd): + return +operand + if isinstance(node.op, ast.Invert): + return ~operand + return None + + # BinOp + return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_full(n, ctx)) + + # ================================================================== + # 内部辅助 + # ================================================================== + + @staticmethod + def _eval_arith(node: ast.AST, recurse) -> Optional[Any]: + """通用算术求值:BinOp + UnaryOp""" + if isinstance(node, ast.BinOp): + left = recurse(node.left) + right = recurse(node.right) + if left is None or right is None: + return None + return ConstEvaluator._apply_binop(node.op, left, right) + if isinstance(node, ast.UnaryOp): + operand = recurse(node.operand) + if operand is None: + return None + if isinstance(node.op, ast.USub): + return -operand + if isinstance(node.op, ast.UAdd): + return +operand + if isinstance(node.op, ast.Invert): + return ~operand + return None + return None + + @staticmethod + def _apply_binop(op: ast.operator, left, right) -> Optional[Any]: + """应用二元运算符""" + try: + if isinstance(op, ast.Add): + return left + right + elif isinstance(op, ast.Sub): + return left - right + elif isinstance(op, ast.Mult): + return left * right + elif isinstance(op, ast.Div): + return left // right if isinstance(left, int) and isinstance(right, int) else left / right + elif isinstance(op, ast.FloorDiv): + if isinstance(right, (int, float)) and right == 0: + return None + return left // right + elif isinstance(op, ast.Mod): + if isinstance(right, (int, float)) and right == 0: + return None + return left % right + elif isinstance(op, ast.Pow): + return left ** right + elif isinstance(op, ast.LShift): + return left << right + elif isinstance(op, ast.RShift): + return left >> right + elif isinstance(op, ast.BitOr): + return left | right + elif isinstance(op, ast.BitXor): + return left ^ right + elif isinstance(op, ast.BitAnd): + return left & right + except Exception: + return None + return None + + @staticmethod + def _eval_compare_op(op, left, right) -> Optional[bool]: + """应用比较运算符""" + if isinstance(op, ast.Eq): + return left == right + elif isinstance(op, ast.NotEq): + return left != right + elif isinstance(op, ast.Lt): + return left < right + elif isinstance(op, ast.LtE): + return left <= right + elif isinstance(op, ast.Gt): + return left > right + elif isinstance(op, ast.GtE): + return left >= right + return None + + @staticmethod + def _eval_attribute_define(node: ast.Attribute, symtab) -> Optional[Any]: + """从 SymbolTable 查找 Attribute 形式的 define 值""" + parts = [] + current = node + while isinstance(current, ast.Attribute): + parts.append(current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.append(current.id) + parts.reverse() + attr_name = parts[-1] + possible_keys = [attr_name, '.'.join(parts)] + for key in possible_keys: + if hasattr(symtab, '__contains__') and key in symtab: + info = symtab[key] + if info.IsDefine and isinstance(info.DefineValue, int): + return info.DefineValue + # 模糊匹配 + if len(parts) >= 2: + for mod_key, mod_info in (symtab.items() if hasattr(symtab, 'items') else []): + if mod_info.IsDefine and isinstance(mod_info.DefineValue, int): + if mod_key.endswith('.' + attr_name) or mod_key == attr_name: + return mod_info.DefineValue + return None + + @staticmethod + def _intify(val): + """float → int 转换(仅当 float 值恰好是整数时)""" + if isinstance(val, float) and val == int(val): + return int(val) + return val + + +class EvalContext: + """常量求值上下文,封装 Gen / SymbolTable / 平台宏查找逻辑。 + + 由调用方构造并传入 ConstEvaluator.eval_full()。 + """ + + def __init__(self, Gen=None, symtab=None, platform_macros: dict | None = None): + self.Gen = Gen + self.symtab = symtab + self._platform_macros = platform_macros + + def lookup_name(self, name: str) -> Optional[Any]: + """查找 Name 节点的值:define_constants → SymbolTable → 平台宏""" + # 1. Gen._define_constants + if self.Gen and hasattr(self.Gen, '_define_constants') and name in self.Gen._define_constants: + val = self.Gen._define_constants[name] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + + # 2. Gen._DefineConstants (大写版本) + if self.Gen and hasattr(self.Gen, '_DefineConstants') and name in self.Gen._DefineConstants: + val = self.Gen._DefineConstants[name] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + + # 3. SymbolTable + if self.symtab and name in self.symtab: + info = self.symtab[name] + val = info.value + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + if info.IsDefine and isinstance(info.DefineValue, (int, float)): + return ConstEvaluator._intify(info.DefineValue) + + # 4. 平台宏 + macros = self._get_platform_macros() + if name in macros: + return macros[name] + + return None + + def lookup_attribute(self, node: ast.Attribute) -> Optional[Any]: + """查找 Attribute 节点的值""" + module_name = node.value.id if isinstance(node.value, ast.Name) else None + attr_name = node.attr + + if module_name and attr_name: + combined_key = f"{module_name}.{attr_name}" + + # 1. Gen._define_constants + if self.Gen and hasattr(self.Gen, '_define_constants') and combined_key in self.Gen._define_constants: + val = self.Gen._define_constants[combined_key] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + + # 2. SymbolTable (精确匹配 + 后缀匹配) + if self.symtab: + for key, info in self.symtab.items(): + if key.endswith(f".{combined_key}") or key == combined_key: + if info.IsDefine and isinstance(info.DefineValue, (int, float)): + return ConstEvaluator._intify(info.DefineValue) + + # 3. _all_define_constants + all_dc = self._get_all_define_constants() + if combined_key in all_dc: + val = all_dc[combined_key] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + if attr_name in all_dc: + val = all_dc[attr_name] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + for dc_key, dc_val in all_dc.items(): + if dc_key == attr_name or dc_key.endswith(f".{attr_name}"): + if isinstance(dc_val, (int, float)): + return ConstEvaluator._intify(dc_val) + + # 4. SymbolTable 短名查找 + if self.symtab and attr_name in self.symtab: + info = self.symtab[attr_name] + if info.IsDefine and isinstance(info.DefineValue, (int, float)): + return ConstEvaluator._intify(info.DefineValue) + + # 5. Gen._define_constants 短名 + if self.Gen and hasattr(self.Gen, '_define_constants') and attr_name in self.Gen._define_constants: + val = self.Gen._define_constants[attr_name] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + + # 6. 平台宏 + macros = self._get_platform_macros() + full_key = self._get_attr_full_name(node) + if full_key: + if full_key in macros: + return macros[full_key] + short_name = full_key.split('.')[-1] if '.' in full_key else full_key + if short_name in macros: + return macros[short_name] + + return None + + def _get_all_define_constants(self) -> dict: + """获取 _all_define_constants""" + if self.Gen and hasattr(self.Gen, '_all_define_constants'): + return self.Gen._all_define_constants + return {} + + def _get_platform_macros(self) -> dict: + """获取平台宏""" + if self._platform_macros is not None: + return self._platform_macros + if not self.Gen: + return {} + macros = {} + pi = getattr(self.Gen, '_platform_info', {}) + ptr_size = getattr(self.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 + + @staticmethod + def _get_attr_full_name(node: ast.Attribute) -> Optional[str]: + """从 Attribute 节点提取完整名称 (e.g. 'module.name')""" + parts = [] + current = node + while isinstance(current, ast.Attribute): + parts.append(current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.append(current.id) + parts.reverse() + return '.'.join(parts) if parts else None diff --git a/lib/core/DiagnosticCollector.py b/lib/core/DiagnosticCollector.py new file mode 100644 index 0000000..0758bdc --- /dev/null +++ b/lib/core/DiagnosticCollector.py @@ -0,0 +1,79 @@ +"""诊断系统 — 收集编译过程中的警告和错误 + +替代原先静默回退的模式: + - return 'i32' → 记录 Warning + 回退到 'i32' + - return [] → 记录 Error + 回退到 [] + +使用方式: + diag = DiagnosticCollector() + diag.warn(file, lineno, "无法解析类型,回退到 i32") + diag.error(file, lineno, f"加载模块失败: {path}") + diag.report() # 打印所有诊断信息 +""" +from __future__ import annotations + +import os +from dataclasses import dataclass, field +from enum import Enum +from typing import List, Optional + + +class DiagnosticLevel(Enum): + WARNING = "WARNING" + ERROR = "ERROR" + + +@dataclass +class Diagnostic: + level: DiagnosticLevel + file: str + lineno: int + message: str + + def __str__(self): + short_file = os.path.basename(self.file) if self.file else "" + return f"[{self.level.value}] {short_file}:{self.lineno} — {self.message}" + + +class DiagnosticCollector: + """诊断信息收集器""" + + def __init__(self): + self._diagnostics: List[Diagnostic] = [] + + def warn(self, file: str, lineno: int, message: str): + self._diagnostics.append(Diagnostic(DiagnosticLevel.WARNING, file, lineno, message)) + + def error(self, file: str, lineno: int, message: str): + self._diagnostics.append(Diagnostic(DiagnosticLevel.ERROR, file, lineno, message)) + + @property + def warnings(self) -> List[Diagnostic]: + return [d for d in self._diagnostics if d.level == DiagnosticLevel.WARNING] + + @property + def errors(self) -> List[Diagnostic]: + return [d for d in self._diagnostics if d.level == DiagnosticLevel.ERROR] + + @property + def has_errors(self) -> bool: + return any(d.level == DiagnosticLevel.ERROR for d in self._diagnostics) + + @property + def has_warnings(self) -> bool: + return any(d.level == DiagnosticLevel.WARNING for d in self._diagnostics) + + def report(self, min_level: DiagnosticLevel = DiagnosticLevel.WARNING): + """打印所有诊断信息""" + for d in self._diagnostics: + if d.level.value >= min_level.value: + print(d) + + def clear(self): + self._diagnostics.clear() + + def __len__(self): + return len(self._diagnostics) + + def __bool__(self): + return len(self._diagnostics) > 0 diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 6afab8d..3949045 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -82,7 +82,7 @@ class AnnAssignHandle(BaseHandle): IsUnion = False if ClassName and ClassName in self.Trans.SymbolTable: TypeInfo = self.Trans.SymbolTable[ClassName] - if hasattr(TypeInfo, 'IsUnion') and TypeInfo.IsUnion: + if TypeInfo.IsUnion: IsUnion = True if ClassName and ClassName in Gen.structs: ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index 17161eb..e747599 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -440,8 +440,8 @@ class AssignHandle: sym_key = f"{ModulePath}.{FuncName}" sym_info = self.Trans.SymbolTable.get(sym_key) if sym_info and sym_info.IsFunction: - ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) - param_type_infos = [pt for _, pt in getattr(sym_info, 'FuncPtrParams', [])] + ret_type_info = sym_info.FuncPtrReturn + param_type_infos = [pt for _, pt in (sym_info.FuncPtrParams or [])] if ret_type_info: if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: ret_type = ret_type_info.ToLLVM(Gen) @@ -616,7 +616,7 @@ class AssignHandle: if ClassName and ClassName in Gen.structs: PropKey = f'{ClassName}.{AttrName}' PropInfo = self.Trans.SymbolTable.get(PropKey) - if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: SelfVar = Gen._get_var_ptr('self') if SelfVar: SelfPtr = Gen._load(SelfVar, name="self") @@ -734,7 +734,7 @@ class AssignHandle: if ClassName and ClassName in Gen.structs: PropKey = f'{ClassName}.{AttrName}' PropInfo = self.Trans.SymbolTable.get(PropKey) - if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) SetterFunc = Gen._get_function(PropKey + '$set') if SetterFunc and ObjVal: @@ -1222,7 +1222,7 @@ class AssignHandle: elif isinstance(count_node, ast.Name): if count_node.id in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[count_node.id] - if isinstance(getattr(SymInfo, 'value', None), int): + if isinstance(SymInfo.value, int): ArrayCount = SymInfo.value if ArrayCount == 1 and count_node.id in getattr(Gen, '_define_constants', {}): DefVal = Gen._define_constants[count_node.id] @@ -1558,94 +1558,10 @@ class AssignHandle: Gen.variables[VarName] = GlobalVar def _eval_const_expr(self, node, Gen): - """计算常量表达式的值""" - import ast - if isinstance(node, ast.Constant): - return node.value - elif isinstance(node, ast.BinOp): - left = self._eval_const_expr(node.left, Gen) - right = self._eval_const_expr(node.right, Gen) - if left is None or right is None: - return None - if isinstance(node.op, ast.Add): - return left + right - elif isinstance(node.op, ast.Sub): - return left - right - elif isinstance(node.op, ast.Mult): - return left * right - elif isinstance(node.op, ast.Div): - return left // right if isinstance(left, int) and isinstance(right, int) else left / right - elif isinstance(node.op, ast.FloorDiv): - return left // right - elif isinstance(node.op, ast.Mod): - return left % right - elif isinstance(node.op, ast.Pow): - return left ** right - elif isinstance(node.op, ast.LShift): - return left << right - elif isinstance(node.op, ast.RShift): - return left >> right - elif isinstance(node.op, ast.BitOr): - return left | right - elif isinstance(node.op, ast.BitXor): - return left ^ right - elif isinstance(node.op, ast.BitAnd): - return left & right - elif isinstance(node, ast.UnaryOp): - operand = self._eval_const_expr(node.operand, Gen) - if operand is None: - return None - if isinstance(node.op, ast.USub): - return -operand - elif isinstance(node.op, ast.UAdd): - return +operand - elif isinstance(node.op, ast.Invert): - return ~operand - elif isinstance(node, ast.Name): - if node.id in getattr(Gen, '_define_constants', {}): - return Gen._define_constants[node.id] - if node.id in self.Trans.SymbolTable: - SymInfo = self.Trans.SymbolTable[node.id] - val = getattr(SymInfo, 'value', None) - if isinstance(val, (int, float)): - return val - if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)): - return SymInfo.DefineValue - elif isinstance(node, ast.Attribute): - module_name = node.value.id if isinstance(node.value, ast.Name) else None - attr_name = node.attr - if module_name and attr_name: - combined_key = f"{module_name}.{attr_name}" - if combined_key in getattr(Gen, '_define_constants', {}): - val = Gen._define_constants[combined_key] - if isinstance(val, (int, float)): - return int(val) if isinstance(val, float) and val == int(val) else val - for key, SymInfo in self.Trans.SymbolTable.items(): - if key.endswith(f".{combined_key}") or key == combined_key: - if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)): - return int(SymInfo.DefineValue) if isinstance(SymInfo.DefineValue, float) and SymInfo.DefineValue == int(SymInfo.DefineValue) else SymInfo.DefineValue - all_dc = getattr(self.Trans, '_all_define_constants', None) or getattr(Gen, '_all_define_constants', {}) - if combined_key in all_dc: - val = all_dc[combined_key] - if isinstance(val, (int, float)): - return int(val) if isinstance(val, float) and val == int(val) else val - if attr_name in all_dc: - val = all_dc[attr_name] - if isinstance(val, (int, float)): - return int(val) if isinstance(val, float) and val == int(val) else val - for dc_key, dc_val in all_dc.items(): - if dc_key == attr_name or dc_key.endswith(f".{attr_name}"): - if isinstance(dc_val, (int, float)): - return int(dc_val) if isinstance(dc_val, float) and dc_val == int(dc_val) else dc_val - if attr_name in self.Trans.SymbolTable: - SymInfo = self.Trans.SymbolTable[attr_name] - if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)): - return int(SymInfo.DefineValue) if isinstance(SymInfo.DefineValue, float) and SymInfo.DefineValue == int(SymInfo.DefineValue) else SymInfo.DefineValue - if attr_name in getattr(Gen, '_define_constants', {}): - val = Gen._define_constants[attr_name] - if isinstance(val, (int, float)): - return int(val) if isinstance(val, float) and val == int(val) else val - return None + """计算常量表达式的值(委托到 ConstEvaluator)""" + from lib.core.ConstEvaluator import ConstEvaluator, EvalContext + ctx = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable) + return ConstEvaluator.eval_full(node, ctx) def _eval_global_count(self, node, Gen): val = self._eval_const_expr(node, Gen) diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index b958144..09a3875 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -395,74 +395,8 @@ class CTypeInfo: @staticmethod def TryEvalConstExpr(node, SymbolTable): - if isinstance(node, ast.Constant) and isinstance(node.value, int): - return node.value - if isinstance(node, ast.BinOp): - left = CTypeInfo.TryEvalConstExpr(node.left, SymbolTable) - right = CTypeInfo.TryEvalConstExpr(node.right, SymbolTable) - if left is None or right is None: - return None - if isinstance(node.op, ast.Add): - return left + right - elif isinstance(node.op, ast.Sub): - return left - right - elif isinstance(node.op, ast.Mult): - return left * right - elif isinstance(node.op, ast.FloorDiv): - return left // right if right != 0 else None - elif isinstance(node.op, ast.Mod): - return left % right if right != 0 else None - elif isinstance(node.op, ast.LShift): - return left << right - elif isinstance(node.op, ast.RShift): - return left >> right - elif isinstance(node.op, ast.BitOr): - return left | right - elif isinstance(node.op, ast.BitAnd): - return left & right - elif isinstance(node.op, ast.BitXor): - return left ^ right - elif isinstance(node.op, ast.Pow): - return left ** right - return None - if isinstance(node, ast.UnaryOp): - operand = CTypeInfo.TryEvalConstExpr(node.operand, SymbolTable) - if operand is None: - return None - if isinstance(node.op, ast.USub): - return -operand - elif isinstance(node.op, ast.UAdd): - return +operand - elif isinstance(node.op, ast.Invert): - return ~operand - return None - if isinstance(node, ast.Name): - if node.id in SymbolTable: - info = SymbolTable[node.id] - if getattr(info, 'IsDefine', None) and isinstance(getattr(info, 'DefineValue', None), int): - return info.DefineValue - if isinstance(node, ast.Attribute): - parts = [] - current = node - while isinstance(current, ast.Attribute): - parts.append(current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.append(current.id) - parts.reverse() - attr_name = parts[-1] - possible_keys = [attr_name, '.'.join(parts)] - for key in possible_keys: - if key in SymbolTable: - info = SymbolTable[key] - if getattr(info, 'IsDefine', None) and isinstance(getattr(info, 'DefineValue', None), int): - return info.DefineValue - if len(parts) >= 2: - for mod_key, mod_info in SymbolTable.items(): - if getattr(mod_info, 'IsDefine', None) and isinstance(getattr(mod_info, 'DefineValue', None), int): - if mod_key.endswith('.' + attr_name) or mod_key == attr_name: - return mod_info.DefineValue - return None + from lib.core.ConstEvaluator import ConstEvaluator + return ConstEvaluator.eval_with_symtab(node, SymbolTable) @classmethod def FromNode(cls, Node: ast.AST, SymbolTable: dict) -> "CTypeInfo": @@ -1136,10 +1070,6 @@ class CTypeInfo: NewInfo._ts.original_type = NewInfo._ts.original_type.Copy() if NewInfo._ts.array_ptr: NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy() - # 实例上的动态属性也需要拷贝(如 IsSigned 等) - for key, val in self.__dict__.items(): - if key not in ('_ts', '_sm'): - object.__setattr__(NewInfo, key, val) return NewInfo def get(self, key, default=None): diff --git a/lib/core/Handles/HandlesDelete.py b/lib/core/Handles/HandlesDelete.py index 243733b..b9a2218 100644 --- a/lib/core/Handles/HandlesDelete.py +++ b/lib/core/Handles/HandlesDelete.py @@ -40,7 +40,7 @@ class DeleteHandle(BaseHandle): if ClassName: PropKey = f'{ClassName}.{AttrName}' PropInfo = self.Trans.SymbolTable.get(PropKey) - if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: SelfVar = Gen._get_var_ptr('self') if SelfVar: SelfPtr = Gen._load(SelfVar, name="self") @@ -54,7 +54,7 @@ class DeleteHandle(BaseHandle): if ClassName: PropKey = f'{ClassName}.{AttrName}' PropInfo = self.Trans.SymbolTable.get(PropKey) - if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: obj_val = self.Trans.ExprHandler.HandleExprLlvm(target.value) if obj_val: DeleterFunc = Gen._get_function(PropKey + '$del') diff --git a/lib/core/Handles/HandlesExpr.py b/lib/core/Handles/HandlesExpr.py index dbf117c..9335983 100644 --- a/lib/core/Handles/HandlesExpr.py +++ b/lib/core/Handles/HandlesExpr.py @@ -329,7 +329,7 @@ class ExprHandle(BaseHandle): if VarName not in getattr(Gen, '_define_constants', {}): try: sym_info = self.translator.SymbolTable.get(VarName) - if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None: + if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None: val = sym_info.DefineValue if isinstance(val, int): # Use VarType hint if available @@ -400,9 +400,9 @@ class ExprHandle(BaseHandle): return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0) if VarName in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[VarName] - if getattr(SymInfo, 'IsEnumMember', None) and isinstance(getattr(SymInfo, 'value', None), int): + if SymInfo.IsEnumMember and isinstance(SymInfo.value, int): return ir.Constant(ir.IntType(32), SymInfo.value) - if getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsFuncPtr', False): + if SymInfo.IsFunction or SymInfo.IsFuncPtr: MangledName = Gen._mangle_func_name(VarName) if MangledName in Gen.module.globals: g = Gen.module.globals[MangledName] diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py index 2a29cce..53821ab 100644 --- a/lib/core/Handles/HandlesExprAttr.py +++ b/lib/core/Handles/HandlesExprAttr.py @@ -92,7 +92,7 @@ class ExprAttrHandle(BaseHandle): PossibleKeys.append(key) for lookup_key in PossibleKeys: SymInfo = self.Trans.SymbolTable.get(lookup_key) - if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None: + if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None: return self._make_define_constant(Gen, SymInfo.DefineValue) # 也检查 _define_constants define_constants = getattr(Gen, '_define_constants', {}) @@ -202,7 +202,7 @@ class ExprAttrHandle(BaseHandle): # 检查 property getter PropKey = f'{ClassName}.{Node.attr}' PropInfo = self.Trans.SymbolTable.get(PropKey) - if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: SelfVar = Gen._get_var_ptr('self') if SelfVar: SelfPtr = Gen._load(SelfVar, name="self") @@ -234,16 +234,16 @@ class ExprAttrHandle(BaseHandle): def _handle_attr_enum(self, Node, VarName): """处理枚举成员访问 (VarName 是枚举类型名)""" SymInfo = self.Trans.SymbolTable.get(VarName) - if not SymInfo or not getattr(SymInfo, 'IsEnum', None): + if not SymInfo or not SymInfo.IsEnum: return None if Node.attr in self.Trans.SymbolTable: MemberInfo = self.Trans.SymbolTable[Node.attr] - if getattr(MemberInfo, 'IsEnumMember', None) and getattr(MemberInfo, 'EnumName', None) == VarName: - if isinstance(getattr(MemberInfo, 'value', None), int): + if MemberInfo.IsEnumMember and MemberInfo.EnumName == VarName: + if isinstance(MemberInfo.value, int): return ir.Constant(ir.IntType(32), MemberInfo.value) for key, info in self.Trans.SymbolTable.items(): - if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == VarName and key == Node.attr: - if isinstance(getattr(info, 'value', None), int): + if info.IsEnumMember and info.EnumName == VarName and key == Node.attr: + if isinstance(info.value, int): return ir.Constant(ir.IntType(32), info.value) return None @@ -285,7 +285,7 @@ class ExprAttrHandle(BaseHandle): # 检查 property getter PropKey = f'{ClassName}.{AttrName}' PropInfo = self.Trans.SymbolTable.get(PropKey) - if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: ObjVal = self.HandleExprLlvm(Node.value) GetterFunc = Gen._get_function(PropKey) if GetterFunc and ObjVal: @@ -297,7 +297,7 @@ class ExprAttrHandle(BaseHandle): TypeInfo = self.Trans.SymbolTable.get(ClassName) IsUnion = TypeInfo.IsUnion if TypeInfo else False IsCenum = TypeInfo.IsEnum if TypeInfo else False - IsRenum = getattr(TypeInfo, 'IsRenum', False) if TypeInfo else False + IsRenum = TypeInfo.IsRenum if TypeInfo else False # REnum 处理 if IsRenum: @@ -322,12 +322,12 @@ class ExprAttrHandle(BaseHandle): for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"): if qname in self.Trans.SymbolTable: info = self.Trans.SymbolTable[qname] - if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int): + if info.IsEnumMember and isinstance(info.value, int): return ir.Constant(ir.IntType(32), info.value) for key, info in self.Trans.SymbolTable.items(): if key == AttrName: - if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == ClassName: - if isinstance(getattr(info, 'value', None), int): + if info.IsEnumMember and info.EnumName == ClassName: + if isinstance(info.value, int): return ir.Constant(ir.IntType(32), info.value) break @@ -1062,7 +1062,7 @@ class ExprAttrHandle(BaseHandle): possible_keys.append(key) for lookup_key in possible_keys: SymInfo = self.Trans.SymbolTable.get(lookup_key) - if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None: + if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None: val = SymInfo.DefineValue if isinstance(val, int): if val > 0x7FFFFFFF or val < -0x80000000: @@ -1085,21 +1085,21 @@ class ExprAttrHandle(BaseHandle): for enum_key in enum_keys: if enum_key in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[enum_key] - if getattr(SymInfo, 'IsEnum', None): + if SymInfo.IsEnum: for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"): if qname in self.Trans.SymbolTable: info = self.Trans.SymbolTable[qname] - if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int): + if info.IsEnumMember and isinstance(info.value, int): return ir.Constant(ir.IntType(32), info.value) for key, info in self.Trans.SymbolTable.items(): - if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_key and key == member_name: - if isinstance(getattr(info, 'value', None), int): + if info.IsEnumMember and info.EnumName == enum_key and key == member_name: + if isinstance(info.value, int): return ir.Constant(ir.IntType(32), info.value) for key, info in self.Trans.SymbolTable.items(): - if getattr(info, 'IsEnumMember', None) and key == member_name: - if isinstance(getattr(info, 'value', None), int): + if info.IsEnumMember and key == member_name: + if isinstance(info.value, int): for enum_key in enum_keys: - if getattr(info, 'EnumName', None) == enum_key: + if info.EnumName == enum_key: return ir.Constant(ir.IntType(32), info.value) return None diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py index 6b7c02c..c6e698f 100644 --- a/lib/core/Handles/HandlesExprBuiltin.py +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -539,7 +539,7 @@ class ExprBuiltinHandle(BaseHandle): LastPart = arg.attr if LastPart in self.Trans.SymbolTable: AttrInfo = self.Trans.SymbolTable[LastPart] - if getattr(AttrInfo, 'IsEnumMember', None) and getattr(AttrInfo, 'EnumName', None): + if AttrInfo.IsEnumMember and AttrInfo.EnumName: enum_type_name = AttrInfo.EnumName elif isinstance(arg.value, ast.Attribute): attr_path = _get_attr_path(arg) @@ -554,14 +554,14 @@ class ExprBuiltinHandle(BaseHandle): for qname in (qualified_name_dot, qualified_name_under): if qname in self.Trans.SymbolTable: info = self.Trans.SymbolTable[qname] - if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name: + if info.IsEnumMember and info.EnumName == enum_class_name: enum_member_found = info break if not enum_member_found: for key in self.Trans.SymbolTable: if key == LastPart: info = self.Trans.SymbolTable[key] - if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name: + if info.IsEnumMember and info.EnumName == enum_class_name: enum_member_found = info break if enum_member_found: diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index c4d3913..46987d3 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -435,7 +435,7 @@ class ExprCallHandle(BaseHandle): if first_part in aliases: ModulePath = aliases[first_part] + ModulePath[len(first_part):] is_instance_var = isinstance(Node.func.value, ast.Name) and Node.func.value.id in Gen.var_struct_class and Node.func.value.id not in Gen.ModuleSha1Map - is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or (Node.func.value.id in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[Node.func.value.id], 'IsStruct', False))) + is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or (Node.func.value.id in self.Trans.SymbolTable and self.Trans.SymbolTable[Node.func.value.id].IsStruct)) if is_instance_var and not is_class_name: return self._HandleMethodCallLlvm(Node) FuncAttr = Node.func.attr @@ -454,11 +454,11 @@ class ExprCallHandle(BaseHandle): result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result - if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None): + if SymInfo.IsEnumMember and SymInfo.EnumName: EnumName = SymInfo.EnumName if EnumName in self.Trans.SymbolTable: EnumInfo = self.Trans.SymbolTable[EnumName] - if getattr(EnumInfo, 'IsRenum', False): + if EnumInfo.IsRenum: result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value) if result is not None: return result @@ -480,9 +480,9 @@ class ExprCallHandle(BaseHandle): FullAttrKey = f"{ModulePath}.{FuncAttr}" if FullAttrKey in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[FullAttrKey] - if getattr(SymInfo, 'IsTypedef', False): + if SymInfo.IsTypedef: return ir.Constant(ir.IntType(32), 0) - if getattr(SymInfo, 'IsStruct', False): + if SymInfo.IsStruct: if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr) if FuncAttr in Gen.structs: @@ -533,7 +533,7 @@ class ExprCallHandle(BaseHandle): raise Exception(f"Undefined method: 't.{FuncAttr}'") if isinstance(Node.func.value, ast.Attribute): inner_attr = Node.func.value.attr - if inner_attr in Gen.structs or (inner_attr in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[inner_attr], 'IsStruct', False)): + if inner_attr in Gen.structs or (inner_attr in self.Trans.SymbolTable and self.Trans.SymbolTable[inner_attr].IsStruct): static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, FuncAttr) if static_result is not None: return static_result @@ -569,11 +569,11 @@ class ExprCallHandle(BaseHandle): if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}: # 先检查 FuncAttr 是否是函数/变量,如果是则跳过 struct 声明 _attr_sym = self.Trans.SymbolTable.get(FuncAttr) - _is_func_or_var = _attr_sym and (getattr(_attr_sym, 'IsFunction', False) or getattr(_attr_sym, 'IsVariable', False)) + _is_func_or_var = _attr_sym and (_attr_sym.IsFunction or _attr_sym.IsVariable) if not _is_func_or_var and ModulePath: _full_key = f"{ModulePath}.{FuncAttr}" _full_sym = self.Trans.SymbolTable.get(_full_key) - if _full_sym and (getattr(_full_sym, 'IsFunction', False) or getattr(_full_sym, 'IsVariable', False)): + if _full_sym and (_full_sym.IsFunction or _full_sym.IsVariable): _is_func_or_var = True # 优先检查 FuncAttr 是否为 struct/类构造器 if not _is_func_or_var and FuncAttr not in Gen.structs: @@ -587,7 +587,7 @@ class ExprCallHandle(BaseHandle): FullAttrKey = f"{ModulePath}.{FuncAttr}" if FullAttrKey in self.Trans.SymbolTable: FullSymInfo = self.Trans.SymbolTable[FullAttrKey] - if getattr(FullSymInfo, 'IsStruct', False) or getattr(FullSymInfo, 'IsCpythonObject', False): + if FullSymInfo.IsStruct or FullSymInfo.IsCpythonObject: if FuncAttr not in Gen.structs: self._ensure_struct_declared(FuncAttr) if FuncAttr in Gen.structs: @@ -649,7 +649,7 @@ class ExprCallHandle(BaseHandle): Gen = self.Trans.LlvmGen # 如果名称是函数或变量,不应创建 struct SymInfo = self.Trans.SymbolTable.get(class_name) - if SymInfo and (getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsVariable', False)): + if SymInfo and (SymInfo.IsFunction or SymInfo.IsVariable): return if class_name in Gen.structs: existing = Gen.structs[class_name] @@ -721,16 +721,16 @@ class ExprCallHandle(BaseHandle): SymKey = f'{ClassName}.{MethodName}' SymInfo = self.Trans.SymbolTable.get(SymKey) or self.Trans.SymbolTable.get(MethodName) if SymInfo and SymInfo.IsFunction: - ret_type_info = getattr(SymInfo, 'FuncPtrReturn', None) + ret_type_info = SymInfo.FuncPtrReturn if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: ret_type = ret_type_info.ToLLVM(Gen) else: ret_type = Gen._CType2LLVM('i32', False) - param_type_infos = [pt for _, pt in (getattr(SymInfo, 'FuncPtrParams', None) or [])] + param_type_infos = [pt for _, pt in (SymInfo.FuncPtrParams or [])] if isinstance(ret_type, ir.VoidType): ret_type = ir.IntType(32) llvm_param_types = [] - is_static = hasattr(SymInfo, 'MetaList') and FuncMeta.STATIC_METHOD in SymInfo.MetaList + is_static = FuncMeta.STATIC_METHOD in SymInfo.MetaList if ClassName in Gen.structs and not is_static: llvm_param_types.append(ir.PointerType(Gen.structs[ClassName])) for pt in param_type_infos: @@ -762,8 +762,8 @@ class ExprCallHandle(BaseHandle): CallArgs = [] SymKey = f'{ClassName}.{MethodName}' SymInfo = self.Trans.SymbolTable.get(SymKey) or self.Trans.SymbolTable.get(MethodName) - is_static_call = SymInfo is not None and hasattr(SymInfo, 'MetaList') and FuncMeta.STATIC_METHOD in SymInfo.MetaList - is_classmethod_call = SymInfo is not None and hasattr(SymInfo, 'MetaList') and FuncMeta.CLASS_METHOD in SymInfo.MetaList + is_static_call = SymInfo is not None and FuncMeta.STATIC_METHOD in SymInfo.MetaList + is_classmethod_call = SymInfo is not None and FuncMeta.CLASS_METHOD in SymInfo.MetaList # @classmethod: 在参数列表前插入 cls(栈上分配的类实例指针) if is_classmethod_call and ClassName in Gen.structs: ClsPtr = Gen._alloca(Gen.structs[ClassName], name=f"cls_{ClassName}") @@ -1230,13 +1230,13 @@ class ExprCallHandle(BaseHandle): mangled_name = Gen._mangle_func_name(func_name, ModulePath) sym_key = f'{ModulePath}.{func_name}' sym_info = self.Trans.SymbolTable.get(sym_key) or self.Trans.SymbolTable.get(func_name) - is_inline = sym_info and (getattr(sym_info, 'IsInline', False) or isinstance(getattr(sym_info, 'Storage', None), t.CInline)) - if is_inline and getattr(sym_info, 'InlineBody', None): + is_inline = sym_info and (sym_info.IsInline or isinstance(sym_info.Storage, t.CInline)) + if is_inline and sym_info.InlineBody: self._HandleInlineExpandLlvm(Node, sym_info) return ir.Constant(ir.IntType(32), 1) sym_info_exact = self.Trans.SymbolTable.get(sym_key) if sym_info_exact: - exact_params = getattr(sym_info_exact, 'FuncPtrParams', []) + exact_params = sym_info_exact.FuncPtrParams exact_param_names = [pn for pn, _ in exact_params] if exact_param_names: provided = len(Node.args) @@ -1280,15 +1280,15 @@ class ExprCallHandle(BaseHandle): if not sym_info: sym_info = self.Trans.SymbolTable.get(func_name) if sym_info: - is_func = getattr(sym_info, 'IsFunction', False) - sym_is_variadic = getattr(sym_info, 'IsVariadic', False) + is_func = sym_info.IsFunction + sym_is_variadic = sym_info.IsVariadic if is_func: - ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) + ret_type_info = sym_info.FuncPtrReturn if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: ret_type = ret_type_info.ToLLVM(Gen) else: ret_type = Gen._CType2LLVM('i32', False) - sym_params = getattr(sym_info, 'FuncPtrParams', []) + sym_params = sym_info.FuncPtrParams param_type_infos = [pt for _, pt in sym_params] if isinstance(ret_type, ir.VoidType): ret_type = ir.IntType(32) @@ -1411,15 +1411,15 @@ class ExprCallHandle(BaseHandle): if not sym_info: sym_info = self.Trans.SymbolTable.get(func_name) if sym_info: - is_func = getattr(sym_info, 'IsFunction', False) - sym_is_variadic = getattr(sym_info, 'IsVariadic', False) + is_func = sym_info.IsFunction + sym_is_variadic = sym_info.IsVariadic if is_func: - ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) + ret_type_info = sym_info.FuncPtrReturn if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: ret_type = ret_type_info.ToLLVM(Gen) else: ret_type = Gen._CType2LLVM('i32', False) - param_type_infos = [pt for _, pt in getattr(sym_info, 'FuncPtrParams', [])] + param_type_infos = [pt for _, pt in sym_info.FuncPtrParams] if isinstance(ret_type, ir.VoidType): ret_type = ir.IntType(32) llvm_param_types = [] @@ -1830,7 +1830,7 @@ class ExprCallHandle(BaseHandle): if ClassName: SymKey = f'{ClassName}.{MethodName}' SymInfo = self.Trans.SymbolTable.get(SymKey) - if SymInfo and hasattr(SymInfo, 'MetaList'): + if SymInfo and SymInfo.MetaList: if FuncMeta.STATIC_METHOD in SymInfo.MetaList: return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName) if FuncMeta.CLASS_METHOD in SymInfo.MetaList: diff --git a/lib/core/Handles/HandlesIf.py b/lib/core/Handles/HandlesIf.py index 3329eb7..b5ac138 100644 --- a/lib/core/Handles/HandlesIf.py +++ b/lib/core/Handles/HandlesIf.py @@ -73,7 +73,7 @@ class IfHandle(BaseHandle): return True if name in self.Trans.SymbolTable: info = self.Trans.SymbolTable[name] - if getattr(info, 'IsDefine', False): + if info.IsDefine: return True platform_macros = self._get_platform_macros() return name in platform_macros @@ -86,8 +86,8 @@ class IfHandle(BaseHandle): return val if name in self.Trans.SymbolTable: info = self.Trans.SymbolTable[name] - if getattr(info, 'IsDefine', False): - val = getattr(info, 'DefineValue', 0) + if info.IsDefine: + val = info.DefineValue if isinstance(val, (int, float)): return val platform_macros = self._get_platform_macros() @@ -129,118 +129,21 @@ class IfHandle(BaseHandle): return macros def _eval_const_expr(self, node): - if isinstance(node, ast.Constant): - val = node.value - if isinstance(val, bool): - return 1 if val else 0 - if isinstance(val, int): - return val - if isinstance(val, float): - return 1 if val != 0.0 else 0 - return 0 - if isinstance(node, ast.Name): - name = node.id - val = self._get_macro_value(name) - if val is not None: - return val - return None - if isinstance(node, ast.Attribute): - full_key = self._get_attr_full_name(node) - if full_key: - val = self._get_macro_value(full_key) - if val is not None: - return val - short_name = full_key.split('.')[-1] if '.' in full_key else full_key - val = self._get_macro_value(short_name) - if val is not None: - return val - return None - if isinstance(node, ast.UnaryOp): - operand = self._eval_const_expr(node.operand) - if operand is None: - return None - if isinstance(node.op, ast.Not): - return 1 if not operand else 0 - if isinstance(node.op, ast.USub): - return -operand - if isinstance(node.op, ast.Invert): - return ~operand - return None - if isinstance(node, ast.BinOp): - left = self._eval_const_expr(node.left) - right = self._eval_const_expr(node.right) - if left is None or right is None: - return None - try: - if isinstance(node.op, ast.Add): - return left + right - elif isinstance(node.op, ast.Sub): - return left - right - elif isinstance(node.op, ast.Mult): - return left * right - elif isinstance(node.op, ast.FloorDiv): - return left // right if right != 0 else 0 - elif isinstance(node.op, ast.Mod): - return left % right if right != 0 else 0 - elif isinstance(node.op, ast.LShift): - return left << right - elif isinstance(node.op, ast.RShift): - return left >> right - elif isinstance(node.op, ast.BitOr): - return left | right - elif isinstance(node.op, ast.BitAnd): - return left & right - elif isinstance(node.op, ast.BitXor): - return left ^ right - except Exception: - return None - return None - if isinstance(node, ast.BoolOp): - if isinstance(node.op, ast.And): - for val in node.values: - result = self._eval_const_expr(val) - if result is None: - return None - if not result: - return 0 - return 1 - elif isinstance(node.op, ast.Or): - for val in node.values: - result = self._eval_const_expr(val) - if result is None: - return None - if result: - return 1 - return 0 - if isinstance(node, ast.Compare): - left = self._eval_const_expr(node.left) - if left is None: - return None - for op, comparator in zip(node.ops, node.comparators): - right = self._eval_const_expr(comparator) - if right is None: - return None - if isinstance(op, ast.Eq): - result = left == right - elif isinstance(op, ast.NotEq): - result = left != right - elif isinstance(op, ast.Lt): - result = left < right - elif isinstance(op, ast.LtE): - result = left <= right - elif isinstance(op, ast.Gt): - result = left > right - elif isinstance(op, ast.GtE): - result = left >= right - else: - return None - if not result: - return 0 - return 1 - if isinstance(node, ast.Call): - if self._is_cif_call(node): + from lib.core.ConstEvaluator import ConstEvaluator, EvalContext + Gen = self.Trans.LlvmGen + ctx = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable) + result = 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 + 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): Gen = self.Trans.LlvmGen diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 86f5b61..332e41b 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -74,14 +74,14 @@ class ImportHandle(BaseHandle): if not asname or asname == name: # Check if this name is a CDefine constant in SymbolTable sym_info = self.Trans.SymbolTable.get(name) - if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None: + 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.get(prefix_key) - if sym_info2 and getattr(sym_info2, 'IsDefine', None) and getattr(sym_info2, 'DefineValue', None) is not None: + 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 @@ -893,7 +893,7 @@ class ImportHandle(BaseHandle): elif isinstance(value_node, ast.Name): if value_node.id in getattr(self.Trans, 'SymbolTable', {}): info = self.Trans.SymbolTable[value_node.id] - if getattr(info, 'IsDefine', None) and getattr(info, 'DefineValue', None) is not None: + if info.IsDefine and info.DefineValue is not None: return info.DefineValue elif isinstance(value_node, ast.Call): if isinstance(value_node.func, ast.Attribute): @@ -1020,7 +1020,7 @@ class ImportHandle(BaseHandle): ParamTypes = [] is_method = is_class_method or '.__' in FuncName class_name_for_method = FuncName.split('.')[0] if '.' in FuncName else None - class_is_cpython = class_name_for_method and class_name_for_method in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[class_name_for_method], 'IsCpythonObject', False) + class_is_cpython = class_name_for_method and class_name_for_method in self.Trans.SymbolTable and self.Trans.SymbolTable[class_name_for_method].IsCpythonObject for i, Arg in enumerate(Node.args.args): if i == 0 and is_method: # self parameter of a method should always be a pointer to the struct diff --git a/lib/core/Handles/HandlesMatch.py b/lib/core/Handles/HandlesMatch.py index f224008..c65f661 100644 --- a/lib/core/Handles/HandlesMatch.py +++ b/lib/core/Handles/HandlesMatch.py @@ -21,7 +21,7 @@ class MatchHandle(BaseHandle): VarName = Node.subject.id if VarName in self.Trans.SymbolTable: TypeInfo = self.Trans.SymbolTable[VarName] - if getattr(TypeInfo, 'IsRenum', False): + if TypeInfo.IsRenum: IsRenumMatch = True RenumName = TypeInfo.Name SubjectPtr = Gen._loadVar(VarName) @@ -37,11 +37,11 @@ class MatchHandle(BaseHandle): VariantName = cls_node.attr if VariantName and VariantName in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[VariantName] - if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None): + if SymInfo.IsEnumMember and SymInfo.EnumName: EnumName = SymInfo.EnumName if EnumName in self.Trans.SymbolTable: EnumInfo = self.Trans.SymbolTable[EnumName] - if getattr(EnumInfo, 'IsRenum', False): + if EnumInfo.IsRenum: IsRenumMatch = True RenumName = EnumName if SubjectPtr is None: @@ -209,7 +209,7 @@ class MatchHandle(BaseHandle): TagValue = None if VariantName in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[VariantName] - if getattr(SymInfo, 'IsEnumMember', False): + if SymInfo.IsEnumMember: TagValue = SymInfo.value if TagValue is not None: CaseValues.append(ir.Constant(ir.IntType(32), TagValue)) diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index cf9f676..278e4d4 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -120,8 +120,8 @@ class HandlesTypeMerge(BaseHandle): # 也尝试在符号表中查找模块别名 if ModulePath in self.Trans.SymbolTable: entry = self.Trans.SymbolTable[ModulePath] - if isinstance(entry, CTypeInfo) and getattr(entry, 'IsModuleAlias', False): - resolved = getattr(entry, 'ResolvedModule', None) + if isinstance(entry, CTypeInfo) and entry.IsModuleAlias: + resolved = entry.ResolvedModule if resolved: ModulePath = resolved diff --git a/lib/core/Handles/HandlesWith.py b/lib/core/Handles/HandlesWith.py index 1b1fc34..f1d700b 100644 --- a/lib/core/Handles/HandlesWith.py +++ b/lib/core/Handles/HandlesWith.py @@ -25,7 +25,7 @@ class WithHandle(BaseHandle): if ClassName and ClassName not in Gen.structs: if ClassName in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[ClassName] - if getattr(SymInfo, 'IsStruct', False) or getattr(SymInfo, 'IsRenum', False): + if SymInfo.IsStruct or SymInfo.IsRenum: pass else: ClassName = None diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index 5c80522..6d7ef20 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -173,28 +173,28 @@ class BaseGenMixin: return ir.IntType(8) if hasattr(self, 'SymbolTable') and self.SymbolTable and clean_name in self.SymbolTable: Entry = self.SymbolTable[clean_name] - if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: + if Entry.IsTypedef: resolved_str = self._resolve_typedef(clean_name) if resolved_str != clean_name: return self._type_str_to_llvm(resolved_str) - if hasattr(Entry, 'BaseType') and Entry.BaseType: + if Entry.BaseType: from lib.includes import t as _t - if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0: + if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: resolved = self._resolve_ctype_to_str(Entry) if resolved: return self._type_str_to_llvm(resolved) - if hasattr(Entry, 'IsRenum') and Entry.IsRenum: + if Entry.IsRenum: if clean_name in self.structs: return self.structs[clean_name] - if hasattr(Entry, 'IsEnum') and Entry.IsEnum: + if Entry.IsEnum: return ir.IntType(32) - if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + if Entry.IsExceptionClass: return ir.IntType(32) - if hasattr(Entry, 'IsFunction') and Entry.IsFunction: + if Entry.IsFunction: return ir.PointerType(ir.IntType(8)) - if hasattr(Entry, 'IsVariable') and Entry.IsVariable: + if Entry.IsVariable: return ir.PointerType(ir.IntType(8)) - if hasattr(Entry, 'BaseType'): + if Entry.BaseType: from lib.includes import t as _t if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum): return ir.IntType(32) @@ -237,17 +237,17 @@ class BaseGenMixin: # 2. 再查 SymbolTable(用户定义的 typedef) if hasattr(self, 'SymbolTable') and self.SymbolTable and name in self.SymbolTable: Entry = self.SymbolTable[name] - if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: - if hasattr(Entry, 'BaseType') and Entry.BaseType: + if Entry.IsTypedef: + if Entry.BaseType: from lib.includes import t as _t - if not isinstance(Entry.BaseType, (_t._CTypedef,)) and getattr(Entry, 'PtrCount', 0) == 0: + if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0: llvm_str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType) if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): return int(llvm_str[1:]) - if hasattr(Entry, 'OriginalType') and Entry.OriginalType: + if Entry.OriginalType: from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType: - if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and getattr(Entry.OriginalType, 'PtrCount', 0) == 0: + if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0: llvm_str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType) if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): return int(llvm_str[1:]) diff --git a/lib/core/LLVMCG/StructGen.py b/lib/core/LLVMCG/StructGen.py index 2c0f089..ec6af62 100644 --- a/lib/core/LLVMCG/StructGen.py +++ b/lib/core/LLVMCG/StructGen.py @@ -207,13 +207,13 @@ class StructGenMixin: is_packed = ClassName in self.class_packed if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable: Entry = self.SymbolTable[ClassName] - if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + if Entry.IsExceptionClass: continue - if hasattr(Entry, 'IsEnum') and Entry.IsEnum: - if not getattr(Entry, 'IsRenum', False): + if Entry.IsEnum: + if not Entry.IsRenum: continue - if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: - if hasattr(Entry, 'BaseType') and Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)): + if Entry.IsTypedef: + if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)): import lib.includes.t as _t if not isinstance(Entry.BaseType, (_t._CTypedef,)): continue @@ -304,10 +304,10 @@ class StructGenMixin: for ClassName in all_classes: if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable: Entry = self.SymbolTable[ClassName] - if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + if Entry.IsExceptionClass: continue - if hasattr(Entry, 'IsEnum') and Entry.IsEnum: - if not getattr(Entry, 'IsRenum', False): + if Entry.IsEnum: + if not Entry.IsRenum: continue existing_st = self.structs.get(ClassName) if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0: diff --git a/lib/core/LLVMCG/TypeConvert.py b/lib/core/LLVMCG/TypeConvert.py index ac64018..2e4b1a1 100644 --- a/lib/core/LLVMCG/TypeConvert.py +++ b/lib/core/LLVMCG/TypeConvert.py @@ -137,7 +137,7 @@ class TypeConvertMixin: if isinstance(BaseType, _t.CDefine): # Use 64-bit type if the define value exceeds 32-bit range - if type_info and hasattr(type_info, 'DefineValue') and isinstance(type_info.DefineValue, int): + if type_info and isinstance(type_info.DefineValue, int): if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF: return ir.IntType(64) return ir.IntType(32) @@ -180,8 +180,8 @@ class TypeConvertMixin: if OriginalType: current = OriginalType continue - elif hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: - if hasattr(Entry, 'OriginalType') and Entry.OriginalType: + elif Entry.IsTypedef: + if Entry.OriginalType: if isinstance(Entry.OriginalType, _CTypeInfo): if Entry.OriginalType.IsFuncPtr: return 'Callable' @@ -189,9 +189,9 @@ class TypeConvertMixin: elif isinstance(Entry.OriginalType, str): current = Entry.OriginalType continue - if hasattr(Entry, 'BaseType') and Entry.BaseType: + if Entry.BaseType: from lib.includes import t as _t - if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0: + if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: resolved = self._resolve_ctype_to_str(Entry) if resolved and resolved != current: current = resolved @@ -396,24 +396,24 @@ class TypeConvertMixin: return basic_stripped if hasattr(self, 'SymbolTable') and self.SymbolTable and type_str in self.SymbolTable: _Entry = self.SymbolTable[type_str] - if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef: + if _Entry.IsTypedef: resolved_str = self._resolve_typedef(type_str) if resolved_str != type_str: return self._type_str_to_llvm(resolved_str, IsPtr) - if hasattr(_Entry, 'BaseType') and _Entry.BaseType: + if _Entry.BaseType: from lib.includes import t as _t - if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0: + if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or _Entry.PtrCount > 0: resolved = self._resolve_ctype_to_str(_Entry) if resolved: return self._type_str_to_llvm(resolved, IsPtr) - if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum: + if _Entry.IsRenum: if type_str in self.structs: return self.structs[type_str] - if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum: + if _Entry.IsEnum: return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass: + if _Entry.IsExceptionClass: return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if hasattr(_Entry, 'BaseType'): + if _Entry.BaseType: from lib.includes import t as _t if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) @@ -431,24 +431,24 @@ class TypeConvertMixin: return basic_last if hasattr(self, 'SymbolTable') and self.SymbolTable and LastPart in self.SymbolTable: _Entry = self.SymbolTable[LastPart] - if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef: + if _Entry.IsTypedef: resolved_str = self._resolve_typedef(LastPart) if resolved_str != LastPart: return self._type_str_to_llvm(resolved_str, IsPtr) - if hasattr(_Entry, 'BaseType') and _Entry.BaseType: + if _Entry.BaseType: from lib.includes import t as _t - if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0: + if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or _Entry.PtrCount > 0: resolved = self._resolve_ctype_to_str(_Entry) if resolved: return self._type_str_to_llvm(resolved, IsPtr) - if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum: + if _Entry.IsRenum: if LastPart in self.structs: return self.structs[LastPart] - if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum: + if _Entry.IsEnum: return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass: + if _Entry.IsExceptionClass: return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if hasattr(_Entry, 'BaseType'): + if _Entry.BaseType: from lib.includes import t as _t if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) diff --git a/lib/core/SymbolData.py b/lib/core/SymbolData.py new file mode 100644 index 0000000..21aa109 --- /dev/null +++ b/lib/core/SymbolData.py @@ -0,0 +1,79 @@ +"""符号表处理的数据结构:四阶段管线中传递的中间数据""" +from __future__ import annotations +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional, Tuple + + +@dataclass +class ClassSymbolData: + """从 AST 提取的类符号数据""" + name: str + type_kind: str # 'struct', 'union', 'enum', 'exception' + lineno: int + members: Dict[str, Any] + 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: Any = None + value: Any = None + has_cdefine: bool = False + has_postdef: bool = False + has_ctypedef: bool = False + # 解析结果(由 Resolver 设置,Inserter 使用) + original_type_kind: Optional[str] = None + original_class: Any = None + members: Optional[Dict] = None + + +@dataclass +class FuncSymbolData: + """函数符号数据(含原始注解和解析结果)""" + name: str + lineno: int + # 原始数据(由 Extractor 设置) + returns_node: Any = None + params: List = field(default_factory=list) # [(name, annotation_node), ...] + is_variadic: bool = False + is_inline: bool = False + # 解析结果(由 Resolver 设置) + ret_type: Any = None + param_types: List = field(default_factory=list) # [str, ...] + + +@dataclass +class DefineSymbolData: + """Define 符号数据(含原始值和解析结果)""" + name: str + lineno: int + # 原始数据(由 Extractor 设置) + value_node: Any = None + # 解析结果(由 Resolver 设置) + value: Any = None + + +@dataclass +class AnonymousTypeData: + """匿名类型数据""" + name: str + is_union: bool + members: Dict[str, Any] + 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) diff --git a/lib/core/SymbolExtractor.py b/lib/core/SymbolExtractor.py new file mode 100644 index 0000000..288f9d7 --- /dev/null +++ b/lib/core/SymbolExtractor.py @@ -0,0 +1,237 @@ +"""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.includes import t +from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline + + +class ASTSymbolExtractor: + """从 Python 源文件的 AST 中提取所有符号信息""" + + def __init__(self, symbol_table: SymbolTable): + self._symtab = symbol_table + + def extract(self, file_path: str) -> ModuleSymbols: + """提取文件中的所有符号信息""" + with open(file_path, 'r', encoding='utf-8') as f: + code = f.read() + tree = ast.parse(code) + + result = ModuleSymbols(file_path=file_path) + + # 第一步:收集所有类的成员和匿名类型 + class_members = {} + for node in tree.body: + if isinstance(node, ast.ClassDef): + members = {} + 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 = 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, members, anonymous_types, prefix=''): + """递归收集类成员,包括嵌套匿名类型""" + for item in class_node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + member_name = item.target.id + full_name = f'{prefix}{member_name}' if prefix else member_name + member_type = CTypeInfo.FromNode(item.annotation, self._symtab) + if member_type is None: + member_type = CTypeInfo() + member_type.BaseType = t.CInt() + is_ptr = member_type.IsPtr + if isinstance(item.annotation, ast.BinOp): + annotation_str = ast.dump(item.annotation) + if 'CPtr' in annotation_str: + is_ptr = True + members[full_name] = member_type.Copy() + + elif isinstance(item, ast.ClassDef): + is_anonymous = any( + any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases) + ) if item.bases else False + + if is_anonymous: + is_union = any( + any(AnnotationContainsTType(base, 'CUnion') for base in item.bases) + ) + + nested_name = 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 = f'{prefix}{item.name}.' if prefix else f'{item.name}.' + self._collect_members(item, members, anonymous_types, new_prefix) + + anonymous_members = {} + for full_name, member_info in members.items(): + if full_name.startswith(f"{nested_name}."): + member_name = 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, members_info) -> ClassSymbolData: + """从 ClassDef 节点提取类符号数据""" + type_kind = 'struct' + is_cpython_object = False + is_packed = 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 + decorator.value.id == 't' and + decorator.attr == 'Object'): + is_cpython_object = True + break + 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 arg.value.value.id == 't' 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, '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 = self._symtab.get(base.id) + if base_entry and base_entry.IsExceptionClass: + type_kind = 'exception' + break + + # 提取枚举成员 + enum_members = [] + if type_kind == 'enum': + next_enum_value = 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 = 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 = 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)) + + 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, result: ModuleSymbols): + """从 AnnAssign 节点提取 typedef 或 define 数据""" + var_name = node.target.id + has_cdefine = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False + has_postdef = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False + has_ctypedef = 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) -> FuncSymbolData: + """从 FunctionDef 节点提取函数符号数据""" + params = [(arg.arg, arg.annotation) for arg in node.args.args] + is_variadic = node.args.vararg is not None + is_inline = 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, + ) diff --git a/lib/core/SymbolInserter.py b/lib/core/SymbolInserter.py new file mode 100644 index 0000000..c1a1453 --- /dev/null +++ b/lib/core/SymbolInserter.py @@ -0,0 +1,68 @@ +"""Pass 3: SymbolInserter — 将解析后的符号插入 SymbolTable(主命名空间)""" +from __future__ import annotations +from typing import TYPE_CHECKING, List +if TYPE_CHECKING: + from lib.core.SymbolTable import SymbolTable + +from lib.core.SymbolData import ModuleSymbols + + +class SymbolInserter: + """将解析后的符号插入 SymbolTable 的主命名空间(无前缀)""" + + def __init__(self, symbol_table: SymbolTable): + self._symtab = symbol_table + + def insert(self, module_symbols: ModuleSymbols) -> List[str]: + """插入所有符号到主命名空间,返回已加载的符号名列表""" + loaded = [] + file_path = module_symbols.file_path + + # 插入类符号 + for cls in module_symbols.classes: + self._symtab._InsertClassSymbol( + cls.name, cls.type_kind, cls.lineno, file_path, + cls.members, cls.is_cpython_object, cls.is_packed + ) + loaded.append(cls.name) + + # 插入枚举成员(短名 + 类名.成员名) + if cls.type_kind == 'enum': + for member_name, _member_value, member_lineno in cls.enum_members: + self._symtab._InsertEnumMemberSymbol(member_name, cls.name, member_lineno, file_path) + loaded.append(member_name) + class_member_name = f"{cls.name}.{member_name}" + self._symtab._InsertEnumMemberSymbol(class_member_name, cls.name, member_lineno, file_path) + loaded.append(class_member_name) + + # 插入 typedef 符号 + for td in module_symbols.typedefs: + self._symtab._InsertTypedefSymbol( + td.name, td.original_type_kind, td.original_class, + td.lineno, file_path, td.members + ) + loaded.append(td.name) + + # 插入函数符号 + for func in module_symbols.functions: + self._symtab._InsertFuncSymbol( + func.name, func.ret_type, func.param_types, + func.lineno, file_path, func.is_variadic, func.is_inline + ) + loaded.append(func.name) + + # 插入 define 符号 + for define in module_symbols.defines: + self._symtab._InsertDefineSymbol( + define.name, define.value, define.lineno, file_path + ) + loaded.append(define.name) + + # 插入匿名类型符号(短名) + for anon_name, anon_data in module_symbols.anonymous_types.items(): + self._symtab._InsertAnonymousSymbol( + anon_name, anon_data.is_union, anon_data.members, + anon_data.lineno, file_path + ) + + return loaded diff --git a/lib/core/SymbolReexporter.py b/lib/core/SymbolReexporter.py new file mode 100644 index 0000000..5226c08 --- /dev/null +++ b/lib/core/SymbolReexporter.py @@ -0,0 +1,76 @@ +"""Pass 4: PackageReexporter — 将符号重新导出到命名空间前缀下""" +from __future__ import annotations +from typing import TYPE_CHECKING, List +if TYPE_CHECKING: + from lib.core.SymbolTable import SymbolTable + +from lib.core.SymbolData import ModuleSymbols + + +class PackageReexporter: + """将已解析的符号重新导出到命名空间前缀下(如 mpool.MPool)""" + + def __init__(self, symbol_table: SymbolTable): + self._symtab = symbol_table + + def reexport(self, module_symbols: ModuleSymbols, prefixes: List[str], lineno: int = 0) -> List[str]: + """将符号重新导出到所有命名空间前缀下,返回新增的符号名列表""" + loaded = [] + file_path = module_symbols.file_path + primary_prefix = prefixes[0] if prefixes else None + + for prefix in prefixes: + # 插入类符号(前缀.类名) + for cls in module_symbols.classes: + full_name = f"{prefix}.{cls.name}" + self._symtab._InsertClassSymbol( + full_name, cls.type_kind, cls.lineno, file_path, + cls.members, cls.is_cpython_object, cls.is_packed + ) + loaded.append(full_name) + + # 插入枚举成员(前缀.成员名) + if cls.type_kind == 'enum': + for member_name, _member_value, member_lineno in cls.enum_members: + full_member_name = f"{prefix}.{member_name}" + self._symtab._InsertEnumMemberSymbol(full_member_name, cls.name, member_lineno, file_path) + loaded.append(full_member_name) + + # 插入 typedef 符号(前缀.名称) + for td in module_symbols.typedefs: + full_name = f"{prefix}.{td.name}" + self._symtab._InsertTypedefSymbol( + full_name, td.original_type_kind, td.original_class, + td.lineno, file_path, td.members + ) + loaded.append(full_name) + + # 插入函数符号(前缀.名称) + for func in module_symbols.functions: + full_name = f"{prefix}.{func.name}" + self._symtab._InsertFuncSymbol( + full_name, func.ret_type, func.param_types, + func.lineno, file_path, func.is_variadic, func.is_inline + ) + loaded.append(full_name) + + # 插入 define 符号(前缀.名称) + for define in module_symbols.defines: + full_name = f"{prefix}.{define.name}" + self._symtab._InsertDefineSymbol( + full_name, define.value, define.lineno, file_path + ) + loaded.append(full_name) + + # 插入模块别名 + self._symtab._InsertModuleSymbol(prefix, lineno, file_path) + + # 插入匿名类型符号(前缀.名称) + for anon_name, anon_data in module_symbols.anonymous_types.items(): + full_type_name = f"{prefix}.{anon_name}" + self._symtab._InsertAnonymousSymbol( + full_type_name, anon_data.is_union, anon_data.members, + anon_data.lineno, file_path + ) + + return loaded diff --git a/lib/core/SymbolTable.py b/lib/core/SymbolTable.py index c6626c4..fc6f891 100644 --- a/lib/core/SymbolTable.py +++ b/lib/core/SymbolTable.py @@ -1,53 +1,24 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper -from lib.includes import t -from typing import Any, Dict, Iterator -import ast -import re - -def _IsTModuleType(TypeName: str) -> bool: - """检测类型名称是否是 t 模块中的类型(CType 或其他特殊类型)""" - if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'): - return True - TypeClass = getattr(t, TypeName, None) - if TypeClass and isinstance(TypeClass, type): - if issubclass(TypeClass, t.CType): - return True - FallbackClass = getattr(t, f'_{TypeName}', None) - if FallbackClass and isinstance(FallbackClass, type): - if issubclass(FallbackClass, t.CType): - return True - return False - -def _AnnotationContainsTType(node, TypeName: str) -> bool: - """检测 AST 节点中是否包含指定名称的 t 模块类型""" - if isinstance(node, ast.Attribute): - if (hasattr(node.value, 'id') and node.value.id == 't' 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 - - +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper +from lib.includes import t +from typing import Any, Dict, Iterator +import ast + +# 从 SymbolUtils 重导出,保持向后兼容 +from lib.core.SymbolUtils import IsTModuleType as _IsTModuleType +from lib.core.SymbolUtils import AnnotationContainsTType as _AnnotationContainsTType +from lib.core.SymbolUtils import CheckAnnotationHasCInline as _CheckAnnotationHasCInline + + class SymbolTable: def __init__(self, translator: "Translator"): self.translator = translator self._symbols: Dict[str, CTypeInfo] = {} + from lib.core.DiagnosticCollector import DiagnosticCollector + self.diagnostics = DiagnosticCollector() def clear(self): self._symbols.clear() @@ -204,731 +175,333 @@ class SymbolTable: if key not in skip_keys: info.set(key, value) - return info - - def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]: - return self._LoadSymbolsFromFile(FullModulePath, asname, lineno) - - def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]: - from lib.core.Handles.HandlesTypeMerge import HandlesTypeMerge - import ast - - LoadedSymbols = [] - - try: - with open(FilePath, 'r', encoding='utf-8') as f: - ModuleCode = f.read() - ModuleTree = ast.parse(ModuleCode) - - ClassMembers = {} - AnonymousTypes = {} - - for node in ModuleTree.body: - if isinstance(node, ast.ClassDef): - ClassName = node.name - MembersInfo = {} - - def CollectMembers(ClassNode, prefix=''): - for item in ClassNode.body: - if isinstance(item, ast.AnnAssign): - if isinstance(item.target, ast.Name): - MemberName = item.target.id - FullName = f'{prefix}{MemberName}' if prefix else MemberName - MemberTypeInfo = CTypeInfo.FromNode(item.annotation, self.translator.SymbolTable) - if MemberTypeInfo is None: - MemberTypeInfo = CTypeInfo() - MemberTypeInfo.BaseType = t.CInt() - IsPtr = MemberTypeInfo.IsPtr - if isinstance(item.annotation, ast.BinOp): - AnnotationStr = ast.dump(item.annotation) - if 'CPtr' in AnnotationStr: - IsPtr = True - MembersInfo[FullName] = MemberTypeInfo.Copy() - elif isinstance(item, ast.ClassDef): - IsAnonymous = any( - any(_AnnotationContainsTType(base, 'Anonymous') for base in item.bases) - ) if item.bases else False - - if IsAnonymous: - IsUnion = any( - any(_AnnotationContainsTType(base, 'CUnion') for base in item.bases) - ) - - NestedMemberName = f'{prefix}{item.name}' if prefix else item.name - MembersInfo[NestedMemberName] = CTypeInfo() - MembersInfo[NestedMemberName].BaseType = f'union {item.name}' if IsUnion else f'struct {item.name}' - MembersInfo[NestedMemberName].PtrCount = 0 - MembersInfo[NestedMemberName].ArrayDims = [] - - NewPrefix = f'{prefix}{item.name}.' if prefix else f'{item.name}.' - CollectMembers(item, NewPrefix) - - AnonymousMembers = {} - for FullName, MemberInfo in MembersInfo.items(): - if FullName.startswith(f"{NestedMemberName}."): - MemberName = FullName[len(NestedMemberName) + 1:] - AnonymousMembers[MemberName] = MemberInfo - - if item.name not in AnonymousTypes: - AnonymousTypes[item.name] = { - 'IsUnion': IsUnion, - 'members': AnonymousMembers, - 'lineno': item.lineno - } - - CollectMembers(node) - ClassMembers[ClassName] = MembersInfo - - LoadedSymbols = [] - - prefixes = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix - - for prefix in prefixes: - for node in ModuleTree.body: - if isinstance(node, ast.ClassDef): - ClassName = node.name - MembersInfo = ClassMembers.get(ClassName, {}) - - TypeKind = 'struct' - IsCpythonObject = False - IsPacked = 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 - decorator.value.id == 't' and - decorator.attr == 'Object'): - IsCpythonObject = True - break - 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 arg.value.value.id == 't' and arg.value.attr == 'attr' and arg.attr == 'packed': - IsPacked = True - - for base in node.bases: - if _AnnotationContainsTType(base, 'CUnion'): - TypeKind = 'union' - break - elif _AnnotationContainsTType(base, 'CEnum'): - TypeKind = 'enum' - break - elif _AnnotationContainsTType(base, 'CStruct'): - TypeKind = 'struct' - break - elif _AnnotationContainsTType(base, 'Object'): - IsCpythonObject = True - TypeKind = 'struct' - break - elif isinstance(base, ast.Name) and base.id == 'Exception': - TypeKind = 'exception' - break - elif isinstance(base, ast.Name): - base_entry = self.get(base.id) - if base_entry and hasattr(base_entry, 'IsExceptionClass') and base_entry.IsExceptionClass: - TypeKind = 'exception' - break - - if prefix == prefixes[0]: - self._InsertClassSymbol(ClassName, TypeKind, node.lineno, FilePath, MembersInfo, IsCpythonObject, IsPacked) - LoadedSymbols.append(ClassName) - - FullName = f"{prefix}.{ClassName}" - self._InsertClassSymbol(FullName, TypeKind, node.lineno, FilePath, MembersInfo, IsCpythonObject, IsPacked) - LoadedSymbols.append(FullName) - - if TypeKind == 'enum': - next_enum_value = 0 - for item in node.body: - if isinstance(item, ast.Assign): - if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): - MemberName = 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 - if prefix == prefixes[0]: - self._InsertEnumMemberSymbol(MemberName, ClassName, item.lineno, FilePath) - LoadedSymbols.append(MemberName) - ClassMemberName = f"{ClassName}.{MemberName}" - self._InsertEnumMemberSymbol(ClassMemberName, ClassName, item.lineno, FilePath) - LoadedSymbols.append(ClassMemberName) - FullMemberName = f"{prefix}.{MemberName}" - self._InsertEnumMemberSymbol(FullMemberName, ClassName, item.lineno, FilePath) - LoadedSymbols.append(FullMemberName) - elif isinstance(item, ast.AnnAssign): - if isinstance(item.target, ast.Name): - MemberName = 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 - if prefix == prefixes[0]: - self._InsertEnumMemberSymbol(MemberName, ClassName, item.lineno, FilePath) - LoadedSymbols.append(MemberName) - ClassMemberName = f"{ClassName}.{MemberName}" - self._InsertEnumMemberSymbol(ClassMemberName, ClassName, item.lineno, FilePath) - LoadedSymbols.append(ClassMemberName) - FullMemberName = f"{prefix}.{MemberName}" - self._InsertEnumMemberSymbol(FullMemberName, ClassName, item.lineno, FilePath) - LoadedSymbols.append(FullMemberName) - - elif isinstance(node, ast.AnnAssign): - if isinstance(node.target, ast.Name): - VarName = node.target.id - HasCDefine = _AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False - HasPostdef = _AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False - HasCtypedef = _AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False - IsPostdefWithTypedef = HasPostdef and HasCtypedef - - if HasCDefine: - DefineValue = None - if node.value: - DefineValue = self._eval_const_expr(node.value) - if prefix == prefixes[0]: - self._InsertDefineSymbol(VarName, DefineValue, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertDefineSymbol(FullName, DefineValue, node.lineno, FilePath) - LoadedSymbols.append(FullName) - continue - - def FindBaseType(n): - if isinstance(n, ast.Attribute): - if hasattr(n.value, 'id') and n.value.id == 't': - if n.attr == 'CPtr': - return 'ptr' - return n.attr - elif isinstance(n, ast.Subscript): - if isinstance(n.value, ast.Attribute) and isinstance(n.value.value, ast.Name) and n.value.value.id == 't' and n.value.attr == 'Callable': - return 'Callable' - elif isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr): - LeftResult = FindBaseType(n.left) - if LeftResult == 'ptr': - RightResult = FindBaseType(n.right) - return (RightResult if RightResult and RightResult != 'ptr' else 'void') + ' *' - if LeftResult == 'Callable': - return 'Callable' - RightResult = FindBaseType(n.right) - if RightResult == 'ptr': - return (LeftResult if LeftResult and LeftResult != 'ptr' else 'void') + ' *' - if RightResult == 'Callable': - return 'Callable' - if LeftResult: - return LeftResult - if RightResult: - return RightResult - return None - - if IsPostdefWithTypedef: - def FindPostdefArg(n): - if isinstance(n, ast.Call): - if isinstance(n.func, ast.Attribute): - if hasattr(n.func.value, 'id') and n.func.value.id == 't' and n.func.attr == 'Postdefinition': - if n.args and isinstance(n.args[0], ast.Name): - return n.args[0].id - elif isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr): - LeftResult = FindPostdefArg(n.left) - if LeftResult: - return LeftResult - RightResult = FindPostdefArg(n.right) - if RightResult: - return RightResult - return None - - OriginalClass = FindPostdefArg(node.annotation) - if OriginalClass and OriginalClass in ClassMembers: - MembersInfo = ClassMembers[OriginalClass] - OriginalType_kind = 'struct' - if OriginalClass in self: - OrigTypeInfo = self[OriginalClass] - if OrigTypeInfo.type_cls in (t.CStruct, t.CEnum, t.CUnion): - if OrigTypeInfo.type_cls is t.CStruct: - OriginalType_kind = 'struct' - elif OrigTypeInfo.type_cls is t.CEnum: - OriginalType_kind = 'enum' - elif OrigTypeInfo.type_cls is t.CUnion: - OriginalType_kind = 'union' - - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, OriginalType_kind, OriginalClass, node.lineno, FilePath, MembersInfo) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, OriginalType_kind, OriginalClass, node.lineno, FilePath, MembersInfo) - LoadedSymbols.append(FullName) - else: - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) - LoadedSymbols.append(FullName) - elif HasCtypedef: - BaseTypeName = FindBaseType(node.annotation) - _TYPE_QUALIFIERS = {'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'} - if BaseTypeName == 'Callable': - OriginalType = CTypeInfo() - OriginalType.IsFuncPtr = True - OriginalType.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - OriginalType.FuncPtrParams = [] - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) - LoadedSymbols.append(FullName) - continue - elif BaseTypeName and BaseTypeName not in _TYPE_QUALIFIERS: - CName = CTypeHelper.GetCName(BaseTypeName) - if CName and CName != BaseTypeName: - OriginalType = CName - else: - OriginalType = BaseTypeName[1:] if BaseTypeName.startswith('C') else BaseTypeName - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) - LoadedSymbols.append(FullName) - else: - if node.value: - ValueBaseType = FindBaseType(node.value) - _PTR_MODIFIERS = {'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'} - if ValueBaseType and ValueBaseType not in _PTR_MODIFIERS: - CName = CTypeHelper.GetCName(ValueBaseType) - if CName and CName != ValueBaseType: - OriginalType = CName - else: - OriginalType = ValueBaseType[1:] if ValueBaseType.startswith('C') else ValueBaseType - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) - LoadedSymbols.append(FullName) - continue - if isinstance(node.value, ast.BinOp) and isinstance(node.value.op, ast.BitOr): - LeftType = self._ResolveTypedefValueType(node.value.left) - RightType = self._ResolveTypedefValueType(node.value.right) - IsPtrType = RightType == 'ptr' or LeftType == 'ptr' - if IsPtrType: - BaseName = LeftType if LeftType != 'ptr' else (RightType if RightType != 'ptr' else '') - if BaseName: - OriginalType = BaseName + ' *' - else: - OriginalType = 'void *' - elif LeftType: - OriginalType = LeftType - elif RightType: - OriginalType = RightType - if OriginalType: - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) - LoadedSymbols.append(FullName) - continue - if isinstance(node.value, ast.Name): - RefName = node.value.id - if RefName in self: - RefInfo = self[RefName] - if RefInfo and RefInfo.IsTypedef and RefInfo.OriginalType: - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, 'typedef', RefInfo.OriginalType, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, 'typedef', RefInfo.OriginalType, node.lineno, FilePath) - LoadedSymbols.append(FullName) - continue - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) - LoadedSymbols.append(FullName) - else: - if prefix == prefixes[0]: - self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) - LoadedSymbols.append(VarName) - FullName = f"{prefix}.{VarName}" - self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) - LoadedSymbols.append(FullName) - - elif isinstance(node, ast.FunctionDef): - FuncName = node.name - RetType = self._GetFuncRetTypeStr(node.returns) - ParamTypes = [] - for arg in node.args.args: - if arg.annotation: - ParamTypes.append(self._GetFuncParamTypeStr(arg.annotation)) - else: - ParamTypes.append('i8*') - FuncIsVariadic = node.args.vararg is not None - FuncIsInline = self._CheckAnnotationHasCInline(node.returns) - if prefix == prefixes[0]: - self._InsertFuncSymbol(FuncName, RetType, ParamTypes, node.lineno, FilePath, FuncIsVariadic, FuncIsInline) - LoadedSymbols.append(FuncName) - FullName = f"{prefix}.{FuncName}" - self._InsertFuncSymbol(FullName, RetType, ParamTypes, node.lineno, FilePath, FuncIsVariadic, FuncIsInline) - LoadedSymbols.append(FullName) - - self._InsertModuleSymbol(prefix, lineno, FilePath) - - for AnonymousTypeName, AnonymousTypeData in AnonymousTypes.items(): - if prefix == prefixes[0]: - self._InsertAnonymousSymbol(AnonymousTypeName, AnonymousTypeData['IsUnion'], AnonymousTypeData['members'], AnonymousTypeData['lineno'], FilePath) - FullTypeName = f"{prefix}.{AnonymousTypeName}" - self._InsertAnonymousSymbol(FullTypeName, AnonymousTypeData['IsUnion'], AnonymousTypeData['members'], AnonymousTypeData['lineno'], FilePath) - - if LoadedSymbols: - pass - return LoadedSymbols - - except Exception as e: - import traceback - print(traceback.format_exc()) - print(f"[SymbolTable Error] Failed to Load module: {FilePath} - {e}") - return [] - - def _GetLLVMTypeStr(self, node): - if node is None: - return 'i32' - if isinstance(node, ast.Name): - if node.id == 'str': - return 'i8*' - elif node.id == 'int': - return 'i32' - elif node.id == 'bool': - return 'i8' - elif node.id == 'float': - return 'double' - elif node.id == 'None': - return 'void' - elif node.id in ('UINT8PTR', 'INT8PTR', 'BYTEPTR'): - return 'i8*' - elif node.id in ('UINT16PTR', 'INT16PTR'): - return 'i16*' - elif node.id in ('UINT32PTR', 'INT32PTR'): - return 'i32*' - elif node.id in ('UINT64PTR', 'INT64PTR'): - return 'i64*' - else: - if node.id in self: - entry = self[node.id] - if entry and hasattr(entry, 'IsTypedef') and entry.IsTypedef and hasattr(entry, 'OriginalType') and entry.OriginalType: - if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr: - return 'i8*' - elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType: - return entry.OriginalType.ToString() - elif isinstance(entry.OriginalType, str): - return entry.OriginalType - return 'i32' - elif isinstance(node, ast.Attribute): - attr_name = node.attr if hasattr(node, 'attr') else '' - from lib.includes.t import CTypeRegistry - llvm_str = 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}*' - return 'i32' - elif isinstance(node, ast.Subscript): - if isinstance(node.value, ast.Name) and node.value.id == 'tuple': - slice_node = node.slice - elem_types = [] - if isinstance(slice_node, ast.Tuple): - for elt in slice_node.elts: - elem_types.append(self._GetLLVMTypeStr(elt)) - else: - elem_types.append(self._GetLLVMTypeStr(slice_node)) - if elem_types: - return '{ ' + ', '.join(elem_types) + ' }' - if isinstance(node.value, ast.Name) and node.value.id == 'list': - slice_node = node.slice - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: - elem_type = self._GetLLVMTypeStr(slice_node.elts[0]) - else: - elem_type = self._GetLLVMTypeStr(slice_node) - return elem_type + '*' - return 'i32' - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - left = self._GetLLVMTypeStr(node.left) - right = self._GetLLVMTypeStr(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 - elif isinstance(node, ast.Constant): - if isinstance(node.value, bool): - return 'i8' - return 'i32' - elif isinstance(node, ast.Call): - if isinstance(node.func, ast.Attribute): - if hasattr(node.func.value, 'id') and node.func.value.id == 't': - return self._GetLLVMTypeStr(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr)) - return 'i32' - return 'i32' - - def _GetFuncRetTypeStr(self, returns_node): - if returns_node is None: - return 'i32' - actual = returns_node - if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr): - left_str = self._GetLLVMTypeStr(returns_node.left) - right_str = self._GetLLVMTypeStr(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 = self._GetLLVMTypeStr(actual) - return result if result else 'i32' - - @staticmethod - def _CheckAnnotationHasCInline(annotation_node) -> bool: - if annotation_node is None: - return False - if isinstance(annotation_node, ast.Attribute): - if hasattr(annotation_node.value, 'id') and annotation_node.value.id == 't' 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 SymbolTable._CheckAnnotationHasCInline(annotation_node.left) or SymbolTable._CheckAnnotationHasCInline(annotation_node.right) - return False - - def _GetFuncParamTypeStr(self, annotation_node): - if annotation_node is None: - return 'i8*' - actual = annotation_node - if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): - left_str = self._GetLLVMTypeStr(annotation_node.left) - right_str = self._GetLLVMTypeStr(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 - if left_str and left_str.endswith('*'): - return left_str - return right_str if right_str else left_str - result = self._GetLLVMTypeStr(actual) - return result if result else 'i8*' - - def _ResolveTypedefValueType(self, node): - if node is None: - return '' - if isinstance(node, ast.Name): - if node.id in self: - Entry = self[node.id] - if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef and Entry.OriginalType: - return Entry.OriginalType - return '' - if isinstance(node, ast.Attribute): - if isinstance(node.value, ast.Name) and node.value.id == 't': - CName = CTypeHelper.GetCName(node.attr) - if CName and CName == '*': - return 'ptr' - if CName: - return CName - return '' - if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - left_str = self._ResolveTypedefValueType(node.left) - right_str = self._ResolveTypedefValueType(node.right) - if right_str == 'ptr' or (right_str and right_str.endswith('*')): - base = 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 = 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 _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict, IsCpythonObject: bool, IsPacked: bool = False): - info = CTypeInfo() - info.Lineno = lineno - info.file = FilePath - info.Members = members if members else {} - - if TypeKind == 'struct': - info.IsStruct = True - elif TypeKind == 'union': - info.IsUnion = True - elif TypeKind == 'enum': - info.IsEnum = True - elif TypeKind == 'exception': - info.IsStruct = True - info.IsExceptionClass = True - - if IsCpythonObject: - info.IsCpythonObject = True - if IsPacked: - info.IsPacked = True - - self._symbols[FullName] = info - - def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str): - info = CTypeInfo() - info.IsEnumMember = True - info.EnumName = EnumName - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info - - def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None): - info = CTypeInfo() - info.IsTypedef = True - info.Lineno = lineno - info.file = FilePath - if members: - info.Members = members - - if isinstance(OriginalClass, CTypeInfo): - info.OriginalType = OriginalClass - elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass): - OriginalType = OriginalClass - if OriginalType == 'CVoid *': - OriginalType = 'void *' - info.OriginalType = OriginalType - elif OriginalType_kind == 'typedef' and OriginalClass == 'void': - info.OriginalType = 'void *' - elif OriginalType_kind == 'typedef' and OriginalClass: - info.OriginalType = OriginalClass - elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str): - info.OriginalType = f'{OriginalType_kind} {OriginalClass}' - else: - info.OriginalType = OriginalClass - - self._symbols[FullName] = info - - def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str): - info = CTypeInfo() - info.IsModuleAlias = True - info.Lineno = lineno - info.file = FilePath - self._symbols[name] = info - - def _InsertFuncSymbol(self, FullName: str, RetType, ParamTypes: list, lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False): - info = CTypeInfo() - info.IsFunction = True - if isinstance(RetType, str): - info.FuncPtrReturn = CTypeInfo.FromTypeName(RetType) if RetType else CTypeInfo.VoidTypeInfo() - elif isinstance(RetType, CTypeInfo): - info.FuncPtrReturn = RetType - else: - info.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - info.FuncPtrParams = [(f'arg{i}', pt) for i, pt in enumerate(ParamTypes)] - info.IsVariadic = IsVariadic - info.IsInline = IsInline - if IsInline: - info.Storage = t.CInline() - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info - - def _InsertDefineSymbol(self, FullName: str, DefineValue, lineno: int, FilePath: str): - info = CTypeInfo() - info.IsDefine = True - info.DefineValue = DefineValue - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info - - def _eval_const_expr(self, node): - """计算常量表达式的值""" - import ast - if isinstance(node, ast.Constant): - return node.value - elif isinstance(node, ast.BinOp): - left = self._eval_const_expr(node.left) - right = self._eval_const_expr(node.right) - if left is None or right is None: - return None - if isinstance(node.op, ast.Add): - return left + right - elif isinstance(node.op, ast.Sub): - return left - right - elif isinstance(node.op, ast.Mult): - return left * right - elif isinstance(node.op, ast.Div): - return left // right if isinstance(left, int) and isinstance(right, int) else left / right - elif isinstance(node.op, ast.FloorDiv): - return left // right - elif isinstance(node.op, ast.Mod): - return left % right - elif isinstance(node.op, ast.Pow): - return left ** right - elif isinstance(node.op, ast.LShift): - return left << right - elif isinstance(node.op, ast.RShift): - return left >> right - elif isinstance(node.op, ast.BitOr): - return left | right - elif isinstance(node.op, ast.BitXor): - return left ^ right - elif isinstance(node.op, ast.BitAnd): - return left & right - elif isinstance(node, ast.UnaryOp): - operand = self._eval_const_expr(node.operand) - if operand is None: - return None - if isinstance(node.op, ast.USub): - return -operand - elif isinstance(node.op, ast.UAdd): - return +operand - elif isinstance(node.op, ast.Invert): - return ~operand - elif isinstance(node, ast.Name): - # 引用其他常量 - if node.id in self: - info = self[node.id] - if hasattr(info, 'IsDefine') and info.IsDefine and hasattr(info, 'DefineValue') and info.DefineValue is not None: - return info.DefineValue - return None - - def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict, lineno: int, FilePath: str): - info = CTypeInfo() - if IsUnion: - info.IsUnion = True - else: - info.IsStruct = True - info.IsAnonymous = True - info.Members = members if members else {} - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info - - + return info + + # ================================================================== + # 模块符号加载:四阶段管线 + # ================================================================== + + def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]: + return self._LoadSymbolsFromFile(FullModulePath, asname, lineno) + + def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]: + from lib.core.SymbolExtractor import ASTSymbolExtractor + from lib.core.SymbolTypeResolver import TypeResolver + from lib.core.SymbolInserter import SymbolInserter + from lib.core.SymbolReexporter import PackageReexporter + + try: + # Pass 1: 从 AST 提取原始符号信息 + extractor = ASTSymbolExtractor(self) + module_symbols = extractor.extract(FilePath) + + # Pass 2: 解析类型信息(typedef、函数签名、define 值) + resolver = TypeResolver(self) + resolver.resolve(module_symbols) + + # Pass 3: 插入符号到主命名空间(无前缀) + inserter = SymbolInserter(self) + loaded = inserter.insert(module_symbols) + + # Pass 4: 重新导出到命名空间前缀下 + prefixes = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix + reexporter = PackageReexporter(self) + loaded.extend(reexporter.reexport(module_symbols, prefixes, lineno)) + + return loaded + + except Exception as e: + import traceback + print(traceback.format_exc()) + self.diagnostics.error(FilePath, lineno, f"加载模块失败: {e}") + return [] + + # ================================================================== + # 类型解析辅助方法(供 TypeResolver 通过 SymbolTable 引用调用) + # ================================================================== + + def _GetLLVMTypeStr(self, node): + if node is None: + self.diagnostics.warn('', 0, "类型注解为 None,回退到 i32") + return 'i32' + if isinstance(node, ast.Name): + if node.id == 'str': + return 'i8*' + elif node.id == 'int': + return 'i32' + elif node.id == 'bool': + return 'i8' + elif node.id == 'float': + return 'double' + elif node.id == 'None': + return 'void' + elif node.id in ('UINT8PTR', 'INT8PTR', 'BYTEPTR'): + return 'i8*' + elif node.id in ('UINT16PTR', 'INT16PTR'): + return 'i16*' + elif node.id in ('UINT32PTR', 'INT32PTR'): + return 'i32*' + elif node.id in ('UINT64PTR', 'INT64PTR'): + return 'i64*' + else: + if node.id in self: + entry = self[node.id] + if entry and entry.IsTypedef and entry.OriginalType: + if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr: + return 'i8*' + elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType: + return entry.OriginalType.ToString() + elif isinstance(entry.OriginalType, str): + return entry.OriginalType + self.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}',回退到 i32") + return 'i32' + elif isinstance(node, ast.Attribute): + attr_name = node.attr if hasattr(node, 'attr') else '' + from lib.includes.t import CTypeRegistry + llvm_str = 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.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}',回退到 i32") + return 'i32' + elif isinstance(node, ast.Subscript): + if isinstance(node.value, ast.Name) and node.value.id == 'tuple': + slice_node = node.slice + elem_types = [] + if isinstance(slice_node, ast.Tuple): + for elt in slice_node.elts: + elem_types.append(self._GetLLVMTypeStr(elt)) + else: + elem_types.append(self._GetLLVMTypeStr(slice_node)) + if elem_types: + return '{ ' + ', '.join(elem_types) + ' }' + if isinstance(node.value, ast.Name) and node.value.id == 'list': + slice_node = node.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: + elem_type = self._GetLLVMTypeStr(slice_node.elts[0]) + else: + elem_type = self._GetLLVMTypeStr(slice_node) + return elem_type + '*' + self.diagnostics.warn('', 0, f"无法解析 Subscript 类型,回退到 i32") + return 'i32' + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + left = self._GetLLVMTypeStr(node.left) + right = self._GetLLVMTypeStr(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 + elif isinstance(node, ast.Constant): + if isinstance(node.value, bool): + return 'i8' + return 'i32' + elif isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if hasattr(node.func.value, 'id') and node.func.value.id == 't': + return self._GetLLVMTypeStr(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr)) + self.diagnostics.warn('', 0, "无法解析 Call 类型,回退到 i32") + return 'i32' + self.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32") + return 'i32' + + def _GetFuncRetTypeStr(self, returns_node): + if returns_node is None: + return 'i32' + actual = returns_node + if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr): + left_str = self._GetLLVMTypeStr(returns_node.left) + right_str = self._GetLLVMTypeStr(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 = self._GetLLVMTypeStr(actual) + return result if result else 'i32' + + @staticmethod + def _CheckAnnotationHasCInline(annotation_node) -> bool: + return _CheckAnnotationHasCInline(annotation_node) + + def _GetFuncParamTypeStr(self, annotation_node): + if annotation_node is None: + return 'i8*' + actual = annotation_node + if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): + left_str = self._GetLLVMTypeStr(annotation_node.left) + right_str = self._GetLLVMTypeStr(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 + if left_str and left_str.endswith('*'): + return left_str + return right_str if right_str else left_str + result = self._GetLLVMTypeStr(actual) + return result if result else 'i8*' + + def _ResolveTypedefValueType(self, node): + if node is None: + return '' + if isinstance(node, ast.Name): + if node.id in self: + Entry = self[node.id] + if Entry.IsTypedef and Entry.OriginalType: + return Entry.OriginalType + return '' + if isinstance(node, ast.Attribute): + if isinstance(node.value, ast.Name) and node.value.id == 't': + CName = CTypeHelper.GetCName(node.attr) + if CName and CName == '*': + return 'ptr' + if CName: + return CName + return '' + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + left_str = self._ResolveTypedefValueType(node.left) + right_str = self._ResolveTypedefValueType(node.right) + if right_str == 'ptr' or (right_str and right_str.endswith('*')): + base = 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 = 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 '' + + # ================================================================== + # 符号插入方法(供 SymbolInserter / PackageReexporter 调用) + # ================================================================== + + def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict, IsCpythonObject: bool, IsPacked: bool = False): + info = CTypeInfo() + info.Lineno = lineno + info.file = FilePath + info.Members = members if members else {} + + if TypeKind == 'struct': + info.IsStruct = True + elif TypeKind == 'union': + info.IsUnion = True + elif TypeKind == 'enum': + info.IsEnum = True + elif TypeKind == 'exception': + info.IsStruct = True + info.IsExceptionClass = True + + if IsCpythonObject: + info.IsCpythonObject = True + if IsPacked: + info.IsPacked = True + + self._symbols[FullName] = info + + def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str): + info = CTypeInfo() + info.IsEnumMember = True + info.EnumName = EnumName + info.Lineno = lineno + info.file = FilePath + self._symbols[FullName] = info + + def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None): + info = CTypeInfo() + info.IsTypedef = True + info.Lineno = lineno + info.file = FilePath + if members: + info.Members = members + + if isinstance(OriginalClass, CTypeInfo): + info.OriginalType = OriginalClass + elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass): + OriginalType = OriginalClass + if OriginalType == 'CVoid *': + OriginalType = 'void *' + info.OriginalType = OriginalType + elif OriginalType_kind == 'typedef' and OriginalClass == 'void': + info.OriginalType = 'void *' + elif OriginalType_kind == 'typedef' and OriginalClass: + info.OriginalType = OriginalClass + elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str): + info.OriginalType = f'{OriginalType_kind} {OriginalClass}' + else: + info.OriginalType = OriginalClass + + self._symbols[FullName] = info + + def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str): + info = CTypeInfo() + info.IsModuleAlias = True + info.Lineno = lineno + info.file = FilePath + self._symbols[name] = info + + def _InsertFuncSymbol(self, FullName: str, RetType, ParamTypes: list, lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False): + info = CTypeInfo() + info.IsFunction = True + if isinstance(RetType, str): + info.FuncPtrReturn = CTypeInfo.FromTypeName(RetType) if RetType else CTypeInfo.VoidTypeInfo() + elif isinstance(RetType, CTypeInfo): + info.FuncPtrReturn = RetType + else: + info.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + info.FuncPtrParams = [(f'arg{i}', pt) for i, pt in enumerate(ParamTypes)] + info.IsVariadic = IsVariadic + info.IsInline = IsInline + if IsInline: + info.Storage = t.CInline() + info.Lineno = lineno + info.file = FilePath + self._symbols[FullName] = info + + def _InsertDefineSymbol(self, FullName: str, DefineValue, lineno: int, FilePath: str): + info = CTypeInfo() + info.IsDefine = True + info.DefineValue = DefineValue + info.Lineno = lineno + info.file = FilePath + self._symbols[FullName] = info + + def _eval_const_expr(self, node): + """计算常量表达式的值(委托到 ConstEvaluator)""" + from lib.core.ConstEvaluator import ConstEvaluator + return ConstEvaluator.eval_with_symtab(node, self) + + def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict, lineno: int, FilePath: str): + info = CTypeInfo() + if IsUnion: + info.IsUnion = True + else: + info.IsStruct = True + info.IsAnonymous = True + info.Members = members if members else {} + info.Lineno = lineno + info.file = FilePath + self._symbols[FullName] = info diff --git a/lib/core/SymbolTypeResolver.py b/lib/core/SymbolTypeResolver.py new file mode 100644 index 0000000..8bd6408 --- /dev/null +++ b/lib/core/SymbolTypeResolver.py @@ -0,0 +1,224 @@ +"""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.includes import t + + +class TypeResolver: + """解析从 AST 提取的原始符号中的类型信息""" + + def __init__(self, symbol_table: SymbolTable): + self._symtab = symbol_table + + def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols: + """解析所有类型信息,就地更新 ModuleSymbols""" + # 构建 class_members 查找表(typedef Postdefinition 需要) + class_members = {cls.name: cls.members for cls in module_symbols.classes} + + # 解析 typedef + for td in module_symbols.typedefs: + self._resolve_typedef(td, class_members) + + # 解析函数签名 + for func in module_symbols.functions: + self._resolve_function(func) + + # 解析 define 值 + for define in module_symbols.defines: + self._resolve_define(define) + + return module_symbols + + # ------------------------------------------------------------------ + # Typedef 解析 + # ------------------------------------------------------------------ + + def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict): + """解析单个 typedef 的类型信息""" + is_postdef_with_typedef = 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): + """解析 Postdefinition + CTypedef 组合注解""" + original_class = self._find_postdef_arg(td.annotation) + if original_class and original_class in class_members: + members_info = class_members[original_class] + original_type_kind = 'struct' + if original_class in self._symtab: + orig_type_info = 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 = self._find_base_type(td.annotation) + _TYPE_QUALIFIERS = {'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'} + + if base_type_name == 'Callable': + original_type = 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 = CTypeHelper.GetCName(base_type_name) + if cname and cname != base_type_name: + td.original_class = cname + else: + td.original_class = base_type_name[1:] if base_type_name.startswith('C') else base_type_name + td.original_type_kind = 'typedef' + else: + # 尝试从值表达式解析 + self._resolve_typedef_from_value(td) + + def _resolve_typedef_from_value(self, td: TypedefSymbolData): + """从值表达式解析 typedef 类型""" + if not td.value: + td.original_type_kind = None + td.original_class = None + return + + value_base_type = self._find_base_type(td.value) + _PTR_MODIFIERS = {'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'} + + if value_base_type and value_base_type not in _PTR_MODIFIERS: + cname = CTypeHelper.GetCName(value_base_type) + if cname and cname != value_base_type: + td.original_class = cname + else: + td.original_class = value_base_type[1:] if value_base_type.startswith('C') else value_base_type + td.original_type_kind = 'typedef' + return + + if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr): + left_type = self._symtab._ResolveTypedefValueType(td.value.left) + right_type = self._symtab._ResolveTypedefValueType(td.value.right) + is_ptr_type = right_type == 'ptr' or left_type == 'ptr' + if is_ptr_type: + base_name = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '') + if base_name: + original_type = base_name + ' *' + else: + original_type = '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' + return + + if isinstance(td.value, ast.Name): + ref_name = td.value.id + if ref_name in self._symtab: + ref_info = 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_function(self, func: FuncSymbolData): + """解析函数的返回类型和参数类型""" + func.ret_type = self._symtab._GetFuncRetTypeStr(func.returns_node) + func.param_types = [] + for _arg_name, annotation in func.params: + if annotation: + func.param_types.append(self._symtab._GetFuncParamTypeStr(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 节点中查找基础类型名称""" + if isinstance(node, ast.Attribute): + if hasattr(node.value, 'id') and node.value.id == 't': + 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 node.value.value.id == 't' and node.value.attr == 'Callable': + return 'Callable' + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + left_result = TypeResolver._find_base_type(node.left) + if left_result == 'ptr': + right_result = 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 = 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' + if left_result: + return left_result + if right_result: + return right_result + return None + + @staticmethod + def _find_postdef_arg(node): + """从注解 AST 节点中查找 Postdefinition 参数""" + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if hasattr(node.func.value, 'id') and node.func.value.id == 't' 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 = TypeResolver._find_postdef_arg(node.left) + if left_result: + return left_result + right_result = TypeResolver._find_postdef_arg(node.right) + if right_result: + return right_result + return None diff --git a/lib/core/SymbolUtils.py b/lib/core/SymbolUtils.py new file mode 100644 index 0000000..5f14a09 --- /dev/null +++ b/lib/core/SymbolUtils.py @@ -0,0 +1,56 @@ +"""共享工具函数:符号表处理中使用的 AST 分析工具""" +from __future__ import annotations +import ast +from lib.includes import t + + +def IsTModuleType(TypeName: str) -> bool: + """检测类型名称是否是 t 模块中的类型(CType 或其他特殊类型)""" + if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'): + return True + TypeClass = getattr(t, TypeName, None) + if TypeClass and isinstance(TypeClass, type): + if issubclass(TypeClass, t.CType): + return True + FallbackClass = getattr(t, f'_{TypeName}', None) + if FallbackClass and isinstance(FallbackClass, type): + if issubclass(FallbackClass, t.CType): + return True + return False + + +def AnnotationContainsTType(node, TypeName: str) -> bool: + """检测 AST 节点中是否包含指定名称的 t 模块类型""" + if isinstance(node, ast.Attribute): + if (hasattr(node.value, 'id') and node.value.id == 't' 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 CheckAnnotationHasCInline(annotation_node) -> bool: + """检测注解节点中是否包含 CInline""" + if annotation_node is None: + return False + if isinstance(annotation_node, ast.Attribute): + if hasattr(annotation_node.value, 'id') and annotation_node.value.id == 't' 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 diff --git a/lib/core/Translator/AnnotationLoader.py b/lib/core/Translator/AnnotationLoader.py index 8d17636..4b0f982 100644 --- a/lib/core/Translator/AnnotationLoader.py +++ b/lib/core/Translator/AnnotationLoader.py @@ -328,9 +328,9 @@ class AnnotationLoaderMixin: orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}') elif orig_entry.get('type') == 'enum': orig_type_str = f'enum {original_name}' - elif hasattr(orig_entry, 'IsTypedef') and orig_entry.IsTypedef: - orig_type_str = getattr(orig_entry, 'OriginalType', f'struct {original_name}') - elif hasattr(orig_entry, 'IsEnum') and orig_entry.IsEnum: + elif orig_entry.IsTypedef: + orig_type_str = orig_entry.OriginalType or f'struct {original_name}' + elif orig_entry.IsEnum: orig_type_str = f'enum {original_name}' TypedefNode.OriginalType = orig_type_str TypedefNode.set('source', 'annotation_module') diff --git a/lib/core/Translator/ConstEval.py b/lib/core/Translator/ConstEval.py index 780e1a2..0cad71e 100644 --- a/lib/core/Translator/ConstEval.py +++ b/lib/core/Translator/ConstEval.py @@ -112,42 +112,8 @@ class ConstEvalMixin: return self._try_eval_const_expr(node, Gen) def _try_eval_const_expr(self, node, Gen): - import ast - if isinstance(node, ast.Constant): - return node.value - elif isinstance(node, ast.BinOp): - left = self._try_eval_const_expr(node.left, Gen) - right = self._try_eval_const_expr(node.right, Gen) - if left is None or right is None: - return None - if isinstance(node.op, ast.Add): - return left + right - elif isinstance(node.op, ast.Sub): - return left - right - elif isinstance(node.op, ast.Mult): - return left * right - elif isinstance(node.op, ast.LShift): - return left << right - elif isinstance(node.op, ast.RShift): - return left >> right - elif isinstance(node.op, ast.BitOr): - return left | right - elif isinstance(node.op, ast.BitAnd): - return left & right - elif isinstance(node.op, ast.BitXor): - return left ^ right - elif isinstance(node, ast.UnaryOp): - operand = self._try_eval_const_expr(node.operand, Gen) - if operand is None: - return None - if isinstance(node.op, ast.USub): - return -operand - elif isinstance(node.op, ast.Invert): - return ~operand - elif isinstance(node, ast.Name): - if node.id in getattr(Gen, '_DefineConstants', {}): - return Gen._DefineConstants[node.id] - return None + from lib.core.ConstEvaluator import ConstEvaluator + return ConstEvaluator.eval_with_symtab(node, self.SymbolTable) def _BuildMultiDimArrayInitConstants(self, value_node, ArrayType, Gen): from lib.core.Handles.HandlesAssign import AssignHandle diff --git a/lib/core/TypeSpec.py b/lib/core/TypeSpec.py index ec741fe..64e85fc 100644 --- a/lib/core/TypeSpec.py +++ b/lib/core/TypeSpec.py @@ -67,6 +67,7 @@ FIELD_ROUTES = { 'ArrayPtr': ('ts', 'array_ptr'), 'IsState': ('ts', 'is_state'), 'OriginalType': ('ts', 'original_type'), + 'IsSigned': ('ts', 'is_signed'), # --- SymbolMeta 字段 --- 'Name': ('sm', 'name'), @@ -87,6 +88,8 @@ FIELD_ROUTES = { 'IsModuleAlias': ('sm', 'is_module_alias'), 'ResolvedModule': ('sm', 'resolved_module'), 'DefineValue': ('sm', 'define_value'), + 'EnumName': ('sm', 'enum_name'), + 'value': ('sm', 'enum_value'), # --- _kind_flags(独立 bool,存储在 SymbolMeta._kind_flags)--- 'IsStruct': ('kf', 'IsStruct'), @@ -127,6 +130,7 @@ class TypeSpec: 'is_array_ptr', 'array_ptr', 'is_state', 'original_type', + 'is_signed', ) def __init__(self): @@ -150,6 +154,7 @@ class TypeSpec: self.array_ptr: Any = None # CTypeInfo self.is_state: bool = False self.original_type: Any = None # CTypeInfo | str | None (typedef 原始类型) + self.is_signed: Optional[bool] = None # None = 未设置, True/False = 有符号/无符号 @property def base_type(self) -> Any: @@ -203,6 +208,7 @@ class TypeSpec: new.array_ptr = self.array_ptr new.is_state = self.is_state new.original_type = self.original_type + new.is_signed = self.is_signed return new @@ -222,6 +228,7 @@ class SymbolMeta: 'members', 'is_cpython_object', 'is_packed', 'define_value', + 'enum_name', 'enum_value', 'is_inline', 'inline_body', 'inline_params', 'is_anonymous', 'renum_variants', @@ -241,6 +248,8 @@ class SymbolMeta: self.is_cpython_object: bool = False self.is_packed: bool = False self.define_value: Any = None + self.enum_name: str = "" # 枚举成员所属的枚举类名 + self.enum_value: Any = None # 枚举成员的值 self.is_inline: bool = False self.inline_body: list | None = None self.inline_params: list | None = None @@ -287,6 +296,8 @@ class SymbolMeta: new.is_cpython_object = self.is_cpython_object new.is_packed = self.is_packed new.define_value = self.define_value + new.enum_name = self.enum_name + new.enum_value = self.enum_value new.is_inline = self.is_inline new.inline_body = self.inline_body new.inline_params = list(self.inline_params) if self.inline_params else None