feat(vast): 新增自研 Viper/Python 语法解析器取代标准库 ast
TPC 侧取缔对 Python 标准库 ast 模块的依赖,改用 lib/vast 包: - Nodes: 与 CPython 3.12 ast 完全同构的 131 个节点类(含抽象基类继承) - Tokenizer: 词法分析(缩进/字符串/f-string/数字/运算符/软关键字) - ExprParser: 表达式递归下降解析(优先级/lambda/推导式/f-string/切片) - Parser: 语句解析(def/class/if/for/try/with/match/import/注解) - Utils/Unparser: walk/dump/unparse/copy_location/literal_eval 等辅助 - 软关键字 fn/fun/func/function 并入解析器, 废除 ExpandSoftKeywords 预处理 - lib/_bootstrap 将 lib 目录加入 sys.path, import vast as ast 零修改替换 - 52 个文件 import ast 替换为 import vast as ast; 94 文件差分测试 0 失败
This commit is contained in:
1 parent
a7bbd68507
commit
6fc9e19e24
62 files changed
+19293
-15066
No files matched your search
@@ -147,6 +147,7 @@ def main() -> None:
|
||||
parser.add_argument('--run', action='store_true', help='编译成功后立即执行生成的可执行文件')
|
||||
parser.add_argument('--rebuild-includes', action='store_true', help='删除 includes.binary 预编译缓存并重新编译所有 includes')
|
||||
parser.add_argument('--clear-cache', action='store_true', help='清除 .transpyc_cache 全局缓存(.vpi/.stub.ll/.doc.json)')
|
||||
parser.add_argument('--nowarn-register', action='store_true', help='抑制"外部函数返回类型未登记"类 WARN 输出(透传给自举编译的 TransPyV.exe)')
|
||||
|
||||
args: argparse.Namespace = parser.parse_args()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import vast as ast
|
||||
import re
|
||||
from typing import List
|
||||
|
||||
@@ -214,85 +214,85 @@ class DeclarationGenerator:
|
||||
"""递归检查类型注解中是否包含 CExport 或 t.State"""
|
||||
return bool(annotation) and (AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State'))
|
||||
|
||||
def _generate_global_decl(self, node: ast.AnnAssign) -> str | None:
|
||||
"""生成全局变量声明"""
|
||||
if not isinstance(node.target, ast.Name):
|
||||
return None
|
||||
var_name: str = node.target.id
|
||||
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.List):
|
||||
for elt in node.annotation.elts:
|
||||
if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'):
|
||||
return None
|
||||
if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable':
|
||||
return None
|
||||
VarType: str = self._get_type_str(node.annotation)
|
||||
if VarType.startswith('[0 x ') and node.value and isinstance(node.value, ast.List):
|
||||
elem_type: str = VarType[5:-1]
|
||||
actual_count: int = len(node.value.elts)
|
||||
if actual_count > 0:
|
||||
VarType = f'[{actual_count} x {elem_type}]'
|
||||
return f'@{var_name} = external global {VarType}'
|
||||
|
||||
def _generate_global_assign_decl(self, node: ast.Assign) -> str | None:
|
||||
"""从无类型标注赋值推断并生成全局变量声明"""
|
||||
if not node.targets or not isinstance(node.targets[0], ast.Name):
|
||||
return None
|
||||
var_name: str = node.targets[0].id
|
||||
VarType: str | None = self._infer_type(node.value)
|
||||
if VarType:
|
||||
return f'@{var_name} = external global {VarType}'
|
||||
return None
|
||||
|
||||
def _resolve_base_kind(self, base_name: str) -> str | None:
|
||||
"""解析基类名称的类型种类(支持别名)
|
||||
|
||||
Returns:
|
||||
'enum' | 'union' | 'renum' | 'struct' | 'ctype_marker' | None
|
||||
"""
|
||||
# 1) 查 t 别名映射(from t import CEnum as en)
|
||||
if base_name in self._t_alias_map:
|
||||
t_cls: type = self._t_alias_map[base_name]
|
||||
if issubclass(t_cls, (t.CEnum, t.REnum)):
|
||||
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
|
||||
if issubclass(t_cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(t_cls, t.CStruct):
|
||||
return 'struct'
|
||||
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
|
||||
# 不应被编译为真实结构体,也不应被生成 stub 声明。
|
||||
if issubclass(t_cls, t.CType):
|
||||
return 'ctype_marker'
|
||||
|
||||
# 2) 直接查 t 模块属性
|
||||
t_cls: type | None = getattr(t, base_name, None)
|
||||
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
|
||||
if issubclass(t_cls, (t.CEnum, t.REnum)):
|
||||
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
|
||||
if issubclass(t_cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(t_cls, t.CStruct):
|
||||
return 'struct'
|
||||
# CType 及其子类是"类型强转"标记,不编译为结构体。
|
||||
return 'ctype_marker'
|
||||
|
||||
return None
|
||||
|
||||
def _is_marker_base(self, base_name: str) -> bool:
|
||||
"""检查是否为标记基类(Object/CVTable/Exception/CEnum/CUnion/CStruct/REnum 及其别名)"""
|
||||
if base_name in ('Object', 'CVTable', 'Exception', 'CEnum', 'Enum', 'CStruct', 'CUnion', 'REnum'):
|
||||
return True
|
||||
if self._resolve_base_kind(base_name) is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _generate_global_decl(self, node: ast.AnnAssign) -> str | None:
|
||||
"""生成全局变量声明"""
|
||||
if not isinstance(node.target, ast.Name):
|
||||
return None
|
||||
var_name: str = node.target.id
|
||||
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.List):
|
||||
for elt in node.annotation.elts:
|
||||
if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'):
|
||||
return None
|
||||
if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable':
|
||||
return None
|
||||
VarType: str = self._get_type_str(node.annotation)
|
||||
if VarType.startswith('[0 x ') and node.value and isinstance(node.value, ast.List):
|
||||
elem_type: str = VarType[5:-1]
|
||||
actual_count: int = len(node.value.elts)
|
||||
if actual_count > 0:
|
||||
VarType = f'[{actual_count} x {elem_type}]'
|
||||
return f'@{var_name} = external global {VarType}'
|
||||
|
||||
def _generate_global_assign_decl(self, node: ast.Assign) -> str | None:
|
||||
"""从无类型标注赋值推断并生成全局变量声明"""
|
||||
if not node.targets or not isinstance(node.targets[0], ast.Name):
|
||||
return None
|
||||
var_name: str = node.targets[0].id
|
||||
VarType: str | None = self._infer_type(node.value)
|
||||
if VarType:
|
||||
return f'@{var_name} = external global {VarType}'
|
||||
return None
|
||||
|
||||
def _resolve_base_kind(self, base_name: str) -> str | None:
|
||||
"""解析基类名称的类型种类(支持别名)
|
||||
|
||||
Returns:
|
||||
'enum' | 'union' | 'renum' | 'struct' | 'ctype_marker' | None
|
||||
"""
|
||||
# 1) 查 t 别名映射(from t import CEnum as en)
|
||||
if base_name in self._t_alias_map:
|
||||
t_cls: type = self._t_alias_map[base_name]
|
||||
if issubclass(t_cls, (t.CEnum, t.REnum)):
|
||||
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
|
||||
if issubclass(t_cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(t_cls, t.CStruct):
|
||||
return 'struct'
|
||||
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
|
||||
# 不应被编译为真实结构体,也不应被生成 stub 声明。
|
||||
if issubclass(t_cls, t.CType):
|
||||
return 'ctype_marker'
|
||||
|
||||
# 2) 直接查 t 模块属性
|
||||
t_cls: type | None = getattr(t, base_name, None)
|
||||
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
|
||||
if issubclass(t_cls, (t.CEnum, t.REnum)):
|
||||
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
|
||||
if issubclass(t_cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(t_cls, t.CStruct):
|
||||
return 'struct'
|
||||
# CType 及其子类是"类型强转"标记,不编译为结构体。
|
||||
return 'ctype_marker'
|
||||
|
||||
return None
|
||||
|
||||
def _is_marker_base(self, base_name: str) -> bool:
|
||||
"""检查是否为标记基类(Object/CVTable/Exception/CEnum/CUnion/CStruct/REnum 及其别名)"""
|
||||
if base_name in ('Object', 'CVTable', 'Exception', 'CEnum', 'Enum', 'CStruct', 'CUnion', 'REnum'):
|
||||
return True
|
||||
if self._resolve_base_kind(base_name) is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _generate_class_decl(self, node: ast.ClassDef) -> List[str]:
|
||||
"""生成结构体/类声明"""
|
||||
decls: list[str] = []
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import ast
|
||||
import vast as ast
|
||||
import json
|
||||
import shutil
|
||||
import traceback
|
||||
|
||||
@@ -5,7 +5,7 @@ import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import ast
|
||||
import vast as ast
|
||||
import traceback
|
||||
import json
|
||||
import pickle
|
||||
@@ -1730,7 +1730,7 @@ class Phase2Translator:
|
||||
for root, dirs, files in os.walk(includes_dir):
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
|
||||
for fname in files:
|
||||
if fname.endswith('.vp') or fname.endswith('.py'):
|
||||
if fname.endswith('.vp') or fname.endswith('.py'):
|
||||
py_index.add(os.path.normcase(os.path.join(root, fname)))
|
||||
return py_index
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import ast
|
||||
import vast as ast
|
||||
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _ConfigMode
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import os
|
||||
import ast
|
||||
import vast as ast
|
||||
import shlex
|
||||
import datetime
|
||||
import tempfile
|
||||
|
||||
+1001
-1001
File diff suppressed because it is too large.
Load diff
+6
-1
@@ -1 +1,6 @@
|
||||
"""TransPyC 编译器核心库"""
|
||||
"""TransPyC 编译器核心库
|
||||
|
||||
任何 ``import lib.*`` 都会先触发 _bootstrap(sys.path 设置:
|
||||
项目根 + lib 目录 + lib/includes),保证 ``import vast`` 直接可用。
|
||||
"""
|
||||
import lib._bootstrap # noqa: F401
|
||||
@@ -30,6 +30,9 @@ def _bootstrap() -> None:
|
||||
|
||||
if _ProjectRoot not in sys.path:
|
||||
sys.path.insert(0, _ProjectRoot)
|
||||
if _LibDir not in sys.path:
|
||||
# lib 目录入 path:使 vast 包(lib/vast/)可直接 import vast
|
||||
sys.path.append(_LibDir)
|
||||
if _IncludesDir not in sys.path:
|
||||
sys.path.append(_IncludesDir)
|
||||
|
||||
|
||||
+652
-652
File diff suppressed because it is too large.
Load diff
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
import ast
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
class AssertHandle(BaseHandle):
|
||||
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
cond_val: ir.Value | None = self.HandleExprLlvm(Node.test)
|
||||
if not cond_val:
|
||||
return
|
||||
if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1:
|
||||
zero: ir.Constant = ir.Constant(cond_val.type, 0)
|
||||
cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond")
|
||||
AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail")
|
||||
AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok")
|
||||
Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB)
|
||||
Gen.builder.position_at_start(AssertFailBB)
|
||||
exc_code: int = 9
|
||||
exc_msg: ir.Value | None = None
|
||||
if Node.msg:
|
||||
if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(Node.msg)
|
||||
elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name):
|
||||
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99)
|
||||
if Node.msg.args:
|
||||
first_arg: ast.expr = Node.msg.args[0]
|
||||
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(first_arg)
|
||||
elif isinstance(Node.msg, ast.Name):
|
||||
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99)
|
||||
else:
|
||||
exc_msg = self.HandleExprLlvm(Node.msg)
|
||||
if Gen.eh_except_block_stack:
|
||||
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
|
||||
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
|
||||
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
|
||||
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
|
||||
Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code)
|
||||
if exc_msg:
|
||||
Gen._store(exc_msg, eh_message)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen._store(null_ptr, eh_message)
|
||||
Gen.builder.branch(ExceptBB)
|
||||
else:
|
||||
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
if exc_msg:
|
||||
fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string')
|
||||
Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print")
|
||||
else:
|
||||
fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string')
|
||||
Gen.builder.call(printf_func, [fmt], name="assert_fail_print")
|
||||
exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)]))
|
||||
Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit")
|
||||
Gen.builder.unreachable()
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
class AssertHandle(BaseHandle):
|
||||
def _HandleAssertLlvm(self, Node: ast.Assert) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
cond_val: ir.Value | None = self.HandleExprLlvm(Node.test)
|
||||
if not cond_val:
|
||||
return
|
||||
if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1:
|
||||
zero: ir.Constant = ir.Constant(cond_val.type, 0)
|
||||
cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond")
|
||||
AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail")
|
||||
AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok")
|
||||
Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB)
|
||||
Gen.builder.position_at_start(AssertFailBB)
|
||||
exc_code: int = 9
|
||||
exc_msg: ir.Value | None = None
|
||||
if Node.msg:
|
||||
if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(Node.msg)
|
||||
elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name):
|
||||
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99)
|
||||
if Node.msg.args:
|
||||
first_arg: ast.expr = Node.msg.args[0]
|
||||
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(first_arg)
|
||||
elif isinstance(Node.msg, ast.Name):
|
||||
exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99)
|
||||
else:
|
||||
exc_msg = self.HandleExprLlvm(Node.msg)
|
||||
if Gen.eh_except_block_stack:
|
||||
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
|
||||
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
|
||||
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
|
||||
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
|
||||
Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code)
|
||||
if exc_msg:
|
||||
Gen._store(exc_msg, eh_message)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen._store(null_ptr, eh_message)
|
||||
Gen.builder.branch(ExceptBB)
|
||||
else:
|
||||
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
if exc_msg:
|
||||
fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string')
|
||||
Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print")
|
||||
else:
|
||||
fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string')
|
||||
Gen.builder.call(printf_func, [fmt], name="assert_fail_print")
|
||||
exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)]))
|
||||
Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit")
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_start(AssertOkBB)
|
||||
+1753
-1753
File diff suppressed because it is too large.
Load diff
@@ -1,243 +1,243 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
import ast
|
||||
import sys
|
||||
import llvmlite.ir as ir
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
|
||||
|
||||
class AugAssignHandle(BaseHandle):
|
||||
_AUGOP_MAP: dict[type, str] = {
|
||||
ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__',
|
||||
ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__',
|
||||
}
|
||||
_AUGOP_FALLBACK: dict[type, str] = {
|
||||
ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__',
|
||||
ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__',
|
||||
}
|
||||
|
||||
def _resolve_global_var_type(self, Gen: "Translator.LlvmGen", VarName: str, fallback: ir.Type) -> ir.Type:
|
||||
"""解析 global 变量的 LLVM 类型:优先用模块级 AnnAssign 的注解类型。
|
||||
|
||||
问题场景:函数内 `_g_alloc_count += 1`(global 声明),模块级注解为
|
||||
`_g_alloc_count: t.CSizeT`(i64)。若不查模块级注解类型,此处会用 RHS 字面量
|
||||
类型(i32)自动建 i32 全局,与模块内其他读取/写入(i64)类型不匹配,
|
||||
产生 "Operands must be the same type, got (i64, i32)" 类错误。
|
||||
模块级 AnnAssign 已通过 _EmitGlobalAnnAssignLlvm 创建 LLVM 全局,
|
||||
但注解无初始值(如 `_g_alloc_max: t.CSizeT = 0`)时 initializer 为空、
|
||||
Gen.module.globals 中无该符号,故需在此兜底解析注解类型。
|
||||
"""
|
||||
module_ann: dict = getattr(Gen, '_module_ann_types', None)
|
||||
if module_ann and VarName in module_ann:
|
||||
ann_type: ir.Type = module_ann[VarName]
|
||||
if ann_type is not None:
|
||||
return ann_type
|
||||
if isinstance(fallback, ir.IntType):
|
||||
return fallback
|
||||
return ir.IntType(64)
|
||||
|
||||
def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Node.target, ast.Name):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
elif isinstance(Node.target, ast.Attribute):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
elif isinstance(Node.target, ast.Subscript):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
if Node.value is not None and Gen._check_node_unsigned(Node.value):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _HandleAugAssignLlvm(self, Node: ast.AugAssign) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
if (VarName not in Gen.variables
|
||||
and VarName not in Gen.global_vars
|
||||
and VarName not in Gen._reg_values
|
||||
and VarName not in Gen._direct_values):
|
||||
src_info: str = Gen._get_node_info()
|
||||
_vlog().error(f"变量 '{VarName}' 未声明,不能用于增量赋值(需用 global 声明或先声明局部变量){src_info}")
|
||||
sys.exit(1)
|
||||
if VarName in Gen.var_const_flags:
|
||||
src_info: str = Gen._get_node_info()
|
||||
_vlog().error(f"不能对 const 变量 '{VarName}' 增量赋值{src_info}")
|
||||
sys.exit(1)
|
||||
ClassName: str | None = Gen.var_struct_class.get(VarName)
|
||||
iop_name: str | None = self._AUGOP_MAP.get(type(Node.op))
|
||||
if ClassName and iop_name:
|
||||
iFuncName: str = f'{ClassName}.{iop_name}'
|
||||
FuncName: str = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}'
|
||||
if iFuncName in Gen.functions or FuncName in Gen.functions:
|
||||
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if OldVal and Value:
|
||||
result: ir.Value | None
|
||||
if iFuncName in Gen.functions:
|
||||
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value)
|
||||
else:
|
||||
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value)
|
||||
if result is not None:
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
VarPtr: ir.Value = Gen.variables[VarName]
|
||||
if VarPtr.type.pointee == result.type:
|
||||
Gen._store(result, VarPtr)
|
||||
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType):
|
||||
CastedVal: ir.Value = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}")
|
||||
Gen._store(CastedVal, VarPtr)
|
||||
else:
|
||||
NewVar: ir.AllocaInstr = Gen._allocaEntry(result.type, name=VarName)
|
||||
Gen._store(result, NewVar)
|
||||
Gen.variables[VarName] = NewVar
|
||||
else:
|
||||
Gen._reg_values[VarName] = result
|
||||
Gen.variables[VarName] = None
|
||||
return
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if not Value:
|
||||
return
|
||||
is_unsigned: bool = self._is_aug_unsigned(Node, None, Value)
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if VarName in Gen.global_vars:
|
||||
# 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局
|
||||
# (注解无初始值的全局变量),此处自动创建零初始化全局变量
|
||||
GVar: ir.GlobalVariable
|
||||
if VarName not in Gen.module.globals:
|
||||
_gv_type: ir.Type = self._resolve_global_var_type(Gen, VarName, Value.type)
|
||||
GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName)
|
||||
GVar.initializer = ir.Constant(_gv_type, 0)
|
||||
else:
|
||||
GVar = Gen.module.globals[VarName]
|
||||
Gen.variables[VarName] = GVar
|
||||
OldVal: ir.Value = Gen._load(GVar, name=VarName)
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
Gen._store(NewVal, GVar)
|
||||
return
|
||||
if VarName in Gen._reg_values:
|
||||
OldVal: ir.Value = Gen._reg_values[VarName]
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.variables[VarName] = var
|
||||
del Gen._reg_values[VarName]
|
||||
if VarName in Gen._direct_values:
|
||||
OldVal: ir.Value = Gen._direct_values.pop(VarName)
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.variables[VarName] = var
|
||||
if Gen.builder.block.is_terminated:
|
||||
return
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
OldVal: ir.Value = Gen._load(Gen.variables[VarName], name=VarName)
|
||||
store_ptr: ir.Value = Gen.variables[VarName]
|
||||
if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Value.type.width != 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset")
|
||||
NewVal: ir.Value
|
||||
if Op == '-' or Op == '+':
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add")
|
||||
else:
|
||||
ptr_val: ir.Value = OldVal
|
||||
OldVal = Gen._load(OldVal, name="deref_ptr_for_op")
|
||||
orig_type: ir.Type = OldVal.type
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
|
||||
NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType):
|
||||
if NewVal.type.width > orig_type.width:
|
||||
NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result")
|
||||
store_ptr = ptr_val
|
||||
else:
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
|
||||
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Op in ('+', '-'):
|
||||
if Value.type.width < 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug")
|
||||
NewVal: ir.Value
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_aug")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug")
|
||||
Gen._store(NewVal, store_ptr)
|
||||
return
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(store_ptr.type, ir.PointerType):
|
||||
TargetType: ir.Type = store_ptr.type.pointee
|
||||
if NewVal.type != TargetType:
|
||||
Coerced: ir.Value | None = Gen._coerce_value(NewVal, TargetType)
|
||||
if Coerced is not None:
|
||||
NewVal = Coerced
|
||||
Gen._store(NewVal, store_ptr)
|
||||
elif VarName == 'pos':
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
|
||||
Gen.variables[VarName] = var
|
||||
OldVal: ir.Value = Gen._load(var, name=VarName)
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
Gen._store(NewVal, var)
|
||||
elif isinstance(Node.target, ast.Attribute):
|
||||
AttrName: str = Node.target.attr
|
||||
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.target)
|
||||
if OldVal:
|
||||
def _deref_if_ptr(val: ir.Value) -> ir.Value:
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)):
|
||||
return Gen._load(val, name="deref_aug")
|
||||
return val
|
||||
OldVal = _deref_if_ptr(OldVal)
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr")
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal)
|
||||
elif isinstance(Node.target, ast.Subscript):
|
||||
SubTarget: ast.Subscript = Node.target
|
||||
ElemPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget)
|
||||
if ElemPtr:
|
||||
if isinstance(ElemPtr.type, ir.PointerType):
|
||||
OldVal: ir.Value = Gen._load(ElemPtr, name="old_subscript_val")
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub")
|
||||
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Op in ('+', '-'):
|
||||
if Value.type.width < 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub")
|
||||
NewVal: ir.Value
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_sub")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub")
|
||||
Gen._store(NewVal, ElemPtr)
|
||||
return
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType):
|
||||
if NewVal.type.width > ElemPtr.type.pointee.width:
|
||||
NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result")
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
import vast as ast
|
||||
import sys
|
||||
import llvmlite.ir as ir
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
|
||||
|
||||
class AugAssignHandle(BaseHandle):
|
||||
_AUGOP_MAP: dict[type, str] = {
|
||||
ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__',
|
||||
ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__',
|
||||
}
|
||||
_AUGOP_FALLBACK: dict[type, str] = {
|
||||
ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__',
|
||||
ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__',
|
||||
}
|
||||
|
||||
def _resolve_global_var_type(self, Gen: "Translator.LlvmGen", VarName: str, fallback: ir.Type) -> ir.Type:
|
||||
"""解析 global 变量的 LLVM 类型:优先用模块级 AnnAssign 的注解类型。
|
||||
|
||||
问题场景:函数内 `_g_alloc_count += 1`(global 声明),模块级注解为
|
||||
`_g_alloc_count: t.CSizeT`(i64)。若不查模块级注解类型,此处会用 RHS 字面量
|
||||
类型(i32)自动建 i32 全局,与模块内其他读取/写入(i64)类型不匹配,
|
||||
产生 "Operands must be the same type, got (i64, i32)" 类错误。
|
||||
模块级 AnnAssign 已通过 _EmitGlobalAnnAssignLlvm 创建 LLVM 全局,
|
||||
但注解无初始值(如 `_g_alloc_max: t.CSizeT = 0`)时 initializer 为空、
|
||||
Gen.module.globals 中无该符号,故需在此兜底解析注解类型。
|
||||
"""
|
||||
module_ann: dict = getattr(Gen, '_module_ann_types', None)
|
||||
if module_ann and VarName in module_ann:
|
||||
ann_type: ir.Type = module_ann[VarName]
|
||||
if ann_type is not None:
|
||||
return ann_type
|
||||
if isinstance(fallback, ir.IntType):
|
||||
return fallback
|
||||
return ir.IntType(64)
|
||||
|
||||
def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Node.target, ast.Name):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
elif isinstance(Node.target, ast.Attribute):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
elif isinstance(Node.target, ast.Subscript):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
return True
|
||||
if Node.value is not None and Gen._check_node_unsigned(Node.value):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _HandleAugAssignLlvm(self, Node: ast.AugAssign) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
if (VarName not in Gen.variables
|
||||
and VarName not in Gen.global_vars
|
||||
and VarName not in Gen._reg_values
|
||||
and VarName not in Gen._direct_values):
|
||||
src_info: str = Gen._get_node_info()
|
||||
_vlog().error(f"变量 '{VarName}' 未声明,不能用于增量赋值(需用 global 声明或先声明局部变量){src_info}")
|
||||
sys.exit(1)
|
||||
if VarName in Gen.var_const_flags:
|
||||
src_info: str = Gen._get_node_info()
|
||||
_vlog().error(f"不能对 const 变量 '{VarName}' 增量赋值{src_info}")
|
||||
sys.exit(1)
|
||||
ClassName: str | None = Gen.var_struct_class.get(VarName)
|
||||
iop_name: str | None = self._AUGOP_MAP.get(type(Node.op))
|
||||
if ClassName and iop_name:
|
||||
iFuncName: str = f'{ClassName}.{iop_name}'
|
||||
FuncName: str = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}'
|
||||
if iFuncName in Gen.functions or FuncName in Gen.functions:
|
||||
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if OldVal and Value:
|
||||
result: ir.Value | None
|
||||
if iFuncName in Gen.functions:
|
||||
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value)
|
||||
else:
|
||||
result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value)
|
||||
if result is not None:
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
VarPtr: ir.Value = Gen.variables[VarName]
|
||||
if VarPtr.type.pointee == result.type:
|
||||
Gen._store(result, VarPtr)
|
||||
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType):
|
||||
CastedVal: ir.Value = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}")
|
||||
Gen._store(CastedVal, VarPtr)
|
||||
else:
|
||||
NewVar: ir.AllocaInstr = Gen._allocaEntry(result.type, name=VarName)
|
||||
Gen._store(result, NewVar)
|
||||
Gen.variables[VarName] = NewVar
|
||||
else:
|
||||
Gen._reg_values[VarName] = result
|
||||
Gen.variables[VarName] = None
|
||||
return
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if not Value:
|
||||
return
|
||||
is_unsigned: bool = self._is_aug_unsigned(Node, None, Value)
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if VarName in Gen.global_vars:
|
||||
# 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局
|
||||
# (注解无初始值的全局变量),此处自动创建零初始化全局变量
|
||||
GVar: ir.GlobalVariable
|
||||
if VarName not in Gen.module.globals:
|
||||
_gv_type: ir.Type = self._resolve_global_var_type(Gen, VarName, Value.type)
|
||||
GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName)
|
||||
GVar.initializer = ir.Constant(_gv_type, 0)
|
||||
else:
|
||||
GVar = Gen.module.globals[VarName]
|
||||
Gen.variables[VarName] = GVar
|
||||
OldVal: ir.Value = Gen._load(GVar, name=VarName)
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
Gen._store(NewVal, GVar)
|
||||
return
|
||||
if VarName in Gen._reg_values:
|
||||
OldVal: ir.Value = Gen._reg_values[VarName]
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.variables[VarName] = var
|
||||
del Gen._reg_values[VarName]
|
||||
if VarName in Gen._direct_values:
|
||||
OldVal: ir.Value = Gen._direct_values.pop(VarName)
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.variables[VarName] = var
|
||||
if Gen.builder.block.is_terminated:
|
||||
return
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
OldVal: ir.Value = Gen._load(Gen.variables[VarName], name=VarName)
|
||||
store_ptr: ir.Value = Gen.variables[VarName]
|
||||
if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Value.type.width != 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset")
|
||||
NewVal: ir.Value
|
||||
if Op == '-' or Op == '+':
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add")
|
||||
else:
|
||||
ptr_val: ir.Value = OldVal
|
||||
OldVal = Gen._load(OldVal, name="deref_ptr_for_op")
|
||||
orig_type: ir.Type = OldVal.type
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
|
||||
NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType):
|
||||
if NewVal.type.width > orig_type.width:
|
||||
NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result")
|
||||
store_ptr = ptr_val
|
||||
else:
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right")
|
||||
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Op in ('+', '-'):
|
||||
if Value.type.width < 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug")
|
||||
NewVal: ir.Value
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_aug")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug")
|
||||
Gen._store(NewVal, store_ptr)
|
||||
return
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(store_ptr.type, ir.PointerType):
|
||||
TargetType: ir.Type = store_ptr.type.pointee
|
||||
if NewVal.type != TargetType:
|
||||
Coerced: ir.Value | None = Gen._coerce_value(NewVal, TargetType)
|
||||
if Coerced is not None:
|
||||
NewVal = Coerced
|
||||
Gen._store(NewVal, store_ptr)
|
||||
elif VarName == 'pos':
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName)
|
||||
Gen.variables[VarName] = var
|
||||
OldVal: ir.Value = Gen._load(var, name=VarName)
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
Gen._store(NewVal, var)
|
||||
elif isinstance(Node.target, ast.Attribute):
|
||||
AttrName: str = Node.target.attr
|
||||
OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.target)
|
||||
if OldVal:
|
||||
def _deref_if_ptr(val: ir.Value) -> ir.Value:
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)):
|
||||
return Gen._load(val, name="deref_aug")
|
||||
return val
|
||||
OldVal = _deref_if_ptr(OldVal)
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr")
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal)
|
||||
elif isinstance(Node.target, ast.Subscript):
|
||||
SubTarget: ast.Subscript = Node.target
|
||||
ElemPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget)
|
||||
if ElemPtr:
|
||||
if isinstance(ElemPtr.type, ir.PointerType):
|
||||
OldVal: ir.Value = Gen._load(ElemPtr, name="old_subscript_val")
|
||||
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if OldVal.type.width < Value.type.width:
|
||||
OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub")
|
||||
elif OldVal.type.width > Value.type.width:
|
||||
Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub")
|
||||
elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
if Op in ('+', '-'):
|
||||
if Value.type.width < 64:
|
||||
Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub")
|
||||
NewVal: ir.Value
|
||||
if Op == '-':
|
||||
NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_sub")
|
||||
NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub")
|
||||
else:
|
||||
NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub")
|
||||
Gen._store(NewVal, ElemPtr)
|
||||
return
|
||||
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
|
||||
if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType):
|
||||
if NewVal.type.width > ElemPtr.type.pointee.width:
|
||||
NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result")
|
||||
Gen._store(NewVal, ElemPtr)
|
||||
+841
-841
File diff suppressed because it is too large.
Load diff
@@ -1,77 +1,77 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class BodyHandle(BaseHandle):
|
||||
def __init__(self, translator: "Translator") -> None:
|
||||
super().__init__(translator)
|
||||
|
||||
def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for Node in Body:
|
||||
if Gen.builder and Gen.builder.block.is_terminated:
|
||||
break
|
||||
Gen._set_node_info(Node)
|
||||
try:
|
||||
if isinstance(Node, ast.Expr):
|
||||
self.HandleExprLlvm(Node.value)
|
||||
elif isinstance(Node, ast.Return):
|
||||
self.Trans.ReturnHandler._HandleReturnLlvm(Node)
|
||||
elif isinstance(Node, ast.Assign):
|
||||
self.Trans.AssignHandler._HandleAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.AugAssign):
|
||||
self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.AnnAssign):
|
||||
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.If):
|
||||
self.Trans.IfHandler._HandleIfLlvm(Node)
|
||||
elif isinstance(Node, ast.For):
|
||||
self.Trans.ForHandler._HandleForLlvm(Node)
|
||||
elif isinstance(Node, ast.While):
|
||||
self.Trans.WhileHandler._HandleWhileLlvm(Node)
|
||||
elif isinstance(Node, ast.Break):
|
||||
if Gen.loop_break_targets:
|
||||
Gen.builder.branch(Gen.loop_break_targets[-1])
|
||||
elif isinstance(Node, ast.Continue):
|
||||
if Gen.loop_continue_targets:
|
||||
Gen.builder.branch(Gen.loop_continue_targets[-1])
|
||||
elif isinstance(Node, ast.With):
|
||||
self.Trans.WithHandler._HandleWithLlvm(Node)
|
||||
elif isinstance(Node, ast.ClassDef):
|
||||
pass
|
||||
elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match):
|
||||
self.Trans.MatchHandler._HandleMatchLlvm(Node)
|
||||
elif isinstance(Node, ast.Try):
|
||||
self.Trans.TryHandler._HandleTryLlvm(Node)
|
||||
elif isinstance(Node, ast.Raise):
|
||||
self.Trans.RaiseHandler._HandleRaiseLlvm(Node)
|
||||
elif isinstance(Node, ast.Assert):
|
||||
self.Trans.AssertHandler._HandleAssertLlvm(Node)
|
||||
elif isinstance(Node, ast.Global):
|
||||
self.Trans.ForHandler._HandleGlobalLlvm(Node)
|
||||
elif isinstance(Node, ast.FunctionDef):
|
||||
self.Trans.ForHandler._HandleNestedFunctionLlvm(Node)
|
||||
elif isinstance(Node, ast.Nonlocal):
|
||||
self.Trans.ForHandler._HandleNonlocalLlvm(Node)
|
||||
elif isinstance(Node, ast.Delete):
|
||||
self.Trans.DeleteHandler._HandleDeleteLlvm(Node)
|
||||
except Exception as e:
|
||||
lineno: int = getattr(Node, 'lineno', 0)
|
||||
source_line: str | None = Gen._get_source_line(lineno)
|
||||
src_file: str = Gen._current_source_file or ''
|
||||
src_path: str = src_file if src_file else 'unknown'
|
||||
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
|
||||
if source_line:
|
||||
line_info += ":\n %d | %s" % (lineno, source_line)
|
||||
self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info))
|
||||
raise
|
||||
if Gen.builder and not Gen.builder.block.is_terminated:
|
||||
Gen._EmitTempFrees()
|
||||
|
||||
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None:
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class BodyHandle(BaseHandle):
|
||||
def __init__(self, translator: "Translator") -> None:
|
||||
super().__init__(translator)
|
||||
|
||||
def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for Node in Body:
|
||||
if Gen.builder and Gen.builder.block.is_terminated:
|
||||
break
|
||||
Gen._set_node_info(Node)
|
||||
try:
|
||||
if isinstance(Node, ast.Expr):
|
||||
self.HandleExprLlvm(Node.value)
|
||||
elif isinstance(Node, ast.Return):
|
||||
self.Trans.ReturnHandler._HandleReturnLlvm(Node)
|
||||
elif isinstance(Node, ast.Assign):
|
||||
self.Trans.AssignHandler._HandleAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.AugAssign):
|
||||
self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.AnnAssign):
|
||||
self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node)
|
||||
elif isinstance(Node, ast.If):
|
||||
self.Trans.IfHandler._HandleIfLlvm(Node)
|
||||
elif isinstance(Node, ast.For):
|
||||
self.Trans.ForHandler._HandleForLlvm(Node)
|
||||
elif isinstance(Node, ast.While):
|
||||
self.Trans.WhileHandler._HandleWhileLlvm(Node)
|
||||
elif isinstance(Node, ast.Break):
|
||||
if Gen.loop_break_targets:
|
||||
Gen.builder.branch(Gen.loop_break_targets[-1])
|
||||
elif isinstance(Node, ast.Continue):
|
||||
if Gen.loop_continue_targets:
|
||||
Gen.builder.branch(Gen.loop_continue_targets[-1])
|
||||
elif isinstance(Node, ast.With):
|
||||
self.Trans.WithHandler._HandleWithLlvm(Node)
|
||||
elif isinstance(Node, ast.ClassDef):
|
||||
pass
|
||||
elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match):
|
||||
self.Trans.MatchHandler._HandleMatchLlvm(Node)
|
||||
elif isinstance(Node, ast.Try):
|
||||
self.Trans.TryHandler._HandleTryLlvm(Node)
|
||||
elif isinstance(Node, ast.Raise):
|
||||
self.Trans.RaiseHandler._HandleRaiseLlvm(Node)
|
||||
elif isinstance(Node, ast.Assert):
|
||||
self.Trans.AssertHandler._HandleAssertLlvm(Node)
|
||||
elif isinstance(Node, ast.Global):
|
||||
self.Trans.ForHandler._HandleGlobalLlvm(Node)
|
||||
elif isinstance(Node, ast.FunctionDef):
|
||||
self.Trans.ForHandler._HandleNestedFunctionLlvm(Node)
|
||||
elif isinstance(Node, ast.Nonlocal):
|
||||
self.Trans.ForHandler._HandleNonlocalLlvm(Node)
|
||||
elif isinstance(Node, ast.Delete):
|
||||
self.Trans.DeleteHandler._HandleDeleteLlvm(Node)
|
||||
except Exception as e:
|
||||
lineno: int = getattr(Node, 'lineno', 0)
|
||||
source_line: str | None = Gen._get_source_line(lineno)
|
||||
src_file: str = Gen._current_source_file or ''
|
||||
src_path: str = src_file if src_file else 'unknown'
|
||||
line_info: str = "源代码 (%s, line %d)" % (src_path, lineno)
|
||||
if source_line:
|
||||
line_info += ":\n %d | %s" % (lineno, source_line)
|
||||
self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info))
|
||||
raise
|
||||
if Gen.builder and not Gen.builder.block.is_terminated:
|
||||
Gen._EmitTempFrees()
|
||||
|
||||
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None:
|
||||
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType)
|
||||
+196
-196
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
import ast
|
||||
import vast as ast
|
||||
import copy
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Exportable import EnumMember as ExportEnumMember
|
||||
@@ -247,125 +247,125 @@ class ClassHandle(BaseHandle):
|
||||
Gen._struct_sha1_map[spec_name] = self.Trans._module_sha1
|
||||
return spec_name
|
||||
|
||||
def _resolve_base_kind(self, base_name: str, Gen: LlvmGeneratorMixin) -> str | None:
|
||||
"""解析基类名称的类型种类
|
||||
|
||||
查询顺序:
|
||||
1. _t_type_symbols(from t import CEnum as en)
|
||||
2. t 模块属性(t.CEnum / t.CUnion / t.CStruct / t.REnum)
|
||||
3. 返回 None 表示不是已知标记基类
|
||||
|
||||
Returns:
|
||||
'enum' | 'union' | 'renum' | 'struct' | None
|
||||
"""
|
||||
# 1) 查 _t_type_symbols(别名导入)
|
||||
symtab: object = self.Trans.SymbolTable
|
||||
cls: type | None = symtab._t_type_symbols.get(base_name)
|
||||
if cls is not None:
|
||||
if issubclass(cls, (t.CEnum, t.REnum)):
|
||||
return 'renum' if issubclass(cls, t.REnum) else 'enum'
|
||||
if issubclass(cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(cls, t.CStruct):
|
||||
return 'struct'
|
||||
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
|
||||
# 不应被编译为真实结构体。
|
||||
if issubclass(cls, t.CType):
|
||||
return 'ctype_marker'
|
||||
|
||||
# 2) 查 t 模块属性(直接引用 t.CEnum 等)
|
||||
t_cls: type | None = getattr(t, base_name, None)
|
||||
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
|
||||
if issubclass(t_cls, (t.CEnum, t.REnum)):
|
||||
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
|
||||
if issubclass(t_cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(t_cls, t.CStruct):
|
||||
return 'struct'
|
||||
# CType 及其子类是"类型强转"标记,不编译为结构体。
|
||||
return 'ctype_marker'
|
||||
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _is_classname_ctype_marker(class_name: str) -> bool:
|
||||
"""检查类名是否是 t.CType 的"类型强转"标记子类。
|
||||
|
||||
只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/
|
||||
CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等)
|
||||
才应跳过编译。有 BASE position 的基本类型(CInt/CChar/CSizeT/CLong 等)
|
||||
有具体大小,应被正常编译。CType 基类本身无 bases,base 检测无法触发,
|
||||
需要直接按类名检查。
|
||||
|
||||
注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault,
|
||||
所以这里直接用 getattr(t, name) 检查 t 模块属性。
|
||||
|
||||
Returns:
|
||||
True 如果 class_name 是 CType 标记子类名(应跳过编译)
|
||||
"""
|
||||
if not class_name:
|
||||
return False
|
||||
# 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian)
|
||||
t_cls: type | None = getattr(t, class_name, None)
|
||||
if not isinstance(t_cls, type) or not issubclass(t_cls, t.CType):
|
||||
return False
|
||||
if issubclass(t_cls, (t.CStruct, t.CEnum, t.REnum, t.CUnion)):
|
||||
return False
|
||||
# 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过
|
||||
# CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过
|
||||
if t.CType.BASE in t_cls.position:
|
||||
try:
|
||||
inst = t_cls()
|
||||
size_val = getattr(inst, 'Size', None)
|
||||
if size_val is not None and size_val > 0:
|
||||
return False
|
||||
except Exception:
|
||||
pass
|
||||
return True
|
||||
|
||||
def _resolve_decorator_kind(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> str | None:
|
||||
"""从装饰器列表中解析结构体类型种类
|
||||
|
||||
支持 @t.CStruct, @t.CUnion, @t.CEnum, @t.REnum
|
||||
也支持 from t import CStruct 等别名形式
|
||||
|
||||
Returns:
|
||||
'enum' | 'union' | 'renum' | 'struct' | None
|
||||
"""
|
||||
if not hasattr(Node, 'decorator_list') or not Node.decorator_list:
|
||||
return None
|
||||
symtab: object = self.Trans.SymbolTable
|
||||
for decorator in Node.decorator_list:
|
||||
attr_name: str | None = None
|
||||
# @t.CStruct 形式
|
||||
if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name):
|
||||
if IsTModule(decorator.value.id, symtab):
|
||||
attr_name = decorator.attr
|
||||
# @CStruct 形式 (from t import CStruct)
|
||||
elif isinstance(decorator, ast.Name):
|
||||
cls: type | None = getattr(t, decorator.id, None)
|
||||
if cls is None and hasattr(symtab, '_t_type_symbols'):
|
||||
cls = symtab._t_type_symbols.get(decorator.id)
|
||||
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
|
||||
attr_name = cls.__name__
|
||||
if attr_name:
|
||||
# 查 _t_type_symbols 和 t 模块属性以确定种类
|
||||
resolved_cls: type | None = None
|
||||
if hasattr(symtab, '_t_type_symbols'):
|
||||
resolved_cls = symtab._t_type_symbols.get(attr_name)
|
||||
if resolved_cls is None:
|
||||
resolved_cls = getattr(t, attr_name, None)
|
||||
if resolved_cls is not None and isinstance(resolved_cls, type):
|
||||
if issubclass(resolved_cls, t.REnum):
|
||||
return 'renum'
|
||||
if issubclass(resolved_cls, t.CEnum):
|
||||
return 'enum'
|
||||
if issubclass(resolved_cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(resolved_cls, t.CStruct):
|
||||
return 'struct'
|
||||
return None
|
||||
|
||||
def _resolve_base_kind(self, base_name: str, Gen: LlvmGeneratorMixin) -> str | None:
|
||||
"""解析基类名称的类型种类
|
||||
|
||||
查询顺序:
|
||||
1. _t_type_symbols(from t import CEnum as en)
|
||||
2. t 模块属性(t.CEnum / t.CUnion / t.CStruct / t.REnum)
|
||||
3. 返回 None 表示不是已知标记基类
|
||||
|
||||
Returns:
|
||||
'enum' | 'union' | 'renum' | 'struct' | None
|
||||
"""
|
||||
# 1) 查 _t_type_symbols(别名导入)
|
||||
symtab: object = self.Trans.SymbolTable
|
||||
cls: type | None = symtab._t_type_symbols.get(base_name)
|
||||
if cls is not None:
|
||||
if issubclass(cls, (t.CEnum, t.REnum)):
|
||||
return 'renum' if issubclass(cls, t.REnum) else 'enum'
|
||||
if issubclass(cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(cls, t.CStruct):
|
||||
return 'struct'
|
||||
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
|
||||
# 不应被编译为真实结构体。
|
||||
if issubclass(cls, t.CType):
|
||||
return 'ctype_marker'
|
||||
|
||||
# 2) 查 t 模块属性(直接引用 t.CEnum 等)
|
||||
t_cls: type | None = getattr(t, base_name, None)
|
||||
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
|
||||
if issubclass(t_cls, (t.CEnum, t.REnum)):
|
||||
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
|
||||
if issubclass(t_cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(t_cls, t.CStruct):
|
||||
return 'struct'
|
||||
# CType 及其子类是"类型强转"标记,不编译为结构体。
|
||||
return 'ctype_marker'
|
||||
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _is_classname_ctype_marker(class_name: str) -> bool:
|
||||
"""检查类名是否是 t.CType 的"类型强转"标记子类。
|
||||
|
||||
只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/
|
||||
CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等)
|
||||
才应跳过编译。有 BASE position 的基本类型(CInt/CChar/CSizeT/CLong 等)
|
||||
有具体大小,应被正常编译。CType 基类本身无 bases,base 检测无法触发,
|
||||
需要直接按类名检查。
|
||||
|
||||
注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault,
|
||||
所以这里直接用 getattr(t, name) 检查 t 模块属性。
|
||||
|
||||
Returns:
|
||||
True 如果 class_name 是 CType 标记子类名(应跳过编译)
|
||||
"""
|
||||
if not class_name:
|
||||
return False
|
||||
# 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian)
|
||||
t_cls: type | None = getattr(t, class_name, None)
|
||||
if not isinstance(t_cls, type) or not issubclass(t_cls, t.CType):
|
||||
return False
|
||||
if issubclass(t_cls, (t.CStruct, t.CEnum, t.REnum, t.CUnion)):
|
||||
return False
|
||||
# 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过
|
||||
# CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过
|
||||
if t.CType.BASE in t_cls.position:
|
||||
try:
|
||||
inst = t_cls()
|
||||
size_val = getattr(inst, 'Size', None)
|
||||
if size_val is not None and size_val > 0:
|
||||
return False
|
||||
except Exception:
|
||||
pass
|
||||
return True
|
||||
|
||||
def _resolve_decorator_kind(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> str | None:
|
||||
"""从装饰器列表中解析结构体类型种类
|
||||
|
||||
支持 @t.CStruct, @t.CUnion, @t.CEnum, @t.REnum
|
||||
也支持 from t import CStruct 等别名形式
|
||||
|
||||
Returns:
|
||||
'enum' | 'union' | 'renum' | 'struct' | None
|
||||
"""
|
||||
if not hasattr(Node, 'decorator_list') or not Node.decorator_list:
|
||||
return None
|
||||
symtab: object = self.Trans.SymbolTable
|
||||
for decorator in Node.decorator_list:
|
||||
attr_name: str | None = None
|
||||
# @t.CStruct 形式
|
||||
if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name):
|
||||
if IsTModule(decorator.value.id, symtab):
|
||||
attr_name = decorator.attr
|
||||
# @CStruct 形式 (from t import CStruct)
|
||||
elif isinstance(decorator, ast.Name):
|
||||
cls: type | None = getattr(t, decorator.id, None)
|
||||
if cls is None and hasattr(symtab, '_t_type_symbols'):
|
||||
cls = symtab._t_type_symbols.get(decorator.id)
|
||||
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
|
||||
attr_name = cls.__name__
|
||||
if attr_name:
|
||||
# 查 _t_type_symbols 和 t 模块属性以确定种类
|
||||
resolved_cls: type | None = None
|
||||
if hasattr(symtab, '_t_type_symbols'):
|
||||
resolved_cls = symtab._t_type_symbols.get(attr_name)
|
||||
if resolved_cls is None:
|
||||
resolved_cls = getattr(t, attr_name, None)
|
||||
if resolved_cls is not None and isinstance(resolved_cls, type):
|
||||
if issubclass(resolved_cls, t.REnum):
|
||||
return 'renum'
|
||||
if issubclass(resolved_cls, t.CEnum):
|
||||
return 'enum'
|
||||
if issubclass(resolved_cls, t.CUnion):
|
||||
return 'union'
|
||||
if issubclass(resolved_cls, t.CStruct):
|
||||
return 'struct'
|
||||
return None
|
||||
|
||||
def _resolve_class_flags(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> tuple[bool, bool, str | None, bool]:
|
||||
"""解析类的 Object/CVTable 标志和父类信息
|
||||
|
||||
@@ -467,8 +467,8 @@ class ClassHandle(BaseHandle):
|
||||
if IsCVTable:
|
||||
Gen.class_vtable.add(ClassName)
|
||||
# 沿继承链向上传播,将所有祖先类加入 vtable
|
||||
visited: set[str] = {ClassName}
|
||||
ancestor: str | None = ParentClassName
|
||||
visited: set[str] = {ClassName}
|
||||
ancestor: str | None = ParentClassName
|
||||
while ancestor and ancestor not in visited:
|
||||
visited.add(ancestor)
|
||||
Gen.class_vtable.add(ancestor)
|
||||
@@ -550,44 +550,44 @@ class ClassHandle(BaseHandle):
|
||||
if IsRenum:
|
||||
self._EmitREnumLlvm(Node, Gen)
|
||||
return
|
||||
IsCpythonObject: bool
|
||||
IsCVTable: bool
|
||||
ParentClassName: str | None
|
||||
IsNoVTable: bool
|
||||
IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable = self._resolve_class_flags(Node, Gen)
|
||||
# 跟踪正在发射的类,防止递归特化时 _generate_structs 过早为空成员类设置 body
|
||||
Gen._classes_in_progress.add(ClassName)
|
||||
# 标记正在收集字段,阻止继承处理(_ResolveGenericSlice → _specialize_generic_class)
|
||||
# 和 CollectAnnAssignMember 触发的嵌套 _generate_structs 用不完整 class_members 调用 set_body
|
||||
Gen._collecting_members_set.add(ClassName)
|
||||
if ClassName not in Gen.class_methods:
|
||||
Gen.class_methods[ClassName] = []
|
||||
else:
|
||||
# 防御性清除:移除导入阶段可能添加的构造函数(__new__/__init__/__before_init__)。
|
||||
# 构造函数不参与虚分派,放入 vtable 会导致子类与基类 vtable 大小不一致,
|
||||
# 索引偏移破坏多态分派(如 Module 有 __new__/__init__ 使 vtable=7,而 AST 无它们 vtable=5,
|
||||
# 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。
|
||||
Gen.class_methods[ClassName] = [
|
||||
m for m in Gen.class_methods[ClassName]
|
||||
if m.split('.')[-1] not in ('__new__', '__init__', '__before_init__')
|
||||
]
|
||||
# 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明。
|
||||
# 关键:如果本地类是 @t.NoVTable 但同名导入类有 vtable(名称冲突),
|
||||
# 必须清除 vtable 状态,否则 _generate_structs 会错误添加 vtable 指针。
|
||||
if IsNoVTable:
|
||||
Gen.class_vtable.discard(ClassName)
|
||||
Gen._cross_module_vtable_classes.discard(ClassName)
|
||||
Gen._cross_module_novtable.add(ClassName)
|
||||
# 清除可能从导入 stub 加载的旧 struct body(含错误 vtable 指针),
|
||||
# 让 _generate_structs 用本地 class_members 重新生成
|
||||
_old_st = Gen.structs.get(ClassName)
|
||||
if isinstance(_old_st, ir.IdentifiedStructType) and _old_st.elements is not None:
|
||||
_old_st._elements = None
|
||||
_ih = getattr(Gen, '_import_handler_ref', None)
|
||||
if _ih is not None:
|
||||
_ck = (id(Gen), ClassName)
|
||||
if _ck in _ih._struct_Load_cache:
|
||||
del _ih._struct_Load_cache[_ck]
|
||||
IsCpythonObject: bool
|
||||
IsCVTable: bool
|
||||
ParentClassName: str | None
|
||||
IsNoVTable: bool
|
||||
IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable = self._resolve_class_flags(Node, Gen)
|
||||
# 跟踪正在发射的类,防止递归特化时 _generate_structs 过早为空成员类设置 body
|
||||
Gen._classes_in_progress.add(ClassName)
|
||||
# 标记正在收集字段,阻止继承处理(_ResolveGenericSlice → _specialize_generic_class)
|
||||
# 和 CollectAnnAssignMember 触发的嵌套 _generate_structs 用不完整 class_members 调用 set_body
|
||||
Gen._collecting_members_set.add(ClassName)
|
||||
if ClassName not in Gen.class_methods:
|
||||
Gen.class_methods[ClassName] = []
|
||||
else:
|
||||
# 防御性清除:移除导入阶段可能添加的构造函数(__new__/__init__/__before_init__)。
|
||||
# 构造函数不参与虚分派,放入 vtable 会导致子类与基类 vtable 大小不一致,
|
||||
# 索引偏移破坏多态分派(如 Module 有 __new__/__init__ 使 vtable=7,而 AST 无它们 vtable=5,
|
||||
# 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。
|
||||
Gen.class_methods[ClassName] = [
|
||||
m for m in Gen.class_methods[ClassName]
|
||||
if m.split('.')[-1] not in ('__new__', '__init__', '__before_init__')
|
||||
]
|
||||
# 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明。
|
||||
# 关键:如果本地类是 @t.NoVTable 但同名导入类有 vtable(名称冲突),
|
||||
# 必须清除 vtable 状态,否则 _generate_structs 会错误添加 vtable 指针。
|
||||
if IsNoVTable:
|
||||
Gen.class_vtable.discard(ClassName)
|
||||
Gen._cross_module_vtable_classes.discard(ClassName)
|
||||
Gen._cross_module_novtable.add(ClassName)
|
||||
# 清除可能从导入 stub 加载的旧 struct body(含错误 vtable 指针),
|
||||
# 让 _generate_structs 用本地 class_members 重新生成
|
||||
_old_st = Gen.structs.get(ClassName)
|
||||
if isinstance(_old_st, ir.IdentifiedStructType) and _old_st.elements is not None:
|
||||
_old_st._elements = None
|
||||
_ih = getattr(Gen, '_import_handler_ref', None)
|
||||
if _ih is not None:
|
||||
_ck = (id(Gen), ClassName)
|
||||
if _ck in _ih._struct_Load_cache:
|
||||
del _ih._struct_Load_cache[_ck]
|
||||
Gen.class_members[ClassName] = []
|
||||
Gen.class_member_defaults[ClassName] = {}
|
||||
Gen.class_member_signeds[ClassName] = {}
|
||||
@@ -707,13 +707,13 @@ class ClassHandle(BaseHandle):
|
||||
if method_name not in covered_names:
|
||||
new_methods.append(m)
|
||||
Gen.class_methods[ClassName] = new_methods
|
||||
# 提取首个裸字符串字面量作为结构体 __doc__ docstring
|
||||
if (Node.body and isinstance(Node.body[0], ast.Expr)
|
||||
and isinstance(Node.body[0].value, ast.Constant)
|
||||
and isinstance(Node.body[0].value.value, str)):
|
||||
Gen._create_doc_global(ClassName, Node.body[0].value.value)
|
||||
else:
|
||||
Gen._create_doc_global(ClassName, None)
|
||||
# 提取首个裸字符串字面量作为结构体 __doc__ docstring
|
||||
if (Node.body and isinstance(Node.body[0], ast.Expr)
|
||||
and isinstance(Node.body[0].value, ast.Constant)
|
||||
and isinstance(Node.body[0].value.value, str)):
|
||||
Gen._create_doc_global(ClassName, Node.body[0].value.value)
|
||||
else:
|
||||
Gen._create_doc_global(ClassName, None)
|
||||
# 解析 __provides__/__requires__/__require_must__ 编译期元数据
|
||||
for item in Node.body:
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
@@ -1081,35 +1081,35 @@ class ClassHandle(BaseHandle):
|
||||
continue
|
||||
self._scan_node_for_self_assign(child, ClassName, existing_members, Gen)
|
||||
|
||||
def _EmitUnionLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
|
||||
ClassName: str = Node.name
|
||||
union_member_types: list[ir.Type] = []
|
||||
for item in Node.body:
|
||||
if isinstance(item, ast.ClassDef):
|
||||
nested_class_name: str = item.name
|
||||
nested_member_types: list[ir.Type] = []
|
||||
for nested_item in item.body:
|
||||
parsed = self.CollectAnnAssignMember(nested_item, Gen)
|
||||
if parsed:
|
||||
nested_member_types.append(parsed[1])
|
||||
if nested_member_types:
|
||||
nested_struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}")
|
||||
nested_struct_type.set_body(*nested_member_types)
|
||||
Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type
|
||||
union_member_types.append(nested_struct_type)
|
||||
nested_class_full_name: str = f"{ClassName}_{nested_class_name}"
|
||||
if nested_class_full_name not in Gen.class_members:
|
||||
Gen.class_members[nested_class_full_name] = []
|
||||
if nested_class_full_name not in Gen.class_member_signeds:
|
||||
Gen.class_member_signeds[nested_class_full_name] = {}
|
||||
for nested_item in item.body:
|
||||
parsed = self.CollectAnnAssignMember(nested_item, Gen)
|
||||
if parsed:
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
Gen.class_members[nested_class_full_name].append((VarName, MemberType))
|
||||
if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'):
|
||||
Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned
|
||||
else:
|
||||
def _EmitUnionLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
|
||||
ClassName: str = Node.name
|
||||
union_member_types: list[ir.Type] = []
|
||||
for item in Node.body:
|
||||
if isinstance(item, ast.ClassDef):
|
||||
nested_class_name: str = item.name
|
||||
nested_member_types: list[ir.Type] = []
|
||||
for nested_item in item.body:
|
||||
parsed = self.CollectAnnAssignMember(nested_item, Gen)
|
||||
if parsed:
|
||||
nested_member_types.append(parsed[1])
|
||||
if nested_member_types:
|
||||
nested_struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}")
|
||||
nested_struct_type.set_body(*nested_member_types)
|
||||
Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type
|
||||
union_member_types.append(nested_struct_type)
|
||||
nested_class_full_name: str = f"{ClassName}_{nested_class_name}"
|
||||
if nested_class_full_name not in Gen.class_members:
|
||||
Gen.class_members[nested_class_full_name] = []
|
||||
if nested_class_full_name not in Gen.class_member_signeds:
|
||||
Gen.class_member_signeds[nested_class_full_name] = {}
|
||||
for nested_item in item.body:
|
||||
parsed = self.CollectAnnAssignMember(nested_item, Gen)
|
||||
if parsed:
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
Gen.class_members[nested_class_full_name].append((VarName, MemberType))
|
||||
if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'):
|
||||
Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned
|
||||
else:
|
||||
Gen.class_member_signeds[nested_class_full_name][VarName] = None
|
||||
if union_member_types:
|
||||
max_size: int = 0
|
||||
|
||||
+101
-101
@@ -1,102 +1,102 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class DeleteHandle(BaseHandle):
|
||||
def _HandleDeleteLlvm(self, Node: ast.Delete) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for target in Node.targets:
|
||||
if isinstance(target, ast.Subscript):
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__delitem__'):
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
|
||||
idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.slice)
|
||||
if obj_val and idx_val:
|
||||
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
|
||||
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__")
|
||||
elif isinstance(target, ast.Name):
|
||||
ClassName: str | None = Gen.var_struct_class.get(target.id)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__delete__'):
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
|
||||
if obj_val:
|
||||
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
|
||||
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__")
|
||||
elif isinstance(target, ast.Attribute):
|
||||
# 检查 property deleter
|
||||
AttrName: str = target.attr
|
||||
ClassName: str | None = None
|
||||
obj_val_for_prop: ir.Value | None = None
|
||||
|
||||
if isinstance(target.value, ast.Name) and target.value.id == 'self':
|
||||
# del self.attr — 检查当前类的 property deleter
|
||||
ClassName = self.Trans._CurrentCpythonObjectClass
|
||||
if ClassName:
|
||||
PropKey: str = f'{ClassName}.{AttrName}'
|
||||
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
|
||||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
|
||||
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
|
||||
if SelfVar:
|
||||
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
|
||||
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
|
||||
if DeleterFunc and SelfPtr:
|
||||
Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}")
|
||||
continue
|
||||
else:
|
||||
# del obj.attr — 检查 obj 类的 property deleter
|
||||
ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen)
|
||||
if ClassName:
|
||||
PropKey: str = f'{ClassName}.{AttrName}'
|
||||
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
|
||||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
|
||||
if obj_val:
|
||||
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
|
||||
if DeleterFunc:
|
||||
Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}")
|
||||
continue
|
||||
|
||||
# 原有的 __del__ 处理逻辑
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
|
||||
if obj_val:
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType):
|
||||
obj_val = Gen._load(obj_val, name="Load_del_ptr")
|
||||
ClassName = None
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if obj_val.type.pointee == ST:
|
||||
ClassName = CN
|
||||
break
|
||||
elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
if isinstance(target.value, ast.Name) and target.value.id == 'self':
|
||||
AttrName = target.attr
|
||||
SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass
|
||||
if SelfClassName and SelfClassName in Gen.class_members:
|
||||
for member_name, member_type in Gen.class_members[SelfClassName]:
|
||||
if member_name == AttrName:
|
||||
for CN in Gen.structs:
|
||||
if CN == AttrName or Gen._has_function(f'{CN}.__del__'):
|
||||
ClassName = CN
|
||||
break
|
||||
break
|
||||
if not ClassName:
|
||||
for CN, ST in Gen.structs.items():
|
||||
if Gen._has_function(f'{CN}.__del__'):
|
||||
ClassName = CN
|
||||
break
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__del__'):
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class DeleteHandle(BaseHandle):
|
||||
def _HandleDeleteLlvm(self, Node: ast.Delete) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for target in Node.targets:
|
||||
if isinstance(target, ast.Subscript):
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__delitem__'):
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
|
||||
idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.slice)
|
||||
if obj_val and idx_val:
|
||||
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
|
||||
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__")
|
||||
elif isinstance(target, ast.Name):
|
||||
ClassName: str | None = Gen.var_struct_class.get(target.id)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__delete__'):
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
|
||||
if obj_val:
|
||||
# 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
|
||||
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__")
|
||||
elif isinstance(target, ast.Attribute):
|
||||
# 检查 property deleter
|
||||
AttrName: str = target.attr
|
||||
ClassName: str | None = None
|
||||
obj_val_for_prop: ir.Value | None = None
|
||||
|
||||
if isinstance(target.value, ast.Name) and target.value.id == 'self':
|
||||
# del self.attr — 检查当前类的 property deleter
|
||||
ClassName = self.Trans._CurrentCpythonObjectClass
|
||||
if ClassName:
|
||||
PropKey: str = f'{ClassName}.{AttrName}'
|
||||
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
|
||||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
|
||||
SelfVar: ir.Value | None = Gen._get_var_ptr('self')
|
||||
if SelfVar:
|
||||
SelfPtr: ir.Value = Gen._load(SelfVar, name="self")
|
||||
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
|
||||
if DeleterFunc and SelfPtr:
|
||||
Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}")
|
||||
continue
|
||||
else:
|
||||
# del obj.attr — 检查 obj 类的 property deleter
|
||||
ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen)
|
||||
if ClassName:
|
||||
PropKey: str = f'{ClassName}.{AttrName}'
|
||||
PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey)
|
||||
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value)
|
||||
if obj_val:
|
||||
DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del')
|
||||
if DeleterFunc:
|
||||
Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}")
|
||||
continue
|
||||
|
||||
# 原有的 __del__ 处理逻辑
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target)
|
||||
if obj_val:
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType):
|
||||
obj_val = Gen._load(obj_val, name="Load_del_ptr")
|
||||
ClassName = None
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if obj_val.type.pointee == ST:
|
||||
ClassName = CN
|
||||
break
|
||||
elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
if isinstance(target.value, ast.Name) and target.value.id == 'self':
|
||||
AttrName = target.attr
|
||||
SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass
|
||||
if SelfClassName and SelfClassName in Gen.class_members:
|
||||
for member_name, member_type in Gen.class_members[SelfClassName]:
|
||||
if member_name == AttrName:
|
||||
for CN in Gen.structs:
|
||||
if CN == AttrName or Gen._has_function(f'{CN}.__del__'):
|
||||
ClassName = CN
|
||||
break
|
||||
break
|
||||
if not ClassName:
|
||||
for CN, ST in Gen.structs.items():
|
||||
if Gen._has_function(f'{CN}.__del__'):
|
||||
ClassName = CN
|
||||
break
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__del__'):
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Gen.builder.call(Gen._get_function(f'{ClassName}.__del__'), [obj_val], name=f"call_{ClassName}.__del__")
|
||||
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
import ast
|
||||
import vast as ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
import ast
|
||||
import vast as ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
if TYPE_CHECKING:
|
||||
|
||||
@@ -4,7 +4,7 @@ if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
|
||||
import ast
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
import ast
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
+156
-156
@@ -1,31 +1,31 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
import ast
|
||||
import os
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp
|
||||
|
||||
|
||||
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
|
||||
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*(对应 C 的 void* 语义)"""
|
||||
if isinstance(ty, ir.PointerType):
|
||||
cur: ir.Type = ty
|
||||
while isinstance(cur, ir.PointerType):
|
||||
if isinstance(cur.pointee, ir.VoidType):
|
||||
return ir.IntType(8).as_pointer()
|
||||
cur = cur.pointee
|
||||
return ty
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
import vast as ast
|
||||
import os
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp
|
||||
|
||||
|
||||
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
|
||||
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*(对应 C 的 void* 语义)"""
|
||||
if isinstance(ty, ir.PointerType):
|
||||
cur: ir.Type = ty
|
||||
while isinstance(cur, ir.PointerType):
|
||||
if isinstance(cur.pointee, ir.VoidType):
|
||||
return ir.IntType(8).as_pointer()
|
||||
cur = cur.pointee
|
||||
return ty
|
||||
|
||||
|
||||
class ExprCallHandle(BaseHandle):
|
||||
def _append_eh_msg_out_arg(self, CallArgs: list[ir.Value], func: ir.Function | None, Gen: LlvmGeneratorMixin) -> None:
|
||||
if not func:
|
||||
@@ -929,15 +929,15 @@ class ExprCallHandle(BaseHandle):
|
||||
ArgVal = self.HandleExprLlvm(arg)
|
||||
if ArgVal:
|
||||
CallArgs.append(ArgVal)
|
||||
if (ClassName not in Gen.class_vtable
|
||||
and ClassName not in Gen._cross_module_vtable_classes
|
||||
and class_sha1):
|
||||
self._try_register_vtable_ondemand(ClassName, class_sha1, Gen)
|
||||
# 跨模块多继承:确保 class_parents 可用(MRO 回退需要)。
|
||||
# 如 HandlesType 委托调用 Generator 的方法——Generator 定义在
|
||||
# 另一模块,class_parents 未随 import 填充,需从 vpi 按需加载。
|
||||
self._EnsureClassParentsLoaded(ClassName, Gen)
|
||||
if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call:
|
||||
if (ClassName not in Gen.class_vtable
|
||||
and ClassName not in Gen._cross_module_vtable_classes
|
||||
and class_sha1):
|
||||
self._try_register_vtable_ondemand(ClassName, class_sha1, Gen)
|
||||
# 跨模块多继承:确保 class_parents 可用(MRO 回退需要)。
|
||||
# 如 HandlesType 委托调用 Generator 的方法——Generator 定义在
|
||||
# 另一模块,class_parents 未随 import 填充,需从 vpi 按需加载。
|
||||
self._EnsureClassParentsLoaded(ClassName, Gen)
|
||||
if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call:
|
||||
methods = Gen.class_methods[ClassName]
|
||||
if class_sha1:
|
||||
FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}'
|
||||
@@ -2407,125 +2407,125 @@ class ExprCallHandle(BaseHandle):
|
||||
# 失败时恢复 declare_only 标记,避免后续调用跳过补发
|
||||
Gen._generic_class_specializations[spec_key] = (cached_name, True)
|
||||
|
||||
def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None:
|
||||
"""计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。
|
||||
|
||||
遍历 struct elements 带对齐累加(与 _get_struct_size/_get_align 一致)。
|
||||
有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。
|
||||
返回 None 表示无法计算(struct 未定义 / 字段不存在)。
|
||||
"""
|
||||
st = Gen.structs.get(ClassName)
|
||||
if not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||||
return None
|
||||
members: list = Gen.class_members.get(ClassName, [])
|
||||
has_vtable: bool = (ClassName in Gen.class_vtable
|
||||
or ClassName in Gen._cross_module_vtable_classes)
|
||||
base: int = 1 if has_vtable else 0
|
||||
idx: int | None = None
|
||||
for i, (name, _) in enumerate(members):
|
||||
if name == field_name:
|
||||
idx = base + i
|
||||
break
|
||||
if idx is None or idx >= len(st.elements):
|
||||
return None
|
||||
# ============================================================
|
||||
# 修复(2026-08-13):class_members 与 struct.elements 数量不一致时对齐。
|
||||
# 根因链(NewAstTest ASTCtx 枚举丢失):
|
||||
# DeclarationGenerator/收集路径生成的 class_members 可能漏部分 Mixin/自动
|
||||
# 字段(如 Generator 漏 GenericSpecDepth/GenericClassFiles/ISINSTANCE_CLASS_MAX
|
||||
# 3 个,class_members=88 vs struct=91),导致 this_adjust 用 class_members
|
||||
# 索引算错字节偏移(Generator 624 vs 真实 644)。StmtGenMixin 方法(find_enum/
|
||||
# register_enum/is_enum_class)字段访问错位 20 字节 → EnumTable 落在
|
||||
# ReexportSrcs 内存 → 与 reexport 数据冲突覆盖 → ASTCtx 等枚举丢失。
|
||||
# 修正:字段真实 struct 索引 = class_members 索引 + (struct 元素数 - members 数)。
|
||||
# 前提:遗漏字段位于目标字段之前(本 bug 场景成立:漏字段在 StmtGenMixin 前)。
|
||||
# ============================================================
|
||||
diff_elems: int = len(st.elements) - len(members)
|
||||
if diff_elems > 0:
|
||||
idx += diff_elems
|
||||
if idx >= len(st.elements):
|
||||
return None
|
||||
offset: int = 0
|
||||
for i in range(idx):
|
||||
et = st.elements[i]
|
||||
align: int = Gen._get_align(et)
|
||||
size: int = Gen._get_struct_size(et)
|
||||
if align > 1:
|
||||
offset = ((offset + align - 1) // align) * align
|
||||
offset += size
|
||||
align = Gen._get_align(st.elements[idx])
|
||||
if align > 1:
|
||||
offset = ((offset + align - 1) // align) * align
|
||||
return offset
|
||||
|
||||
def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value,
|
||||
ClassName: str, method_anc: str | None) -> ir.Value:
|
||||
"""多继承 this 调整(与 TPV _translate_method_call 一致):
|
||||
|
||||
继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内
|
||||
GEP(self_B, [0, 1]),字节偏移为 B 布局中 b 的 offset 8)。父类字段区
|
||||
在子类中的**字节偏移**可能不同(如 AB={i8*,a@8,b@12} 中 b 偏移 12),
|
||||
self 需按字节差前移,使父类方法内二次 GEP 恰好落到子类字段。
|
||||
|
||||
修复(2026-08-10):字段索引法在"父类与子类元素大小不同"时错位
|
||||
(GEP 索引按元素个数计,非字节等价)。改用字节偏移:
|
||||
delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移
|
||||
delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节
|
||||
GEP 到父类字段区在子类中的等效基址,再 bitcast 成父类指针。
|
||||
"""
|
||||
if method_anc is None or method_anc == ClassName:
|
||||
return ObjVal
|
||||
anc_members: list = Gen.class_members.get(method_anc, [])
|
||||
if not anc_members:
|
||||
return ObjVal
|
||||
first_field_name: str | None = None
|
||||
for _fn, _ft in anc_members:
|
||||
if _fn == '__vtable__':
|
||||
continue
|
||||
first_field_name = _fn
|
||||
break
|
||||
if first_field_name is None:
|
||||
return ObjVal
|
||||
sub_off: int | None = self._compute_field_byte_offset(Gen, ClassName, first_field_name)
|
||||
if sub_off is None:
|
||||
return ObjVal
|
||||
anc_off: int | None = self._compute_field_byte_offset(Gen, method_anc, first_field_name)
|
||||
if anc_off is None:
|
||||
return ObjVal
|
||||
delta: int = sub_off - anc_off
|
||||
if delta <= 0:
|
||||
return ObjVal
|
||||
if method_anc not in Gen.structs:
|
||||
return ObjVal
|
||||
obj_i8: ir.Value = Gen.builder.bitcast(ObjVal, ir.PointerType(ir.IntType(8)),
|
||||
name=f"this_adjust_i8_{method_anc}")
|
||||
adj: ir.Value = Gen.builder.gep(obj_i8, [ir.Constant(ir.IntType(64), delta)],
|
||||
name=f"this_adjust_{method_anc}")
|
||||
return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]),
|
||||
name=f"this_adjust_cast_{method_anc}")
|
||||
|
||||
def _EnsureClassParentsLoaded(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
|
||||
"""跨模块多继承:class_parents 缺失时从 vpi 按需加载继承信息。
|
||||
|
||||
调用方(如 HandlesType 委托)引用的类定义在另一模块,其父类
|
||||
信息未随 import 填充。_TryLoadClassMembersFromPyi 读取 .vpi 中
|
||||
的 ClassDef 并经 _EmitExternalClassDeclLlvm 填充 class_parents,
|
||||
使 _get_mro_chain 能沿 MRO 回退到定义类(如 TypeGenMixin)。
|
||||
"""
|
||||
if not ClassName:
|
||||
return
|
||||
if Gen.class_parents.get(ClassName):
|
||||
return
|
||||
sha1_cls = Gen.ModuleSha1Map.get(ClassName)
|
||||
if not sha1_cls:
|
||||
sha1_cls = getattr(Gen, '_struct_sha1_map', {}).get(ClassName)
|
||||
if not sha1_cls:
|
||||
return
|
||||
try:
|
||||
self.Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, f"{sha1_cls}.stub.ll", Gen)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None:
|
||||
"""计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。
|
||||
|
||||
遍历 struct elements 带对齐累加(与 _get_struct_size/_get_align 一致)。
|
||||
有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。
|
||||
返回 None 表示无法计算(struct 未定义 / 字段不存在)。
|
||||
"""
|
||||
st = Gen.structs.get(ClassName)
|
||||
if not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||||
return None
|
||||
members: list = Gen.class_members.get(ClassName, [])
|
||||
has_vtable: bool = (ClassName in Gen.class_vtable
|
||||
or ClassName in Gen._cross_module_vtable_classes)
|
||||
base: int = 1 if has_vtable else 0
|
||||
idx: int | None = None
|
||||
for i, (name, _) in enumerate(members):
|
||||
if name == field_name:
|
||||
idx = base + i
|
||||
break
|
||||
if idx is None or idx >= len(st.elements):
|
||||
return None
|
||||
# ============================================================
|
||||
# 修复(2026-08-13):class_members 与 struct.elements 数量不一致时对齐。
|
||||
# 根因链(NewAstTest ASTCtx 枚举丢失):
|
||||
# DeclarationGenerator/收集路径生成的 class_members 可能漏部分 Mixin/自动
|
||||
# 字段(如 Generator 漏 GenericSpecDepth/GenericClassFiles/ISINSTANCE_CLASS_MAX
|
||||
# 3 个,class_members=88 vs struct=91),导致 this_adjust 用 class_members
|
||||
# 索引算错字节偏移(Generator 624 vs 真实 644)。StmtGenMixin 方法(find_enum/
|
||||
# register_enum/is_enum_class)字段访问错位 20 字节 → EnumTable 落在
|
||||
# ReexportSrcs 内存 → 与 reexport 数据冲突覆盖 → ASTCtx 等枚举丢失。
|
||||
# 修正:字段真实 struct 索引 = class_members 索引 + (struct 元素数 - members 数)。
|
||||
# 前提:遗漏字段位于目标字段之前(本 bug 场景成立:漏字段在 StmtGenMixin 前)。
|
||||
# ============================================================
|
||||
diff_elems: int = len(st.elements) - len(members)
|
||||
if diff_elems > 0:
|
||||
idx += diff_elems
|
||||
if idx >= len(st.elements):
|
||||
return None
|
||||
offset: int = 0
|
||||
for i in range(idx):
|
||||
et = st.elements[i]
|
||||
align: int = Gen._get_align(et)
|
||||
size: int = Gen._get_struct_size(et)
|
||||
if align > 1:
|
||||
offset = ((offset + align - 1) // align) * align
|
||||
offset += size
|
||||
align = Gen._get_align(st.elements[idx])
|
||||
if align > 1:
|
||||
offset = ((offset + align - 1) // align) * align
|
||||
return offset
|
||||
|
||||
def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value,
|
||||
ClassName: str, method_anc: str | None) -> ir.Value:
|
||||
"""多继承 this 调整(与 TPV _translate_method_call 一致):
|
||||
|
||||
继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内
|
||||
GEP(self_B, [0, 1]),字节偏移为 B 布局中 b 的 offset 8)。父类字段区
|
||||
在子类中的**字节偏移**可能不同(如 AB={i8*,a@8,b@12} 中 b 偏移 12),
|
||||
self 需按字节差前移,使父类方法内二次 GEP 恰好落到子类字段。
|
||||
|
||||
修复(2026-08-10):字段索引法在"父类与子类元素大小不同"时错位
|
||||
(GEP 索引按元素个数计,非字节等价)。改用字节偏移:
|
||||
delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移
|
||||
delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节
|
||||
GEP 到父类字段区在子类中的等效基址,再 bitcast 成父类指针。
|
||||
"""
|
||||
if method_anc is None or method_anc == ClassName:
|
||||
return ObjVal
|
||||
anc_members: list = Gen.class_members.get(method_anc, [])
|
||||
if not anc_members:
|
||||
return ObjVal
|
||||
first_field_name: str | None = None
|
||||
for _fn, _ft in anc_members:
|
||||
if _fn == '__vtable__':
|
||||
continue
|
||||
first_field_name = _fn
|
||||
break
|
||||
if first_field_name is None:
|
||||
return ObjVal
|
||||
sub_off: int | None = self._compute_field_byte_offset(Gen, ClassName, first_field_name)
|
||||
if sub_off is None:
|
||||
return ObjVal
|
||||
anc_off: int | None = self._compute_field_byte_offset(Gen, method_anc, first_field_name)
|
||||
if anc_off is None:
|
||||
return ObjVal
|
||||
delta: int = sub_off - anc_off
|
||||
if delta <= 0:
|
||||
return ObjVal
|
||||
if method_anc not in Gen.structs:
|
||||
return ObjVal
|
||||
obj_i8: ir.Value = Gen.builder.bitcast(ObjVal, ir.PointerType(ir.IntType(8)),
|
||||
name=f"this_adjust_i8_{method_anc}")
|
||||
adj: ir.Value = Gen.builder.gep(obj_i8, [ir.Constant(ir.IntType(64), delta)],
|
||||
name=f"this_adjust_{method_anc}")
|
||||
return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]),
|
||||
name=f"this_adjust_cast_{method_anc}")
|
||||
|
||||
def _EnsureClassParentsLoaded(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
|
||||
"""跨模块多继承:class_parents 缺失时从 vpi 按需加载继承信息。
|
||||
|
||||
调用方(如 HandlesType 委托)引用的类定义在另一模块,其父类
|
||||
信息未随 import 填充。_TryLoadClassMembersFromPyi 读取 .vpi 中
|
||||
的 ClassDef 并经 _EmitExternalClassDeclLlvm 填充 class_parents,
|
||||
使 _get_mro_chain 能沿 MRO 回退到定义类(如 TypeGenMixin)。
|
||||
"""
|
||||
if not ClassName:
|
||||
return
|
||||
if Gen.class_parents.get(ClassName):
|
||||
return
|
||||
sha1_cls = Gen.ModuleSha1Map.get(ClassName)
|
||||
if not sha1_cls:
|
||||
sha1_cls = getattr(Gen, '_struct_sha1_map', {}).get(ClassName)
|
||||
if not sha1_cls:
|
||||
return
|
||||
try:
|
||||
self.Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, f"{sha1_cls}.stub.ll", Gen)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen = self.Trans.LlvmGen
|
||||
MethodName = Node.func.attr
|
||||
|
||||
@@ -1,271 +1,271 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprFormatHandle(BaseHandle):
|
||||
def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if not Gen or not Gen.builder:
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
format_str: str = ""
|
||||
cast_args: list[Any] = []
|
||||
for part in Node.values:
|
||||
if isinstance(part, ast.Constant) and isinstance(part.value, str):
|
||||
format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0')
|
||||
elif isinstance(part, ast.FormattedValue):
|
||||
fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen)
|
||||
if fmt_class and Gen._has_function(f'{fmt_class}.__str__'):
|
||||
obj_val: Any = self.HandleExprLlvm(part.value)
|
||||
if obj_val:
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
if fmt_class in Gen.structs:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}")
|
||||
val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__")
|
||||
Gen._RegisterTempPtr(val)
|
||||
format_str += "%s"
|
||||
cast_args.append(val)
|
||||
else:
|
||||
format_str += "%s"
|
||||
cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
|
||||
continue
|
||||
val = self.HandleExprLlvm(part.value)
|
||||
if not val:
|
||||
format_str += "%d"
|
||||
cast_args.append(ir.Constant(ir.IntType(32), 0))
|
||||
continue
|
||||
# 检查 format_spec(Python f-string 格式说明符)
|
||||
if part.format_spec is not None:
|
||||
c_fmt: str | None = self._parse_format_spec(part.format_spec, val)
|
||||
if c_fmt is not None:
|
||||
cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value)
|
||||
format_str += c_fmt
|
||||
cast_args.append(cast_val)
|
||||
continue
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
format_str += "%s"
|
||||
cast_args.append(val)
|
||||
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int")
|
||||
trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc")
|
||||
format_str += "%d"
|
||||
cast_args.append(trunc_val)
|
||||
else:
|
||||
Loaded: Any = Gen._load(val, name="fstr_deref")
|
||||
if isinstance(Loaded.type, ir.IntType):
|
||||
if Loaded.type.width == 8:
|
||||
format_str += "%c"
|
||||
ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int")
|
||||
cast_args.append(ext)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)):
|
||||
format_str += "%f"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(Loaded.type, ir.PointerType):
|
||||
format_str += "%s"
|
||||
cast_args.append(Loaded)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
format_str += "%c"
|
||||
ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int")
|
||||
cast_args.append(ext)
|
||||
elif val.type.width == 1:
|
||||
zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int")
|
||||
format_str += "%d"
|
||||
cast_args.append(zext)
|
||||
else:
|
||||
is_u: bool = Gen._check_node_unsigned(part.value)
|
||||
format_str += "%u" if is_u else "%d"
|
||||
cast_args.append(val)
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
format_str += "%f"
|
||||
cast_args.append(val)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(val)
|
||||
if not format_str:
|
||||
return Gen.emit_constant("", 'string')
|
||||
format_ptr: Any = Gen._create_string_global(format_str)
|
||||
# 统一使用 snprintf 生成字符串,返回 i8*
|
||||
# __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放)
|
||||
in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__'))
|
||||
snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.IntType(64),
|
||||
ir.PointerType(ir.IntType(8))
|
||||
], var_arg=True)
|
||||
snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type)
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
# 第一遍:获取所需长度(NULL 缓冲,size=0)
|
||||
len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len")
|
||||
# 加 1 用于 null 终止符
|
||||
size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size")
|
||||
size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext")
|
||||
if in_str_method:
|
||||
# 堆分配(__str__ 返回值需跨函数生命周期)
|
||||
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
||||
malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type)
|
||||
buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf")
|
||||
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
|
||||
Gen._RegisterTempPtr(buf_ptr)
|
||||
return buf_ptr
|
||||
# 栈分配(局部使用,自动释放)
|
||||
buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val)
|
||||
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
|
||||
return buf_ptr
|
||||
|
||||
def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None:
|
||||
"""将 Python f-string format_spec 转换为 C printf 格式说明符。
|
||||
|
||||
支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。
|
||||
返回 None 表示无法解析,调用方应回退到类型推断。
|
||||
"""
|
||||
if isinstance(format_spec_node, ast.JoinedStr):
|
||||
parts: list[str] = []
|
||||
for v in format_spec_node.values:
|
||||
if isinstance(v, ast.Constant) and isinstance(v.value, str):
|
||||
parts.append(v.value)
|
||||
else:
|
||||
return None
|
||||
spec_str: str = ''.join(parts)
|
||||
elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str):
|
||||
spec_str = format_spec_node.value
|
||||
else:
|
||||
return None
|
||||
|
||||
if not spec_str:
|
||||
return None
|
||||
|
||||
m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups()
|
||||
|
||||
c_flags: str = ''
|
||||
if sign == '+':
|
||||
c_flags += '+'
|
||||
elif sign == ' ':
|
||||
c_flags += ' '
|
||||
if alt:
|
||||
c_flags += '#'
|
||||
|
||||
if fill_align:
|
||||
align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0]
|
||||
if align_char in ('<', '^'):
|
||||
c_flags += '-'
|
||||
if zero:
|
||||
c_flags += '0'
|
||||
|
||||
c_width: str = width or ''
|
||||
c_precision: str = precision or ''
|
||||
|
||||
length_mod: str = ''
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 64:
|
||||
length_mod = 'll'
|
||||
elif val.type.width == 32:
|
||||
length_mod = 'l'
|
||||
elif val.type.width == 16:
|
||||
length_mod = 'h'
|
||||
elif val.type.width == 8:
|
||||
length_mod = 'hh'
|
||||
|
||||
c_specifier: str = ''
|
||||
if fmt_type in ('d', 'n'):
|
||||
c_specifier = f'{length_mod}d'
|
||||
elif fmt_type == 'x':
|
||||
c_specifier = f'{length_mod}x'
|
||||
elif fmt_type == 'X':
|
||||
c_specifier = f'{length_mod}X'
|
||||
elif fmt_type == 'o':
|
||||
c_specifier = f'{length_mod}o'
|
||||
elif fmt_type == 'b':
|
||||
return None
|
||||
elif fmt_type == 'c':
|
||||
c_specifier = 'c'
|
||||
elif fmt_type in ('f', 'F'):
|
||||
c_specifier = 'f'
|
||||
elif fmt_type in ('e', 'E', 'g', 'G'):
|
||||
c_specifier = fmt_type
|
||||
elif fmt_type == 's':
|
||||
c_specifier = 's'
|
||||
elif fmt_type == '%':
|
||||
c_specifier = 'f%%'
|
||||
else:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
c_specifier = 'c'
|
||||
elif val.type.width == 1:
|
||||
c_specifier = 'd'
|
||||
else:
|
||||
c_specifier = f'{length_mod}d'
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
c_specifier = 'f'
|
||||
elif isinstance(val.type, ir.PointerType):
|
||||
c_specifier = 's'
|
||||
else:
|
||||
c_specifier = 'd'
|
||||
|
||||
return f'%{c_flags}{c_width}{c_precision}{c_specifier}'
|
||||
|
||||
def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value:
|
||||
"""根据 C printf 格式说明符转换值类型。"""
|
||||
fmt_type_char: str = ''
|
||||
for ch in reversed(c_fmt):
|
||||
if ch.isalpha() and ch not in ('l', 'h'):
|
||||
fmt_type_char = ch
|
||||
break
|
||||
elif ch == '%':
|
||||
break
|
||||
|
||||
if fmt_type_char == 's':
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
return val
|
||||
if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
|
||||
return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr")
|
||||
return val
|
||||
elif fmt_type_char == 'c':
|
||||
if isinstance(val.type, ir.IntType) and val.type.width < 32:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c")
|
||||
return val
|
||||
elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'):
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
is_u: bool = Gen._check_node_unsigned(arg_node)
|
||||
if is_u:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8")
|
||||
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8")
|
||||
elif val.type.width == 16:
|
||||
is_u = Gen._check_node_unsigned(arg_node)
|
||||
if is_u:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16")
|
||||
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16")
|
||||
elif val.type.width == 1:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool")
|
||||
return val
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i")
|
||||
return val
|
||||
elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'):
|
||||
if isinstance(val.type, ir.FloatType):
|
||||
return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext")
|
||||
elif isinstance(val.type, ir.IntType):
|
||||
return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f")
|
||||
return val
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import vast as ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprFormatHandle(BaseHandle):
|
||||
def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if not Gen or not Gen.builder:
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
format_str: str = ""
|
||||
cast_args: list[Any] = []
|
||||
for part in Node.values:
|
||||
if isinstance(part, ast.Constant) and isinstance(part.value, str):
|
||||
format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0')
|
||||
elif isinstance(part, ast.FormattedValue):
|
||||
fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen)
|
||||
if fmt_class and Gen._has_function(f'{fmt_class}.__str__'):
|
||||
obj_val: Any = self.HandleExprLlvm(part.value)
|
||||
if obj_val:
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
if fmt_class in Gen.structs:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}")
|
||||
val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__")
|
||||
Gen._RegisterTempPtr(val)
|
||||
format_str += "%s"
|
||||
cast_args.append(val)
|
||||
else:
|
||||
format_str += "%s"
|
||||
cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
|
||||
continue
|
||||
val = self.HandleExprLlvm(part.value)
|
||||
if not val:
|
||||
format_str += "%d"
|
||||
cast_args.append(ir.Constant(ir.IntType(32), 0))
|
||||
continue
|
||||
# 检查 format_spec(Python f-string 格式说明符)
|
||||
if part.format_spec is not None:
|
||||
c_fmt: str | None = self._parse_format_spec(part.format_spec, val)
|
||||
if c_fmt is not None:
|
||||
cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value)
|
||||
format_str += c_fmt
|
||||
cast_args.append(cast_val)
|
||||
continue
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
format_str += "%s"
|
||||
cast_args.append(val)
|
||||
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int")
|
||||
trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc")
|
||||
format_str += "%d"
|
||||
cast_args.append(trunc_val)
|
||||
else:
|
||||
Loaded: Any = Gen._load(val, name="fstr_deref")
|
||||
if isinstance(Loaded.type, ir.IntType):
|
||||
if Loaded.type.width == 8:
|
||||
format_str += "%c"
|
||||
ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int")
|
||||
cast_args.append(ext)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)):
|
||||
format_str += "%f"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(Loaded.type, ir.PointerType):
|
||||
format_str += "%s"
|
||||
cast_args.append(Loaded)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(Loaded)
|
||||
elif isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
format_str += "%c"
|
||||
ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int")
|
||||
cast_args.append(ext)
|
||||
elif val.type.width == 1:
|
||||
zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int")
|
||||
format_str += "%d"
|
||||
cast_args.append(zext)
|
||||
else:
|
||||
is_u: bool = Gen._check_node_unsigned(part.value)
|
||||
format_str += "%u" if is_u else "%d"
|
||||
cast_args.append(val)
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
format_str += "%f"
|
||||
cast_args.append(val)
|
||||
else:
|
||||
format_str += "%d"
|
||||
cast_args.append(val)
|
||||
if not format_str:
|
||||
return Gen.emit_constant("", 'string')
|
||||
format_ptr: Any = Gen._create_string_global(format_str)
|
||||
# 统一使用 snprintf 生成字符串,返回 i8*
|
||||
# __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放)
|
||||
in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__'))
|
||||
snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.IntType(64),
|
||||
ir.PointerType(ir.IntType(8))
|
||||
], var_arg=True)
|
||||
snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type)
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
# 第一遍:获取所需长度(NULL 缓冲,size=0)
|
||||
len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len")
|
||||
# 加 1 用于 null 终止符
|
||||
size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size")
|
||||
size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext")
|
||||
if in_str_method:
|
||||
# 堆分配(__str__ 返回值需跨函数生命周期)
|
||||
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
||||
malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type)
|
||||
buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf")
|
||||
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
|
||||
Gen._RegisterTempPtr(buf_ptr)
|
||||
return buf_ptr
|
||||
# 栈分配(局部使用,自动释放)
|
||||
buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val)
|
||||
Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf")
|
||||
return buf_ptr
|
||||
|
||||
def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None:
|
||||
"""将 Python f-string format_spec 转换为 C printf 格式说明符。
|
||||
|
||||
支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。
|
||||
返回 None 表示无法解析,调用方应回退到类型推断。
|
||||
"""
|
||||
if isinstance(format_spec_node, ast.JoinedStr):
|
||||
parts: list[str] = []
|
||||
for v in format_spec_node.values:
|
||||
if isinstance(v, ast.Constant) and isinstance(v.value, str):
|
||||
parts.append(v.value)
|
||||
else:
|
||||
return None
|
||||
spec_str: str = ''.join(parts)
|
||||
elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str):
|
||||
spec_str = format_spec_node.value
|
||||
else:
|
||||
return None
|
||||
|
||||
if not spec_str:
|
||||
return None
|
||||
|
||||
m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups()
|
||||
|
||||
c_flags: str = ''
|
||||
if sign == '+':
|
||||
c_flags += '+'
|
||||
elif sign == ' ':
|
||||
c_flags += ' '
|
||||
if alt:
|
||||
c_flags += '#'
|
||||
|
||||
if fill_align:
|
||||
align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0]
|
||||
if align_char in ('<', '^'):
|
||||
c_flags += '-'
|
||||
if zero:
|
||||
c_flags += '0'
|
||||
|
||||
c_width: str = width or ''
|
||||
c_precision: str = precision or ''
|
||||
|
||||
length_mod: str = ''
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 64:
|
||||
length_mod = 'll'
|
||||
elif val.type.width == 32:
|
||||
length_mod = 'l'
|
||||
elif val.type.width == 16:
|
||||
length_mod = 'h'
|
||||
elif val.type.width == 8:
|
||||
length_mod = 'hh'
|
||||
|
||||
c_specifier: str = ''
|
||||
if fmt_type in ('d', 'n'):
|
||||
c_specifier = f'{length_mod}d'
|
||||
elif fmt_type == 'x':
|
||||
c_specifier = f'{length_mod}x'
|
||||
elif fmt_type == 'X':
|
||||
c_specifier = f'{length_mod}X'
|
||||
elif fmt_type == 'o':
|
||||
c_specifier = f'{length_mod}o'
|
||||
elif fmt_type == 'b':
|
||||
return None
|
||||
elif fmt_type == 'c':
|
||||
c_specifier = 'c'
|
||||
elif fmt_type in ('f', 'F'):
|
||||
c_specifier = 'f'
|
||||
elif fmt_type in ('e', 'E', 'g', 'G'):
|
||||
c_specifier = fmt_type
|
||||
elif fmt_type == 's':
|
||||
c_specifier = 's'
|
||||
elif fmt_type == '%':
|
||||
c_specifier = 'f%%'
|
||||
else:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
c_specifier = 'c'
|
||||
elif val.type.width == 1:
|
||||
c_specifier = 'd'
|
||||
else:
|
||||
c_specifier = f'{length_mod}d'
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
c_specifier = 'f'
|
||||
elif isinstance(val.type, ir.PointerType):
|
||||
c_specifier = 's'
|
||||
else:
|
||||
c_specifier = 'd'
|
||||
|
||||
return f'%{c_flags}{c_width}{c_precision}{c_specifier}'
|
||||
|
||||
def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value:
|
||||
"""根据 C printf 格式说明符转换值类型。"""
|
||||
fmt_type_char: str = ''
|
||||
for ch in reversed(c_fmt):
|
||||
if ch.isalpha() and ch not in ('l', 'h'):
|
||||
fmt_type_char = ch
|
||||
break
|
||||
elif ch == '%':
|
||||
break
|
||||
|
||||
if fmt_type_char == 's':
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
pointee: ir.Type = val.type.pointee
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
return val
|
||||
if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8:
|
||||
return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr")
|
||||
return val
|
||||
elif fmt_type_char == 'c':
|
||||
if isinstance(val.type, ir.IntType) and val.type.width < 32:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c")
|
||||
return val
|
||||
elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'):
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
is_u: bool = Gen._check_node_unsigned(arg_node)
|
||||
if is_u:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8")
|
||||
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8")
|
||||
elif val.type.width == 16:
|
||||
is_u = Gen._check_node_unsigned(arg_node)
|
||||
if is_u:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16")
|
||||
return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16")
|
||||
elif val.type.width == 1:
|
||||
return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool")
|
||||
return val
|
||||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i")
|
||||
return val
|
||||
elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'):
|
||||
if isinstance(val.type, ir.FloatType):
|
||||
return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext")
|
||||
elif isinstance(val.type, ir.IntType):
|
||||
return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f")
|
||||
return val
|
||||
return val
|
||||
@@ -1,249 +1,249 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprLambdaHandle(BaseHandle):
|
||||
def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if not getattr(Gen, '_lambda_counter', None):
|
||||
Gen._lambda_counter = 0
|
||||
lambda_id: int = Gen._lambda_counter
|
||||
Gen._lambda_counter += 1
|
||||
fn_name: str = f"lambda_fn_{lambda_id}"
|
||||
captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node)
|
||||
env_types: list[ir.Type] = []
|
||||
env_var_names: list[str] = []
|
||||
for var_name, var_val in captured_vars:
|
||||
env_types.append(var_val.type)
|
||||
env_var_names.append(var_name)
|
||||
env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([])
|
||||
ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body)
|
||||
param_types: list[ir.Type] = [ir.PointerType(env_struct_type)]
|
||||
if Node.args:
|
||||
for arg in Node.args.args:
|
||||
param_types.append(ir.IntType(32))
|
||||
fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
|
||||
fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name)
|
||||
Gen.functions[fn_name] = fn
|
||||
entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry")
|
||||
prev_builder: Any = Gen.builder
|
||||
prev_func: Any = Gen.func
|
||||
prev_vars: dict[str, Any] = dict(Gen.variables)
|
||||
Gen.builder = ir.IRBuilder(entry_block)
|
||||
Gen.func = fn
|
||||
Gen.variables = {}
|
||||
for i, arg in enumerate(fn.args):
|
||||
arg.name = f"arg_{i}" if i > 0 else "env"
|
||||
if env_types:
|
||||
for idx, var_name in enumerate(env_var_names):
|
||||
env_ptr: Any = fn.args[0]
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}")
|
||||
Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}")
|
||||
temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}")
|
||||
Gen._store(Loaded, temp_alloca)
|
||||
Gen.variables[var_name] = temp_alloca
|
||||
if Node.args:
|
||||
for i, arg in enumerate(Node.args.args):
|
||||
Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg)
|
||||
Gen._store(fn.args[i + 1], Gen.variables[arg.arg])
|
||||
body_val: Any = self.HandleExprLlvm(Node.body)
|
||||
if body_val:
|
||||
if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType):
|
||||
body_val = Gen._load(body_val, name="Load_lambda_ret")
|
||||
if body_val.type != ret_type:
|
||||
if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType):
|
||||
if body_val.type.width < ret_type.width:
|
||||
body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret")
|
||||
elif body_val.type.width > ret_type.width:
|
||||
body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret")
|
||||
elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType):
|
||||
body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret")
|
||||
Gen.builder.ret(body_val)
|
||||
else:
|
||||
if isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
Gen.builder = prev_builder
|
||||
Gen.func = prev_func
|
||||
Gen.variables = prev_vars
|
||||
closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.PointerType(fn_type)
|
||||
])
|
||||
closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}")
|
||||
env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}")
|
||||
if env_types:
|
||||
for idx, (var_name, var_val) in enumerate(captured_vars):
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}")
|
||||
Gen._store(var_val, member_ptr)
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr")
|
||||
env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr")
|
||||
Gen._store(env_i8_ptr, env_field_ptr)
|
||||
fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr")
|
||||
Gen._store(fn, fn_field_ptr)
|
||||
return closure_ptr
|
||||
|
||||
def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
captured: list[tuple[str, Any]] = []
|
||||
free_vars: list[str] = self._get_lambda_free_vars(Node)
|
||||
for var_name in free_vars:
|
||||
if var_name in Gen.variables:
|
||||
var_ptr: Any = Gen.variables[var_name]
|
||||
if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable):
|
||||
Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}")
|
||||
captured.append((var_name, Loaded))
|
||||
return captured
|
||||
|
||||
def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]:
|
||||
bound_vars: set[str] = set()
|
||||
free_vars: set[str] = set()
|
||||
# 收集 lambda body 中的 bound 和 free 变量
|
||||
self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars)
|
||||
# lambda 参数也是 bound 的
|
||||
if Node.args:
|
||||
for arg in Node.args.args:
|
||||
bound_vars.add(arg.arg)
|
||||
# free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量
|
||||
result: list[str] = list(free_vars - bound_vars)
|
||||
return result
|
||||
|
||||
def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
TestVal: Any = self.HandleExprLlvm(Node.test)
|
||||
if not TestVal:
|
||||
return None
|
||||
if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1:
|
||||
TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond")
|
||||
ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then")
|
||||
ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else")
|
||||
MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end")
|
||||
Gen.builder.cbranch(TestVal, ThenBB, ElseBB)
|
||||
# 先在 ThenBB 中生成 BodyVal
|
||||
Gen.builder.position_at_start(ThenBB)
|
||||
BodyVal: Any = self.HandleExprLlvm(Node.body)
|
||||
if not BodyVal:
|
||||
BodyVal = ir.Constant(ir.IntType(32), 0)
|
||||
ThenEndBB: ir.Block = Gen.builder.block
|
||||
# 在 ElseBB 中生成 OrelseVal
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
OrelseVal: Any = self.HandleExprLlvm(Node.orelse)
|
||||
if not OrelseVal:
|
||||
OrelseVal = ir.Constant(ir.IntType(32), 0)
|
||||
ElseEndBB: ir.Block = Gen.builder.block
|
||||
# 确定 phi 节点的目标类型
|
||||
result_type: ir.Type = BodyVal.type
|
||||
if BodyVal.type != OrelseVal.type:
|
||||
if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType):
|
||||
result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType):
|
||||
# 指针类型,使用 BodyVal 的类型
|
||||
result_type = BodyVal.type
|
||||
elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType):
|
||||
# BodyVal 是整数,OrelseVal 是指针(字符串字面量)
|
||||
# 如果指针指向 i8,将指针转换为 i8(加载字符)
|
||||
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
|
||||
result_type = ir.IntType(8)
|
||||
else:
|
||||
result_type = OrelseVal.type
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType):
|
||||
# BodyVal 是指针(字符串字面量),OrelseVal 是整数
|
||||
# 如果指针指向 i8,将指针转换为 i8(加载字符)
|
||||
if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8:
|
||||
result_type = ir.IntType(8)
|
||||
else:
|
||||
result_type = BodyVal.type
|
||||
else:
|
||||
result_type = OrelseVal.type
|
||||
# 在 ThenBB 末尾添加类型转换(如果需要)和分支
|
||||
if not ThenEndBB.is_terminated:
|
||||
Gen.builder.position_at_end(ThenEndBB)
|
||||
if BodyVal.type != result_type:
|
||||
if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if BodyVal.type.width < result_type.width:
|
||||
BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext")
|
||||
else:
|
||||
BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc")
|
||||
elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
|
||||
# 如果 result_type 是 i8*,说明 Else 分支是字符串字面量
|
||||
# 不应该将整数转换为指针,而应该保持整数类型
|
||||
# 这里将 result_type 改为 i8
|
||||
result_type = ir.IntType(8)
|
||||
# 重新处理 Else 分支的类型转换
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
|
||||
# 指针转整数
|
||||
BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int")
|
||||
Gen.builder.branch(MergeBB)
|
||||
# 在 ElseBB 末尾添加类型转换(如果需要)和分支
|
||||
if not ElseEndBB.is_terminated:
|
||||
Gen.builder.position_at_end(ElseEndBB)
|
||||
if OrelseVal.type != result_type:
|
||||
if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if OrelseVal.type.width < result_type.width:
|
||||
OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext")
|
||||
else:
|
||||
OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc")
|
||||
elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
|
||||
# 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量
|
||||
# 不应该将整数转换为指针,而应该保持整数类型
|
||||
# 这里将 result_type 改为 i8
|
||||
result_type = ir.IntType(8)
|
||||
# 重新处理 BodyVal 分支的类型转换(已经在上面处理过了)
|
||||
elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
|
||||
# 如果指针指向 i8,加载字符值
|
||||
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
|
||||
OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char")
|
||||
else:
|
||||
OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int")
|
||||
Gen.builder.branch(MergeBB)
|
||||
Gen.builder.position_at_start(MergeBB)
|
||||
result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result")
|
||||
result_phi.add_incoming(BodyVal, ThenEndBB)
|
||||
result_phi.add_incoming(OrelseVal, ElseEndBB)
|
||||
return result_phi
|
||||
|
||||
def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
ValueVal: Any = self.HandleExprLlvm(Node.value)
|
||||
if not ValueVal:
|
||||
return None
|
||||
TargetName: str = Node.target.id
|
||||
if TargetName in Gen._reg_values:
|
||||
del Gen._reg_values[TargetName]
|
||||
if TargetName in Gen.variables and Gen.variables[TargetName] is not None:
|
||||
VarPtr: Any = Gen.variables[TargetName]
|
||||
if VarPtr.type.pointee == ValueVal.type:
|
||||
Gen._store(ValueVal, VarPtr)
|
||||
else:
|
||||
NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName)
|
||||
Gen._store(ValueVal, NewVar)
|
||||
Gen.variables[TargetName] = NewVar
|
||||
else:
|
||||
NewVar = Gen._alloca(ValueVal.type, name=TargetName)
|
||||
Gen._store(ValueVal, NewVar)
|
||||
Gen.variables[TargetName] = NewVar
|
||||
Gen._reg_values[TargetName] = ValueVal
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprLambdaHandle(BaseHandle):
|
||||
def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if not getattr(Gen, '_lambda_counter', None):
|
||||
Gen._lambda_counter = 0
|
||||
lambda_id: int = Gen._lambda_counter
|
||||
Gen._lambda_counter += 1
|
||||
fn_name: str = f"lambda_fn_{lambda_id}"
|
||||
captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node)
|
||||
env_types: list[ir.Type] = []
|
||||
env_var_names: list[str] = []
|
||||
for var_name, var_val in captured_vars:
|
||||
env_types.append(var_val.type)
|
||||
env_var_names.append(var_name)
|
||||
env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([])
|
||||
ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body)
|
||||
param_types: list[ir.Type] = [ir.PointerType(env_struct_type)]
|
||||
if Node.args:
|
||||
for arg in Node.args.args:
|
||||
param_types.append(ir.IntType(32))
|
||||
fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types)
|
||||
fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name)
|
||||
Gen.functions[fn_name] = fn
|
||||
entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry")
|
||||
prev_builder: Any = Gen.builder
|
||||
prev_func: Any = Gen.func
|
||||
prev_vars: dict[str, Any] = dict(Gen.variables)
|
||||
Gen.builder = ir.IRBuilder(entry_block)
|
||||
Gen.func = fn
|
||||
Gen.variables = {}
|
||||
for i, arg in enumerate(fn.args):
|
||||
arg.name = f"arg_{i}" if i > 0 else "env"
|
||||
if env_types:
|
||||
for idx, var_name in enumerate(env_var_names):
|
||||
env_ptr: Any = fn.args[0]
|
||||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||||
member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}")
|
||||
Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}")
|
||||
temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}")
|
||||
Gen._store(Loaded, temp_alloca)
|
||||
Gen.variables[var_name] = temp_alloca
|
||||
if Node.args:
|
||||
for i, arg in enumerate(Node.args.args):
|
||||
Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg)
|
||||
Gen._store(fn.args[i + 1], Gen.variables[arg.arg])
|
||||
body_val: Any = self.HandleExprLlvm(Node.body)
|
||||
if body_val:
|
||||
if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType):
|
||||
body_val = Gen._load(body_val, name="Load_lambda_ret")
|
||||
if body_val.type != ret_type:
|
||||
if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType):
|
||||
if body_val.type.width < ret_type.width:
|
||||
body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret")
|
||||
elif body_val.type.width > ret_type.width:
|
||||
body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret")
|
||||
elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType):
|
||||
body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret")
|
||||
Gen.builder.ret(body_val)
|
||||
else:
|
||||
if isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
Gen.builder = prev_builder
|
||||
Gen.func = prev_func
|
||||
Gen.variables = prev_vars
|
||||
closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.PointerType(fn_type)
|
||||
])
|
||||
closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}")
|
||||
env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}")
|
||||
if env_types:
|
||||
for idx, (var_name, var_val) in enumerate(captured_vars):
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}")
|
||||
Gen._store(var_val, member_ptr)
|
||||
zero = ir.Constant(ir.IntType(32), 0)
|
||||
env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr")
|
||||
env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr")
|
||||
Gen._store(env_i8_ptr, env_field_ptr)
|
||||
fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr")
|
||||
Gen._store(fn, fn_field_ptr)
|
||||
return closure_ptr
|
||||
|
||||
def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
captured: list[tuple[str, Any]] = []
|
||||
free_vars: list[str] = self._get_lambda_free_vars(Node)
|
||||
for var_name in free_vars:
|
||||
if var_name in Gen.variables:
|
||||
var_ptr: Any = Gen.variables[var_name]
|
||||
if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable):
|
||||
Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}")
|
||||
captured.append((var_name, Loaded))
|
||||
return captured
|
||||
|
||||
def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]:
|
||||
bound_vars: set[str] = set()
|
||||
free_vars: set[str] = set()
|
||||
# 收集 lambda body 中的 bound 和 free 变量
|
||||
self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars)
|
||||
# lambda 参数也是 bound 的
|
||||
if Node.args:
|
||||
for arg in Node.args.args:
|
||||
bound_vars.add(arg.arg)
|
||||
# free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量
|
||||
result: list[str] = list(free_vars - bound_vars)
|
||||
return result
|
||||
|
||||
def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
TestVal: Any = self.HandleExprLlvm(Node.test)
|
||||
if not TestVal:
|
||||
return None
|
||||
if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1:
|
||||
TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond")
|
||||
ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then")
|
||||
ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else")
|
||||
MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end")
|
||||
Gen.builder.cbranch(TestVal, ThenBB, ElseBB)
|
||||
# 先在 ThenBB 中生成 BodyVal
|
||||
Gen.builder.position_at_start(ThenBB)
|
||||
BodyVal: Any = self.HandleExprLlvm(Node.body)
|
||||
if not BodyVal:
|
||||
BodyVal = ir.Constant(ir.IntType(32), 0)
|
||||
ThenEndBB: ir.Block = Gen.builder.block
|
||||
# 在 ElseBB 中生成 OrelseVal
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
OrelseVal: Any = self.HandleExprLlvm(Node.orelse)
|
||||
if not OrelseVal:
|
||||
OrelseVal = ir.Constant(ir.IntType(32), 0)
|
||||
ElseEndBB: ir.Block = Gen.builder.block
|
||||
# 确定 phi 节点的目标类型
|
||||
result_type: ir.Type = BodyVal.type
|
||||
if BodyVal.type != OrelseVal.type:
|
||||
if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType):
|
||||
result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType):
|
||||
# 指针类型,使用 BodyVal 的类型
|
||||
result_type = BodyVal.type
|
||||
elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType):
|
||||
# BodyVal 是整数,OrelseVal 是指针(字符串字面量)
|
||||
# 如果指针指向 i8,将指针转换为 i8(加载字符)
|
||||
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
|
||||
result_type = ir.IntType(8)
|
||||
else:
|
||||
result_type = OrelseVal.type
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType):
|
||||
# BodyVal 是指针(字符串字面量),OrelseVal 是整数
|
||||
# 如果指针指向 i8,将指针转换为 i8(加载字符)
|
||||
if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8:
|
||||
result_type = ir.IntType(8)
|
||||
else:
|
||||
result_type = BodyVal.type
|
||||
else:
|
||||
result_type = OrelseVal.type
|
||||
# 在 ThenBB 末尾添加类型转换(如果需要)和分支
|
||||
if not ThenEndBB.is_terminated:
|
||||
Gen.builder.position_at_end(ThenEndBB)
|
||||
if BodyVal.type != result_type:
|
||||
if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if BodyVal.type.width < result_type.width:
|
||||
BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext")
|
||||
else:
|
||||
BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc")
|
||||
elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
|
||||
# 如果 result_type 是 i8*,说明 Else 分支是字符串字面量
|
||||
# 不应该将整数转换为指针,而应该保持整数类型
|
||||
# 这里将 result_type 改为 i8
|
||||
result_type = ir.IntType(8)
|
||||
# 重新处理 Else 分支的类型转换
|
||||
elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
|
||||
# 指针转整数
|
||||
BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int")
|
||||
Gen.builder.branch(MergeBB)
|
||||
# 在 ElseBB 末尾添加类型转换(如果需要)和分支
|
||||
if not ElseEndBB.is_terminated:
|
||||
Gen.builder.position_at_end(ElseEndBB)
|
||||
if OrelseVal.type != result_type:
|
||||
if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType):
|
||||
if OrelseVal.type.width < result_type.width:
|
||||
OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext")
|
||||
else:
|
||||
OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc")
|
||||
elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType):
|
||||
# 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量
|
||||
# 不应该将整数转换为指针,而应该保持整数类型
|
||||
# 这里将 result_type 改为 i8
|
||||
result_type = ir.IntType(8)
|
||||
# 重新处理 BodyVal 分支的类型转换(已经在上面处理过了)
|
||||
elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType):
|
||||
# 如果指针指向 i8,加载字符值
|
||||
if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8:
|
||||
OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char")
|
||||
else:
|
||||
OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int")
|
||||
Gen.builder.branch(MergeBB)
|
||||
Gen.builder.position_at_start(MergeBB)
|
||||
result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result")
|
||||
result_phi.add_incoming(BodyVal, ThenEndBB)
|
||||
result_phi.add_incoming(OrelseVal, ElseEndBB)
|
||||
return result_phi
|
||||
|
||||
def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
ValueVal: Any = self.HandleExprLlvm(Node.value)
|
||||
if not ValueVal:
|
||||
return None
|
||||
TargetName: str = Node.target.id
|
||||
if TargetName in Gen._reg_values:
|
||||
del Gen._reg_values[TargetName]
|
||||
if TargetName in Gen.variables and Gen.variables[TargetName] is not None:
|
||||
VarPtr: Any = Gen.variables[TargetName]
|
||||
if VarPtr.type.pointee == ValueVal.type:
|
||||
Gen._store(ValueVal, VarPtr)
|
||||
else:
|
||||
NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName)
|
||||
Gen._store(ValueVal, NewVar)
|
||||
Gen.variables[TargetName] = NewVar
|
||||
else:
|
||||
NewVar = Gen._alloca(ValueVal.type, name=TargetName)
|
||||
Gen._store(ValueVal, NewVar)
|
||||
Gen.variables[TargetName] = NewVar
|
||||
Gen._reg_values[TargetName] = ValueVal
|
||||
return ValueVal
|
||||
+486
-486
@@ -1,487 +1,487 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprOpsHandle(BaseHandle):
|
||||
def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
Gen._set_node_info(Node, "BinOp")
|
||||
LeftVal: Any = self.HandleExprLlvm(Node.left, VarType)
|
||||
if not LeftVal:
|
||||
return None
|
||||
RightVal: Any = self.HandleExprLlvm(Node.right, VarType)
|
||||
if not RightVal:
|
||||
return None
|
||||
Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if not Op:
|
||||
return None
|
||||
OP_OVERLOAD_MAP: dict[str, list[str]] = {
|
||||
'+': ['__add__'], '-': ['__sub__'], '*': ['__mul__'],
|
||||
'/': ['__truediv__', '__div__'], '//': ['__floordiv__'], '%': ['__mod__'],
|
||||
'**': ['__pow__'],
|
||||
'&': ['__and__'], '|': ['__or__'], '^': ['__xor__'],
|
||||
'<<': ['__lshift__'], '>>': ['__rshift__'],
|
||||
}
|
||||
if Op in OP_OVERLOAD_MAP:
|
||||
LeftClassName: str | None = None
|
||||
if isinstance(LeftVal.type, ir.PointerType):
|
||||
pointee: ir.Type = LeftVal.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
LeftClassName = CN
|
||||
break
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName is None and isinstance(Node.left, ast.Name):
|
||||
LeftClassName = Gen.var_struct_class.get(Node.left.id)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName:
|
||||
op_names: list[str] = OP_OVERLOAD_MAP[Op]
|
||||
for op_name in op_names:
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
|
||||
if result is not None:
|
||||
return result
|
||||
if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
|
||||
if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1:
|
||||
CharVal: Any = Gen._load(LeftVal, name="Load_char_const")
|
||||
CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
|
||||
result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
|
||||
TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
|
||||
return TruncResult
|
||||
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right)
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right")
|
||||
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType):
|
||||
LeftVal = Gen._load(LeftVal, name="deref_ptr_binop")
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref")
|
||||
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
|
||||
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType):
|
||||
RightVal = Gen._load(RightVal, name="deref_ptr_binop_r")
|
||||
if RightVal.type.width < LeftVal.type.width:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
|
||||
elif RightVal.type.width > LeftVal.type.width:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
|
||||
if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
|
||||
vname: str = Node.left.id
|
||||
if vname in Gen.var_signedness and Gen.var_signedness[vname]:
|
||||
is_unsigned = True
|
||||
result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned)
|
||||
return result
|
||||
|
||||
def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
|
||||
def _to_bool(val: Any, name: str) -> Any:
|
||||
if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name)
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name)
|
||||
return val
|
||||
|
||||
values: list[ast.expr] = Node.values
|
||||
if len(values) < 2:
|
||||
return self.HandleExprLlvm(values[0]) if values else None
|
||||
if isinstance(Node.op, ast.And):
|
||||
phi_incomings: list[tuple[ir.Constant, ir.Block]] = []
|
||||
end_bb: ir.Block = Gen.func.append_basic_block(name="and.end")
|
||||
for idx in range(len(values) - 1):
|
||||
val: Any = self.HandleExprLlvm(values[idx])
|
||||
if not val:
|
||||
if not end_bb.is_terminated:
|
||||
saved_block: ir.Block = Gen.builder.block
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
return None
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
val = _to_bool(val, f"andcond{idx}")
|
||||
cur_bb: ir.Block = Gen.builder.block
|
||||
next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}")
|
||||
Gen.builder.cbranch(val, next_bb, end_bb)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
|
||||
Gen.builder.position_at_start(next_bb)
|
||||
last_val: Any = self.HandleExprLlvm(values[-1])
|
||||
if not last_val:
|
||||
last_val = ir.Constant(ir.IntType(1), 0)
|
||||
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
|
||||
last_val = _to_bool(last_val, "andcond_last")
|
||||
last_bb: ir.Block = Gen.builder.block
|
||||
Gen.builder.branch(end_bb)
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result")
|
||||
for const_val, bb in phi_incomings:
|
||||
result_phi.add_incoming(const_val, bb)
|
||||
result_phi.add_incoming(last_val, last_bb)
|
||||
return result_phi
|
||||
elif isinstance(Node.op, ast.Or):
|
||||
phi_incomings = []
|
||||
end_bb = Gen.func.append_basic_block(name="or.end")
|
||||
for idx in range(len(values) - 1):
|
||||
val = self.HandleExprLlvm(values[idx])
|
||||
if not val:
|
||||
if not end_bb.is_terminated:
|
||||
saved_block = Gen.builder.block
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
return None
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
val = _to_bool(val, f"orcond{idx}")
|
||||
cur_bb = Gen.builder.block
|
||||
next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
|
||||
Gen.builder.cbranch(val, end_bb, next_bb)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
|
||||
Gen.builder.position_at_start(next_bb)
|
||||
last_val = self.HandleExprLlvm(values[-1])
|
||||
if not last_val:
|
||||
last_val = ir.Constant(ir.IntType(1), 1)
|
||||
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
|
||||
last_val = _to_bool(last_val, "orcond_last")
|
||||
last_bb = Gen.builder.block
|
||||
Gen.builder.branch(end_bb)
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
|
||||
for const_val, bb in phi_incomings:
|
||||
result_phi.add_incoming(const_val, bb)
|
||||
result_phi.add_incoming(last_val, last_bb)
|
||||
return result_phi
|
||||
return None
|
||||
|
||||
def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
OperandVal: Any = self.HandleExprLlvm(Node.operand)
|
||||
if not OperandVal:
|
||||
return None
|
||||
OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
|
||||
if not OpSymbol:
|
||||
return None
|
||||
UNARY_OVERLOAD_MAP: dict[str, str] = {
|
||||
'-': '__neg__',
|
||||
'+': '__pos__',
|
||||
'~': '__invert__',
|
||||
}
|
||||
if OpSymbol in UNARY_OVERLOAD_MAP:
|
||||
ClassName: str | None = None
|
||||
if isinstance(OperandVal.type, ir.PointerType):
|
||||
pointee: ir.Type = OperandVal.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
ClassName = CN
|
||||
break
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName])
|
||||
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
|
||||
if ClassName is None and isinstance(Node.operand, ast.Name):
|
||||
ClassName = Gen.var_struct_class.get(Node.operand.id)
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
|
||||
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
|
||||
if ClassName:
|
||||
op_name: str = UNARY_OVERLOAD_MAP[OpSymbol]
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
if OpSymbol == 'not':
|
||||
if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
|
||||
return Gen.builder.not_(OperandVal, name="not_result")
|
||||
if isinstance(OperandVal.type, ir.PointerType):
|
||||
null_val: ir.Constant = ir.Constant(OperandVal.type, None)
|
||||
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
|
||||
zero: ir.Constant = ir.Constant(OperandVal.type, 0)
|
||||
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
|
||||
elif OpSymbol == '~':
|
||||
if isinstance(OperandVal.type, ir.IntType):
|
||||
mask: int = (1 << OperandVal.type.width) - 1
|
||||
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
|
||||
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
|
||||
elif OpSymbol == '+':
|
||||
return OperandVal
|
||||
elif OpSymbol == '-':
|
||||
if isinstance(OperandVal.type, ir.IntType):
|
||||
return Gen.builder.neg(OperandVal, name="neg_result")
|
||||
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fneg(OperandVal, name="fneg_result")
|
||||
return None
|
||||
|
||||
def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
LeftVal: Any = self.HandleExprLlvm(Node.left)
|
||||
if not LeftVal:
|
||||
return None
|
||||
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
|
||||
if len(Node.ops) == 1:
|
||||
Op: ast.cmpop = Node.ops[0]
|
||||
# in/not in: 调用 __contains__
|
||||
if isinstance(Op, (ast.In, ast.NotIn)):
|
||||
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
|
||||
if RightVal:
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__contains__'):
|
||||
# 处理 RightVal 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
|
||||
RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8:
|
||||
RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__')
|
||||
result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__")
|
||||
# 归一化为 i1
|
||||
if isinstance(result.type, ir.IntType) and result.type.width > 1:
|
||||
zero: ir.Constant = ir.Constant(result.type, 0)
|
||||
result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool")
|
||||
if isinstance(Op, ast.NotIn):
|
||||
result = Gen.builder.not_(result, name="not_in_result")
|
||||
return result
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op)
|
||||
if not ComparatorSymbol:
|
||||
return None
|
||||
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
|
||||
if not RightVal:
|
||||
return None
|
||||
# 比较运算符重载检测:当左侧是结构体指针时,尝试调用 __eq__/__ne__/__lt__/__le__/__gt__/__ge__
|
||||
CMP_OVERLOAD_MAP: dict[str, str] = {
|
||||
'==': '__eq__', '!=': '__ne__', '<': '__lt__',
|
||||
'<=': '__le__', '>': '__gt__', '>=': '__ge__',
|
||||
}
|
||||
if ComparatorSymbol in CMP_OVERLOAD_MAP:
|
||||
LeftClassName: str | None = None
|
||||
if isinstance(LeftVal.type, ir.PointerType):
|
||||
pointee: ir.Type = LeftVal.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
LeftClassName = CN
|
||||
break
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName is None and isinstance(Node.left, ast.Name):
|
||||
LeftClassName = Gen.var_struct_class.get(Node.left.id)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName:
|
||||
op_name: str = CMP_OVERLOAD_MAP[ComparatorSymbol]
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
|
||||
if result is not None:
|
||||
return result
|
||||
if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
lv: int = LeftVal.constant
|
||||
rv: int = RightVal.constant
|
||||
lw: int = LeftVal.type.width
|
||||
rw: int = RightVal.type.width
|
||||
if lw < rw:
|
||||
lv = lv if lv >= 0 else lv + (1 << lw)
|
||||
elif rw < lw:
|
||||
rv = rv if rv >= 0 else rv + (1 << rw)
|
||||
if is_unsigned:
|
||||
mask_l: int = (1 << max(lw, rw)) - 1
|
||||
lv = lv & mask_l
|
||||
rv = rv & mask_l
|
||||
cmp_map: dict[str, bool] = {
|
||||
'==': lv == rv, '!=': lv != rv,
|
||||
'<': lv < rv, '>': lv > rv,
|
||||
'<=': lv <= rv, '>=': lv >= rv,
|
||||
}
|
||||
result: bool = cmp_map.get(ComparatorSymbol, False)
|
||||
return ir.Constant(ir.IntType(1), 1 if result else 0)
|
||||
# is / is not: 值类型(IntType)与 None(空指针常量)比较
|
||||
# 值类型(如 i8/i32)永远不可能为 None,因此:
|
||||
# - 值类型 is None → 恒为 false (i1 0)
|
||||
# - 值类型 is not None → 恒为 true (i1 1)
|
||||
# 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load(空指针解引用)导致崩溃
|
||||
if ComparatorSymbol in ('is', 'is not'):
|
||||
LeftIsNullPtr: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None and isinstance(LeftVal.type, ir.PointerType)
|
||||
RightIsNullPtr: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None and isinstance(RightVal.type, ir.PointerType)
|
||||
LeftIsValueType: bool = isinstance(LeftVal.type, ir.IntType)
|
||||
RightIsValueType: bool = isinstance(RightVal.type, ir.IntType)
|
||||
if (LeftIsValueType and RightIsNullPtr) or (RightIsValueType and LeftIsNullPtr):
|
||||
IsNotResult: int = 1 if ComparatorSymbol == 'is not' else 0
|
||||
return ir.Constant(ir.IntType(1), IsNotResult)
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
# 如果宽类型常量值超出窄类型有符号范围,则必须用zext
|
||||
# i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节)
|
||||
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max or RightVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max or LeftVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
|
||||
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
|
||||
LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
|
||||
else:
|
||||
if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
|
||||
RightVal = ir.Constant(LeftVal.type, None)
|
||||
else:
|
||||
# 指针 vs 非零整数: 将指针转为整数走正常 ==(地址值比较)
|
||||
LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp")
|
||||
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
|
||||
if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
|
||||
RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
|
||||
else:
|
||||
if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
|
||||
LeftVal = ir.Constant(RightVal.type, None)
|
||||
else:
|
||||
# 非零整数 vs 指针: 将指针转为整数走正常 ==(地址值比较)
|
||||
RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp")
|
||||
# is / is not: 地址比较(指针)或值比较(int)
|
||||
if ComparatorSymbol in ('is', 'is not'):
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
|
||||
addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp")
|
||||
if ComparatorSymbol == 'is not':
|
||||
addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result")
|
||||
return addr_cmp
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp")
|
||||
if ComparatorSymbol == 'is not':
|
||||
val_cmp = Gen.builder.not_(val_cmp, name="is_not_result")
|
||||
return val_cmp
|
||||
# == / !=: 指针间做地址比较(C-Like 语义,不隐式调用 strcmp)
|
||||
# 如需字符串内容比较,应显式调用 string.strcmp()
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
|
||||
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
|
||||
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
|
||||
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
|
||||
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
|
||||
result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
elif is_unsigned:
|
||||
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
else:
|
||||
result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
return result
|
||||
EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end")
|
||||
phi_incomings: list[tuple[ir.Value, ir.Block]] = []
|
||||
for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
|
||||
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
|
||||
if not ComparatorSymbol:
|
||||
continue
|
||||
RightVal = self.HandleExprLlvm(Comparator)
|
||||
if not RightVal:
|
||||
continue
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max or RightVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max or LeftVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
|
||||
if is_unsigned:
|
||||
cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
|
||||
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
|
||||
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
|
||||
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
|
||||
cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
else:
|
||||
cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
if i < len(Node.ops) - 1:
|
||||
NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}")
|
||||
cur_bb: ir.Block = Gen.builder.block
|
||||
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
|
||||
Gen.builder.position_at_start(NextBB)
|
||||
LeftVal = RightVal
|
||||
else:
|
||||
cur_bb = Gen.builder.block
|
||||
Gen.builder.branch(EndBB)
|
||||
phi_incomings.append((cmp_result, cur_bb))
|
||||
Gen.builder.position_at_start(EndBB)
|
||||
final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp")
|
||||
for val, bb in phi_incomings:
|
||||
final_result.add_incoming(val, bb)
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ExprOpsHandle(BaseHandle):
|
||||
def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
Gen._set_node_info(Node, "BinOp")
|
||||
LeftVal: Any = self.HandleExprLlvm(Node.left, VarType)
|
||||
if not LeftVal:
|
||||
return None
|
||||
RightVal: Any = self.HandleExprLlvm(Node.right, VarType)
|
||||
if not RightVal:
|
||||
return None
|
||||
Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if not Op:
|
||||
return None
|
||||
OP_OVERLOAD_MAP: dict[str, list[str]] = {
|
||||
'+': ['__add__'], '-': ['__sub__'], '*': ['__mul__'],
|
||||
'/': ['__truediv__', '__div__'], '//': ['__floordiv__'], '%': ['__mod__'],
|
||||
'**': ['__pow__'],
|
||||
'&': ['__and__'], '|': ['__or__'], '^': ['__xor__'],
|
||||
'<<': ['__lshift__'], '>>': ['__rshift__'],
|
||||
}
|
||||
if Op in OP_OVERLOAD_MAP:
|
||||
LeftClassName: str | None = None
|
||||
if isinstance(LeftVal.type, ir.PointerType):
|
||||
pointee: ir.Type = LeftVal.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
LeftClassName = CN
|
||||
break
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName is None and isinstance(Node.left, ast.Name):
|
||||
LeftClassName = Gen.var_struct_class.get(Node.left.id)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName:
|
||||
op_names: list[str] = OP_OVERLOAD_MAP[Op]
|
||||
for op_name in op_names:
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
|
||||
if result is not None:
|
||||
return result
|
||||
if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
|
||||
if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1:
|
||||
CharVal: Any = Gen._load(LeftVal, name="Load_char_const")
|
||||
CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
|
||||
result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
|
||||
TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
|
||||
return TruncResult
|
||||
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right)
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right")
|
||||
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType):
|
||||
LeftVal = Gen._load(LeftVal, name="deref_ptr_binop")
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref")
|
||||
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
|
||||
if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType):
|
||||
RightVal = Gen._load(RightVal, name="deref_ptr_binop_r")
|
||||
if RightVal.type.width < LeftVal.type.width:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
|
||||
elif RightVal.type.width > LeftVal.type.width:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
|
||||
if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
|
||||
vname: str = Node.left.id
|
||||
if vname in Gen.var_signedness and Gen.var_signedness[vname]:
|
||||
is_unsigned = True
|
||||
result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned)
|
||||
return result
|
||||
|
||||
def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
|
||||
def _to_bool(val: Any, name: str) -> Any:
|
||||
if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name)
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name)
|
||||
return val
|
||||
|
||||
values: list[ast.expr] = Node.values
|
||||
if len(values) < 2:
|
||||
return self.HandleExprLlvm(values[0]) if values else None
|
||||
if isinstance(Node.op, ast.And):
|
||||
phi_incomings: list[tuple[ir.Constant, ir.Block]] = []
|
||||
end_bb: ir.Block = Gen.func.append_basic_block(name="and.end")
|
||||
for idx in range(len(values) - 1):
|
||||
val: Any = self.HandleExprLlvm(values[idx])
|
||||
if not val:
|
||||
if not end_bb.is_terminated:
|
||||
saved_block: ir.Block = Gen.builder.block
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
return None
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
val = _to_bool(val, f"andcond{idx}")
|
||||
cur_bb: ir.Block = Gen.builder.block
|
||||
next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}")
|
||||
Gen.builder.cbranch(val, next_bb, end_bb)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
|
||||
Gen.builder.position_at_start(next_bb)
|
||||
last_val: Any = self.HandleExprLlvm(values[-1])
|
||||
if not last_val:
|
||||
last_val = ir.Constant(ir.IntType(1), 0)
|
||||
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
|
||||
last_val = _to_bool(last_val, "andcond_last")
|
||||
last_bb: ir.Block = Gen.builder.block
|
||||
Gen.builder.branch(end_bb)
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result")
|
||||
for const_val, bb in phi_incomings:
|
||||
result_phi.add_incoming(const_val, bb)
|
||||
result_phi.add_incoming(last_val, last_bb)
|
||||
return result_phi
|
||||
elif isinstance(Node.op, ast.Or):
|
||||
phi_incomings = []
|
||||
end_bb = Gen.func.append_basic_block(name="or.end")
|
||||
for idx in range(len(values) - 1):
|
||||
val = self.HandleExprLlvm(values[idx])
|
||||
if not val:
|
||||
if not end_bb.is_terminated:
|
||||
saved_block = Gen.builder.block
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
Gen.builder.unreachable()
|
||||
Gen.builder.position_at_end(saved_block)
|
||||
return None
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width != 1:
|
||||
val = _to_bool(val, f"orcond{idx}")
|
||||
cur_bb = Gen.builder.block
|
||||
next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
|
||||
Gen.builder.cbranch(val, end_bb, next_bb)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
|
||||
Gen.builder.position_at_start(next_bb)
|
||||
last_val = self.HandleExprLlvm(values[-1])
|
||||
if not last_val:
|
||||
last_val = ir.Constant(ir.IntType(1), 1)
|
||||
if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
|
||||
last_val = _to_bool(last_val, "orcond_last")
|
||||
last_bb = Gen.builder.block
|
||||
Gen.builder.branch(end_bb)
|
||||
Gen.builder.position_at_start(end_bb)
|
||||
result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
|
||||
for const_val, bb in phi_incomings:
|
||||
result_phi.add_incoming(const_val, bb)
|
||||
result_phi.add_incoming(last_val, last_bb)
|
||||
return result_phi
|
||||
return None
|
||||
|
||||
def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
OperandVal: Any = self.HandleExprLlvm(Node.operand)
|
||||
if not OperandVal:
|
||||
return None
|
||||
OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
|
||||
if not OpSymbol:
|
||||
return None
|
||||
UNARY_OVERLOAD_MAP: dict[str, str] = {
|
||||
'-': '__neg__',
|
||||
'+': '__pos__',
|
||||
'~': '__invert__',
|
||||
}
|
||||
if OpSymbol in UNARY_OVERLOAD_MAP:
|
||||
ClassName: str | None = None
|
||||
if isinstance(OperandVal.type, ir.PointerType):
|
||||
pointee: ir.Type = OperandVal.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
ClassName = CN
|
||||
break
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName])
|
||||
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
|
||||
if ClassName is None and isinstance(Node.operand, ast.Name):
|
||||
ClassName = Gen.var_struct_class.get(Node.operand.id)
|
||||
if ClassName and ClassName in Gen.structs:
|
||||
if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
|
||||
OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
|
||||
if ClassName:
|
||||
op_name: str = UNARY_OVERLOAD_MAP[OpSymbol]
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
if OpSymbol == 'not':
|
||||
if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
|
||||
return Gen.builder.not_(OperandVal, name="not_result")
|
||||
if isinstance(OperandVal.type, ir.PointerType):
|
||||
null_val: ir.Constant = ir.Constant(OperandVal.type, None)
|
||||
return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
|
||||
zero: ir.Constant = ir.Constant(OperandVal.type, 0)
|
||||
return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
|
||||
elif OpSymbol == '~':
|
||||
if isinstance(OperandVal.type, ir.IntType):
|
||||
mask: int = (1 << OperandVal.type.width) - 1
|
||||
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
|
||||
return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
|
||||
elif OpSymbol == '+':
|
||||
return OperandVal
|
||||
elif OpSymbol == '-':
|
||||
if isinstance(OperandVal.type, ir.IntType):
|
||||
return Gen.builder.neg(OperandVal, name="neg_result")
|
||||
elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
return Gen.builder.fneg(OperandVal, name="fneg_result")
|
||||
return None
|
||||
|
||||
def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
LeftVal: Any = self.HandleExprLlvm(Node.left)
|
||||
if not LeftVal:
|
||||
return None
|
||||
is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
|
||||
if len(Node.ops) == 1:
|
||||
Op: ast.cmpop = Node.ops[0]
|
||||
# in/not in: 调用 __contains__
|
||||
if isinstance(Op, (ast.In, ast.NotIn)):
|
||||
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
|
||||
if RightVal:
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__contains__'):
|
||||
# 处理 RightVal 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8
|
||||
if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
|
||||
RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8:
|
||||
RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__')
|
||||
result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__")
|
||||
# 归一化为 i1
|
||||
if isinstance(result.type, ir.IntType) and result.type.width > 1:
|
||||
zero: ir.Constant = ir.Constant(result.type, 0)
|
||||
result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool")
|
||||
if isinstance(Op, ast.NotIn):
|
||||
result = Gen.builder.not_(result, name="not_in_result")
|
||||
return result
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op)
|
||||
if not ComparatorSymbol:
|
||||
return None
|
||||
RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
|
||||
if not RightVal:
|
||||
return None
|
||||
# 比较运算符重载检测:当左侧是结构体指针时,尝试调用 __eq__/__ne__/__lt__/__le__/__gt__/__ge__
|
||||
CMP_OVERLOAD_MAP: dict[str, str] = {
|
||||
'==': '__eq__', '!=': '__ne__', '<': '__lt__',
|
||||
'<=': '__le__', '>': '__gt__', '>=': '__ge__',
|
||||
}
|
||||
if ComparatorSymbol in CMP_OVERLOAD_MAP:
|
||||
LeftClassName: str | None = None
|
||||
if isinstance(LeftVal.type, ir.PointerType):
|
||||
pointee: ir.Type = LeftVal.type.pointee
|
||||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
LeftClassName = CN
|
||||
break
|
||||
elif isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName is None and isinstance(Node.left, ast.Name):
|
||||
LeftClassName = Gen.var_struct_class.get(Node.left.id)
|
||||
if LeftClassName and LeftClassName in Gen.structs:
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName:
|
||||
op_name: str = CMP_OVERLOAD_MAP[ComparatorSymbol]
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
|
||||
if result is not None:
|
||||
return result
|
||||
if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
lv: int = LeftVal.constant
|
||||
rv: int = RightVal.constant
|
||||
lw: int = LeftVal.type.width
|
||||
rw: int = RightVal.type.width
|
||||
if lw < rw:
|
||||
lv = lv if lv >= 0 else lv + (1 << lw)
|
||||
elif rw < lw:
|
||||
rv = rv if rv >= 0 else rv + (1 << rw)
|
||||
if is_unsigned:
|
||||
mask_l: int = (1 << max(lw, rw)) - 1
|
||||
lv = lv & mask_l
|
||||
rv = rv & mask_l
|
||||
cmp_map: dict[str, bool] = {
|
||||
'==': lv == rv, '!=': lv != rv,
|
||||
'<': lv < rv, '>': lv > rv,
|
||||
'<=': lv <= rv, '>=': lv >= rv,
|
||||
}
|
||||
result: bool = cmp_map.get(ComparatorSymbol, False)
|
||||
return ir.Constant(ir.IntType(1), 1 if result else 0)
|
||||
# is / is not: 值类型(IntType)与 None(空指针常量)比较
|
||||
# 值类型(如 i8/i32)永远不可能为 None,因此:
|
||||
# - 值类型 is None → 恒为 false (i1 0)
|
||||
# - 值类型 is not None → 恒为 true (i1 1)
|
||||
# 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load(空指针解引用)导致崩溃
|
||||
if ComparatorSymbol in ('is', 'is not'):
|
||||
LeftIsNullPtr: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None and isinstance(LeftVal.type, ir.PointerType)
|
||||
RightIsNullPtr: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None and isinstance(RightVal.type, ir.PointerType)
|
||||
LeftIsValueType: bool = isinstance(LeftVal.type, ir.IntType)
|
||||
RightIsValueType: bool = isinstance(RightVal.type, ir.IntType)
|
||||
if (LeftIsValueType and RightIsNullPtr) or (RightIsValueType and LeftIsNullPtr):
|
||||
IsNotResult: int = 1 if ComparatorSymbol == 'is not' else 0
|
||||
return ir.Constant(ir.IntType(1), IsNotResult)
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
# 如果宽类型常量值超出窄类型有符号范围,则必须用zext
|
||||
# i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节)
|
||||
need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max or RightVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max or LeftVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
|
||||
elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
|
||||
if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
|
||||
LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
|
||||
else:
|
||||
if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
|
||||
RightVal = ir.Constant(LeftVal.type, None)
|
||||
else:
|
||||
# 指针 vs 非零整数: 将指针转为整数走正常 ==(地址值比较)
|
||||
LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp")
|
||||
elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
|
||||
if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
|
||||
RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
|
||||
else:
|
||||
if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
|
||||
LeftVal = ir.Constant(RightVal.type, None)
|
||||
else:
|
||||
# 非零整数 vs 指针: 将指针转为整数走正常 ==(地址值比较)
|
||||
RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp")
|
||||
# is / is not: 地址比较(指针)或值比较(int)
|
||||
if ComparatorSymbol in ('is', 'is not'):
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
|
||||
addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp")
|
||||
if ComparatorSymbol == 'is not':
|
||||
addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result")
|
||||
return addr_cmp
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp")
|
||||
if ComparatorSymbol == 'is not':
|
||||
val_cmp = Gen.builder.not_(val_cmp, name="is_not_result")
|
||||
return val_cmp
|
||||
# == / !=: 指针间做地址比较(C-Like 语义,不隐式调用 strcmp)
|
||||
# 如需字符串内容比较,应显式调用 string.strcmp()
|
||||
if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
|
||||
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
|
||||
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
|
||||
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
|
||||
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
|
||||
result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
elif is_unsigned:
|
||||
result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
else:
|
||||
result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
|
||||
return result
|
||||
EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end")
|
||||
phi_incomings: list[tuple[ir.Value, ir.Block]] = []
|
||||
for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
|
||||
ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
|
||||
if not ComparatorSymbol:
|
||||
continue
|
||||
RightVal = self.HandleExprLlvm(Comparator)
|
||||
if not RightVal:
|
||||
continue
|
||||
if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
|
||||
if LeftVal.type.width < RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
|
||||
if not need_zext and isinstance(RightVal, ir.Constant):
|
||||
signed_max = (1 << (LeftVal.type.width - 1)) - 1
|
||||
try:
|
||||
if RightVal.constant > signed_max or RightVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
|
||||
else:
|
||||
LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
|
||||
elif LeftVal.type.width > RightVal.type.width:
|
||||
need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1
|
||||
if not need_zext and isinstance(LeftVal, ir.Constant):
|
||||
signed_max = (1 << (RightVal.type.width - 1)) - 1
|
||||
try:
|
||||
if LeftVal.constant > signed_max or LeftVal.constant < 0:
|
||||
need_zext = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if need_zext:
|
||||
RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
|
||||
else:
|
||||
RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
|
||||
if is_unsigned:
|
||||
cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
|
||||
if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
|
||||
RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
|
||||
elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
|
||||
LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
|
||||
cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
else:
|
||||
cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
|
||||
if i < len(Node.ops) - 1:
|
||||
NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}")
|
||||
cur_bb: ir.Block = Gen.builder.block
|
||||
Gen.builder.cbranch(cmp_result, NextBB, EndBB)
|
||||
phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
|
||||
Gen.builder.position_at_start(NextBB)
|
||||
LeftVal = RightVal
|
||||
else:
|
||||
cur_bb = Gen.builder.block
|
||||
Gen.builder.branch(EndBB)
|
||||
phi_incomings.append((cmp_result, cur_bb))
|
||||
Gen.builder.position_at_start(EndBB)
|
||||
final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp")
|
||||
for val, bb in phi_incomings:
|
||||
final_result.add_incoming(val, bb)
|
||||
return final_result
|
||||
@@ -1,305 +1,305 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.SymbolUtils import IsTModule
|
||||
|
||||
|
||||
class ExprUtils:
|
||||
def __init__(self, translator: "Translator") -> None:
|
||||
self.Trans: Translator = translator
|
||||
|
||||
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
|
||||
OpMap: dict[type, str] = {
|
||||
ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/',
|
||||
ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&',
|
||||
ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>',
|
||||
ast.MatMult: '@',
|
||||
}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
|
||||
OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
|
||||
OpMap: dict[type, str] = {
|
||||
ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=',
|
||||
ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not',
|
||||
ast.In: 'in', ast.NotIn: 'not in',
|
||||
}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||||
if isinstance(node, ast.Name):
|
||||
VarName: str = node.id
|
||||
return Gen.var_struct_class.get(VarName)
|
||||
if isinstance(node, ast.Attribute):
|
||||
AttrName: str = node.attr
|
||||
# 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable)
|
||||
# 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派
|
||||
# (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST')
|
||||
BaseClass: str | None = self._get_var_class(node.value, Gen)
|
||||
if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self':
|
||||
BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
|
||||
if BaseClass and BaseClass in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[BaseClass]:
|
||||
if m_name == AttrName:
|
||||
if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
found = Gen.find_struct_by_pointee(m_type.pointee)
|
||||
if found:
|
||||
return found[0]
|
||||
# 联合类型(如 GSList[Param] | t.CPtr)降级为 i8* 时,
|
||||
# 从 class_member_element_class 查找泛型特化类名
|
||||
element_class_map = getattr(Gen, 'class_member_element_class', {})
|
||||
element_class = element_class_map.get(BaseClass, {}).get(AttrName)
|
||||
if element_class:
|
||||
return element_class
|
||||
break
|
||||
# Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后,
|
||||
# 避免字段名和变量名冲突导致错误分派)
|
||||
cls: str | None = Gen.var_struct_class.get(AttrName)
|
||||
if cls:
|
||||
return cls
|
||||
return None
|
||||
return None
|
||||
|
||||
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
|
||||
FullMethodName: str = f'{ClassName}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{ClassName}.{op_name}__'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
# 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 TPV 一致)
|
||||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||||
anc_method: str = f'{anc}.{op_name}'
|
||||
if Gen._has_function(anc_method):
|
||||
FullMethodName = anc_method
|
||||
break
|
||||
anc_method_ss = f'{anc}.{op_name}__'
|
||||
if Gen._has_function(anc_method_ss):
|
||||
FullMethodName = anc_method_ss
|
||||
break
|
||||
if not Gen._has_function(FullMethodName):
|
||||
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且
|
||||
# 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
|
||||
# (如 'ndarray[double]')。注解 'numpy.ndarray | t.CPtr' 未指定类型参数时,
|
||||
# var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。
|
||||
# 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。
|
||||
if '[' not in ClassName:
|
||||
SpecClass: str | None = None
|
||||
for CN in Gen.structs.keys():
|
||||
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if SpecClass:
|
||||
FullMethodName = f'{SpecClass}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{SpecClass}.{op_name}__'
|
||||
if Gen._has_function(FullMethodName):
|
||||
func: Any = Gen._get_function(FullMethodName)
|
||||
# 多继承 this 调整:运算符重载方法定义在"无 vtable 父类"且字段区偏移 > 0 时,
|
||||
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
|
||||
method_anc: str | None = None
|
||||
_fm_short: str = FullMethodName.split('.')[-1] if '.' in FullMethodName else FullMethodName
|
||||
if '.' in FullMethodName:
|
||||
_fm_cls: str = FullMethodName.split('.')[0]
|
||||
if _fm_cls != ClassName:
|
||||
method_anc = _fm_cls
|
||||
_call_self: Any = self.Trans.ExprCallHandle._adjust_this_for_inherited_method(Gen, obj_val, ClassName, method_anc)
|
||||
call_args: list[Any] = [_call_self]
|
||||
if other_val is not None:
|
||||
call_args.append(other_val)
|
||||
if len(func.ftype.args) == len(call_args):
|
||||
for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)):
|
||||
if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType):
|
||||
if expected_type != actual_val.type:
|
||||
if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}")
|
||||
result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
|
||||
return result
|
||||
return None
|
||||
|
||||
def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]:
|
||||
info: dict[str, Any] = {
|
||||
'name': "unknown",
|
||||
'size': 0,
|
||||
'signed': False,
|
||||
'ptr': False
|
||||
}
|
||||
if isinstance(llvm_type, ir.IntType):
|
||||
info['size'] = llvm_type.width // 8
|
||||
info['signed'] = True
|
||||
if llvm_type.width == 8:
|
||||
info['name'] = "char"
|
||||
elif llvm_type.width == 16:
|
||||
info['name'] = "short"
|
||||
elif llvm_type.width == 32:
|
||||
info['name'] = "int"
|
||||
elif llvm_type.width == 64:
|
||||
info['name'] = "long long"
|
||||
else:
|
||||
info['name'] = f"int{llvm_type.width}"
|
||||
elif isinstance(llvm_type, ir.DoubleType):
|
||||
info['size'] = 8
|
||||
info['signed'] = True
|
||||
info['name'] = "double"
|
||||
elif isinstance(llvm_type, ir.FloatType):
|
||||
info['size'] = 4
|
||||
info['signed'] = True
|
||||
info['name'] = "float"
|
||||
elif isinstance(llvm_type, ir.PointerType):
|
||||
info['size'] = 8
|
||||
info['signed'] = False
|
||||
info['ptr'] = True
|
||||
pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee)
|
||||
info['name'] = f"{pointee_info['name']}*"
|
||||
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
size: int = 0
|
||||
for elem in llvm_type.elements:
|
||||
elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem)
|
||||
size += elem_info['size']
|
||||
info['size'] = size
|
||||
info['signed'] = False
|
||||
if isinstance(llvm_type, ir.IdentifiedStructType):
|
||||
info['name'] = llvm_type.name
|
||||
else:
|
||||
info['name'] = "struct"
|
||||
elif isinstance(llvm_type, ir.ArrayType):
|
||||
elem_info = self._llvm_type_to_detailed_string(llvm_type.element)
|
||||
info['size'] = elem_info['size'] * llvm_type.count
|
||||
info['signed'] = elem_info['signed']
|
||||
info['name'] = f"{elem_info['name']}[]"
|
||||
elif isinstance(llvm_type, ir.VoidType):
|
||||
info['size'] = 0
|
||||
info['signed'] = False
|
||||
info['name'] = "void"
|
||||
else:
|
||||
info['size'] = 0
|
||||
info['signed'] = False
|
||||
info['name'] = str(llvm_type)
|
||||
return info
|
||||
|
||||
def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if isinstance(node, ast.Constant):
|
||||
if isinstance(node.value, bool):
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node.value, int):
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node.value, float):
|
||||
return ir.DoubleType()
|
||||
elif isinstance(node.value, str):
|
||||
if getattr(node, 'kind', None) == 'u':
|
||||
return ir.PointerType(ir.IntType(16))
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Name):
|
||||
if node.id in Gen.variables:
|
||||
var_ptr: Any = Gen.variables[node.id]
|
||||
if isinstance(var_ptr.type, ir.PointerType):
|
||||
return var_ptr.type.pointee
|
||||
return var_ptr.type
|
||||
if node.id in Gen._reg_values:
|
||||
return Gen._reg_values[node.id].type
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
attr_name: str = node.attr
|
||||
AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name)
|
||||
if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None):
|
||||
return ir.IntType(32)
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.BinOp):
|
||||
left_type: ir.Type = self._infer_expr_llvm_type_full(node.left)
|
||||
right_type: ir.Type = self._infer_expr_llvm_type_full(node.right)
|
||||
if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)):
|
||||
return ir.DoubleType()
|
||||
if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.UnaryOp):
|
||||
return self._infer_expr_llvm_type_full(node.operand)
|
||||
elif isinstance(node, ast.Subscript):
|
||||
val_type: ir.Type = self._infer_expr_llvm_type_full(node.value)
|
||||
if isinstance(val_type, ir.PointerType):
|
||||
if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8:
|
||||
return ir.IntType(8)
|
||||
if isinstance(val_type.pointee, ir.ArrayType):
|
||||
return ir.PointerType(val_type.pointee.element)
|
||||
return val_type.pointee
|
||||
if isinstance(val_type, ir.ArrayType):
|
||||
return val_type.element
|
||||
if isinstance(val_type, ir.IntType):
|
||||
return ir.IntType(8)
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Name):
|
||||
func_name: str = node.func.id
|
||||
if Gen._has_function(func_name):
|
||||
fn: Any = Gen._get_function(func_name)
|
||||
return fn.function_type.return_type
|
||||
if func_name == 'len':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'sizeof':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'ord':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'chr':
|
||||
return ir.IntType(8)
|
||||
if func_name == 'int':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'float' or func_name == 'double':
|
||||
return ir.DoubleType()
|
||||
elif isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
|
||||
if node.func.attr == 'Deref':
|
||||
return ir.IntType(64)
|
||||
if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable):
|
||||
if node.func.attr == 'CChar':
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Compare):
|
||||
return ir.IntType(1)
|
||||
elif isinstance(node, ast.BoolOp):
|
||||
return ir.IntType(1)
|
||||
elif isinstance(node, ast.IfExp):
|
||||
return self._infer_expr_llvm_type_full(node.body)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
|
||||
def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None:
|
||||
"""收集 AST 节点中的绑定变量和自由变量
|
||||
|
||||
Args:
|
||||
node: AST 节点
|
||||
bound: 集合,收集绑定变量(ast.Store 上下文)
|
||||
free: 集合,收集自由变量(ast.Load 上下文),可为 None
|
||||
"""
|
||||
if free is None:
|
||||
free = set()
|
||||
if isinstance(node, ast.Name):
|
||||
if isinstance(node.ctx, ast.Store):
|
||||
bound.add(node.id)
|
||||
elif isinstance(node.ctx, ast.Load):
|
||||
free.add(node.id)
|
||||
elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
# 这些节点有自己的作用域,不递归进入
|
||||
# 但需要收集参数名作为 bound
|
||||
if hasattr(node, 'args') and node.args:
|
||||
for arg in node.args.args:
|
||||
bound.add(arg.arg)
|
||||
elif getattr(node, '_fields', None):
|
||||
for field in node._fields:
|
||||
value: Any = getattr(node, field, None)
|
||||
if isinstance(value, list):
|
||||
for item in value:
|
||||
if isinstance(item, (ast.stmt, ast.expr)):
|
||||
self._collect_names(item, bound, free)
|
||||
elif isinstance(value, (ast.stmt, ast.expr)):
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.SymbolUtils import IsTModule
|
||||
|
||||
|
||||
class ExprUtils:
|
||||
def __init__(self, translator: "Translator") -> None:
|
||||
self.Trans: Translator = translator
|
||||
|
||||
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
|
||||
OpMap: dict[type, str] = {
|
||||
ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/',
|
||||
ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&',
|
||||
ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>',
|
||||
ast.MatMult: '@',
|
||||
}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
|
||||
OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
|
||||
OpMap: dict[type, str] = {
|
||||
ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=',
|
||||
ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not',
|
||||
ast.In: 'in', ast.NotIn: 'not in',
|
||||
}
|
||||
return OpMap.get(type(Op), None)
|
||||
|
||||
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||||
if isinstance(node, ast.Name):
|
||||
VarName: str = node.id
|
||||
return Gen.var_struct_class.get(VarName)
|
||||
if isinstance(node, ast.Attribute):
|
||||
AttrName: str = node.attr
|
||||
# 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable)
|
||||
# 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派
|
||||
# (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST')
|
||||
BaseClass: str | None = self._get_var_class(node.value, Gen)
|
||||
if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self':
|
||||
BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
|
||||
if BaseClass and BaseClass in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[BaseClass]:
|
||||
if m_name == AttrName:
|
||||
if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
found = Gen.find_struct_by_pointee(m_type.pointee)
|
||||
if found:
|
||||
return found[0]
|
||||
# 联合类型(如 GSList[Param] | t.CPtr)降级为 i8* 时,
|
||||
# 从 class_member_element_class 查找泛型特化类名
|
||||
element_class_map = getattr(Gen, 'class_member_element_class', {})
|
||||
element_class = element_class_map.get(BaseClass, {}).get(AttrName)
|
||||
if element_class:
|
||||
return element_class
|
||||
break
|
||||
# Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后,
|
||||
# 避免字段名和变量名冲突导致错误分派)
|
||||
cls: str | None = Gen.var_struct_class.get(AttrName)
|
||||
if cls:
|
||||
return cls
|
||||
return None
|
||||
return None
|
||||
|
||||
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
|
||||
FullMethodName: str = f'{ClassName}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{ClassName}.{op_name}__'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
# 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 TPV 一致)
|
||||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||||
anc_method: str = f'{anc}.{op_name}'
|
||||
if Gen._has_function(anc_method):
|
||||
FullMethodName = anc_method
|
||||
break
|
||||
anc_method_ss = f'{anc}.{op_name}__'
|
||||
if Gen._has_function(anc_method_ss):
|
||||
FullMethodName = anc_method_ss
|
||||
break
|
||||
if not Gen._has_function(FullMethodName):
|
||||
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且
|
||||
# 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
|
||||
# (如 'ndarray[double]')。注解 'numpy.ndarray | t.CPtr' 未指定类型参数时,
|
||||
# var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。
|
||||
# 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。
|
||||
if '[' not in ClassName:
|
||||
SpecClass: str | None = None
|
||||
for CN in Gen.structs.keys():
|
||||
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if SpecClass:
|
||||
FullMethodName = f'{SpecClass}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{SpecClass}.{op_name}__'
|
||||
if Gen._has_function(FullMethodName):
|
||||
func: Any = Gen._get_function(FullMethodName)
|
||||
# 多继承 this 调整:运算符重载方法定义在"无 vtable 父类"且字段区偏移 > 0 时,
|
||||
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
|
||||
method_anc: str | None = None
|
||||
_fm_short: str = FullMethodName.split('.')[-1] if '.' in FullMethodName else FullMethodName
|
||||
if '.' in FullMethodName:
|
||||
_fm_cls: str = FullMethodName.split('.')[0]
|
||||
if _fm_cls != ClassName:
|
||||
method_anc = _fm_cls
|
||||
_call_self: Any = self.Trans.ExprCallHandle._adjust_this_for_inherited_method(Gen, obj_val, ClassName, method_anc)
|
||||
call_args: list[Any] = [_call_self]
|
||||
if other_val is not None:
|
||||
call_args.append(other_val)
|
||||
if len(func.ftype.args) == len(call_args):
|
||||
for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)):
|
||||
if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType):
|
||||
if expected_type != actual_val.type:
|
||||
if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||||
call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}")
|
||||
result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
|
||||
return result
|
||||
return None
|
||||
|
||||
def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]:
|
||||
info: dict[str, Any] = {
|
||||
'name': "unknown",
|
||||
'size': 0,
|
||||
'signed': False,
|
||||
'ptr': False
|
||||
}
|
||||
if isinstance(llvm_type, ir.IntType):
|
||||
info['size'] = llvm_type.width // 8
|
||||
info['signed'] = True
|
||||
if llvm_type.width == 8:
|
||||
info['name'] = "char"
|
||||
elif llvm_type.width == 16:
|
||||
info['name'] = "short"
|
||||
elif llvm_type.width == 32:
|
||||
info['name'] = "int"
|
||||
elif llvm_type.width == 64:
|
||||
info['name'] = "long long"
|
||||
else:
|
||||
info['name'] = f"int{llvm_type.width}"
|
||||
elif isinstance(llvm_type, ir.DoubleType):
|
||||
info['size'] = 8
|
||||
info['signed'] = True
|
||||
info['name'] = "double"
|
||||
elif isinstance(llvm_type, ir.FloatType):
|
||||
info['size'] = 4
|
||||
info['signed'] = True
|
||||
info['name'] = "float"
|
||||
elif isinstance(llvm_type, ir.PointerType):
|
||||
info['size'] = 8
|
||||
info['signed'] = False
|
||||
info['ptr'] = True
|
||||
pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee)
|
||||
info['name'] = f"{pointee_info['name']}*"
|
||||
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
size: int = 0
|
||||
for elem in llvm_type.elements:
|
||||
elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem)
|
||||
size += elem_info['size']
|
||||
info['size'] = size
|
||||
info['signed'] = False
|
||||
if isinstance(llvm_type, ir.IdentifiedStructType):
|
||||
info['name'] = llvm_type.name
|
||||
else:
|
||||
info['name'] = "struct"
|
||||
elif isinstance(llvm_type, ir.ArrayType):
|
||||
elem_info = self._llvm_type_to_detailed_string(llvm_type.element)
|
||||
info['size'] = elem_info['size'] * llvm_type.count
|
||||
info['signed'] = elem_info['signed']
|
||||
info['name'] = f"{elem_info['name']}[]"
|
||||
elif isinstance(llvm_type, ir.VoidType):
|
||||
info['size'] = 0
|
||||
info['signed'] = False
|
||||
info['name'] = "void"
|
||||
else:
|
||||
info['size'] = 0
|
||||
info['signed'] = False
|
||||
info['name'] = str(llvm_type)
|
||||
return info
|
||||
|
||||
def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
if isinstance(node, ast.Constant):
|
||||
if isinstance(node.value, bool):
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node.value, int):
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node.value, float):
|
||||
return ir.DoubleType()
|
||||
elif isinstance(node.value, str):
|
||||
if getattr(node, 'kind', None) == 'u':
|
||||
return ir.PointerType(ir.IntType(16))
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Name):
|
||||
if node.id in Gen.variables:
|
||||
var_ptr: Any = Gen.variables[node.id]
|
||||
if isinstance(var_ptr.type, ir.PointerType):
|
||||
return var_ptr.type.pointee
|
||||
return var_ptr.type
|
||||
if node.id in Gen._reg_values:
|
||||
return Gen._reg_values[node.id].type
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
attr_name: str = node.attr
|
||||
AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name)
|
||||
if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None):
|
||||
return ir.IntType(32)
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.BinOp):
|
||||
left_type: ir.Type = self._infer_expr_llvm_type_full(node.left)
|
||||
right_type: ir.Type = self._infer_expr_llvm_type_full(node.right)
|
||||
if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)):
|
||||
return ir.DoubleType()
|
||||
if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.UnaryOp):
|
||||
return self._infer_expr_llvm_type_full(node.operand)
|
||||
elif isinstance(node, ast.Subscript):
|
||||
val_type: ir.Type = self._infer_expr_llvm_type_full(node.value)
|
||||
if isinstance(val_type, ir.PointerType):
|
||||
if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8:
|
||||
return ir.IntType(8)
|
||||
if isinstance(val_type.pointee, ir.ArrayType):
|
||||
return ir.PointerType(val_type.pointee.element)
|
||||
return val_type.pointee
|
||||
if isinstance(val_type, ir.ArrayType):
|
||||
return val_type.element
|
||||
if isinstance(val_type, ir.IntType):
|
||||
return ir.IntType(8)
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Name):
|
||||
func_name: str = node.func.id
|
||||
if Gen._has_function(func_name):
|
||||
fn: Any = Gen._get_function(func_name)
|
||||
return fn.function_type.return_type
|
||||
if func_name == 'len':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'sizeof':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'ord':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'chr':
|
||||
return ir.IntType(8)
|
||||
if func_name == 'int':
|
||||
return ir.IntType(32)
|
||||
if func_name == 'float' or func_name == 'double':
|
||||
return ir.DoubleType()
|
||||
elif isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
|
||||
if node.func.attr == 'Deref':
|
||||
return ir.IntType(64)
|
||||
if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable):
|
||||
if node.func.attr == 'CChar':
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
elif isinstance(node, ast.Compare):
|
||||
return ir.IntType(1)
|
||||
elif isinstance(node, ast.BoolOp):
|
||||
return ir.IntType(1)
|
||||
elif isinstance(node, ast.IfExp):
|
||||
return self._infer_expr_llvm_type_full(node.body)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
return ir.IntType(32)
|
||||
|
||||
def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None:
|
||||
"""收集 AST 节点中的绑定变量和自由变量
|
||||
|
||||
Args:
|
||||
node: AST 节点
|
||||
bound: 集合,收集绑定变量(ast.Store 上下文)
|
||||
free: 集合,收集自由变量(ast.Load 上下文),可为 None
|
||||
"""
|
||||
if free is None:
|
||||
free = set()
|
||||
if isinstance(node, ast.Name):
|
||||
if isinstance(node.ctx, ast.Store):
|
||||
bound.add(node.id)
|
||||
elif isinstance(node.ctx, ast.Load):
|
||||
free.add(node.id)
|
||||
elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
# 这些节点有自己的作用域,不递归进入
|
||||
# 但需要收集参数名作为 bound
|
||||
if hasattr(node, 'args') and node.args:
|
||||
for arg in node.args.args:
|
||||
bound.add(arg.arg)
|
||||
elif getattr(node, '_fields', None):
|
||||
for field in node._fields:
|
||||
value: Any = getattr(node, field, None)
|
||||
if isinstance(value, list):
|
||||
for item in value:
|
||||
if isinstance(item, (ast.stmt, ast.expr)):
|
||||
self._collect_names(item, bound, free)
|
||||
elif isinstance(value, (ast.stmt, ast.expr)):
|
||||
self._collect_names(value, bound, free)
|
||||
+1093
-1093
File diff suppressed because it is too large.
Load diff
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
import ast
|
||||
import vast as ast
|
||||
import copy
|
||||
import traceback
|
||||
import llvmlite.ir as ir
|
||||
@@ -1757,8 +1757,8 @@ class FunctionHandle(BaseHandle):
|
||||
Gen.builder.store(last_param_ptr, last_param_alloc)
|
||||
Gen.emit_va_start(va_list_ptr)
|
||||
Gen._variadic_info['va_start_called'] = True
|
||||
# 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*),
|
||||
# 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节)
|
||||
# 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*),
|
||||
# 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节)
|
||||
Gen._direct_values[vararg_name] = va_list_ptr
|
||||
# @t.TLS 一次性初始化检查:首次调用执行函数体,后续调用直接返回
|
||||
if is_tls_func:
|
||||
@@ -1790,18 +1790,18 @@ class FunctionHandle(BaseHandle):
|
||||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||||
Gen.builder.position_at_end(cont_bb)
|
||||
Gen.builder.store(ir.Constant(ir.IntType(1), 1), flag_global)
|
||||
_saved_class_name = getattr(Gen, '_current_class_name', None)
|
||||
Gen._current_class_name = ClassName
|
||||
# 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码
|
||||
func_body: list[ast.stmt] = Node.body
|
||||
doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name
|
||||
if (func_body and isinstance(func_body[0], ast.Expr)
|
||||
and isinstance(func_body[0].value, ast.Constant)
|
||||
and isinstance(func_body[0].value.value, str)):
|
||||
Gen._create_doc_global(doc_symbol, func_body[0].value.value)
|
||||
func_body = func_body[1:]
|
||||
else:
|
||||
Gen._create_doc_global(doc_symbol, None)
|
||||
_saved_class_name = getattr(Gen, '_current_class_name', None)
|
||||
Gen._current_class_name = ClassName
|
||||
# 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码
|
||||
func_body: list[ast.stmt] = Node.body
|
||||
doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name
|
||||
if (func_body and isinstance(func_body[0], ast.Expr)
|
||||
and isinstance(func_body[0].value, ast.Constant)
|
||||
and isinstance(func_body[0].value.value, str)):
|
||||
Gen._create_doc_global(doc_symbol, func_body[0].value.value)
|
||||
func_body = func_body[1:]
|
||||
else:
|
||||
Gen._create_doc_global(doc_symbol, None)
|
||||
try:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(func_body)
|
||||
except Exception as _body_exc:
|
||||
|
||||
+213
-213
@@ -1,214 +1,214 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
|
||||
|
||||
|
||||
class IfHandle(BaseHandle):
|
||||
def _get_attr_full_name(self, node: ast.expr) -> str | None:
|
||||
if isinstance(node, ast.Attribute):
|
||||
parts: list[str] = []
|
||||
cur: ast.expr = node
|
||||
while isinstance(cur, ast.Attribute):
|
||||
parts.append(cur.attr)
|
||||
cur = cur.value
|
||||
if isinstance(cur, ast.Name):
|
||||
parts.append(cur.id)
|
||||
parts.reverse()
|
||||
return '.'.join(parts)
|
||||
return None
|
||||
|
||||
def _is_cif_call(self, node: ast.expr) -> bool:
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
|
||||
return node.func.attr in ('CIf', 'CIfdef', 'CIfndef')
|
||||
if isinstance(node.func, ast.Name):
|
||||
return node.func.id in ('CIf', 'CIfdef', 'CIfndef')
|
||||
return False
|
||||
|
||||
def _resolve_macro_name(self, arg: ast.expr) -> str | None:
|
||||
if isinstance(arg, ast.Name):
|
||||
return arg.id
|
||||
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
||||
return arg.value
|
||||
if isinstance(arg, ast.Attribute):
|
||||
full_name: str | None = self._get_attr_full_name(arg)
|
||||
if full_name:
|
||||
return full_name
|
||||
return None
|
||||
|
||||
def _evaluate_cif_condition(self, node: ast.Call) -> int | None:
|
||||
if not isinstance(node, ast.Call):
|
||||
return None
|
||||
args: list[ast.expr] = node.args
|
||||
if not args:
|
||||
return 0
|
||||
kind: str | None = None
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
kind = node.func.attr
|
||||
elif isinstance(node.func, ast.Name):
|
||||
kind = node.func.id
|
||||
else:
|
||||
return None
|
||||
if kind == 'CIfdef':
|
||||
name: str | None = self._resolve_macro_name(args[0])
|
||||
if name is None:
|
||||
return 0
|
||||
return 1 if self._is_macro_defined(name) else 0
|
||||
elif kind == 'CIfndef':
|
||||
name: str | None = self._resolve_macro_name(args[0])
|
||||
if name is None:
|
||||
return 1
|
||||
return 0 if self._is_macro_defined(name) else 1
|
||||
elif kind == 'CIf':
|
||||
return self._eval_const_expr(args[0])
|
||||
return None
|
||||
|
||||
def _is_macro_defined(self, name: str) -> bool:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
|
||||
return True
|
||||
if self.Trans.SymbolTable.is_define(name):
|
||||
return True
|
||||
platform_macros: dict[str, int] = self._get_platform_macros()
|
||||
return name in platform_macros
|
||||
|
||||
def _get_macro_value(self, name: str) -> int | float | None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
|
||||
val: int | float | None = Gen._define_constants[name]
|
||||
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖
|
||||
try:
|
||||
if hasattr(Gen, 'module') and name in Gen.module.globals:
|
||||
_gv: Any = Gen.module.globals[name]
|
||||
if getattr(_gv, 'initializer', None) is not None:
|
||||
_iv: Any = _gv.initializer
|
||||
if hasattr(_iv, 'constant') and isinstance(_iv.constant, (int, float)):
|
||||
val = _iv.constant
|
||||
except Exception:
|
||||
pass
|
||||
if isinstance(val, (int, float)):
|
||||
return val
|
||||
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name)
|
||||
if info:
|
||||
if info.IsDefine:
|
||||
val: int | float | None = info.DefineValue
|
||||
if isinstance(val, (int, float)):
|
||||
return val
|
||||
platform_macros: dict[str, int] = self._get_platform_macros()
|
||||
if name in platform_macros:
|
||||
return platform_macros[name]
|
||||
return None
|
||||
|
||||
def _get_platform_macros(self) -> dict[str, int]:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
macros: dict[str, int] = {}
|
||||
pi: dict[str, object] = Gen._platform_info
|
||||
ptr_size: int = getattr(Gen, 'ptr_size', 8)
|
||||
# 根据目标平台设置宏(从三元组推导)
|
||||
if pi.get('is_windows'):
|
||||
macros['_WIN32'] = 1
|
||||
if not pi.get('is_32bit'):
|
||||
macros['_WIN64'] = 1
|
||||
macros['WIN64'] = 1
|
||||
macros['WIN32'] = 1
|
||||
if pi.get('is_linux'):
|
||||
macros['__linux__'] = 1
|
||||
if pi.get('is_macos'):
|
||||
macros['__APPLE__'] = 1
|
||||
macros['__MACH__'] = 1
|
||||
if pi.get('is_x86_64'):
|
||||
macros['__x86_64__'] = 1
|
||||
macros['__x86_64'] = 1
|
||||
macros['_M_X64'] = 1
|
||||
elif pi.get('is_arm64'):
|
||||
macros['__aarch64__'] = 1
|
||||
macros['_M_ARM64'] = 1
|
||||
if not pi.get('is_32bit') and pi.get('is_linux'):
|
||||
macros['__LP64__'] = 1
|
||||
elif pi.get('is_32bit'):
|
||||
macros['_ILP32'] = 1
|
||||
macros['SIZEOF_VOID_P'] = ptr_size
|
||||
macros['__SIZEOF_POINTER__'] = ptr_size
|
||||
macros['NDEBUG'] = 0
|
||||
return macros
|
||||
|
||||
def _eval_const_expr(self, node: ast.expr) -> int | None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
|
||||
result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx)
|
||||
if result is None:
|
||||
# 保留 CIf 嵌套调用处理(HandlesIf 特有逻辑)
|
||||
if isinstance(node, ast.Call) and self._is_cif_call(node):
|
||||
return self._evaluate_cif_condition(node)
|
||||
return None
|
||||
# HandlesIf 需要 bool/float → int 转换(#if 条件编译语义)
|
||||
if isinstance(result, bool):
|
||||
return 1 if result else 0
|
||||
if isinstance(result, float):
|
||||
return 1 if result != 0.0 else 0
|
||||
return result
|
||||
|
||||
def _HandleIfLlvm(self, Node: ast.If) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if self._is_cif_call(Node.test):
|
||||
compile_time_val: int | None = self._evaluate_cif_condition(Node.test)
|
||||
if compile_time_val is not None:
|
||||
if compile_time_val:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
elif Node.orelse:
|
||||
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
|
||||
self._HandleIfLlvm(Node.orelse[0])
|
||||
else:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
return
|
||||
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
|
||||
if not Cond:
|
||||
return
|
||||
is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1
|
||||
if is_const:
|
||||
if Cond.constant:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
elif Node.orelse:
|
||||
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
|
||||
self._HandleIfLlvm(Node.orelse[0])
|
||||
else:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
return
|
||||
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
|
||||
obj_val: ir.Value = Cond
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__")
|
||||
if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result")
|
||||
else:
|
||||
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
|
||||
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond")
|
||||
else:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond")
|
||||
ThenBB: ir.Block = Gen.func.append_basic_block(name="then")
|
||||
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None
|
||||
MergeBB: ir.Block = Gen.func.append_basic_block(name="endif")
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
|
||||
Gen.builder.position_at_start(ThenBB)
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(MergeBB)
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(MergeBB)
|
||||
if not MergeBB.is_terminated:
|
||||
Gen.builder.position_at_start(MergeBB)
|
||||
else:
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
|
||||
|
||||
|
||||
class IfHandle(BaseHandle):
|
||||
def _get_attr_full_name(self, node: ast.expr) -> str | None:
|
||||
if isinstance(node, ast.Attribute):
|
||||
parts: list[str] = []
|
||||
cur: ast.expr = node
|
||||
while isinstance(cur, ast.Attribute):
|
||||
parts.append(cur.attr)
|
||||
cur = cur.value
|
||||
if isinstance(cur, ast.Name):
|
||||
parts.append(cur.id)
|
||||
parts.reverse()
|
||||
return '.'.join(parts)
|
||||
return None
|
||||
|
||||
def _is_cif_call(self, node: ast.expr) -> bool:
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
|
||||
return node.func.attr in ('CIf', 'CIfdef', 'CIfndef')
|
||||
if isinstance(node.func, ast.Name):
|
||||
return node.func.id in ('CIf', 'CIfdef', 'CIfndef')
|
||||
return False
|
||||
|
||||
def _resolve_macro_name(self, arg: ast.expr) -> str | None:
|
||||
if isinstance(arg, ast.Name):
|
||||
return arg.id
|
||||
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
||||
return arg.value
|
||||
if isinstance(arg, ast.Attribute):
|
||||
full_name: str | None = self._get_attr_full_name(arg)
|
||||
if full_name:
|
||||
return full_name
|
||||
return None
|
||||
|
||||
def _evaluate_cif_condition(self, node: ast.Call) -> int | None:
|
||||
if not isinstance(node, ast.Call):
|
||||
return None
|
||||
args: list[ast.expr] = node.args
|
||||
if not args:
|
||||
return 0
|
||||
kind: str | None = None
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
kind = node.func.attr
|
||||
elif isinstance(node.func, ast.Name):
|
||||
kind = node.func.id
|
||||
else:
|
||||
return None
|
||||
if kind == 'CIfdef':
|
||||
name: str | None = self._resolve_macro_name(args[0])
|
||||
if name is None:
|
||||
return 0
|
||||
return 1 if self._is_macro_defined(name) else 0
|
||||
elif kind == 'CIfndef':
|
||||
name: str | None = self._resolve_macro_name(args[0])
|
||||
if name is None:
|
||||
return 1
|
||||
return 0 if self._is_macro_defined(name) else 1
|
||||
elif kind == 'CIf':
|
||||
return self._eval_const_expr(args[0])
|
||||
return None
|
||||
|
||||
def _is_macro_defined(self, name: str) -> bool:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
|
||||
return True
|
||||
if self.Trans.SymbolTable.is_define(name):
|
||||
return True
|
||||
platform_macros: dict[str, int] = self._get_platform_macros()
|
||||
return name in platform_macros
|
||||
|
||||
def _get_macro_value(self, name: str) -> int | float | None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
|
||||
val: int | float | None = Gen._define_constants[name]
|
||||
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖
|
||||
try:
|
||||
if hasattr(Gen, 'module') and name in Gen.module.globals:
|
||||
_gv: Any = Gen.module.globals[name]
|
||||
if getattr(_gv, 'initializer', None) is not None:
|
||||
_iv: Any = _gv.initializer
|
||||
if hasattr(_iv, 'constant') and isinstance(_iv.constant, (int, float)):
|
||||
val = _iv.constant
|
||||
except Exception:
|
||||
pass
|
||||
if isinstance(val, (int, float)):
|
||||
return val
|
||||
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name)
|
||||
if info:
|
||||
if info.IsDefine:
|
||||
val: int | float | None = info.DefineValue
|
||||
if isinstance(val, (int, float)):
|
||||
return val
|
||||
platform_macros: dict[str, int] = self._get_platform_macros()
|
||||
if name in platform_macros:
|
||||
return platform_macros[name]
|
||||
return None
|
||||
|
||||
def _get_platform_macros(self) -> dict[str, int]:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
macros: dict[str, int] = {}
|
||||
pi: dict[str, object] = Gen._platform_info
|
||||
ptr_size: int = getattr(Gen, 'ptr_size', 8)
|
||||
# 根据目标平台设置宏(从三元组推导)
|
||||
if pi.get('is_windows'):
|
||||
macros['_WIN32'] = 1
|
||||
if not pi.get('is_32bit'):
|
||||
macros['_WIN64'] = 1
|
||||
macros['WIN64'] = 1
|
||||
macros['WIN32'] = 1
|
||||
if pi.get('is_linux'):
|
||||
macros['__linux__'] = 1
|
||||
if pi.get('is_macos'):
|
||||
macros['__APPLE__'] = 1
|
||||
macros['__MACH__'] = 1
|
||||
if pi.get('is_x86_64'):
|
||||
macros['__x86_64__'] = 1
|
||||
macros['__x86_64'] = 1
|
||||
macros['_M_X64'] = 1
|
||||
elif pi.get('is_arm64'):
|
||||
macros['__aarch64__'] = 1
|
||||
macros['_M_ARM64'] = 1
|
||||
if not pi.get('is_32bit') and pi.get('is_linux'):
|
||||
macros['__LP64__'] = 1
|
||||
elif pi.get('is_32bit'):
|
||||
macros['_ILP32'] = 1
|
||||
macros['SIZEOF_VOID_P'] = ptr_size
|
||||
macros['__SIZEOF_POINTER__'] = ptr_size
|
||||
macros['NDEBUG'] = 0
|
||||
return macros
|
||||
|
||||
def _eval_const_expr(self, node: ast.expr) -> int | None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
|
||||
result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx)
|
||||
if result is None:
|
||||
# 保留 CIf 嵌套调用处理(HandlesIf 特有逻辑)
|
||||
if isinstance(node, ast.Call) and self._is_cif_call(node):
|
||||
return self._evaluate_cif_condition(node)
|
||||
return None
|
||||
# HandlesIf 需要 bool/float → int 转换(#if 条件编译语义)
|
||||
if isinstance(result, bool):
|
||||
return 1 if result else 0
|
||||
if isinstance(result, float):
|
||||
return 1 if result != 0.0 else 0
|
||||
return result
|
||||
|
||||
def _HandleIfLlvm(self, Node: ast.If) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if self._is_cif_call(Node.test):
|
||||
compile_time_val: int | None = self._evaluate_cif_condition(Node.test)
|
||||
if compile_time_val is not None:
|
||||
if compile_time_val:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
elif Node.orelse:
|
||||
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
|
||||
self._HandleIfLlvm(Node.orelse[0])
|
||||
else:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
return
|
||||
Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
|
||||
if not Cond:
|
||||
return
|
||||
is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1
|
||||
if is_const:
|
||||
if Cond.constant:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
elif Node.orelse:
|
||||
if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
|
||||
self._HandleIfLlvm(Node.orelse[0])
|
||||
else:
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
return
|
||||
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
|
||||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen)
|
||||
if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
|
||||
obj_val: ir.Value = Cond
|
||||
if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
|
||||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__")
|
||||
if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result")
|
||||
else:
|
||||
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
|
||||
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond")
|
||||
else:
|
||||
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond")
|
||||
ThenBB: ir.Block = Gen.func.append_basic_block(name="then")
|
||||
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None
|
||||
MergeBB: ir.Block = Gen.func.append_basic_block(name="endif")
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
|
||||
Gen.builder.position_at_start(ThenBB)
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(MergeBB)
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(MergeBB)
|
||||
if not MergeBB.is_terminated:
|
||||
Gen.builder.position_at_start(MergeBB)
|
||||
else:
|
||||
Gen.builder.position_at_end(MergeBB)
|
||||
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
import ast
|
||||
import vast as ast
|
||||
import inspect
|
||||
import os
|
||||
import re
|
||||
@@ -381,7 +381,7 @@ class ImportHandle(BaseHandle):
|
||||
# 治本修复:使用 file_module_name(源模块名)而非 module_name(可能是别名/类名)。
|
||||
# 这样 _EmitExternalClassDeclLlvm 内的 ModuleSha1Map 查找才能命中,
|
||||
# _EmitExternalFuncDeclLlvm 才能拿到正确的 source_module_name → 正确的 struct sha1。
|
||||
# 注意:actual_module_name 保持原值(可能为 None),不回退到 module_name(可能是别名)
|
||||
# 注意:actual_module_name 保持原值(可能为 None),不回退到 module_name(可能是别名)
|
||||
self._EmitExternalClassDeclLlvm(node, Gen, module_name=file_module_name, actual_module_name=actual_module_name)
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
if node.level > 0:
|
||||
|
||||
+419
-419
@@ -1,420 +1,420 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class MatchHandle(BaseHandle):
|
||||
def _HandleMatchLlvm(self, Node: ast.Match) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject)
|
||||
if not SubjectVal:
|
||||
return
|
||||
|
||||
IsRenumMatch: bool = False
|
||||
RenumName: str | None = None
|
||||
SubjectPtr: ir.Value | None = None
|
||||
if isinstance(Node.subject, ast.Name):
|
||||
VarName: str = Node.subject.id
|
||||
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName)
|
||||
if TypeInfo and TypeInfo.IsRenum:
|
||||
IsRenumMatch = True
|
||||
RenumName = TypeInfo.Name
|
||||
SubjectPtr = Gen._Load_var(VarName)
|
||||
|
||||
if not IsRenumMatch:
|
||||
for case in Node.cases:
|
||||
if isinstance(case.pattern, ast.MatchClass):
|
||||
cls_node: ast.expr = case.pattern.cls
|
||||
VariantName: str | None = None
|
||||
QualifiedName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
# Extract enum name for qualified lookup to avoid collision
|
||||
# with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr)
|
||||
if isinstance(cls_node.value, ast.Attribute):
|
||||
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
|
||||
elif isinstance(cls_node.value, ast.Name):
|
||||
QualifiedName = f"{cls_node.value.id}.{VariantName}"
|
||||
if VariantName:
|
||||
# Try qualified name first (e.g., "LLVMType.Ptr") to avoid
|
||||
# collision with same-name functions (e.g., def Ptr(...))
|
||||
SymInfo: "SymbolTable.SymbolInfo" = None
|
||||
if QualifiedName:
|
||||
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
|
||||
if not (SymInfo and SymInfo.IsEnumMember):
|
||||
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
|
||||
if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName:
|
||||
EnumName: str = SymInfo.EnumName
|
||||
EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName)
|
||||
if EnumInfo and EnumInfo.IsRenum:
|
||||
IsRenumMatch = True
|
||||
RenumName = EnumName
|
||||
if SubjectPtr is None:
|
||||
SubjectPtr = self.HandleExprLlvm(Node.subject)
|
||||
break
|
||||
|
||||
if IsRenumMatch and SubjectPtr:
|
||||
self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr)
|
||||
return
|
||||
|
||||
if not isinstance(SubjectVal.type, ir.IntType):
|
||||
try:
|
||||
SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj")
|
||||
SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32")
|
||||
except Exception: # 回退:ptrtoint 失败时直接返回
|
||||
return
|
||||
SwitchIntType: ir.IntType = SubjectVal.type
|
||||
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
|
||||
CaseBBs: list[ir.Block] = []
|
||||
CaseValues: list[ir.Value] = []
|
||||
HasDefault: bool = False
|
||||
HasNoBreak: list[bool] = []
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
if Val.type != SwitchIntType:
|
||||
if Val.type.width > SwitchIntType.width:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
|
||||
else:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant)
|
||||
else:
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(SwitchIntType, 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
elif isinstance(pattern, ast.MatchOr):
|
||||
for j, SubPattern in enumerate(pattern.patterns):
|
||||
if isinstance(SubPattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
if Val.type != SwitchIntType:
|
||||
if Val.type.width > SwitchIntType.width:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
|
||||
else:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant)
|
||||
else:
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(SwitchIntType, 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}"))
|
||||
elif isinstance(pattern, ast.MatchSingleton):
|
||||
if pattern.value is None:
|
||||
CaseValues.append(ir.Constant(SwitchIntType, 0))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
elif isinstance(pattern, ast.MatchClass):
|
||||
# 兜底处理:REnum 检测失败但 case 是 MatchClass(REnum 变体模式)
|
||||
# 尝试从变体名查找 tag 值,按整数值处理
|
||||
cls_node_mc: ast.expr = pattern.cls
|
||||
VariantName_mc: str | None = None
|
||||
QualifiedName_mc: str | None = None
|
||||
if isinstance(cls_node_mc, ast.Name):
|
||||
VariantName_mc = cls_node_mc.id
|
||||
elif isinstance(cls_node_mc, ast.Attribute):
|
||||
VariantName_mc = cls_node_mc.attr
|
||||
if isinstance(cls_node_mc.value, ast.Attribute):
|
||||
QualifiedName_mc = f"{cls_node_mc.value.attr}.{VariantName_mc}"
|
||||
elif isinstance(cls_node_mc.value, ast.Name):
|
||||
QualifiedName_mc = f"{cls_node_mc.value.id}.{VariantName_mc}"
|
||||
TagValue_mc: int | None = None
|
||||
SymInfo_mc: "SymbolTable.SymbolInfo" = None
|
||||
if QualifiedName_mc:
|
||||
SymInfo_mc = self.Trans.SymbolTable.lookup(QualifiedName_mc)
|
||||
if not (SymInfo_mc and SymInfo_mc.IsEnumMember):
|
||||
SymInfo_mc = self.Trans.SymbolTable.lookup(VariantName_mc)
|
||||
if SymInfo_mc and SymInfo_mc.IsEnumMember:
|
||||
TagValue_mc = SymInfo_mc.value
|
||||
if TagValue_mc is not None:
|
||||
CaseValues.append(ir.Constant(SwitchIntType, TagValue_mc))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{VariantName_mc}"))
|
||||
else:
|
||||
# 变体名未找到,跳过此 case(fast-fail 已在外层处理)
|
||||
pass
|
||||
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
|
||||
for stmt in stmts:
|
||||
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
|
||||
if isinstance(stmt.value.func, ast.Attribute):
|
||||
if (isinstance(stmt.value.func.value, ast.Name) and
|
||||
stmt.value.func.value.id == 'c' and
|
||||
stmt.value.func.attr == 'NoBreak'):
|
||||
return True
|
||||
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
|
||||
if _HasNoBreak(stmt.body):
|
||||
return True
|
||||
if getattr(stmt, 'orelse', None):
|
||||
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
|
||||
return True
|
||||
return False
|
||||
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
|
||||
if not HasDefault:
|
||||
CaseBBs.append(DefaultBB)
|
||||
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
|
||||
switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB)
|
||||
for val, bb in SwitchCases:
|
||||
switch_instr.add_case(val, bb)
|
||||
CaseIdx: int = 0
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchOr):
|
||||
NumSubCases: int = len(pattern.patterns)
|
||||
for j in range(NumSubCases):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchClass):
|
||||
# 兜底处理:MatchClass 在非 REnum 路径的 case body 生成
|
||||
# case 收集阶段已创建 CaseBB,此处生成 body
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
if not HasDefault:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
|
||||
def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
|
||||
SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj")
|
||||
# Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。
|
||||
# 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store
|
||||
# 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast
|
||||
NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType)
|
||||
NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and
|
||||
not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)))
|
||||
if NeedAlloca or NeedBitcast:
|
||||
RenumStructType: Any = Gen.structs.get(RenumName)
|
||||
if RenumStructType is None:
|
||||
# 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册
|
||||
# (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。
|
||||
# 使用 _get_or_create_struct 按需创建(可能为 opaque)。
|
||||
RenumStructType = Gen._get_or_create_struct(RenumName)
|
||||
if NeedAlloca:
|
||||
AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca")
|
||||
CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast")
|
||||
Gen._store(SubjectPtr, CastedPtr)
|
||||
SubjectPtr = AllocaPtr
|
||||
else:
|
||||
SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast")
|
||||
# REnum 布局为 { i32 __tag, <payload> },tag 在偏移 0。
|
||||
# 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体
|
||||
# (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。
|
||||
tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr")
|
||||
TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val")
|
||||
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
|
||||
CaseBBs: list[ir.Block] = []
|
||||
CaseValues: list[ir.Value] = []
|
||||
CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = []
|
||||
HasDefault: bool = False
|
||||
HasNoBreak: list[bool] = []
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
bindings: list[tuple[str, str, ir.Type, int]] = []
|
||||
if isinstance(pattern, ast.MatchClass):
|
||||
cls_node: ast.expr = pattern.cls
|
||||
VariantName: str | None = None
|
||||
QualifiedName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
if isinstance(cls_node.value, ast.Attribute):
|
||||
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
|
||||
elif isinstance(cls_node.value, ast.Name):
|
||||
QualifiedName = f"{cls_node.value.id}.{VariantName}"
|
||||
if VariantName:
|
||||
TagValue: int | None = None
|
||||
SymInfo: "SymbolTable.SymbolInfo" = None
|
||||
if QualifiedName:
|
||||
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
|
||||
if not (SymInfo and SymInfo.IsEnumMember):
|
||||
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
|
||||
if SymInfo and SymInfo.IsEnumMember:
|
||||
TagValue = SymInfo.value
|
||||
if TagValue is not None:
|
||||
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
|
||||
CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
|
||||
CaseBBs.append(CaseBB)
|
||||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||||
if NestedStructName in Gen.structs:
|
||||
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
|
||||
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
|
||||
for j, sub_pat in enumerate(pattern.patterns):
|
||||
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
|
||||
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
|
||||
CaseBindings.append(bindings)
|
||||
else:
|
||||
CaseValues.append(ir.Constant(ir.IntType(32), 0))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(ir.IntType(32), 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
CaseBindings.append([])
|
||||
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
|
||||
for stmt in stmts:
|
||||
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
|
||||
if isinstance(stmt.value.func, ast.Attribute):
|
||||
if (isinstance(stmt.value.func.value, ast.Name) and
|
||||
stmt.value.func.value.id == 'c' and
|
||||
stmt.value.func.attr == 'NoBreak'):
|
||||
return True
|
||||
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
|
||||
if _HasNoBreak(stmt.body):
|
||||
return True
|
||||
if getattr(stmt, 'orelse', None):
|
||||
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
|
||||
return True
|
||||
return False
|
||||
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
|
||||
if not HasDefault:
|
||||
CaseBBs.append(DefaultBB)
|
||||
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
|
||||
switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB)
|
||||
for val, bb in SwitchCases:
|
||||
switch_instr.add_case(val, bb)
|
||||
CaseIdx: int = 0
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchClass):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
|
||||
cls_node: ast.expr = pattern.cls
|
||||
VariantName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
if VariantName:
|
||||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||||
if NestedStructName in Gen.structs:
|
||||
NestedStructType: ir.Type = Gen.structs[NestedStructName]
|
||||
NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType)
|
||||
variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
|
||||
for bind_name, member_name, member_type, member_idx in bindings:
|
||||
elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
|
||||
# REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与
|
||||
# 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。
|
||||
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
|
||||
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast")
|
||||
Gen.variables[bind_name] = elem_ptr
|
||||
self.HandleBodyLlvm(case.body)
|
||||
for bind_name, _, _, _ in bindings:
|
||||
if bind_name in Gen.variables:
|
||||
del Gen.variables[bind_name]
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchValue):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
if not HasDefault:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class MatchHandle(BaseHandle):
|
||||
def _HandleMatchLlvm(self, Node: ast.Match) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject)
|
||||
if not SubjectVal:
|
||||
return
|
||||
|
||||
IsRenumMatch: bool = False
|
||||
RenumName: str | None = None
|
||||
SubjectPtr: ir.Value | None = None
|
||||
if isinstance(Node.subject, ast.Name):
|
||||
VarName: str = Node.subject.id
|
||||
TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName)
|
||||
if TypeInfo and TypeInfo.IsRenum:
|
||||
IsRenumMatch = True
|
||||
RenumName = TypeInfo.Name
|
||||
SubjectPtr = Gen._Load_var(VarName)
|
||||
|
||||
if not IsRenumMatch:
|
||||
for case in Node.cases:
|
||||
if isinstance(case.pattern, ast.MatchClass):
|
||||
cls_node: ast.expr = case.pattern.cls
|
||||
VariantName: str | None = None
|
||||
QualifiedName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
# Extract enum name for qualified lookup to avoid collision
|
||||
# with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr)
|
||||
if isinstance(cls_node.value, ast.Attribute):
|
||||
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
|
||||
elif isinstance(cls_node.value, ast.Name):
|
||||
QualifiedName = f"{cls_node.value.id}.{VariantName}"
|
||||
if VariantName:
|
||||
# Try qualified name first (e.g., "LLVMType.Ptr") to avoid
|
||||
# collision with same-name functions (e.g., def Ptr(...))
|
||||
SymInfo: "SymbolTable.SymbolInfo" = None
|
||||
if QualifiedName:
|
||||
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
|
||||
if not (SymInfo and SymInfo.IsEnumMember):
|
||||
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
|
||||
if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName:
|
||||
EnumName: str = SymInfo.EnumName
|
||||
EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName)
|
||||
if EnumInfo and EnumInfo.IsRenum:
|
||||
IsRenumMatch = True
|
||||
RenumName = EnumName
|
||||
if SubjectPtr is None:
|
||||
SubjectPtr = self.HandleExprLlvm(Node.subject)
|
||||
break
|
||||
|
||||
if IsRenumMatch and SubjectPtr:
|
||||
self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr)
|
||||
return
|
||||
|
||||
if not isinstance(SubjectVal.type, ir.IntType):
|
||||
try:
|
||||
SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj")
|
||||
SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32")
|
||||
except Exception: # 回退:ptrtoint 失败时直接返回
|
||||
return
|
||||
SwitchIntType: ir.IntType = SubjectVal.type
|
||||
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
|
||||
CaseBBs: list[ir.Block] = []
|
||||
CaseValues: list[ir.Value] = []
|
||||
HasDefault: bool = False
|
||||
HasNoBreak: list[bool] = []
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
if Val.type != SwitchIntType:
|
||||
if Val.type.width > SwitchIntType.width:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
|
||||
else:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant)
|
||||
else:
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(SwitchIntType, 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
elif isinstance(pattern, ast.MatchOr):
|
||||
for j, SubPattern in enumerate(pattern.patterns):
|
||||
if isinstance(SubPattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
if Val.type != SwitchIntType:
|
||||
if Val.type.width > SwitchIntType.width:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1))
|
||||
else:
|
||||
CaseVal = ir.Constant(SwitchIntType, Val.constant)
|
||||
else:
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(SwitchIntType, 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}"))
|
||||
elif isinstance(pattern, ast.MatchSingleton):
|
||||
if pattern.value is None:
|
||||
CaseValues.append(ir.Constant(SwitchIntType, 0))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
elif isinstance(pattern, ast.MatchClass):
|
||||
# 兜底处理:REnum 检测失败但 case 是 MatchClass(REnum 变体模式)
|
||||
# 尝试从变体名查找 tag 值,按整数值处理
|
||||
cls_node_mc: ast.expr = pattern.cls
|
||||
VariantName_mc: str | None = None
|
||||
QualifiedName_mc: str | None = None
|
||||
if isinstance(cls_node_mc, ast.Name):
|
||||
VariantName_mc = cls_node_mc.id
|
||||
elif isinstance(cls_node_mc, ast.Attribute):
|
||||
VariantName_mc = cls_node_mc.attr
|
||||
if isinstance(cls_node_mc.value, ast.Attribute):
|
||||
QualifiedName_mc = f"{cls_node_mc.value.attr}.{VariantName_mc}"
|
||||
elif isinstance(cls_node_mc.value, ast.Name):
|
||||
QualifiedName_mc = f"{cls_node_mc.value.id}.{VariantName_mc}"
|
||||
TagValue_mc: int | None = None
|
||||
SymInfo_mc: "SymbolTable.SymbolInfo" = None
|
||||
if QualifiedName_mc:
|
||||
SymInfo_mc = self.Trans.SymbolTable.lookup(QualifiedName_mc)
|
||||
if not (SymInfo_mc and SymInfo_mc.IsEnumMember):
|
||||
SymInfo_mc = self.Trans.SymbolTable.lookup(VariantName_mc)
|
||||
if SymInfo_mc and SymInfo_mc.IsEnumMember:
|
||||
TagValue_mc = SymInfo_mc.value
|
||||
if TagValue_mc is not None:
|
||||
CaseValues.append(ir.Constant(SwitchIntType, TagValue_mc))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{VariantName_mc}"))
|
||||
else:
|
||||
# 变体名未找到,跳过此 case(fast-fail 已在外层处理)
|
||||
pass
|
||||
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
|
||||
for stmt in stmts:
|
||||
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
|
||||
if isinstance(stmt.value.func, ast.Attribute):
|
||||
if (isinstance(stmt.value.func.value, ast.Name) and
|
||||
stmt.value.func.value.id == 'c' and
|
||||
stmt.value.func.attr == 'NoBreak'):
|
||||
return True
|
||||
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
|
||||
if _HasNoBreak(stmt.body):
|
||||
return True
|
||||
if getattr(stmt, 'orelse', None):
|
||||
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
|
||||
return True
|
||||
return False
|
||||
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
|
||||
if not HasDefault:
|
||||
CaseBBs.append(DefaultBB)
|
||||
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
|
||||
switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB)
|
||||
for val, bb in SwitchCases:
|
||||
switch_instr.add_case(val, bb)
|
||||
CaseIdx: int = 0
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchOr):
|
||||
NumSubCases: int = len(pattern.patterns)
|
||||
for j in range(NumSubCases):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchClass):
|
||||
# 兜底处理:MatchClass 在非 REnum 路径的 case body 生成
|
||||
# case 收集阶段已创建 CaseBB,此处生成 body
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
if not HasDefault:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
|
||||
def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
|
||||
SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj")
|
||||
# Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。
|
||||
# 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store
|
||||
# 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast
|
||||
NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType)
|
||||
NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and
|
||||
not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)))
|
||||
if NeedAlloca or NeedBitcast:
|
||||
RenumStructType: Any = Gen.structs.get(RenumName)
|
||||
if RenumStructType is None:
|
||||
# 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册
|
||||
# (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。
|
||||
# 使用 _get_or_create_struct 按需创建(可能为 opaque)。
|
||||
RenumStructType = Gen._get_or_create_struct(RenumName)
|
||||
if NeedAlloca:
|
||||
AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca")
|
||||
CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast")
|
||||
Gen._store(SubjectPtr, CastedPtr)
|
||||
SubjectPtr = AllocaPtr
|
||||
else:
|
||||
SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast")
|
||||
# REnum 布局为 { i32 __tag, <payload> },tag 在偏移 0。
|
||||
# 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体
|
||||
# (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。
|
||||
tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr")
|
||||
TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val")
|
||||
DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end")
|
||||
CaseBBs: list[ir.Block] = []
|
||||
CaseValues: list[ir.Value] = []
|
||||
CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = []
|
||||
HasDefault: bool = False
|
||||
HasNoBreak: list[bool] = []
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
bindings: list[tuple[str, str, ir.Type, int]] = []
|
||||
if isinstance(pattern, ast.MatchClass):
|
||||
cls_node: ast.expr = pattern.cls
|
||||
VariantName: str | None = None
|
||||
QualifiedName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
if isinstance(cls_node.value, ast.Attribute):
|
||||
QualifiedName = f"{cls_node.value.attr}.{VariantName}"
|
||||
elif isinstance(cls_node.value, ast.Name):
|
||||
QualifiedName = f"{cls_node.value.id}.{VariantName}"
|
||||
if VariantName:
|
||||
TagValue: int | None = None
|
||||
SymInfo: "SymbolTable.SymbolInfo" = None
|
||||
if QualifiedName:
|
||||
SymInfo = self.Trans.SymbolTable.lookup(QualifiedName)
|
||||
if not (SymInfo and SymInfo.IsEnumMember):
|
||||
SymInfo = self.Trans.SymbolTable.lookup(VariantName)
|
||||
if SymInfo and SymInfo.IsEnumMember:
|
||||
TagValue = SymInfo.value
|
||||
if TagValue is not None:
|
||||
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
|
||||
CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
|
||||
CaseBBs.append(CaseBB)
|
||||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||||
if NestedStructName in Gen.structs:
|
||||
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
|
||||
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
|
||||
for j, sub_pat in enumerate(pattern.patterns):
|
||||
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
|
||||
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
|
||||
CaseBindings.append(bindings)
|
||||
else:
|
||||
CaseValues.append(ir.Constant(ir.IntType(32), 0))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchValue):
|
||||
Val: ir.Value | None = self.HandleExprLlvm(pattern.value)
|
||||
if Val:
|
||||
CaseVal: ir.Value
|
||||
if isinstance(Val.type, ir.IntType):
|
||||
CaseVal = Val
|
||||
else:
|
||||
try:
|
||||
CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}")
|
||||
except Exception: # 回退:ptrtoint 失败时设默认值 0
|
||||
CaseVal = ir.Constant(ir.IntType(32), 0)
|
||||
CaseValues.append(CaseVal)
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}"))
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
CaseBindings.append([])
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
HasDefault = True
|
||||
CaseBBs.append(DefaultBB)
|
||||
CaseBindings.append([])
|
||||
def _HasNoBreak(stmts: list[ast.stmt]) -> bool:
|
||||
for stmt in stmts:
|
||||
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
|
||||
if isinstance(stmt.value.func, ast.Attribute):
|
||||
if (isinstance(stmt.value.func.value, ast.Name) and
|
||||
stmt.value.func.value.id == 'c' and
|
||||
stmt.value.func.attr == 'NoBreak'):
|
||||
return True
|
||||
if getattr(stmt, 'body', None) and isinstance(stmt.body, list):
|
||||
if _HasNoBreak(stmt.body):
|
||||
return True
|
||||
if getattr(stmt, 'orelse', None):
|
||||
if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse):
|
||||
return True
|
||||
return False
|
||||
HasNoBreak.append(_HasNoBreak(case.body) if case.body else False)
|
||||
if not HasDefault:
|
||||
CaseBBs.append(DefaultBB)
|
||||
SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB]
|
||||
switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB)
|
||||
for val, bb in SwitchCases:
|
||||
switch_instr.add_case(val, bb)
|
||||
CaseIdx: int = 0
|
||||
for i, case in enumerate(Node.cases):
|
||||
pattern: ast.pattern = case.pattern
|
||||
if isinstance(pattern, ast.MatchClass):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else []
|
||||
cls_node: ast.expr = pattern.cls
|
||||
VariantName: str | None = None
|
||||
if isinstance(cls_node, ast.Name):
|
||||
VariantName = cls_node.id
|
||||
elif isinstance(cls_node, ast.Attribute):
|
||||
VariantName = cls_node.attr
|
||||
if VariantName:
|
||||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||||
if NestedStructName in Gen.structs:
|
||||
NestedStructType: ir.Type = Gen.structs[NestedStructName]
|
||||
NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType)
|
||||
variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}")
|
||||
for bind_name, member_name, member_type, member_idx in bindings:
|
||||
elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}")
|
||||
# REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与
|
||||
# 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。
|
||||
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
|
||||
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast")
|
||||
Gen.variables[bind_name] = elem_ptr
|
||||
self.HandleBodyLlvm(case.body)
|
||||
for bind_name, _, _, _ in bindings:
|
||||
if bind_name in Gen.variables:
|
||||
del Gen.variables[bind_name]
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchValue):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
CaseIdx += 1
|
||||
if not HasDefault:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
+154
-154
@@ -1,155 +1,155 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
from lib.constants.config import mode as _config_mode
|
||||
|
||||
|
||||
class RaiseHandle(BaseHandle):
|
||||
def _get_exception_code(self, ExcName: str) -> int:
|
||||
if ExcName in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[ExcName]
|
||||
if ExcName in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[ExcName]
|
||||
return 1
|
||||
|
||||
def _HandleRaiseLlvm(self, Node: ast.Raise) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1)
|
||||
exc_msg: ir.Value | None = None
|
||||
IsStopIteration: bool = False
|
||||
if Node.exc:
|
||||
if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int):
|
||||
exc_val = ir.Constant(ir.IntType(32), Node.exc.value)
|
||||
elif isinstance(Node.exc, ast.Name):
|
||||
ExcName: str = Node.exc.id
|
||||
if ExcName == 'StopIteration':
|
||||
IsStopIteration = True
|
||||
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
|
||||
elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name):
|
||||
ExcName: str = Node.exc.func.id
|
||||
if ExcName == 'StopIteration':
|
||||
IsStopIteration = True
|
||||
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
|
||||
if Node.exc.args:
|
||||
first_arg: ast.expr = Node.exc.args[0]
|
||||
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(first_arg)
|
||||
elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)):
|
||||
arg_val: ir.Value | None = self.HandleExprLlvm(first_arg)
|
||||
if arg_val:
|
||||
if isinstance(arg_val.type, ir.PointerType):
|
||||
if self._is_char_pointer(arg_val):
|
||||
exc_msg = arg_val
|
||||
else:
|
||||
try:
|
||||
exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast")
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
else:
|
||||
try:
|
||||
exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr")
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
else:
|
||||
val: ir.Value | None = self.HandleExprLlvm(Node.exc)
|
||||
if val:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width != 32:
|
||||
try:
|
||||
val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc")
|
||||
except Exception: # 回退:trunc 失败时设默认值 1
|
||||
val = ir.Constant(ir.IntType(32), 1)
|
||||
exc_val = val
|
||||
else:
|
||||
try:
|
||||
val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int")
|
||||
exc_val = val
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
if IsStopIteration:
|
||||
if Gen._stop_iter_flag_param is not None:
|
||||
Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param)
|
||||
if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType():
|
||||
ret_type: ir.Type = Gen.func.type.pointee.return_type
|
||||
if isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
return
|
||||
if Gen.eh_except_block_stack:
|
||||
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
|
||||
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
|
||||
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
|
||||
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
|
||||
Gen._store(exc_val, exception_code)
|
||||
if exc_msg:
|
||||
Gen._store(exc_msg, eh_message)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen._store(null_ptr, eh_message)
|
||||
if Gen.func and ExceptBB and ExceptBB.function is Gen.func:
|
||||
Gen.builder.branch(ExceptBB)
|
||||
else:
|
||||
eh_msg_arg: ir.Argument | None = None
|
||||
eh_code_arg: ir.Argument | None = None
|
||||
if Gen.func:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_arg = arg
|
||||
if eh_msg_arg is not None:
|
||||
if exc_msg:
|
||||
Gen.builder.store(exc_msg, eh_msg_arg)
|
||||
else:
|
||||
null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen.builder.store(null_ptr, eh_msg_arg)
|
||||
if eh_code_arg is not None:
|
||||
Gen.builder.store(exc_val, eh_code_arg)
|
||||
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
else:
|
||||
eh_msg_arg: ir.Argument | None = None
|
||||
eh_code_arg: ir.Argument | None = None
|
||||
if Gen.func:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_arg = arg
|
||||
if eh_msg_arg is not None:
|
||||
if exc_msg:
|
||||
Gen.builder.store(exc_msg, eh_msg_arg)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen.builder.store(null_ptr, eh_msg_arg)
|
||||
if eh_code_arg is not None:
|
||||
Gen.builder.store(exc_val, eh_code_arg)
|
||||
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
from lib.constants.config import mode as _config_mode
|
||||
|
||||
|
||||
class RaiseHandle(BaseHandle):
|
||||
def _get_exception_code(self, ExcName: str) -> int:
|
||||
if ExcName in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[ExcName]
|
||||
if ExcName in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[ExcName]
|
||||
return 1
|
||||
|
||||
def _HandleRaiseLlvm(self, Node: ast.Raise) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1)
|
||||
exc_msg: ir.Value | None = None
|
||||
IsStopIteration: bool = False
|
||||
if Node.exc:
|
||||
if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int):
|
||||
exc_val = ir.Constant(ir.IntType(32), Node.exc.value)
|
||||
elif isinstance(Node.exc, ast.Name):
|
||||
ExcName: str = Node.exc.id
|
||||
if ExcName == 'StopIteration':
|
||||
IsStopIteration = True
|
||||
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
|
||||
elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name):
|
||||
ExcName: str = Node.exc.func.id
|
||||
if ExcName == 'StopIteration':
|
||||
IsStopIteration = True
|
||||
exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName))
|
||||
if Node.exc.args:
|
||||
first_arg: ast.expr = Node.exc.args[0]
|
||||
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||||
exc_msg = self.HandleExprLlvm(first_arg)
|
||||
elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)):
|
||||
arg_val: ir.Value | None = self.HandleExprLlvm(first_arg)
|
||||
if arg_val:
|
||||
if isinstance(arg_val.type, ir.PointerType):
|
||||
if self._is_char_pointer(arg_val):
|
||||
exc_msg = arg_val
|
||||
else:
|
||||
try:
|
||||
exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast")
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
else:
|
||||
try:
|
||||
exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr")
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
else:
|
||||
val: ir.Value | None = self.HandleExprLlvm(Node.exc)
|
||||
if val:
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width != 32:
|
||||
try:
|
||||
val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc")
|
||||
except Exception: # 回退:trunc 失败时设默认值 1
|
||||
val = ir.Constant(ir.IntType(32), 1)
|
||||
exc_val = val
|
||||
else:
|
||||
try:
|
||||
val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int")
|
||||
exc_val = val
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
if IsStopIteration:
|
||||
if Gen._stop_iter_flag_param is not None:
|
||||
Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param)
|
||||
if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType():
|
||||
ret_type: ir.Type = Gen.func.type.pointee.return_type
|
||||
if isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
return
|
||||
if Gen.eh_except_block_stack:
|
||||
ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0]
|
||||
EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1]
|
||||
exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2]
|
||||
eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3]
|
||||
Gen._store(exc_val, exception_code)
|
||||
if exc_msg:
|
||||
Gen._store(exc_msg, eh_message)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen._store(null_ptr, eh_message)
|
||||
if Gen.func and ExceptBB and ExceptBB.function is Gen.func:
|
||||
Gen.builder.branch(ExceptBB)
|
||||
else:
|
||||
eh_msg_arg: ir.Argument | None = None
|
||||
eh_code_arg: ir.Argument | None = None
|
||||
if Gen.func:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_arg = arg
|
||||
if eh_msg_arg is not None:
|
||||
if exc_msg:
|
||||
Gen.builder.store(exc_msg, eh_msg_arg)
|
||||
else:
|
||||
null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen.builder.store(null_ptr, eh_msg_arg)
|
||||
if eh_code_arg is not None:
|
||||
Gen.builder.store(exc_val, eh_code_arg)
|
||||
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
else:
|
||||
eh_msg_arg: ir.Argument | None = None
|
||||
eh_code_arg: ir.Argument | None = None
|
||||
if Gen.func:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_arg = arg
|
||||
if eh_msg_arg is not None:
|
||||
if exc_msg:
|
||||
Gen.builder.store(exc_msg, eh_msg_arg)
|
||||
else:
|
||||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||||
Gen.builder.store(null_ptr, eh_msg_arg)
|
||||
if eh_code_arg is not None:
|
||||
Gen.builder.store(exc_val, eh_code_arg)
|
||||
if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32):
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
+227
-227
@@ -1,228 +1,228 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
|
||||
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*"""
|
||||
if isinstance(ty, ir.PointerType):
|
||||
cur: ir.Type = ty
|
||||
while isinstance(cur, ir.PointerType):
|
||||
if isinstance(cur.pointee, ir.VoidType):
|
||||
return ir.IntType(8).as_pointer()
|
||||
cur = cur.pointee
|
||||
return ty
|
||||
|
||||
|
||||
class ReturnHandle(BaseHandle):
|
||||
def _find_active_finally(self, Gen: "Translator.LlvmGen") -> tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None:
|
||||
for item in reversed(Gen.eh_finally_stack):
|
||||
if item is not None and item[0] is not None:
|
||||
return item
|
||||
return None
|
||||
|
||||
def _HandleReturnLlvm(self, Node: ast.Return) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
# 闭包返回检测:当返回值是带 nonlocal 参数的嵌套函数时,创建闭包结构体
|
||||
# 闭包结构体 {i8* env, i8* fn} 在堆上分配,env 指向 nonlocal 变量的堆存储
|
||||
if Node.value and isinstance(Node.value, ast.Name):
|
||||
ret_name: str = Node.value.id
|
||||
if ret_name in Gen.nonlocal_params and ret_name in Gen.functions:
|
||||
nested_fn: ir.Function = Gen.functions[ret_name]
|
||||
nonlocal_params: list[tuple[str, ir.Type]] = Gen.nonlocal_params[ret_name]
|
||||
fn_return_type: ir.Type = nested_fn.function_type.return_type
|
||||
nonlocal_types: list[ir.Type] = [_safe_ptr_type(t) for _, t in nonlocal_params]
|
||||
# 构建 env:收集所有 nonlocal 变量指针
|
||||
env_ptrs: list[ir.Value] = []
|
||||
for var_name, _ in nonlocal_params:
|
||||
vp: ir.Value | None = Gen.variables.get(var_name)
|
||||
if vp is not None:
|
||||
env_ptrs.append(vp)
|
||||
if env_ptrs:
|
||||
# env 值:单个指针直接用,多个指针打包成结构体
|
||||
i8_ptr_type: ir.PointerType = ir.IntType(8).as_pointer()
|
||||
if len(env_ptrs) == 1:
|
||||
env_val: ir.Value = Gen.builder.bitcast(env_ptrs[0], i8_ptr_type, name="closure_env")
|
||||
else:
|
||||
env_struct_type: ir.LiteralStructType = ir.LiteralStructType([p.type for p in env_ptrs])
|
||||
env_size: int = len(env_ptrs) * 8
|
||||
malloc_type: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)])
|
||||
malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type)
|
||||
env_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), env_size)], name="env_struct_raw")
|
||||
env_struct_ptr: ir.Value = Gen.builder.bitcast(env_raw, ir.PointerType(env_struct_type), name="env_struct_ptr")
|
||||
for i, ptr in enumerate(env_ptrs):
|
||||
gep: ir.Value = Gen.builder.gep(env_struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"env_field_{i}")
|
||||
Gen._store(ptr, gep)
|
||||
env_val = Gen.builder.bitcast(env_struct_ptr, i8_ptr_type, name="closure_env")
|
||||
# fn 指针
|
||||
fn_ptr: ir.Value = Gen.builder.bitcast(nested_fn, i8_ptr_type, name="closure_fn")
|
||||
# 创建闭包结构体 {i8* env, i8* fn}
|
||||
closure_type: ir.LiteralStructType = ir.LiteralStructType([i8_ptr_type, i8_ptr_type])
|
||||
malloc_type2: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)])
|
||||
malloc_func2: ir.Function = Gen._get_or_declare_func('malloc', malloc_type2)
|
||||
closure_raw: ir.Value = Gen.builder.call(malloc_func2, [ir.Constant(ir.IntType(64), 16)], name="closure_raw")
|
||||
closure_ptr: ir.Value = Gen.builder.bitcast(closure_raw, ir.PointerType(closure_type), name="closure_ptr")
|
||||
# 填充闭包结构体
|
||||
env_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="closure_env_slot")
|
||||
Gen._store(env_val, env_gep)
|
||||
fn_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name="closure_fn_slot")
|
||||
Gen._store(fn_ptr, fn_gep)
|
||||
# 记录闭包返回类型
|
||||
current_name: str = Gen.func.name if Gen.func else ''
|
||||
short_name: str = current_name.split('.', 1)[1] if '.' in current_name else current_name
|
||||
Gen._closure_return_types[short_name] = (fn_return_type, nonlocal_types)
|
||||
# 返回闭包结构体指针(bitcast 到 i8*)
|
||||
closure_ret: ir.Value = Gen.builder.bitcast(closure_ptr, i8_ptr_type, name="closure_ret")
|
||||
Gen.emit_return(closure_ret)
|
||||
return
|
||||
active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen)
|
||||
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value:
|
||||
return_values: list[ast.expr] = []
|
||||
if isinstance(Node.value, ast.Tuple):
|
||||
return_values = Node.value.elts
|
||||
else:
|
||||
return_values = [Node.value]
|
||||
if len(return_values) == len(self.Trans.CurrentCReturnTypes):
|
||||
llvm_vals: list[ir.Value] = []
|
||||
expected_types: list[ir.Type] = []
|
||||
for i, val in enumerate(return_values):
|
||||
ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable)
|
||||
IsRetPtr: bool = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
|
||||
if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'):
|
||||
IsRetPtr = True
|
||||
ExpectedType: ir.Type = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr)
|
||||
expected_types.append(ExpectedType)
|
||||
Val: ir.Value | None = self.HandleExprLlvm(val)
|
||||
if Val is None:
|
||||
if isinstance(ExpectedType, ir.PointerType):
|
||||
Val = ir.Constant(ExpectedType, None)
|
||||
elif isinstance(ExpectedType, ir.IntType):
|
||||
Val = ir.Constant(ExpectedType, 0)
|
||||
else:
|
||||
Val = ir.Constant(ExpectedType, ir.Undefined)
|
||||
else:
|
||||
if Val.type != ExpectedType:
|
||||
if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < ExpectedType.width:
|
||||
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
|
||||
elif Val.type.width > ExpectedType.width:
|
||||
Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}")
|
||||
elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType):
|
||||
Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}")
|
||||
llvm_vals.append(Val)
|
||||
if llvm_vals:
|
||||
struct_type: ir.LiteralStructType = ir.LiteralStructType(expected_types)
|
||||
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
|
||||
for i, val in enumerate(llvm_vals):
|
||||
result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}")
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(result, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(result)
|
||||
return
|
||||
if Node.value:
|
||||
Val: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if Val:
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None:
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(zero_val, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(zero_val)
|
||||
return
|
||||
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes:
|
||||
struct_type: ir.Type = Gen.func.ftype.return_type
|
||||
if isinstance(struct_type, ir.LiteralStructType):
|
||||
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
|
||||
if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType):
|
||||
result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0")
|
||||
for j in range(1, len(struct_type.elements)):
|
||||
elem_type: ir.Type = struct_type.elements[j]
|
||||
zero_val: ir.Constant = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
for j, elem_type in enumerate(struct_type.elements):
|
||||
if j == 0:
|
||||
if Val.type == elem_type:
|
||||
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
|
||||
elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < elem_type.width:
|
||||
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
|
||||
elif Val.type.width > elem_type.width:
|
||||
Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}")
|
||||
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(result, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(result)
|
||||
return
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(Val, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(Val)
|
||||
else:
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
elif isinstance(ret_type, ir.ArrayType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
else:
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
|
||||
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*"""
|
||||
if isinstance(ty, ir.PointerType):
|
||||
cur: ir.Type = ty
|
||||
while isinstance(cur, ir.PointerType):
|
||||
if isinstance(cur.pointee, ir.VoidType):
|
||||
return ir.IntType(8).as_pointer()
|
||||
cur = cur.pointee
|
||||
return ty
|
||||
|
||||
|
||||
class ReturnHandle(BaseHandle):
|
||||
def _find_active_finally(self, Gen: "Translator.LlvmGen") -> tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None:
|
||||
for item in reversed(Gen.eh_finally_stack):
|
||||
if item is not None and item[0] is not None:
|
||||
return item
|
||||
return None
|
||||
|
||||
def _HandleReturnLlvm(self, Node: ast.Return) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
# 闭包返回检测:当返回值是带 nonlocal 参数的嵌套函数时,创建闭包结构体
|
||||
# 闭包结构体 {i8* env, i8* fn} 在堆上分配,env 指向 nonlocal 变量的堆存储
|
||||
if Node.value and isinstance(Node.value, ast.Name):
|
||||
ret_name: str = Node.value.id
|
||||
if ret_name in Gen.nonlocal_params and ret_name in Gen.functions:
|
||||
nested_fn: ir.Function = Gen.functions[ret_name]
|
||||
nonlocal_params: list[tuple[str, ir.Type]] = Gen.nonlocal_params[ret_name]
|
||||
fn_return_type: ir.Type = nested_fn.function_type.return_type
|
||||
nonlocal_types: list[ir.Type] = [_safe_ptr_type(t) for _, t in nonlocal_params]
|
||||
# 构建 env:收集所有 nonlocal 变量指针
|
||||
env_ptrs: list[ir.Value] = []
|
||||
for var_name, _ in nonlocal_params:
|
||||
vp: ir.Value | None = Gen.variables.get(var_name)
|
||||
if vp is not None:
|
||||
env_ptrs.append(vp)
|
||||
if env_ptrs:
|
||||
# env 值:单个指针直接用,多个指针打包成结构体
|
||||
i8_ptr_type: ir.PointerType = ir.IntType(8).as_pointer()
|
||||
if len(env_ptrs) == 1:
|
||||
env_val: ir.Value = Gen.builder.bitcast(env_ptrs[0], i8_ptr_type, name="closure_env")
|
||||
else:
|
||||
env_struct_type: ir.LiteralStructType = ir.LiteralStructType([p.type for p in env_ptrs])
|
||||
env_size: int = len(env_ptrs) * 8
|
||||
malloc_type: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)])
|
||||
malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type)
|
||||
env_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), env_size)], name="env_struct_raw")
|
||||
env_struct_ptr: ir.Value = Gen.builder.bitcast(env_raw, ir.PointerType(env_struct_type), name="env_struct_ptr")
|
||||
for i, ptr in enumerate(env_ptrs):
|
||||
gep: ir.Value = Gen.builder.gep(env_struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"env_field_{i}")
|
||||
Gen._store(ptr, gep)
|
||||
env_val = Gen.builder.bitcast(env_struct_ptr, i8_ptr_type, name="closure_env")
|
||||
# fn 指针
|
||||
fn_ptr: ir.Value = Gen.builder.bitcast(nested_fn, i8_ptr_type, name="closure_fn")
|
||||
# 创建闭包结构体 {i8* env, i8* fn}
|
||||
closure_type: ir.LiteralStructType = ir.LiteralStructType([i8_ptr_type, i8_ptr_type])
|
||||
malloc_type2: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)])
|
||||
malloc_func2: ir.Function = Gen._get_or_declare_func('malloc', malloc_type2)
|
||||
closure_raw: ir.Value = Gen.builder.call(malloc_func2, [ir.Constant(ir.IntType(64), 16)], name="closure_raw")
|
||||
closure_ptr: ir.Value = Gen.builder.bitcast(closure_raw, ir.PointerType(closure_type), name="closure_ptr")
|
||||
# 填充闭包结构体
|
||||
env_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="closure_env_slot")
|
||||
Gen._store(env_val, env_gep)
|
||||
fn_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name="closure_fn_slot")
|
||||
Gen._store(fn_ptr, fn_gep)
|
||||
# 记录闭包返回类型
|
||||
current_name: str = Gen.func.name if Gen.func else ''
|
||||
short_name: str = current_name.split('.', 1)[1] if '.' in current_name else current_name
|
||||
Gen._closure_return_types[short_name] = (fn_return_type, nonlocal_types)
|
||||
# 返回闭包结构体指针(bitcast 到 i8*)
|
||||
closure_ret: ir.Value = Gen.builder.bitcast(closure_ptr, i8_ptr_type, name="closure_ret")
|
||||
Gen.emit_return(closure_ret)
|
||||
return
|
||||
active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen)
|
||||
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value:
|
||||
return_values: list[ast.expr] = []
|
||||
if isinstance(Node.value, ast.Tuple):
|
||||
return_values = Node.value.elts
|
||||
else:
|
||||
return_values = [Node.value]
|
||||
if len(return_values) == len(self.Trans.CurrentCReturnTypes):
|
||||
llvm_vals: list[ir.Value] = []
|
||||
expected_types: list[ir.Type] = []
|
||||
for i, val in enumerate(return_values):
|
||||
ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable)
|
||||
IsRetPtr: bool = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
|
||||
if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'):
|
||||
IsRetPtr = True
|
||||
ExpectedType: ir.Type = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr)
|
||||
expected_types.append(ExpectedType)
|
||||
Val: ir.Value | None = self.HandleExprLlvm(val)
|
||||
if Val is None:
|
||||
if isinstance(ExpectedType, ir.PointerType):
|
||||
Val = ir.Constant(ExpectedType, None)
|
||||
elif isinstance(ExpectedType, ir.IntType):
|
||||
Val = ir.Constant(ExpectedType, 0)
|
||||
else:
|
||||
Val = ir.Constant(ExpectedType, ir.Undefined)
|
||||
else:
|
||||
if Val.type != ExpectedType:
|
||||
if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < ExpectedType.width:
|
||||
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
|
||||
elif Val.type.width > ExpectedType.width:
|
||||
Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}")
|
||||
elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType):
|
||||
Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}")
|
||||
llvm_vals.append(Val)
|
||||
if llvm_vals:
|
||||
struct_type: ir.LiteralStructType = ir.LiteralStructType(expected_types)
|
||||
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
|
||||
for i, val in enumerate(llvm_vals):
|
||||
result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}")
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(result, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(result)
|
||||
return
|
||||
if Node.value:
|
||||
Val: ir.Value | None = self.HandleExprLlvm(Node.value)
|
||||
if Val:
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None:
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(zero_val, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(zero_val)
|
||||
return
|
||||
if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes:
|
||||
struct_type: ir.Type = Gen.func.ftype.return_type
|
||||
if isinstance(struct_type, ir.LiteralStructType):
|
||||
result: ir.Value = ir.Constant(struct_type, ir.Undefined)
|
||||
if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType):
|
||||
result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0")
|
||||
for j in range(1, len(struct_type.elements)):
|
||||
elem_type: ir.Type = struct_type.elements[j]
|
||||
zero_val: ir.Constant = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
for j, elem_type in enumerate(struct_type.elements):
|
||||
if j == 0:
|
||||
if Val.type == elem_type:
|
||||
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
|
||||
elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < elem_type.width:
|
||||
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
|
||||
elif Val.type.width > elem_type.width:
|
||||
Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}")
|
||||
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
else:
|
||||
zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None)
|
||||
result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}")
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(result, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(result)
|
||||
return
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
if pending_ret_val:
|
||||
Gen._store(Val, pending_ret_val)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
Gen.emit_return(Val)
|
||||
else:
|
||||
if active_finally:
|
||||
FinallyBB: ir.Block = active_finally[0]
|
||||
pending_ret_flag: ir.AllocaInstr = active_finally[1]
|
||||
pending_ret_val: ir.AllocaInstr | None = active_finally[2]
|
||||
Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag)
|
||||
Gen.builder.branch(FinallyBB)
|
||||
else:
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0))
|
||||
elif isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.BaseStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
elif isinstance(ret_type, ir.ArrayType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
else:
|
||||
Gen.emit_return()
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
import ast
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
|
||||
+213
-213
@@ -1,214 +1,214 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class TryHandle(BaseHandle):
|
||||
def _get_exception_type_code(self, type_node: ast.expr) -> int:
|
||||
if isinstance(type_node, ast.Name):
|
||||
name: str = type_node.id
|
||||
if name in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[name]
|
||||
if name in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[name]
|
||||
return 1
|
||||
if isinstance(type_node, ast.Attribute):
|
||||
name: str = type_node.attr
|
||||
if name in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[name]
|
||||
if name in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[name]
|
||||
return 1
|
||||
if isinstance(type_node, ast.Tuple):
|
||||
for elt in type_node.elts:
|
||||
code: int = self._get_exception_type_code(elt)
|
||||
if code != 1:
|
||||
return code
|
||||
return 1
|
||||
return 1
|
||||
|
||||
def _get_exception_name(self, type_node: ast.expr) -> str | None:
|
||||
if isinstance(type_node, ast.Name):
|
||||
return type_node.id
|
||||
if isinstance(type_node, ast.Attribute):
|
||||
return type_node.attr
|
||||
return None
|
||||
|
||||
def _get_all_match_codes(self, type_node: ast.expr) -> list[int]:
|
||||
name: str | None = self._get_exception_name(type_node)
|
||||
if name is None:
|
||||
return [self._get_exception_type_code(type_node)]
|
||||
if name not in self.Trans.exception_registry:
|
||||
return [self._get_exception_type_code(type_node)]
|
||||
codes: list[int] = [self.Trans.exception_registry[name]]
|
||||
self._collect_descendant_codes(name, codes)
|
||||
return codes
|
||||
|
||||
def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None:
|
||||
for child_name, parent in self.Trans.exception_parents.items():
|
||||
if parent == parent_name:
|
||||
child_code: int | None = self.Trans.exception_registry.get(child_name)
|
||||
if child_code is not None and child_code not in codes:
|
||||
codes.append(child_code)
|
||||
self._collect_descendant_codes(child_name, codes)
|
||||
|
||||
def _HandleTryLlvm(self, Node: ast.Try) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if not Gen.func:
|
||||
return
|
||||
exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code")
|
||||
eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message")
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message)
|
||||
HasFinally: bool = bool(Node.finalbody)
|
||||
if HasFinally:
|
||||
Gen.eh_finally_stack.append((None, None, None))
|
||||
else:
|
||||
Gen.eh_finally_stack.append(None)
|
||||
DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after")
|
||||
except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = []
|
||||
for i, handler in enumerate(Node.handlers):
|
||||
ExcTypeCodes: list[int] = [1]
|
||||
if handler.type:
|
||||
ExcTypeCodes = self._get_all_match_codes(handler.type)
|
||||
ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}")
|
||||
Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message))
|
||||
except_blocks.append((ExceptBB, ExcTypeCodes, handler))
|
||||
TryBB: ir.Block = Gen.func.append_basic_block(name="try.body")
|
||||
ElseBB: ir.Block | None = None
|
||||
if Node.orelse:
|
||||
ElseBB = Gen.func.append_basic_block(name="try.else")
|
||||
Gen.builder.branch(TryBB)
|
||||
Gen.builder.position_at_start(TryBB)
|
||||
self.HandleBodyLlvm(Node.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
if ElseBB:
|
||||
Gen.builder.branch(ElseBB)
|
||||
else:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(DispatchBB)
|
||||
eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code")
|
||||
next_check_bb: ir.Block | None = None
|
||||
handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {}
|
||||
UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled")
|
||||
for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
|
||||
MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}")
|
||||
if i > 0 and next_check_bb is not None:
|
||||
Gen.builder.position_at_start(next_check_bb)
|
||||
eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}")
|
||||
if handler.type is None:
|
||||
Gen.builder.branch(MatchBB)
|
||||
else:
|
||||
match_cond: ir.Value | None = None
|
||||
for code in ExcTypeCodes:
|
||||
is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}")
|
||||
if match_cond is None:
|
||||
match_cond = is_code_match
|
||||
else:
|
||||
match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}")
|
||||
if i < len(except_blocks) - 1:
|
||||
next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}")
|
||||
else:
|
||||
next_check_bb = UnhandledBB
|
||||
Gen.builder.cbranch(match_cond, MatchBB, next_check_bb)
|
||||
Gen.builder.position_at_start(MatchBB)
|
||||
if handler.name:
|
||||
var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name)
|
||||
eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}")
|
||||
Gen._store(eh_msg_val, var_alloca)
|
||||
handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name))
|
||||
Gen.builder.branch(ExceptBB)
|
||||
Gen.builder.position_at_start(UnhandledBB)
|
||||
eh_msg_out_arg: ir.Argument | None = None
|
||||
eh_code_out_arg: ir.Argument | None = None
|
||||
if Gen.func and len(Gen.func.args) > 0:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_out_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_out_arg = arg
|
||||
if eh_msg_out_arg is not None and eh_code_out_arg is not None:
|
||||
eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate")
|
||||
eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate")
|
||||
Gen._store(eh_msg_val, eh_msg_out_arg)
|
||||
Gen._store(eh_code_val_prop, eh_code_out_arg)
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IdentifiedStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
elif isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 1))
|
||||
elif isinstance(ret_type, ir.VoidType):
|
||||
Gen.builder.ret_void()
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
Gen.builder.branch(AfterBB)
|
||||
for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
|
||||
Gen.builder.position_at_start(ExceptBB)
|
||||
old_var: ir.Value | None = None
|
||||
if idx in handler_var_map:
|
||||
hname: str = handler_var_map[idx][0]
|
||||
var_alloca: ir.AllocaInstr = handler_var_map[idx][1]
|
||||
old_var = handler_var_map[idx][2]
|
||||
Gen.variables[hname] = var_alloca
|
||||
self.HandleBodyLlvm(handler.body)
|
||||
if idx in handler_var_map:
|
||||
hname = handler_var_map[idx][0]
|
||||
old_var = handler_var_map[idx][2]
|
||||
if old_var is not None:
|
||||
Gen.variables[hname] = old_var
|
||||
elif hname in Gen.variables:
|
||||
del Gen.variables[hname]
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.eh_except_block_stack.pop()
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self.HandleBodyLlvm(Node.orelse)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
if HasFinally:
|
||||
Gen.eh_finally_stack.pop()
|
||||
if Node.finalbody:
|
||||
FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally")
|
||||
pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag")
|
||||
pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None
|
||||
Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val))
|
||||
Gen.builder.branch(FinallyBB)
|
||||
Gen.builder.position_at_start(FinallyBB)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag)
|
||||
self.HandleBodyLlvm(Node.finalbody)
|
||||
if Gen.eh_finally_stack:
|
||||
_, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1]
|
||||
Gen.eh_finally_stack.pop()
|
||||
ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag")
|
||||
ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag")
|
||||
RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret")
|
||||
ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue")
|
||||
Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB)
|
||||
Gen.builder.position_at_start(RetBB)
|
||||
if pending_ret_val:
|
||||
ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val")
|
||||
Gen.builder.ret(ret_val)
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class TryHandle(BaseHandle):
|
||||
def _get_exception_type_code(self, type_node: ast.expr) -> int:
|
||||
if isinstance(type_node, ast.Name):
|
||||
name: str = type_node.id
|
||||
if name in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[name]
|
||||
if name in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[name]
|
||||
return 1
|
||||
if isinstance(type_node, ast.Attribute):
|
||||
name: str = type_node.attr
|
||||
if name in EXCEPTION_CODE_MAP:
|
||||
return EXCEPTION_CODE_MAP[name]
|
||||
if name in self.Trans.exception_registry:
|
||||
return self.Trans.exception_registry[name]
|
||||
return 1
|
||||
if isinstance(type_node, ast.Tuple):
|
||||
for elt in type_node.elts:
|
||||
code: int = self._get_exception_type_code(elt)
|
||||
if code != 1:
|
||||
return code
|
||||
return 1
|
||||
return 1
|
||||
|
||||
def _get_exception_name(self, type_node: ast.expr) -> str | None:
|
||||
if isinstance(type_node, ast.Name):
|
||||
return type_node.id
|
||||
if isinstance(type_node, ast.Attribute):
|
||||
return type_node.attr
|
||||
return None
|
||||
|
||||
def _get_all_match_codes(self, type_node: ast.expr) -> list[int]:
|
||||
name: str | None = self._get_exception_name(type_node)
|
||||
if name is None:
|
||||
return [self._get_exception_type_code(type_node)]
|
||||
if name not in self.Trans.exception_registry:
|
||||
return [self._get_exception_type_code(type_node)]
|
||||
codes: list[int] = [self.Trans.exception_registry[name]]
|
||||
self._collect_descendant_codes(name, codes)
|
||||
return codes
|
||||
|
||||
def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None:
|
||||
for child_name, parent in self.Trans.exception_parents.items():
|
||||
if parent == parent_name:
|
||||
child_code: int | None = self.Trans.exception_registry.get(child_name)
|
||||
if child_code is not None and child_code not in codes:
|
||||
codes.append(child_code)
|
||||
self._collect_descendant_codes(child_name, codes)
|
||||
|
||||
def _HandleTryLlvm(self, Node: ast.Try) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if not Gen.func:
|
||||
return
|
||||
exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code")
|
||||
eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message")
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message)
|
||||
HasFinally: bool = bool(Node.finalbody)
|
||||
if HasFinally:
|
||||
Gen.eh_finally_stack.append((None, None, None))
|
||||
else:
|
||||
Gen.eh_finally_stack.append(None)
|
||||
DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch")
|
||||
AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after")
|
||||
except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = []
|
||||
for i, handler in enumerate(Node.handlers):
|
||||
ExcTypeCodes: list[int] = [1]
|
||||
if handler.type:
|
||||
ExcTypeCodes = self._get_all_match_codes(handler.type)
|
||||
ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}")
|
||||
Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message))
|
||||
except_blocks.append((ExceptBB, ExcTypeCodes, handler))
|
||||
TryBB: ir.Block = Gen.func.append_basic_block(name="try.body")
|
||||
ElseBB: ir.Block | None = None
|
||||
if Node.orelse:
|
||||
ElseBB = Gen.func.append_basic_block(name="try.else")
|
||||
Gen.builder.branch(TryBB)
|
||||
Gen.builder.position_at_start(TryBB)
|
||||
self.HandleBodyLlvm(Node.body)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
if ElseBB:
|
||||
Gen.builder.branch(ElseBB)
|
||||
else:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(DispatchBB)
|
||||
eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code")
|
||||
next_check_bb: ir.Block | None = None
|
||||
handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {}
|
||||
UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled")
|
||||
for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
|
||||
MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}")
|
||||
if i > 0 and next_check_bb is not None:
|
||||
Gen.builder.position_at_start(next_check_bb)
|
||||
eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}")
|
||||
if handler.type is None:
|
||||
Gen.builder.branch(MatchBB)
|
||||
else:
|
||||
match_cond: ir.Value | None = None
|
||||
for code in ExcTypeCodes:
|
||||
is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}")
|
||||
if match_cond is None:
|
||||
match_cond = is_code_match
|
||||
else:
|
||||
match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}")
|
||||
if i < len(except_blocks) - 1:
|
||||
next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}")
|
||||
else:
|
||||
next_check_bb = UnhandledBB
|
||||
Gen.builder.cbranch(match_cond, MatchBB, next_check_bb)
|
||||
Gen.builder.position_at_start(MatchBB)
|
||||
if handler.name:
|
||||
var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name)
|
||||
eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}")
|
||||
Gen._store(eh_msg_val, var_alloca)
|
||||
handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name))
|
||||
Gen.builder.branch(ExceptBB)
|
||||
Gen.builder.position_at_start(UnhandledBB)
|
||||
eh_msg_out_arg: ir.Argument | None = None
|
||||
eh_code_out_arg: ir.Argument | None = None
|
||||
if Gen.func and len(Gen.func.args) > 0:
|
||||
for arg in Gen.func.args:
|
||||
if arg.name == '__eh_msg_out__':
|
||||
eh_msg_out_arg = arg
|
||||
elif arg.name == '__eh_code_out__':
|
||||
eh_code_out_arg = arg
|
||||
if eh_msg_out_arg is not None and eh_code_out_arg is not None:
|
||||
eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate")
|
||||
eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate")
|
||||
Gen._store(eh_msg_val, eh_msg_out_arg)
|
||||
Gen._store(eh_code_val_prop, eh_code_out_arg)
|
||||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||||
if isinstance(ret_type, ir.IdentifiedStructType):
|
||||
if ret_type.elements:
|
||||
zero_val: ir.Constant = ir.Constant(ret_type, [
|
||||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||||
else:
|
||||
zero_val = ir.Constant(ret_type, None)
|
||||
Gen.builder.ret(zero_val)
|
||||
elif isinstance(ret_type, ir.PointerType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, None))
|
||||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 0.0))
|
||||
elif isinstance(ret_type, ir.IntType):
|
||||
Gen.builder.ret(ir.Constant(ret_type, 1))
|
||||
elif isinstance(ret_type, ir.VoidType):
|
||||
Gen.builder.ret_void()
|
||||
else:
|
||||
Gen.builder.ret(ir.Constant(ir.IntType(32), 1))
|
||||
else:
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), exception_code)
|
||||
Gen.builder.branch(AfterBB)
|
||||
for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks):
|
||||
Gen.builder.position_at_start(ExceptBB)
|
||||
old_var: ir.Value | None = None
|
||||
if idx in handler_var_map:
|
||||
hname: str = handler_var_map[idx][0]
|
||||
var_alloca: ir.AllocaInstr = handler_var_map[idx][1]
|
||||
old_var = handler_var_map[idx][2]
|
||||
Gen.variables[hname] = var_alloca
|
||||
self.HandleBodyLlvm(handler.body)
|
||||
if idx in handler_var_map:
|
||||
hname = handler_var_map[idx][0]
|
||||
old_var = handler_var_map[idx][2]
|
||||
if old_var is not None:
|
||||
Gen.variables[hname] = old_var
|
||||
elif hname in Gen.variables:
|
||||
del Gen.variables[hname]
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.eh_except_block_stack.pop()
|
||||
if ElseBB:
|
||||
Gen.builder.position_at_start(ElseBB)
|
||||
self.HandleBodyLlvm(Node.orelse)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
if HasFinally:
|
||||
Gen.eh_finally_stack.pop()
|
||||
if Node.finalbody:
|
||||
FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally")
|
||||
pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag")
|
||||
pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None
|
||||
Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val))
|
||||
Gen.builder.branch(FinallyBB)
|
||||
Gen.builder.position_at_start(FinallyBB)
|
||||
Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag)
|
||||
self.HandleBodyLlvm(Node.finalbody)
|
||||
if Gen.eh_finally_stack:
|
||||
_, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1]
|
||||
Gen.eh_finally_stack.pop()
|
||||
ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag")
|
||||
ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag")
|
||||
RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret")
|
||||
ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue")
|
||||
Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB)
|
||||
Gen.builder.position_at_start(RetBB)
|
||||
if pending_ret_val:
|
||||
ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val")
|
||||
Gen.builder.ret(ret_val)
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
Gen.builder.position_at_start(ContinueBB)
|
||||
@@ -7,7 +7,7 @@ from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo
|
||||
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
|
||||
from lib.includes import t
|
||||
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
|
||||
import ast
|
||||
import vast as ast
|
||||
|
||||
|
||||
class HandlesTypeMerge(BaseHandle):
|
||||
|
||||
+211
-211
@@ -1,212 +1,212 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class WithHandle(BaseHandle):
|
||||
def _ResolveInheritedMethod(self, ClassName: str, MethodName: str, Gen: "Translator.LlvmGen") -> tuple[str | None, "ir.Function | None"]:
|
||||
"""沿继承链查找方法,返回 (定义方法的类名, 函数对象)
|
||||
|
||||
当子类未覆写 __enter__/__exit__ 等方法时,沿 Gen.class_parent 链查找父类实现。
|
||||
_generate_inherited_method_wrappers 只为 class_methods[ClassName] 中的方法生成包装,
|
||||
不包括父类独有方法,因此 with 语句需要单独处理继承查找。
|
||||
"""
|
||||
# 先检查子类自身:必须有函数体(define)才算真方法。
|
||||
# 子类继承方法的 stub declare(如 MemPool.__enter__,Phase1 生成的继承
|
||||
# 包装声明)无函数体且 TPC 不生成对应定义,直接调用会链接 undefined,
|
||||
# 必须跳过并沿 MRO 找父类实现。
|
||||
FullName: str = f'{ClassName}.{MethodName}'
|
||||
func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName)
|
||||
if func and len(list(func.blocks)) > 0:
|
||||
return (ClassName, func)
|
||||
# 沿 MRO 继承链查找(多继承:先声明父类优先)。
|
||||
# 祖先的 stub declare(无函数体)是真实定义的声明(定义在其模块 obj 中),
|
||||
# 可直接调用——与 _HandleMethodCallLlvm 的 MRO 回退语义一致。
|
||||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||||
parent_full: str = f'{anc}.{MethodName}'
|
||||
parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full)
|
||||
if parent_func:
|
||||
return (anc, parent_func)
|
||||
return (None, None)
|
||||
|
||||
def _HandleWithLlvm(self, Node: ast.With) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for item in Node.items:
|
||||
context_expr: ast.expr = item.context_expr
|
||||
asname: str | None = None
|
||||
target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None)))
|
||||
if target and isinstance(target, ast.Name):
|
||||
asname = target.id
|
||||
ClassName: str | None = None
|
||||
if isinstance(context_expr, ast.Call):
|
||||
if isinstance(context_expr.func, ast.Name):
|
||||
ClassName = context_expr.func.id
|
||||
elif isinstance(context_expr.func, ast.Attribute):
|
||||
ClassName = context_expr.func.attr
|
||||
if ClassName and ClassName not in Gen.structs:
|
||||
SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName)
|
||||
if SymInfo:
|
||||
if SymInfo.IsStruct or SymInfo.IsRenum:
|
||||
pass
|
||||
else:
|
||||
ClassName = None
|
||||
else:
|
||||
ClassName = None
|
||||
elif isinstance(context_expr, ast.Name):
|
||||
VarName: str = context_expr.id
|
||||
if VarName in Gen.var_struct_class:
|
||||
ClassName = Gen.var_struct_class[VarName]
|
||||
ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr)
|
||||
if not ctx_val:
|
||||
continue
|
||||
original_ctx_val: ir.Value = ctx_val
|
||||
if ClassName and isinstance(ctx_val.type, ir.PointerType):
|
||||
pointee: ir.Type = ctx_val.type.pointee
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee)
|
||||
if found:
|
||||
CN: str = found[0]
|
||||
ST: ir.Type = found[1]
|
||||
ClassName = CN
|
||||
StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None
|
||||
if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName):
|
||||
ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx")
|
||||
ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx")
|
||||
Gen._store(ctx_val, ctx_alloca)
|
||||
Gen._UnregisterTempPtr(ctx_val)
|
||||
if ClassName:
|
||||
Gen.var_struct_class['__with_ctx'] = ClassName
|
||||
Gen._var_to_heap_ptr['__with_ctx'] = ctx_val
|
||||
original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None
|
||||
ctx_is_var_ref: bool = isinstance(context_expr, ast.Name)
|
||||
enter_result: ir.Value | None = None
|
||||
if ClassName:
|
||||
# 沿继承链查找 __enter__(子类可能未覆写,使用父类实现)
|
||||
enter_class, enter_func = self._ResolveInheritedMethod(ClassName, '__enter__', Gen)
|
||||
if enter_func is not None:
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
# 父类方法需要 self 为父类指针类型,bitcast 子类指针。
|
||||
# bitcast 目标用 enter_func 签名参数类型(args[0] 本身即
|
||||
# MemManager* 指针),避免 Gen.structs 查找返回 opaque/异
|
||||
# sha1 占位对象导致 llvmlite 类型不匹配。
|
||||
if enter_class != ClassName:
|
||||
parent_ptr_type: ir.Type = enter_func.function_type.args[0]
|
||||
if ctx_Loaded.type != parent_ptr_type:
|
||||
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_enter_self")
|
||||
enter_call: ir.CallInstr = Gen.builder.call(enter_func, [ctx_Loaded], name="call_enter")
|
||||
enter_result = enter_call
|
||||
if isinstance(enter_call.type, ir.PointerType):
|
||||
pointee: ir.Type = enter_call.type.pointee
|
||||
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
enter_result = Gen._load(enter_call, name="enter_deref")
|
||||
elif self._is_char_pointer(enter_call) and StructPtrType:
|
||||
enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter")
|
||||
if asname and enter_result:
|
||||
if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee)
|
||||
if found:
|
||||
CN: str = found[0]
|
||||
ST: ir.Type = found[1]
|
||||
Gen.var_struct_class[asname] = CN
|
||||
Gen._var_to_heap_ptr[asname] = enter_result
|
||||
Gen._register_local_heap_ptr(enter_result, VarName=asname)
|
||||
if asname in Gen._reg_values:
|
||||
OldVal: ir.Value = Gen._reg_values[asname]
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.variables[asname] = var
|
||||
del Gen._reg_values[asname]
|
||||
if asname in Gen.variables and Gen.variables[asname] is not None:
|
||||
VarPtr: ir.Value = Gen.variables[asname]
|
||||
if VarPtr.type.pointee == enter_result.type:
|
||||
Gen._store(enter_result, VarPtr)
|
||||
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
|
||||
CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}")
|
||||
Gen._store(CastedVal, VarPtr)
|
||||
else:
|
||||
NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname)
|
||||
Gen._store(enter_result, NewVar)
|
||||
Gen.variables[asname] = NewVar
|
||||
else:
|
||||
Gen._reg_values[asname] = enter_result
|
||||
Gen.variables[asname] = None
|
||||
# 如果类有 __provides__,自动生成 push 代码
|
||||
if ClassName and ClassName in Gen.class_provides:
|
||||
# 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32)
|
||||
# _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈
|
||||
current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack)
|
||||
new_fields: int = len(Gen.class_provides[ClassName])
|
||||
if current_depth + new_fields > 32:
|
||||
raise SyntaxError(
|
||||
f"[TransPyC] with provider stack overflow at line {Node.lineno}: "
|
||||
f"current depth {current_depth} + new {new_fields} fields > max 32. "
|
||||
f"Class '{ClassName}' provides too many fields or with nesting too deep."
|
||||
)
|
||||
# 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查
|
||||
Gen._with_provides_stack.append(Gen.class_provides[ClassName])
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
ctx_i8: ir.Value = ctx_Loaded
|
||||
if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)):
|
||||
ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8")
|
||||
for field_name in Gen.class_provides[ClassName]:
|
||||
field_str: ir.Value = Gen._create_string_global(field_name)
|
||||
push_func = Gen.functions.get('_push_provider')
|
||||
if push_func:
|
||||
Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider")
|
||||
self.Trans.VarScopes.append({})
|
||||
if asname:
|
||||
self.Trans.VarScopes[-1][asname] = True
|
||||
self.HandleBodyLlvm(Node.body)
|
||||
if self.Trans.VarScopes:
|
||||
self.Trans.VarScopes.pop()
|
||||
# 如果类有 __provides__,自动生成 pop 代码
|
||||
if ClassName and ClassName in Gen.class_provides:
|
||||
for _ in Gen.class_provides[ClassName]:
|
||||
pop_func = Gen.functions.get('_pop_provider')
|
||||
if pop_func:
|
||||
Gen.builder.call(pop_func, [], name="call_pop_provider")
|
||||
# 编译期弹栈
|
||||
if Gen._with_provides_stack:
|
||||
Gen._with_provides_stack.pop()
|
||||
if ClassName:
|
||||
# 沿继承链查找 __exit__(子类可能未覆写,使用父类实现)
|
||||
exit_class, exit_func = self._ResolveInheritedMethod(ClassName, '__exit__', Gen)
|
||||
if exit_func is not None:
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
# 父类方法需要 self 为父类指针类型,bitcast 子类指针(同上)
|
||||
if exit_class != ClassName:
|
||||
parent_ptr_type: ir.Type = exit_func.function_type.args[0]
|
||||
if ctx_Loaded.type != parent_ptr_type:
|
||||
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_exit_self")
|
||||
Gen.builder.call(exit_func, [ctx_Loaded], name="call_exit")
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
if ctx_val is not original_ctx_val:
|
||||
Gen._unregister_local_heap_ptr(ctx_val)
|
||||
if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val:
|
||||
Gen._unregister_local_heap_ptr(original_asname_heap_ptr)
|
||||
if '__with_ctx' in Gen._var_to_heap_ptr:
|
||||
del Gen._var_to_heap_ptr['__with_ctx']
|
||||
if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
|
||||
ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int")
|
||||
enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int")
|
||||
same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check")
|
||||
with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx")
|
||||
with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free")
|
||||
Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb)
|
||||
Gen.builder.position_at_start(with_free_bb)
|
||||
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
|
||||
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
|
||||
Gen.builder.call(free_func, [raw])
|
||||
Gen.builder.branch(with_skip_bb)
|
||||
Gen.builder.position_at_start(with_skip_bb)
|
||||
Gen._unregister_local_heap_ptr(enter_result)
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
elif isinstance(ctx_val.type, ir.PointerType):
|
||||
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
|
||||
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
|
||||
Gen.builder.call(free_func, [raw])
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.translator import Translator
|
||||
from lib.core.Handles.HandlesBase import BaseHandle
|
||||
import vast as ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class WithHandle(BaseHandle):
|
||||
def _ResolveInheritedMethod(self, ClassName: str, MethodName: str, Gen: "Translator.LlvmGen") -> tuple[str | None, "ir.Function | None"]:
|
||||
"""沿继承链查找方法,返回 (定义方法的类名, 函数对象)
|
||||
|
||||
当子类未覆写 __enter__/__exit__ 等方法时,沿 Gen.class_parent 链查找父类实现。
|
||||
_generate_inherited_method_wrappers 只为 class_methods[ClassName] 中的方法生成包装,
|
||||
不包括父类独有方法,因此 with 语句需要单独处理继承查找。
|
||||
"""
|
||||
# 先检查子类自身:必须有函数体(define)才算真方法。
|
||||
# 子类继承方法的 stub declare(如 MemPool.__enter__,Phase1 生成的继承
|
||||
# 包装声明)无函数体且 TPC 不生成对应定义,直接调用会链接 undefined,
|
||||
# 必须跳过并沿 MRO 找父类实现。
|
||||
FullName: str = f'{ClassName}.{MethodName}'
|
||||
func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName)
|
||||
if func and len(list(func.blocks)) > 0:
|
||||
return (ClassName, func)
|
||||
# 沿 MRO 继承链查找(多继承:先声明父类优先)。
|
||||
# 祖先的 stub declare(无函数体)是真实定义的声明(定义在其模块 obj 中),
|
||||
# 可直接调用——与 _HandleMethodCallLlvm 的 MRO 回退语义一致。
|
||||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||||
parent_full: str = f'{anc}.{MethodName}'
|
||||
parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full)
|
||||
if parent_func:
|
||||
return (anc, parent_func)
|
||||
return (None, None)
|
||||
|
||||
def _HandleWithLlvm(self, Node: ast.With) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for item in Node.items:
|
||||
context_expr: ast.expr = item.context_expr
|
||||
asname: str | None = None
|
||||
target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None)))
|
||||
if target and isinstance(target, ast.Name):
|
||||
asname = target.id
|
||||
ClassName: str | None = None
|
||||
if isinstance(context_expr, ast.Call):
|
||||
if isinstance(context_expr.func, ast.Name):
|
||||
ClassName = context_expr.func.id
|
||||
elif isinstance(context_expr.func, ast.Attribute):
|
||||
ClassName = context_expr.func.attr
|
||||
if ClassName and ClassName not in Gen.structs:
|
||||
SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName)
|
||||
if SymInfo:
|
||||
if SymInfo.IsStruct or SymInfo.IsRenum:
|
||||
pass
|
||||
else:
|
||||
ClassName = None
|
||||
else:
|
||||
ClassName = None
|
||||
elif isinstance(context_expr, ast.Name):
|
||||
VarName: str = context_expr.id
|
||||
if VarName in Gen.var_struct_class:
|
||||
ClassName = Gen.var_struct_class[VarName]
|
||||
ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr)
|
||||
if not ctx_val:
|
||||
continue
|
||||
original_ctx_val: ir.Value = ctx_val
|
||||
if ClassName and isinstance(ctx_val.type, ir.PointerType):
|
||||
pointee: ir.Type = ctx_val.type.pointee
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee)
|
||||
if found:
|
||||
CN: str = found[0]
|
||||
ST: ir.Type = found[1]
|
||||
ClassName = CN
|
||||
StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None
|
||||
if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName):
|
||||
ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx")
|
||||
ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx")
|
||||
Gen._store(ctx_val, ctx_alloca)
|
||||
Gen._UnregisterTempPtr(ctx_val)
|
||||
if ClassName:
|
||||
Gen.var_struct_class['__with_ctx'] = ClassName
|
||||
Gen._var_to_heap_ptr['__with_ctx'] = ctx_val
|
||||
original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None
|
||||
ctx_is_var_ref: bool = isinstance(context_expr, ast.Name)
|
||||
enter_result: ir.Value | None = None
|
||||
if ClassName:
|
||||
# 沿继承链查找 __enter__(子类可能未覆写,使用父类实现)
|
||||
enter_class, enter_func = self._ResolveInheritedMethod(ClassName, '__enter__', Gen)
|
||||
if enter_func is not None:
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
# 父类方法需要 self 为父类指针类型,bitcast 子类指针。
|
||||
# bitcast 目标用 enter_func 签名参数类型(args[0] 本身即
|
||||
# MemManager* 指针),避免 Gen.structs 查找返回 opaque/异
|
||||
# sha1 占位对象导致 llvmlite 类型不匹配。
|
||||
if enter_class != ClassName:
|
||||
parent_ptr_type: ir.Type = enter_func.function_type.args[0]
|
||||
if ctx_Loaded.type != parent_ptr_type:
|
||||
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_enter_self")
|
||||
enter_call: ir.CallInstr = Gen.builder.call(enter_func, [ctx_Loaded], name="call_enter")
|
||||
enter_result = enter_call
|
||||
if isinstance(enter_call.type, ir.PointerType):
|
||||
pointee: ir.Type = enter_call.type.pointee
|
||||
if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
enter_result = Gen._load(enter_call, name="enter_deref")
|
||||
elif self._is_char_pointer(enter_call) and StructPtrType:
|
||||
enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter")
|
||||
if asname and enter_result:
|
||||
if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee)
|
||||
if found:
|
||||
CN: str = found[0]
|
||||
ST: ir.Type = found[1]
|
||||
Gen.var_struct_class[asname] = CN
|
||||
Gen._var_to_heap_ptr[asname] = enter_result
|
||||
Gen._register_local_heap_ptr(enter_result, VarName=asname)
|
||||
if asname in Gen._reg_values:
|
||||
OldVal: ir.Value = Gen._reg_values[asname]
|
||||
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname)
|
||||
Gen._store(OldVal, var)
|
||||
Gen.variables[asname] = var
|
||||
del Gen._reg_values[asname]
|
||||
if asname in Gen.variables and Gen.variables[asname] is not None:
|
||||
VarPtr: ir.Value = Gen.variables[asname]
|
||||
if VarPtr.type.pointee == enter_result.type:
|
||||
Gen._store(enter_result, VarPtr)
|
||||
elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
|
||||
CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}")
|
||||
Gen._store(CastedVal, VarPtr)
|
||||
else:
|
||||
NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname)
|
||||
Gen._store(enter_result, NewVar)
|
||||
Gen.variables[asname] = NewVar
|
||||
else:
|
||||
Gen._reg_values[asname] = enter_result
|
||||
Gen.variables[asname] = None
|
||||
# 如果类有 __provides__,自动生成 push 代码
|
||||
if ClassName and ClassName in Gen.class_provides:
|
||||
# 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32)
|
||||
# _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈
|
||||
current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack)
|
||||
new_fields: int = len(Gen.class_provides[ClassName])
|
||||
if current_depth + new_fields > 32:
|
||||
raise SyntaxError(
|
||||
f"[TransPyC] with provider stack overflow at line {Node.lineno}: "
|
||||
f"current depth {current_depth} + new {new_fields} fields > max 32. "
|
||||
f"Class '{ClassName}' provides too many fields or with nesting too deep."
|
||||
)
|
||||
# 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查
|
||||
Gen._with_provides_stack.append(Gen.class_provides[ClassName])
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
ctx_i8: ir.Value = ctx_Loaded
|
||||
if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)):
|
||||
ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8")
|
||||
for field_name in Gen.class_provides[ClassName]:
|
||||
field_str: ir.Value = Gen._create_string_global(field_name)
|
||||
push_func = Gen.functions.get('_push_provider')
|
||||
if push_func:
|
||||
Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider")
|
||||
self.Trans.VarScopes.append({})
|
||||
if asname:
|
||||
self.Trans.VarScopes[-1][asname] = True
|
||||
self.HandleBodyLlvm(Node.body)
|
||||
if self.Trans.VarScopes:
|
||||
self.Trans.VarScopes.pop()
|
||||
# 如果类有 __provides__,自动生成 pop 代码
|
||||
if ClassName and ClassName in Gen.class_provides:
|
||||
for _ in Gen.class_provides[ClassName]:
|
||||
pop_func = Gen.functions.get('_pop_provider')
|
||||
if pop_func:
|
||||
Gen.builder.call(pop_func, [], name="call_pop_provider")
|
||||
# 编译期弹栈
|
||||
if Gen._with_provides_stack:
|
||||
Gen._with_provides_stack.pop()
|
||||
if ClassName:
|
||||
# 沿继承链查找 __exit__(子类可能未覆写,使用父类实现)
|
||||
exit_class, exit_func = self._ResolveInheritedMethod(ClassName, '__exit__', Gen)
|
||||
if exit_func is not None:
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
# 父类方法需要 self 为父类指针类型,bitcast 子类指针(同上)
|
||||
if exit_class != ClassName:
|
||||
parent_ptr_type: ir.Type = exit_func.function_type.args[0]
|
||||
if ctx_Loaded.type != parent_ptr_type:
|
||||
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_exit_self")
|
||||
Gen.builder.call(exit_func, [ctx_Loaded], name="call_exit")
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
if ctx_val is not original_ctx_val:
|
||||
Gen._unregister_local_heap_ptr(ctx_val)
|
||||
if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val:
|
||||
Gen._unregister_local_heap_ptr(original_asname_heap_ptr)
|
||||
if '__with_ctx' in Gen._var_to_heap_ptr:
|
||||
del Gen._var_to_heap_ptr['__with_ctx']
|
||||
if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType):
|
||||
ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int")
|
||||
enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int")
|
||||
same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check")
|
||||
with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx")
|
||||
with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free")
|
||||
Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb)
|
||||
Gen.builder.position_at_start(with_free_bb)
|
||||
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
|
||||
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
|
||||
Gen.builder.call(free_func, [raw])
|
||||
Gen.builder.branch(with_skip_bb)
|
||||
Gen.builder.position_at_start(with_skip_bb)
|
||||
Gen._unregister_local_heap_ptr(enter_result)
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
elif isinstance(ctx_val.type, ir.PointerType):
|
||||
raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast")
|
||||
free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]))
|
||||
Gen.builder.call(free_func, [raw])
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
+842
-842
File diff suppressed because it is too large.
Load diff
+557
-557
File diff suppressed because it is too large.
Load diff
+650
-650
File diff suppressed because it is too large.
Load diff
+766
-766
File diff suppressed because it is too large.
Load diff
+301
-301
@@ -1,301 +1,301 @@
|
||||
"""LLVMTypeMapper — AST 注解节点到 LLVM IR 类型字符串的映射器
|
||||
|
||||
从 SymbolTable 中提取的类型解析逻辑,职责单一:
|
||||
将 Python AST 注解节点翻译为 LLVM IR 类型字符串(如 'i32', 'i8*', '{ i32, i8* }')。
|
||||
|
||||
原 SymbolTable 上的 4 个方法:
|
||||
- _GetLLVMTypeStr → LLVMTypeMapper.get_llvm_type_str
|
||||
- _GetFuncRetTypeStr → LLVMTypeMapper.get_func_ret_type_str
|
||||
- _GetFuncParamTypeStr → LLVMTypeMapper.get_func_param_type_str
|
||||
- _ResolveTypedefValueType → LLVMTypeMapper.resolve_typedef_value_type
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.SymbolTable import SymbolTable
|
||||
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
|
||||
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
|
||||
from lib.includes import t as _t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
|
||||
|
||||
class LLVMTypeMapper:
|
||||
"""AST 注解节点 → LLVM IR 类型字符串 映射器"""
|
||||
|
||||
def __init__(self, symtab: SymbolTable):
|
||||
self._symtab = symtab
|
||||
|
||||
# ==================================================================
|
||||
# 公共 API
|
||||
# ==================================================================
|
||||
|
||||
def get_llvm_type_str(self, node: ast.AST | None) -> str:
|
||||
"""将 AST 注解节点转换为 LLVM IR 类型字符串"""
|
||||
if node is None:
|
||||
self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32")
|
||||
return 'i32'
|
||||
if isinstance(node, ast.Name):
|
||||
return self._resolve_name(node)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
return self._resolve_attribute(node)
|
||||
elif isinstance(node, ast.Subscript):
|
||||
return self._resolve_subscript(node)
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
return self._resolve_bitor(node)
|
||||
elif isinstance(node, ast.Constant):
|
||||
if isinstance(node.value, bool):
|
||||
return 'i8'
|
||||
return 'i32'
|
||||
elif isinstance(node, ast.Call):
|
||||
return self._resolve_call(node)
|
||||
self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32")
|
||||
return 'i32'
|
||||
|
||||
def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str:
|
||||
"""提取函数返回类型的 LLVM 字符串"""
|
||||
if returns_node is None:
|
||||
return 'i32'
|
||||
if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr):
|
||||
left_str: str = self.get_llvm_type_str(returns_node.left)
|
||||
right_str: str = self.get_llvm_type_str(returns_node.right)
|
||||
if right_str and right_str.endswith('*'):
|
||||
return right_str
|
||||
if left_str and left_str.endswith('*'):
|
||||
return left_str
|
||||
if left_str and left_str not in ('i32', 'void', 'i64'):
|
||||
return left_str
|
||||
if right_str and right_str not in ('i32', 'void', 'i64'):
|
||||
return right_str
|
||||
return left_str
|
||||
result: str = self.get_llvm_type_str(returns_node)
|
||||
return result if result else 'i32'
|
||||
|
||||
def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str:
|
||||
"""提取函数参数类型的 LLVM 字符串"""
|
||||
if annotation_node is None:
|
||||
return 'i8*'
|
||||
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
|
||||
left_str: str = self.get_llvm_type_str(annotation_node.left)
|
||||
right_str: str = self.get_llvm_type_str(annotation_node.right)
|
||||
if right_str and right_str.endswith('*'):
|
||||
return right_str
|
||||
if left_str and left_str.endswith('*'):
|
||||
return left_str
|
||||
if right_str and right_str not in ('i32', 'void', 'i64'):
|
||||
return right_str
|
||||
if left_str and left_str not in ('i32', 'void', 'i64'):
|
||||
return left_str
|
||||
return right_str if right_str else left_str
|
||||
result: str = self.get_llvm_type_str(annotation_node)
|
||||
return result if result else 'i8*'
|
||||
|
||||
def resolve_typedef_value_type(self, node: ast.AST | None) -> str:
|
||||
"""解析 typedef 值表达式的 C 类型字符串"""
|
||||
if node is None:
|
||||
return ''
|
||||
if isinstance(node, ast.Name):
|
||||
if node.id in self._symtab:
|
||||
Entry: CTypeInfo = self._symtab[node.id]
|
||||
if Entry.IsTypedef and Entry.OriginalType:
|
||||
return Entry.OriginalType
|
||||
return ''
|
||||
if isinstance(node, ast.Attribute):
|
||||
if isinstance(node.value, ast.Name) and IsTModule(node.value.id):
|
||||
# 直接判断属性名是否为 CPtr(消除对 CName=='*' 的依赖)
|
||||
if node.attr == 'CPtr':
|
||||
return 'ptr'
|
||||
CName: str | None = CTypeHelper.GetCName(node.attr)
|
||||
if CName == 'CPtr':
|
||||
return 'ptr'
|
||||
if CName:
|
||||
return CName
|
||||
return ''
|
||||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
left_str: str = self.resolve_typedef_value_type(node.left)
|
||||
right_str: str = self.resolve_typedef_value_type(node.right)
|
||||
if right_str == 'ptr' or (right_str and right_str.endswith('*')):
|
||||
base: str = left_str if left_str and left_str != 'ptr' else ''
|
||||
return base + ' *' if base else 'void *'
|
||||
if left_str == 'ptr' or (left_str and left_str.endswith('*')):
|
||||
base: str = right_str if right_str and right_str != 'ptr' else ''
|
||||
return base + ' *' if base else 'void *'
|
||||
if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'):
|
||||
return right_str
|
||||
if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'):
|
||||
return left_str
|
||||
return left_str if left_str else right_str
|
||||
return ''
|
||||
|
||||
# ==================================================================
|
||||
# 内部解析方法
|
||||
# ==================================================================
|
||||
|
||||
def _ctype_to_llvm_str(self, info: CTypeInfo) -> str:
|
||||
"""从 CTypeInfo 的 BaseType+PtrCount 生成归一化的 LLVM 类型字符串。
|
||||
|
||||
void* 在 LLVM IR 中归一化为 i8*;struct/enum/union 等非基础类型返回空字符串。
|
||||
"""
|
||||
if not info or not info.BaseType:
|
||||
return ''
|
||||
base_type = info.BaseType
|
||||
base_llvm: str = ''
|
||||
if isinstance(base_type, type) and issubclass(base_type, _t.CType):
|
||||
base_llvm = CTypeRegistry.CTypeToLLVM(base_type)
|
||||
elif isinstance(base_type, _t.CType):
|
||||
base_llvm = CTypeRegistry.CTypeToLLVM(type(base_type))
|
||||
if not base_llvm:
|
||||
return ''
|
||||
if info.PtrCount > 0:
|
||||
if base_llvm == 'void':
|
||||
return 'i8*'
|
||||
return base_llvm + '*' * info.PtrCount
|
||||
return base_llvm
|
||||
|
||||
def _ctype_str_to_llvm(self, type_str: str) -> str:
|
||||
"""将 C 类型名字符串(如 'CUnsignedInt *')转换为 LLVM 类型字符串(如 'i32*')
|
||||
|
||||
支持:
|
||||
- C 类名:'CUnsignedInt' → 'i32','CChar' → 'i8'
|
||||
- 指针:'CUnsignedInt *' → 'i32*','void *' → 'i8*'
|
||||
- 已是 LLVM 类型:'i32' → 'i32','i8*' → 'i8*'
|
||||
无法识别返回空字符串。
|
||||
"""
|
||||
s: str = type_str.strip()
|
||||
ptr_count: int = 0
|
||||
while s.endswith('*'):
|
||||
ptr_count += 1
|
||||
s = s[:-1].strip()
|
||||
base_llvm: str = ''
|
||||
if s in ('void', 'CVoid'):
|
||||
base_llvm = 'void'
|
||||
else:
|
||||
base_llvm = CTypeRegistry.NameToLLVM(s)
|
||||
if not base_llvm and s in ('i8', 'i16', 'i32', 'i64', 'float', 'double', 'half', 'fp128', 'void'):
|
||||
base_llvm = s
|
||||
if not base_llvm:
|
||||
return ''
|
||||
if ptr_count > 0:
|
||||
if base_llvm == 'void':
|
||||
return 'i8*'
|
||||
return base_llvm + '*' * ptr_count
|
||||
return base_llvm
|
||||
|
||||
def _resolve_name(self, node: ast.Name) -> str:
|
||||
"""解析 ast.Name 节点"""
|
||||
id_map: dict[str, str] = {
|
||||
'str': 'i8*', 'int': 'i32', 'bool': 'i8',
|
||||
'float': 'double', 'None': 'void',
|
||||
'UINT8PTR': 'i8*', 'INT8PTR': 'i8*', 'BYTEPTR': 'i8*',
|
||||
'UINT16PTR': 'i16*', 'INT16PTR': 'i16*',
|
||||
'UINT32PTR': 'i32*', 'INT32PTR': 'i32*',
|
||||
'UINT64PTR': 'i64*', 'INT64PTR': 'i64*',
|
||||
}
|
||||
if node.id in id_map:
|
||||
return id_map[node.id]
|
||||
# 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名
|
||||
builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id)
|
||||
if builtin_entry:
|
||||
TypeClass: type
|
||||
base_ptr: int
|
||||
TypeClass, base_ptr = builtin_entry
|
||||
base_llvm: str = CTypeRegistry.CTypeToLLVM(TypeClass)
|
||||
if base_ptr > 0:
|
||||
if base_llvm == 'void':
|
||||
return 'i8*'
|
||||
return base_llvm + '*' * base_ptr
|
||||
return base_llvm if base_llvm else 'i32'
|
||||
# 查找 SymbolTable 中的 typedef
|
||||
if node.id in self._symtab:
|
||||
entry: CTypeInfo = self._symtab[node.id]
|
||||
if entry and entry.IsTypedef:
|
||||
# 优先用 OriginalType 解析
|
||||
if entry.OriginalType:
|
||||
if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr:
|
||||
return 'i8*'
|
||||
elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType:
|
||||
# 用 CTypeRegistry 生成归一化 LLVM 字符串(void*→i8*),struct/enum 回退 ToString()
|
||||
resolved: str = self._ctype_to_llvm_str(entry.OriginalType)
|
||||
if resolved:
|
||||
return resolved
|
||||
return entry.OriginalType.ToString()
|
||||
elif isinstance(entry.OriginalType, str):
|
||||
# 字符串形式的 OriginalType(如 'CUnsignedInt *')需转换为 LLVM 类型字符串
|
||||
llvm_str: str = self._ctype_str_to_llvm(entry.OriginalType)
|
||||
if llvm_str:
|
||||
return llvm_str
|
||||
# OriginalType 为空或字符串无法转换时,回退到 BaseType
|
||||
if entry.BaseType and (not isinstance(entry.BaseType, (_t._CTypedef,)) or entry.PtrCount > 0):
|
||||
resolved = self._ctype_to_llvm_str(entry)
|
||||
if resolved:
|
||||
return resolved
|
||||
self._symtab.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}',回退到 i32")
|
||||
return 'i32'
|
||||
|
||||
def _resolve_attribute(self, node: ast.Attribute) -> str:
|
||||
"""解析 ast.Attribute 节点"""
|
||||
attr_name: str = node.attr if hasattr(node, 'attr') else ''
|
||||
llvm_str: str | None = CTypeRegistry.NameToLLVM(attr_name)
|
||||
if llvm_str is not None:
|
||||
return llvm_str
|
||||
if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'):
|
||||
return ''
|
||||
if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'):
|
||||
return 'i8*'
|
||||
if attr_name == 'CVoidPtr':
|
||||
return 'i8*'
|
||||
if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class:
|
||||
return f'%struct.{attr_name}*'
|
||||
if attr_name and attr_name not in CTypeRegistry._name_to_class:
|
||||
return f'%struct.{attr_name}*'
|
||||
self._symtab.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}',回退到 i32")
|
||||
return 'i32'
|
||||
|
||||
def _resolve_subscript(self, node: ast.Subscript) -> str:
|
||||
"""解析 ast.Subscript 节点"""
|
||||
if isinstance(node.value, ast.Name) and node.value.id == 'tuple':
|
||||
slice_node: ast.AST = node.slice
|
||||
elem_types: list[str] = []
|
||||
if isinstance(slice_node, ast.Tuple):
|
||||
elt: ast.AST
|
||||
for elt in slice_node.elts:
|
||||
elem_types.append(self.get_llvm_type_str(elt))
|
||||
else:
|
||||
elem_types.append(self.get_llvm_type_str(slice_node))
|
||||
if elem_types:
|
||||
return '{ ' + ', '.join(elem_types) + ' }'
|
||||
if IsListAnnotation(node):
|
||||
slice_node: ast.AST = node.slice
|
||||
elem_type: str
|
||||
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
|
||||
elem_type = self.get_llvm_type_str(slice_node.elts[0])
|
||||
else:
|
||||
elem_type = self.get_llvm_type_str(slice_node)
|
||||
return elem_type + '*'
|
||||
self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32")
|
||||
return 'i32'
|
||||
|
||||
def _resolve_bitor(self, node: ast.BinOp) -> str:
|
||||
"""解析 ast.BinOp(BitOr) 节点"""
|
||||
left: str = self.get_llvm_type_str(node.left)
|
||||
right: str = self.get_llvm_type_str(node.right)
|
||||
if right and right.endswith('*'):
|
||||
return right
|
||||
if left and left.endswith('*'):
|
||||
return left
|
||||
if left and left not in ('i32', 'void', 'i64'):
|
||||
return left
|
||||
if right and right not in ('i32', 'void', 'i64'):
|
||||
return right
|
||||
return left if left else right
|
||||
|
||||
def _resolve_call(self, node: ast.Call) -> str:
|
||||
"""解析 ast.Call 节点"""
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id):
|
||||
return self.get_llvm_type_str(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr))
|
||||
self._symtab.diagnostics.warn('', 0, "无法解析 Call 类型,回退到 i32")
|
||||
return 'i32'
|
||||
"""LLVMTypeMapper — AST 注解节点到 LLVM IR 类型字符串的映射器
|
||||
|
||||
从 SymbolTable 中提取的类型解析逻辑,职责单一:
|
||||
将 Python AST 注解节点翻译为 LLVM IR 类型字符串(如 'i32', 'i8*', '{ i32, i8* }')。
|
||||
|
||||
原 SymbolTable 上的 4 个方法:
|
||||
- _GetLLVMTypeStr → LLVMTypeMapper.get_llvm_type_str
|
||||
- _GetFuncRetTypeStr → LLVMTypeMapper.get_func_ret_type_str
|
||||
- _GetFuncParamTypeStr → LLVMTypeMapper.get_func_param_type_str
|
||||
- _ResolveTypedefValueType → LLVMTypeMapper.resolve_typedef_value_type
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import vast as ast
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.SymbolTable import SymbolTable
|
||||
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
|
||||
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
|
||||
from lib.includes import t as _t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
|
||||
|
||||
class LLVMTypeMapper:
|
||||
"""AST 注解节点 → LLVM IR 类型字符串 映射器"""
|
||||
|
||||
def __init__(self, symtab: SymbolTable):
|
||||
self._symtab = symtab
|
||||
|
||||
# ==================================================================
|
||||
# 公共 API
|
||||
# ==================================================================
|
||||
|
||||
def get_llvm_type_str(self, node: ast.AST | None) -> str:
|
||||
"""将 AST 注解节点转换为 LLVM IR 类型字符串"""
|
||||
if node is None:
|
||||
self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32")
|
||||
return 'i32'
|
||||
if isinstance(node, ast.Name):
|
||||
return self._resolve_name(node)
|
||||
elif isinstance(node, ast.Attribute):
|
||||
return self._resolve_attribute(node)
|
||||
elif isinstance(node, ast.Subscript):
|
||||
return self._resolve_subscript(node)
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
return self._resolve_bitor(node)
|
||||
elif isinstance(node, ast.Constant):
|
||||
if isinstance(node.value, bool):
|
||||
return 'i8'
|
||||
return 'i32'
|
||||
elif isinstance(node, ast.Call):
|
||||
return self._resolve_call(node)
|
||||
self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32")
|
||||
return 'i32'
|
||||
|
||||
def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str:
|
||||
"""提取函数返回类型的 LLVM 字符串"""
|
||||
if returns_node is None:
|
||||
return 'i32'
|
||||
if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr):
|
||||
left_str: str = self.get_llvm_type_str(returns_node.left)
|
||||
right_str: str = self.get_llvm_type_str(returns_node.right)
|
||||
if right_str and right_str.endswith('*'):
|
||||
return right_str
|
||||
if left_str and left_str.endswith('*'):
|
||||
return left_str
|
||||
if left_str and left_str not in ('i32', 'void', 'i64'):
|
||||
return left_str
|
||||
if right_str and right_str not in ('i32', 'void', 'i64'):
|
||||
return right_str
|
||||
return left_str
|
||||
result: str = self.get_llvm_type_str(returns_node)
|
||||
return result if result else 'i32'
|
||||
|
||||
def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str:
|
||||
"""提取函数参数类型的 LLVM 字符串"""
|
||||
if annotation_node is None:
|
||||
return 'i8*'
|
||||
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
|
||||
left_str: str = self.get_llvm_type_str(annotation_node.left)
|
||||
right_str: str = self.get_llvm_type_str(annotation_node.right)
|
||||
if right_str and right_str.endswith('*'):
|
||||
return right_str
|
||||
if left_str and left_str.endswith('*'):
|
||||
return left_str
|
||||
if right_str and right_str not in ('i32', 'void', 'i64'):
|
||||
return right_str
|
||||
if left_str and left_str not in ('i32', 'void', 'i64'):
|
||||
return left_str
|
||||
return right_str if right_str else left_str
|
||||
result: str = self.get_llvm_type_str(annotation_node)
|
||||
return result if result else 'i8*'
|
||||
|
||||
def resolve_typedef_value_type(self, node: ast.AST | None) -> str:
|
||||
"""解析 typedef 值表达式的 C 类型字符串"""
|
||||
if node is None:
|
||||
return ''
|
||||
if isinstance(node, ast.Name):
|
||||
if node.id in self._symtab:
|
||||
Entry: CTypeInfo = self._symtab[node.id]
|
||||
if Entry.IsTypedef and Entry.OriginalType:
|
||||
return Entry.OriginalType
|
||||
return ''
|
||||
if isinstance(node, ast.Attribute):
|
||||
if isinstance(node.value, ast.Name) and IsTModule(node.value.id):
|
||||
# 直接判断属性名是否为 CPtr(消除对 CName=='*' 的依赖)
|
||||
if node.attr == 'CPtr':
|
||||
return 'ptr'
|
||||
CName: str | None = CTypeHelper.GetCName(node.attr)
|
||||
if CName == 'CPtr':
|
||||
return 'ptr'
|
||||
if CName:
|
||||
return CName
|
||||
return ''
|
||||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
left_str: str = self.resolve_typedef_value_type(node.left)
|
||||
right_str: str = self.resolve_typedef_value_type(node.right)
|
||||
if right_str == 'ptr' or (right_str and right_str.endswith('*')):
|
||||
base: str = left_str if left_str and left_str != 'ptr' else ''
|
||||
return base + ' *' if base else 'void *'
|
||||
if left_str == 'ptr' or (left_str and left_str.endswith('*')):
|
||||
base: str = right_str if right_str and right_str != 'ptr' else ''
|
||||
return base + ' *' if base else 'void *'
|
||||
if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'):
|
||||
return right_str
|
||||
if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'):
|
||||
return left_str
|
||||
return left_str if left_str else right_str
|
||||
return ''
|
||||
|
||||
# ==================================================================
|
||||
# 内部解析方法
|
||||
# ==================================================================
|
||||
|
||||
def _ctype_to_llvm_str(self, info: CTypeInfo) -> str:
|
||||
"""从 CTypeInfo 的 BaseType+PtrCount 生成归一化的 LLVM 类型字符串。
|
||||
|
||||
void* 在 LLVM IR 中归一化为 i8*;struct/enum/union 等非基础类型返回空字符串。
|
||||
"""
|
||||
if not info or not info.BaseType:
|
||||
return ''
|
||||
base_type = info.BaseType
|
||||
base_llvm: str = ''
|
||||
if isinstance(base_type, type) and issubclass(base_type, _t.CType):
|
||||
base_llvm = CTypeRegistry.CTypeToLLVM(base_type)
|
||||
elif isinstance(base_type, _t.CType):
|
||||
base_llvm = CTypeRegistry.CTypeToLLVM(type(base_type))
|
||||
if not base_llvm:
|
||||
return ''
|
||||
if info.PtrCount > 0:
|
||||
if base_llvm == 'void':
|
||||
return 'i8*'
|
||||
return base_llvm + '*' * info.PtrCount
|
||||
return base_llvm
|
||||
|
||||
def _ctype_str_to_llvm(self, type_str: str) -> str:
|
||||
"""将 C 类型名字符串(如 'CUnsignedInt *')转换为 LLVM 类型字符串(如 'i32*')
|
||||
|
||||
支持:
|
||||
- C 类名:'CUnsignedInt' → 'i32','CChar' → 'i8'
|
||||
- 指针:'CUnsignedInt *' → 'i32*','void *' → 'i8*'
|
||||
- 已是 LLVM 类型:'i32' → 'i32','i8*' → 'i8*'
|
||||
无法识别返回空字符串。
|
||||
"""
|
||||
s: str = type_str.strip()
|
||||
ptr_count: int = 0
|
||||
while s.endswith('*'):
|
||||
ptr_count += 1
|
||||
s = s[:-1].strip()
|
||||
base_llvm: str = ''
|
||||
if s in ('void', 'CVoid'):
|
||||
base_llvm = 'void'
|
||||
else:
|
||||
base_llvm = CTypeRegistry.NameToLLVM(s)
|
||||
if not base_llvm and s in ('i8', 'i16', 'i32', 'i64', 'float', 'double', 'half', 'fp128', 'void'):
|
||||
base_llvm = s
|
||||
if not base_llvm:
|
||||
return ''
|
||||
if ptr_count > 0:
|
||||
if base_llvm == 'void':
|
||||
return 'i8*'
|
||||
return base_llvm + '*' * ptr_count
|
||||
return base_llvm
|
||||
|
||||
def _resolve_name(self, node: ast.Name) -> str:
|
||||
"""解析 ast.Name 节点"""
|
||||
id_map: dict[str, str] = {
|
||||
'str': 'i8*', 'int': 'i32', 'bool': 'i8',
|
||||
'float': 'double', 'None': 'void',
|
||||
'UINT8PTR': 'i8*', 'INT8PTR': 'i8*', 'BYTEPTR': 'i8*',
|
||||
'UINT16PTR': 'i16*', 'INT16PTR': 'i16*',
|
||||
'UINT32PTR': 'i32*', 'INT32PTR': 'i32*',
|
||||
'UINT64PTR': 'i64*', 'INT64PTR': 'i64*',
|
||||
}
|
||||
if node.id in id_map:
|
||||
return id_map[node.id]
|
||||
# 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名
|
||||
builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id)
|
||||
if builtin_entry:
|
||||
TypeClass: type
|
||||
base_ptr: int
|
||||
TypeClass, base_ptr = builtin_entry
|
||||
base_llvm: str = CTypeRegistry.CTypeToLLVM(TypeClass)
|
||||
if base_ptr > 0:
|
||||
if base_llvm == 'void':
|
||||
return 'i8*'
|
||||
return base_llvm + '*' * base_ptr
|
||||
return base_llvm if base_llvm else 'i32'
|
||||
# 查找 SymbolTable 中的 typedef
|
||||
if node.id in self._symtab:
|
||||
entry: CTypeInfo = self._symtab[node.id]
|
||||
if entry and entry.IsTypedef:
|
||||
# 优先用 OriginalType 解析
|
||||
if entry.OriginalType:
|
||||
if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr:
|
||||
return 'i8*'
|
||||
elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType:
|
||||
# 用 CTypeRegistry 生成归一化 LLVM 字符串(void*→i8*),struct/enum 回退 ToString()
|
||||
resolved: str = self._ctype_to_llvm_str(entry.OriginalType)
|
||||
if resolved:
|
||||
return resolved
|
||||
return entry.OriginalType.ToString()
|
||||
elif isinstance(entry.OriginalType, str):
|
||||
# 字符串形式的 OriginalType(如 'CUnsignedInt *')需转换为 LLVM 类型字符串
|
||||
llvm_str: str = self._ctype_str_to_llvm(entry.OriginalType)
|
||||
if llvm_str:
|
||||
return llvm_str
|
||||
# OriginalType 为空或字符串无法转换时,回退到 BaseType
|
||||
if entry.BaseType and (not isinstance(entry.BaseType, (_t._CTypedef,)) or entry.PtrCount > 0):
|
||||
resolved = self._ctype_to_llvm_str(entry)
|
||||
if resolved:
|
||||
return resolved
|
||||
self._symtab.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}',回退到 i32")
|
||||
return 'i32'
|
||||
|
||||
def _resolve_attribute(self, node: ast.Attribute) -> str:
|
||||
"""解析 ast.Attribute 节点"""
|
||||
attr_name: str = node.attr if hasattr(node, 'attr') else ''
|
||||
llvm_str: str | None = CTypeRegistry.NameToLLVM(attr_name)
|
||||
if llvm_str is not None:
|
||||
return llvm_str
|
||||
if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'):
|
||||
return ''
|
||||
if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'):
|
||||
return 'i8*'
|
||||
if attr_name == 'CVoidPtr':
|
||||
return 'i8*'
|
||||
if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class:
|
||||
return f'%struct.{attr_name}*'
|
||||
if attr_name and attr_name not in CTypeRegistry._name_to_class:
|
||||
return f'%struct.{attr_name}*'
|
||||
self._symtab.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}',回退到 i32")
|
||||
return 'i32'
|
||||
|
||||
def _resolve_subscript(self, node: ast.Subscript) -> str:
|
||||
"""解析 ast.Subscript 节点"""
|
||||
if isinstance(node.value, ast.Name) and node.value.id == 'tuple':
|
||||
slice_node: ast.AST = node.slice
|
||||
elem_types: list[str] = []
|
||||
if isinstance(slice_node, ast.Tuple):
|
||||
elt: ast.AST
|
||||
for elt in slice_node.elts:
|
||||
elem_types.append(self.get_llvm_type_str(elt))
|
||||
else:
|
||||
elem_types.append(self.get_llvm_type_str(slice_node))
|
||||
if elem_types:
|
||||
return '{ ' + ', '.join(elem_types) + ' }'
|
||||
if IsListAnnotation(node):
|
||||
slice_node: ast.AST = node.slice
|
||||
elem_type: str
|
||||
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
|
||||
elem_type = self.get_llvm_type_str(slice_node.elts[0])
|
||||
else:
|
||||
elem_type = self.get_llvm_type_str(slice_node)
|
||||
return elem_type + '*'
|
||||
self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32")
|
||||
return 'i32'
|
||||
|
||||
def _resolve_bitor(self, node: ast.BinOp) -> str:
|
||||
"""解析 ast.BinOp(BitOr) 节点"""
|
||||
left: str = self.get_llvm_type_str(node.left)
|
||||
right: str = self.get_llvm_type_str(node.right)
|
||||
if right and right.endswith('*'):
|
||||
return right
|
||||
if left and left.endswith('*'):
|
||||
return left
|
||||
if left and left not in ('i32', 'void', 'i64'):
|
||||
return left
|
||||
if right and right not in ('i32', 'void', 'i64'):
|
||||
return right
|
||||
return left if left else right
|
||||
|
||||
def _resolve_call(self, node: ast.Call) -> str:
|
||||
"""解析 ast.Call 节点"""
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id):
|
||||
return self.get_llvm_type_str(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr))
|
||||
self._symtab.diagnostics.warn('', 0, "无法解析 Call 类型,回退到 i32")
|
||||
return 'i32'
|
||||
+85
-85
@@ -1,85 +1,85 @@
|
||||
"""符号表处理的数据结构:四阶段管线中传递的中间数据"""
|
||||
from __future__ import annotations
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, List, Optional, Tuple, TYPE_CHECKING
|
||||
import ast
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
|
||||
|
||||
@dataclass
|
||||
class ClassSymbolData:
|
||||
"""从 AST 提取的类符号数据"""
|
||||
name: str
|
||||
type_kind: str # 'struct', 'union', 'enum', 'exception'
|
||||
lineno: int
|
||||
members: Dict[str, CTypeInfo]
|
||||
is_cpython_object: bool = False
|
||||
is_packed: bool = False
|
||||
enum_members: List[Tuple[str, int, int]] = field(default_factory=list) # (name, value, lineno)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TypedefSymbolData:
|
||||
"""Typedef 符号数据(含原始注解和解析结果)"""
|
||||
name: str
|
||||
lineno: int
|
||||
# 原始注解数据(由 Extractor 设置,Resolver 使用)
|
||||
annotation: ast.expr | None = None
|
||||
value: ast.expr | int | str | float | None = None
|
||||
has_cdefine: bool = False
|
||||
has_postdef: bool = False
|
||||
has_ctypedef: bool = False
|
||||
# 解析结果(由 Resolver 设置,Inserter 使用)
|
||||
original_type_kind: Optional[str] = None
|
||||
original_class: type | None = None
|
||||
members: Optional[Dict] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class FuncSymbolData:
|
||||
"""函数符号数据(含原始注解和解析结果)"""
|
||||
name: str
|
||||
lineno: int
|
||||
# 原始数据(由 Extractor 设置)
|
||||
returns_node: ast.expr | None = None
|
||||
params: List = field(default_factory=list) # [(name, annotation_node), ...]
|
||||
is_variadic: bool = False
|
||||
is_inline: bool = False
|
||||
# 解析结果(由 Resolver 设置)
|
||||
ret_type: str | None = None
|
||||
param_types: List = field(default_factory=list) # [str, ...]
|
||||
# 解析结果(CTypeInfo,保留符号性,由 Resolver 设置)
|
||||
ret_ctype: Optional[CTypeInfo] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class DefineSymbolData:
|
||||
"""Define 符号数据(含原始值和解析结果)"""
|
||||
name: str
|
||||
lineno: int
|
||||
# 原始数据(由 Extractor 设置)
|
||||
value_node: ast.expr | None = None
|
||||
# 解析结果(由 Resolver 设置)
|
||||
value: int | str | float | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class AnonymousTypeData:
|
||||
"""匿名类型数据"""
|
||||
name: str
|
||||
is_union: bool
|
||||
members: Dict[str, CTypeInfo]
|
||||
lineno: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModuleSymbols:
|
||||
"""从模块提取的完整符号数据,在四阶段管线中传递"""
|
||||
file_path: str
|
||||
classes: List[ClassSymbolData] = field(default_factory=list)
|
||||
typedefs: List[TypedefSymbolData] = field(default_factory=list)
|
||||
functions: List[FuncSymbolData] = field(default_factory=list)
|
||||
defines: List[DefineSymbolData] = field(default_factory=list)
|
||||
anonymous_types: Dict[str, AnonymousTypeData] = field(default_factory=dict)
|
||||
"""符号表处理的数据结构:四阶段管线中传递的中间数据"""
|
||||
from __future__ import annotations
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, List, Optional, Tuple, TYPE_CHECKING
|
||||
import vast as ast
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
|
||||
|
||||
@dataclass
|
||||
class ClassSymbolData:
|
||||
"""从 AST 提取的类符号数据"""
|
||||
name: str
|
||||
type_kind: str # 'struct', 'union', 'enum', 'exception'
|
||||
lineno: int
|
||||
members: Dict[str, CTypeInfo]
|
||||
is_cpython_object: bool = False
|
||||
is_packed: bool = False
|
||||
enum_members: List[Tuple[str, int, int]] = field(default_factory=list) # (name, value, lineno)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TypedefSymbolData:
|
||||
"""Typedef 符号数据(含原始注解和解析结果)"""
|
||||
name: str
|
||||
lineno: int
|
||||
# 原始注解数据(由 Extractor 设置,Resolver 使用)
|
||||
annotation: ast.expr | None = None
|
||||
value: ast.expr | int | str | float | None = None
|
||||
has_cdefine: bool = False
|
||||
has_postdef: bool = False
|
||||
has_ctypedef: bool = False
|
||||
# 解析结果(由 Resolver 设置,Inserter 使用)
|
||||
original_type_kind: Optional[str] = None
|
||||
original_class: type | None = None
|
||||
members: Optional[Dict] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class FuncSymbolData:
|
||||
"""函数符号数据(含原始注解和解析结果)"""
|
||||
name: str
|
||||
lineno: int
|
||||
# 原始数据(由 Extractor 设置)
|
||||
returns_node: ast.expr | None = None
|
||||
params: List = field(default_factory=list) # [(name, annotation_node), ...]
|
||||
is_variadic: bool = False
|
||||
is_inline: bool = False
|
||||
# 解析结果(由 Resolver 设置)
|
||||
ret_type: str | None = None
|
||||
param_types: List = field(default_factory=list) # [str, ...]
|
||||
# 解析结果(CTypeInfo,保留符号性,由 Resolver 设置)
|
||||
ret_ctype: Optional[CTypeInfo] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class DefineSymbolData:
|
||||
"""Define 符号数据(含原始值和解析结果)"""
|
||||
name: str
|
||||
lineno: int
|
||||
# 原始数据(由 Extractor 设置)
|
||||
value_node: ast.expr | None = None
|
||||
# 解析结果(由 Resolver 设置)
|
||||
value: int | str | float | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class AnonymousTypeData:
|
||||
"""匿名类型数据"""
|
||||
name: str
|
||||
is_union: bool
|
||||
members: Dict[str, CTypeInfo]
|
||||
lineno: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModuleSymbols:
|
||||
"""从模块提取的完整符号数据,在四阶段管线中传递"""
|
||||
file_path: str
|
||||
classes: List[ClassSymbolData] = field(default_factory=list)
|
||||
typedefs: List[TypedefSymbolData] = field(default_factory=list)
|
||||
functions: List[FuncSymbolData] = field(default_factory=list)
|
||||
defines: List[DefineSymbolData] = field(default_factory=list)
|
||||
anonymous_types: Dict[str, AnonymousTypeData] = field(default_factory=dict)
|
||||
+307
-307
@@ -1,307 +1,307 @@
|
||||
"""Pass 1: ASTSymbolExtractor — 从 AST 提取原始符号信息"""
|
||||
from __future__ import annotations
|
||||
import ast
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.SymbolTable import SymbolTable
|
||||
|
||||
from lib.core.SymbolData import (
|
||||
ModuleSymbols, ClassSymbolData, TypedefSymbolData,
|
||||
FuncSymbolData, DefineSymbolData, AnonymousTypeData
|
||||
)
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline, IsTModule, AnnotationContainsName
|
||||
from lib.includes import t
|
||||
|
||||
|
||||
class ASTSymbolExtractor:
|
||||
"""从 Python 源文件的 AST 中提取所有符号信息"""
|
||||
|
||||
def __init__(self, symbol_table: SymbolTable) -> None:
|
||||
self._symtab: SymbolTable = symbol_table
|
||||
|
||||
def extract(self, file_path: str) -> ModuleSymbols:
|
||||
"""提取文件中的所有符号信息"""
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
code: str = f.read()
|
||||
tree: ast.Module = ast.parse(code)
|
||||
|
||||
result: ModuleSymbols = ModuleSymbols(file_path=file_path)
|
||||
|
||||
# 第一步:收集所有类的成员和匿名类型
|
||||
class_members: dict[str, dict[str, CTypeInfo]] = {}
|
||||
for node in tree.body:
|
||||
if isinstance(node, ast.ClassDef):
|
||||
members: dict[str, CTypeInfo] = {}
|
||||
self._collect_members(node, members, result.anonymous_types)
|
||||
class_members[node.name] = members
|
||||
|
||||
# 第二步:从每个顶层节点提取符号信息
|
||||
for node in tree.body:
|
||||
if isinstance(node, ast.ClassDef):
|
||||
members_info: dict[str, CTypeInfo] = class_members.get(node.name, {})
|
||||
result.classes.append(self._extract_class(node, members_info))
|
||||
elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
|
||||
self._extract_ann_assign(node, result)
|
||||
elif isinstance(node, ast.FunctionDef):
|
||||
result.functions.append(self._extract_function(node))
|
||||
|
||||
return result
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 成员收集(递归处理嵌套匿名类)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _collect_members(self, class_node: ast.ClassDef, members: dict[str, CTypeInfo], anonymous_types: dict[str, AnonymousTypeData], prefix: str = '') -> None:
|
||||
"""递归收集类成员,包括嵌套匿名类型"""
|
||||
for item in class_node.body:
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
member_name: str = item.target.id
|
||||
full_name: str = f'{prefix}{member_name}' if prefix else member_name
|
||||
member_type: CTypeInfo | None = CTypeInfo.FromNode(item.annotation, self._symtab)
|
||||
if member_type is None:
|
||||
member_type = CTypeInfo()
|
||||
member_type.BaseType = t.CInt()
|
||||
is_ptr: bool = member_type.IsPtr
|
||||
if isinstance(item.annotation, ast.BinOp):
|
||||
if AnnotationContainsName(item.annotation, 'CPtr'):
|
||||
is_ptr = True
|
||||
members[full_name] = member_type.Copy()
|
||||
|
||||
elif isinstance(item, ast.ClassDef):
|
||||
is_anonymous: bool = any(
|
||||
any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases)
|
||||
) if item.bases else False
|
||||
|
||||
if is_anonymous:
|
||||
is_union: bool = any(
|
||||
any(AnnotationContainsTType(base, 'CUnion') for base in item.bases)
|
||||
)
|
||||
# 也检查装饰器形式 @t.CUnion
|
||||
if not is_union and hasattr(item, 'decorator_list') and item.decorator_list:
|
||||
for deco in item.decorator_list:
|
||||
if isinstance(deco, ast.Attribute) and hasattr(deco.value, 'id') and IsTModule(deco.value.id, self._symtab) and deco.attr == 'CUnion':
|
||||
is_union = True
|
||||
break
|
||||
elif isinstance(deco, ast.Name):
|
||||
cls2: type | None = getattr(t, deco.id, None)
|
||||
if cls2 is None and hasattr(self._symtab, '_t_type_symbols'):
|
||||
cls2 = self._symtab._t_type_symbols.get(deco.id)
|
||||
if cls2 is not None and isinstance(cls2, type) and issubclass(cls2, t.CUnion):
|
||||
is_union = True
|
||||
break
|
||||
|
||||
nested_name: str = f'{prefix}{item.name}' if prefix else item.name
|
||||
members[nested_name] = CTypeInfo()
|
||||
members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}'
|
||||
members[nested_name].PtrCount = 0
|
||||
members[nested_name].ArrayDims = []
|
||||
|
||||
new_prefix: str = f'{prefix}{item.name}.' if prefix else f'{item.name}.'
|
||||
self._collect_members(item, members, anonymous_types, new_prefix)
|
||||
|
||||
anonymous_members: dict[str, CTypeInfo] = {}
|
||||
for full_name, member_info in members.items():
|
||||
if full_name.startswith(f"{nested_name}."):
|
||||
member_name: str = full_name[len(nested_name) + 1:]
|
||||
anonymous_members[member_name] = member_info
|
||||
|
||||
if item.name not in anonymous_types:
|
||||
anonymous_types[item.name] = AnonymousTypeData(
|
||||
name=item.name,
|
||||
is_union=is_union,
|
||||
members=anonymous_members,
|
||||
lineno=item.lineno
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 类符号提取
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _extract_class(self, node: ast.ClassDef, members_info: dict[str, CTypeInfo]) -> ClassSymbolData:
|
||||
"""从 ClassDef 节点提取类符号数据"""
|
||||
type_kind: str = 'struct'
|
||||
is_cpython_object: bool = False
|
||||
is_packed: bool = False
|
||||
|
||||
# 检查装饰器
|
||||
if hasattr(node, 'decorator_list') and node.decorator_list:
|
||||
for decorator in node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute):
|
||||
if (hasattr(decorator.value, 'id') and
|
||||
IsTModule(decorator.value.id, self._symtab)):
|
||||
if decorator.attr == 'Object':
|
||||
is_cpython_object = True
|
||||
elif decorator.attr == 'CUnion':
|
||||
type_kind = 'union'
|
||||
elif decorator.attr == 'CEnum':
|
||||
type_kind = 'enum'
|
||||
elif decorator.attr == 'REnum':
|
||||
type_kind = 'renum'
|
||||
elif decorator.attr == 'CStruct':
|
||||
type_kind = 'struct'
|
||||
elif isinstance(decorator, ast.Name):
|
||||
# from t import CStruct / CUnion / CEnum / REnum
|
||||
cls: type | None = getattr(t, decorator.id, None)
|
||||
if cls is None and hasattr(self._symtab, '_t_type_symbols'):
|
||||
cls = self._symtab._t_type_symbols.get(decorator.id)
|
||||
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
|
||||
if issubclass(cls, t.CUnion):
|
||||
type_kind = 'union'
|
||||
elif issubclass(cls, t.REnum):
|
||||
type_kind = 'renum'
|
||||
elif issubclass(cls, t.CEnum):
|
||||
type_kind = 'enum'
|
||||
elif issubclass(cls, t.CStruct):
|
||||
type_kind = 'struct'
|
||||
elif decorator.id == 'Object':
|
||||
is_cpython_object = True
|
||||
elif isinstance(decorator, ast.Call):
|
||||
if isinstance(decorator.func, ast.Attribute):
|
||||
if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute':
|
||||
for arg in decorator.args:
|
||||
if isinstance(arg, ast.Attribute):
|
||||
if isinstance(arg.value, ast.Attribute):
|
||||
if hasattr(arg.value.value, 'id') and IsTModule(arg.value.value.id, self._symtab) and arg.value.attr == 'attr' and arg.attr == 'packed':
|
||||
is_packed = True
|
||||
|
||||
# 检查基类
|
||||
for base in node.bases:
|
||||
if AnnotationContainsTType(base, 'CUnion'):
|
||||
type_kind = 'union'
|
||||
break
|
||||
elif AnnotationContainsTType(base, 'CEnum'):
|
||||
type_kind = 'enum'
|
||||
break
|
||||
elif AnnotationContainsTType(base, 'REnum'):
|
||||
type_kind = 'renum'
|
||||
break
|
||||
elif AnnotationContainsTType(base, 'CStruct'):
|
||||
type_kind = 'struct'
|
||||
break
|
||||
elif AnnotationContainsTType(base, 'Object'):
|
||||
is_cpython_object = True
|
||||
type_kind = 'struct'
|
||||
break
|
||||
elif isinstance(base, ast.Name) and base.id == 'Exception':
|
||||
type_kind = 'exception'
|
||||
break
|
||||
elif isinstance(base, ast.Name):
|
||||
base_entry: CTypeInfo | None = self._symtab.get(base.id)
|
||||
if base_entry and base_entry.IsExceptionClass:
|
||||
type_kind = 'exception'
|
||||
break
|
||||
|
||||
# 提取枚举成员
|
||||
enum_members: list[tuple[str, int, int]] = []
|
||||
if type_kind == 'enum':
|
||||
next_enum_value: int = 0
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.Assign):
|
||||
if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name):
|
||||
member_name: str = item.targets[0].id
|
||||
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
|
||||
next_enum_value = item.value.value + 1
|
||||
else:
|
||||
next_enum_value += 1
|
||||
enum_members.append((member_name, next_enum_value - 1, item.lineno))
|
||||
elif isinstance(item, ast.AnnAssign):
|
||||
if isinstance(item.target, ast.Name):
|
||||
member_name: str = item.target.id
|
||||
if item.value:
|
||||
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
|
||||
next_enum_value = item.value.value + 1
|
||||
else:
|
||||
next_enum_value += 1
|
||||
else:
|
||||
next_enum_value += 1
|
||||
enum_members.append((member_name, next_enum_value - 1, item.lineno))
|
||||
|
||||
# REnum 变体提取(嵌套 ClassDef + Assign 显式值)
|
||||
# 与 HandlesClassDef._EmitREnumLlvm 的 tag 分配逻辑对齐:
|
||||
# - 先收集 Assign 显式值
|
||||
# - ClassDef 变体从 max(explicit)+1 开始顺序编号
|
||||
# - Assign 无显式值时用独立计数器 variant_index
|
||||
if type_kind == 'renum':
|
||||
explicit_values: dict[str, int] = {}
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.Assign):
|
||||
for target in item.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
|
||||
explicit_values[target.id] = item.value.value
|
||||
next_class_tag: int = max(explicit_values.values()) + 1 if explicit_values else 0
|
||||
variant_index: int = 0
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.ClassDef):
|
||||
variant_name_r: str = item.name
|
||||
tag: int = next_class_tag
|
||||
next_class_tag += 1
|
||||
enum_members.append((variant_name_r, tag, item.lineno))
|
||||
elif isinstance(item, ast.Assign):
|
||||
for target in item.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
var_name: str = target.id
|
||||
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
|
||||
value: int = item.value.value
|
||||
else:
|
||||
value = variant_index
|
||||
variant_index += 1
|
||||
enum_members.append((var_name, value, item.lineno))
|
||||
|
||||
return ClassSymbolData(
|
||||
name=node.name,
|
||||
type_kind=type_kind,
|
||||
lineno=node.lineno,
|
||||
members=members_info,
|
||||
is_cpython_object=is_cpython_object,
|
||||
is_packed=is_packed,
|
||||
enum_members=enum_members,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# AnnAssign 提取(typedef / define)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None:
|
||||
"""从 AnnAssign 节点提取 typedef 或 define 数据"""
|
||||
var_name: str = node.target.id
|
||||
has_cdefine: bool = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False
|
||||
has_postdef: bool = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False
|
||||
has_ctypedef: bool = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False
|
||||
|
||||
if has_cdefine:
|
||||
result.defines.append(DefineSymbolData(
|
||||
name=var_name,
|
||||
lineno=node.lineno,
|
||||
value_node=node.value,
|
||||
))
|
||||
else:
|
||||
result.typedefs.append(TypedefSymbolData(
|
||||
name=var_name,
|
||||
lineno=node.lineno,
|
||||
annotation=node.annotation,
|
||||
value=node.value,
|
||||
has_cdefine=has_cdefine,
|
||||
has_postdef=has_postdef,
|
||||
has_ctypedef=has_ctypedef,
|
||||
))
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 函数提取
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _extract_function(self, node: ast.FunctionDef) -> FuncSymbolData:
|
||||
"""从 FunctionDef 节点提取函数符号数据"""
|
||||
params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args]
|
||||
is_variadic: bool = node.args.vararg is not None
|
||||
is_inline: bool = CheckAnnotationHasCInline(node.returns)
|
||||
|
||||
return FuncSymbolData(
|
||||
name=node.name,
|
||||
lineno=node.lineno,
|
||||
returns_node=node.returns,
|
||||
params=params,
|
||||
is_variadic=is_variadic,
|
||||
is_inline=is_inline,
|
||||
)
|
||||
"""Pass 1: ASTSymbolExtractor — 从 AST 提取原始符号信息"""
|
||||
from __future__ import annotations
|
||||
import vast as ast
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.SymbolTable import SymbolTable
|
||||
|
||||
from lib.core.SymbolData import (
|
||||
ModuleSymbols, ClassSymbolData, TypedefSymbolData,
|
||||
FuncSymbolData, DefineSymbolData, AnonymousTypeData
|
||||
)
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline, IsTModule, AnnotationContainsName
|
||||
from lib.includes import t
|
||||
|
||||
|
||||
class ASTSymbolExtractor:
|
||||
"""从 Python 源文件的 AST 中提取所有符号信息"""
|
||||
|
||||
def __init__(self, symbol_table: SymbolTable) -> None:
|
||||
self._symtab: SymbolTable = symbol_table
|
||||
|
||||
def extract(self, file_path: str) -> ModuleSymbols:
|
||||
"""提取文件中的所有符号信息"""
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
code: str = f.read()
|
||||
tree: ast.Module = ast.parse(code)
|
||||
|
||||
result: ModuleSymbols = ModuleSymbols(file_path=file_path)
|
||||
|
||||
# 第一步:收集所有类的成员和匿名类型
|
||||
class_members: dict[str, dict[str, CTypeInfo]] = {}
|
||||
for node in tree.body:
|
||||
if isinstance(node, ast.ClassDef):
|
||||
members: dict[str, CTypeInfo] = {}
|
||||
self._collect_members(node, members, result.anonymous_types)
|
||||
class_members[node.name] = members
|
||||
|
||||
# 第二步:从每个顶层节点提取符号信息
|
||||
for node in tree.body:
|
||||
if isinstance(node, ast.ClassDef):
|
||||
members_info: dict[str, CTypeInfo] = class_members.get(node.name, {})
|
||||
result.classes.append(self._extract_class(node, members_info))
|
||||
elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
|
||||
self._extract_ann_assign(node, result)
|
||||
elif isinstance(node, ast.FunctionDef):
|
||||
result.functions.append(self._extract_function(node))
|
||||
|
||||
return result
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 成员收集(递归处理嵌套匿名类)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _collect_members(self, class_node: ast.ClassDef, members: dict[str, CTypeInfo], anonymous_types: dict[str, AnonymousTypeData], prefix: str = '') -> None:
|
||||
"""递归收集类成员,包括嵌套匿名类型"""
|
||||
for item in class_node.body:
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
member_name: str = item.target.id
|
||||
full_name: str = f'{prefix}{member_name}' if prefix else member_name
|
||||
member_type: CTypeInfo | None = CTypeInfo.FromNode(item.annotation, self._symtab)
|
||||
if member_type is None:
|
||||
member_type = CTypeInfo()
|
||||
member_type.BaseType = t.CInt()
|
||||
is_ptr: bool = member_type.IsPtr
|
||||
if isinstance(item.annotation, ast.BinOp):
|
||||
if AnnotationContainsName(item.annotation, 'CPtr'):
|
||||
is_ptr = True
|
||||
members[full_name] = member_type.Copy()
|
||||
|
||||
elif isinstance(item, ast.ClassDef):
|
||||
is_anonymous: bool = any(
|
||||
any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases)
|
||||
) if item.bases else False
|
||||
|
||||
if is_anonymous:
|
||||
is_union: bool = any(
|
||||
any(AnnotationContainsTType(base, 'CUnion') for base in item.bases)
|
||||
)
|
||||
# 也检查装饰器形式 @t.CUnion
|
||||
if not is_union and hasattr(item, 'decorator_list') and item.decorator_list:
|
||||
for deco in item.decorator_list:
|
||||
if isinstance(deco, ast.Attribute) and hasattr(deco.value, 'id') and IsTModule(deco.value.id, self._symtab) and deco.attr == 'CUnion':
|
||||
is_union = True
|
||||
break
|
||||
elif isinstance(deco, ast.Name):
|
||||
cls2: type | None = getattr(t, deco.id, None)
|
||||
if cls2 is None and hasattr(self._symtab, '_t_type_symbols'):
|
||||
cls2 = self._symtab._t_type_symbols.get(deco.id)
|
||||
if cls2 is not None and isinstance(cls2, type) and issubclass(cls2, t.CUnion):
|
||||
is_union = True
|
||||
break
|
||||
|
||||
nested_name: str = f'{prefix}{item.name}' if prefix else item.name
|
||||
members[nested_name] = CTypeInfo()
|
||||
members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}'
|
||||
members[nested_name].PtrCount = 0
|
||||
members[nested_name].ArrayDims = []
|
||||
|
||||
new_prefix: str = f'{prefix}{item.name}.' if prefix else f'{item.name}.'
|
||||
self._collect_members(item, members, anonymous_types, new_prefix)
|
||||
|
||||
anonymous_members: dict[str, CTypeInfo] = {}
|
||||
for full_name, member_info in members.items():
|
||||
if full_name.startswith(f"{nested_name}."):
|
||||
member_name: str = full_name[len(nested_name) + 1:]
|
||||
anonymous_members[member_name] = member_info
|
||||
|
||||
if item.name not in anonymous_types:
|
||||
anonymous_types[item.name] = AnonymousTypeData(
|
||||
name=item.name,
|
||||
is_union=is_union,
|
||||
members=anonymous_members,
|
||||
lineno=item.lineno
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 类符号提取
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _extract_class(self, node: ast.ClassDef, members_info: dict[str, CTypeInfo]) -> ClassSymbolData:
|
||||
"""从 ClassDef 节点提取类符号数据"""
|
||||
type_kind: str = 'struct'
|
||||
is_cpython_object: bool = False
|
||||
is_packed: bool = False
|
||||
|
||||
# 检查装饰器
|
||||
if hasattr(node, 'decorator_list') and node.decorator_list:
|
||||
for decorator in node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute):
|
||||
if (hasattr(decorator.value, 'id') and
|
||||
IsTModule(decorator.value.id, self._symtab)):
|
||||
if decorator.attr == 'Object':
|
||||
is_cpython_object = True
|
||||
elif decorator.attr == 'CUnion':
|
||||
type_kind = 'union'
|
||||
elif decorator.attr == 'CEnum':
|
||||
type_kind = 'enum'
|
||||
elif decorator.attr == 'REnum':
|
||||
type_kind = 'renum'
|
||||
elif decorator.attr == 'CStruct':
|
||||
type_kind = 'struct'
|
||||
elif isinstance(decorator, ast.Name):
|
||||
# from t import CStruct / CUnion / CEnum / REnum
|
||||
cls: type | None = getattr(t, decorator.id, None)
|
||||
if cls is None and hasattr(self._symtab, '_t_type_symbols'):
|
||||
cls = self._symtab._t_type_symbols.get(decorator.id)
|
||||
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
|
||||
if issubclass(cls, t.CUnion):
|
||||
type_kind = 'union'
|
||||
elif issubclass(cls, t.REnum):
|
||||
type_kind = 'renum'
|
||||
elif issubclass(cls, t.CEnum):
|
||||
type_kind = 'enum'
|
||||
elif issubclass(cls, t.CStruct):
|
||||
type_kind = 'struct'
|
||||
elif decorator.id == 'Object':
|
||||
is_cpython_object = True
|
||||
elif isinstance(decorator, ast.Call):
|
||||
if isinstance(decorator.func, ast.Attribute):
|
||||
if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute':
|
||||
for arg in decorator.args:
|
||||
if isinstance(arg, ast.Attribute):
|
||||
if isinstance(arg.value, ast.Attribute):
|
||||
if hasattr(arg.value.value, 'id') and IsTModule(arg.value.value.id, self._symtab) and arg.value.attr == 'attr' and arg.attr == 'packed':
|
||||
is_packed = True
|
||||
|
||||
# 检查基类
|
||||
for base in node.bases:
|
||||
if AnnotationContainsTType(base, 'CUnion'):
|
||||
type_kind = 'union'
|
||||
break
|
||||
elif AnnotationContainsTType(base, 'CEnum'):
|
||||
type_kind = 'enum'
|
||||
break
|
||||
elif AnnotationContainsTType(base, 'REnum'):
|
||||
type_kind = 'renum'
|
||||
break
|
||||
elif AnnotationContainsTType(base, 'CStruct'):
|
||||
type_kind = 'struct'
|
||||
break
|
||||
elif AnnotationContainsTType(base, 'Object'):
|
||||
is_cpython_object = True
|
||||
type_kind = 'struct'
|
||||
break
|
||||
elif isinstance(base, ast.Name) and base.id == 'Exception':
|
||||
type_kind = 'exception'
|
||||
break
|
||||
elif isinstance(base, ast.Name):
|
||||
base_entry: CTypeInfo | None = self._symtab.get(base.id)
|
||||
if base_entry and base_entry.IsExceptionClass:
|
||||
type_kind = 'exception'
|
||||
break
|
||||
|
||||
# 提取枚举成员
|
||||
enum_members: list[tuple[str, int, int]] = []
|
||||
if type_kind == 'enum':
|
||||
next_enum_value: int = 0
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.Assign):
|
||||
if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name):
|
||||
member_name: str = item.targets[0].id
|
||||
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
|
||||
next_enum_value = item.value.value + 1
|
||||
else:
|
||||
next_enum_value += 1
|
||||
enum_members.append((member_name, next_enum_value - 1, item.lineno))
|
||||
elif isinstance(item, ast.AnnAssign):
|
||||
if isinstance(item.target, ast.Name):
|
||||
member_name: str = item.target.id
|
||||
if item.value:
|
||||
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
|
||||
next_enum_value = item.value.value + 1
|
||||
else:
|
||||
next_enum_value += 1
|
||||
else:
|
||||
next_enum_value += 1
|
||||
enum_members.append((member_name, next_enum_value - 1, item.lineno))
|
||||
|
||||
# REnum 变体提取(嵌套 ClassDef + Assign 显式值)
|
||||
# 与 HandlesClassDef._EmitREnumLlvm 的 tag 分配逻辑对齐:
|
||||
# - 先收集 Assign 显式值
|
||||
# - ClassDef 变体从 max(explicit)+1 开始顺序编号
|
||||
# - Assign 无显式值时用独立计数器 variant_index
|
||||
if type_kind == 'renum':
|
||||
explicit_values: dict[str, int] = {}
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.Assign):
|
||||
for target in item.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
|
||||
explicit_values[target.id] = item.value.value
|
||||
next_class_tag: int = max(explicit_values.values()) + 1 if explicit_values else 0
|
||||
variant_index: int = 0
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.ClassDef):
|
||||
variant_name_r: str = item.name
|
||||
tag: int = next_class_tag
|
||||
next_class_tag += 1
|
||||
enum_members.append((variant_name_r, tag, item.lineno))
|
||||
elif isinstance(item, ast.Assign):
|
||||
for target in item.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
var_name: str = target.id
|
||||
if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
|
||||
value: int = item.value.value
|
||||
else:
|
||||
value = variant_index
|
||||
variant_index += 1
|
||||
enum_members.append((var_name, value, item.lineno))
|
||||
|
||||
return ClassSymbolData(
|
||||
name=node.name,
|
||||
type_kind=type_kind,
|
||||
lineno=node.lineno,
|
||||
members=members_info,
|
||||
is_cpython_object=is_cpython_object,
|
||||
is_packed=is_packed,
|
||||
enum_members=enum_members,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# AnnAssign 提取(typedef / define)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None:
|
||||
"""从 AnnAssign 节点提取 typedef 或 define 数据"""
|
||||
var_name: str = node.target.id
|
||||
has_cdefine: bool = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False
|
||||
has_postdef: bool = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False
|
||||
has_ctypedef: bool = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False
|
||||
|
||||
if has_cdefine:
|
||||
result.defines.append(DefineSymbolData(
|
||||
name=var_name,
|
||||
lineno=node.lineno,
|
||||
value_node=node.value,
|
||||
))
|
||||
else:
|
||||
result.typedefs.append(TypedefSymbolData(
|
||||
name=var_name,
|
||||
lineno=node.lineno,
|
||||
annotation=node.annotation,
|
||||
value=node.value,
|
||||
has_cdefine=has_cdefine,
|
||||
has_postdef=has_postdef,
|
||||
has_ctypedef=has_ctypedef,
|
||||
))
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 函数提取
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _extract_function(self, node: ast.FunctionDef) -> FuncSymbolData:
|
||||
"""从 FunctionDef 节点提取函数符号数据"""
|
||||
params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args]
|
||||
is_variadic: bool = node.args.vararg is not None
|
||||
is_inline: bool = CheckAnnotationHasCInline(node.returns)
|
||||
|
||||
return FuncSymbolData(
|
||||
name=node.name,
|
||||
lineno=node.lineno,
|
||||
returns_node=node.returns,
|
||||
params=params,
|
||||
is_variadic=is_variadic,
|
||||
is_inline=is_inline,
|
||||
)
|
||||
+531
-531
File diff suppressed because it is too large.
Load diff
+272
-272
@@ -1,272 +1,272 @@
|
||||
"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值"""
|
||||
from __future__ import annotations
|
||||
import ast
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.SymbolTable import SymbolTable
|
||||
|
||||
from lib.core.SymbolData import (
|
||||
ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData
|
||||
)
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
|
||||
from lib.core.LLVMTypeMapper import LLVMTypeMapper
|
||||
from lib.core.SymbolUtils import IsTModule
|
||||
from lib.includes import t
|
||||
|
||||
|
||||
class TypeResolver:
|
||||
"""解析从 AST 提取的原始符号中的类型信息"""
|
||||
|
||||
def __init__(self, symbol_table: SymbolTable):
|
||||
self._symtab = symbol_table
|
||||
self._type_mapper = LLVMTypeMapper(symbol_table)
|
||||
# 本模块内已解析的 typedef: name → original_class(供同模块 typedef 间引用解析)
|
||||
self._resolved_typedefs: dict[str, str | None] = {}
|
||||
|
||||
def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols:
|
||||
"""解析所有类型信息,就地更新 ModuleSymbols"""
|
||||
# 构建 class_members 查找表(typedef Postdefinition 需要)
|
||||
class_members: dict[str, dict[str, CTypeInfo]] = {cls.name: cls.members for cls in module_symbols.classes}
|
||||
|
||||
# 解析 typedef(按顺序记录,供后续 typedef 引用同模块已解析的 typedef)
|
||||
td: TypedefSymbolData
|
||||
for td in module_symbols.typedefs:
|
||||
self._resolve_typedef(td, class_members)
|
||||
self._resolved_typedefs[td.name] = td.original_class
|
||||
|
||||
# 解析函数签名
|
||||
func: FuncSymbolData
|
||||
for func in module_symbols.functions:
|
||||
self._resolve_function(func)
|
||||
|
||||
# 解析 define 值
|
||||
define: DefineSymbolData
|
||||
for define in module_symbols.defines:
|
||||
self._resolve_define(define)
|
||||
|
||||
return module_symbols
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Typedef 解析
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
|
||||
"""解析单个 typedef 的类型信息"""
|
||||
is_postdef_with_typedef: bool = td.has_postdef and td.has_ctypedef
|
||||
|
||||
if is_postdef_with_typedef:
|
||||
self._resolve_postdef_typedef(td, class_members)
|
||||
elif td.has_ctypedef:
|
||||
self._resolve_ctypedef_typedef(td)
|
||||
else:
|
||||
# 无特殊注解的 typedef
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
|
||||
def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
|
||||
"""解析 Postdefinition + CTypedef 组合注解"""
|
||||
original_class: str | None = self._find_postdef_arg(td.annotation)
|
||||
if original_class and original_class in class_members:
|
||||
members_info: dict[str, CTypeInfo] = class_members[original_class]
|
||||
original_type_kind: str = 'struct'
|
||||
if original_class in self._symtab:
|
||||
orig_type_info: CTypeInfo = self._symtab[original_class]
|
||||
if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion):
|
||||
if orig_type_info.type_cls is t.CStruct:
|
||||
original_type_kind = 'struct'
|
||||
elif orig_type_info.type_cls is t.CEnum:
|
||||
original_type_kind = 'enum'
|
||||
elif orig_type_info.type_cls is t.CUnion:
|
||||
original_type_kind = 'union'
|
||||
td.original_type_kind = original_type_kind
|
||||
td.original_class = original_class
|
||||
td.members = members_info
|
||||
else:
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
|
||||
def _resolve_ctypedef_typedef(self, td: TypedefSymbolData):
|
||||
"""解析 CTypedef 注解"""
|
||||
base_type_name: str | None = self._find_base_type(td.annotation)
|
||||
_TYPE_QUALIFIERS: frozenset[str] = frozenset({'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'})
|
||||
|
||||
if base_type_name == 'Callable':
|
||||
original_type: CTypeInfo = CTypeInfo()
|
||||
original_type.IsFuncPtr = True
|
||||
original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
|
||||
original_type.FuncPtrParams = []
|
||||
td.original_type_kind = 'typedef'
|
||||
td.original_class = original_type
|
||||
elif base_type_name and base_type_name not in _TYPE_QUALIFIERS:
|
||||
cname: str | None = CTypeHelper.GetCName(base_type_name)
|
||||
if cname:
|
||||
td.original_class = cname
|
||||
else:
|
||||
td.original_class = base_type_name
|
||||
td.original_type_kind = 'typedef'
|
||||
else:
|
||||
# 尝试从值表达式解析
|
||||
self._resolve_typedef_from_value(td)
|
||||
|
||||
def _resolve_typedef_from_value(self, td: TypedefSymbolData):
|
||||
"""从值表达式解析 typedef 类型
|
||||
|
||||
BinOp(如 UINT | t.CPtr)优先于 _find_base_type 处理,
|
||||
因为 _find_base_type 是静态方法无法解析 Name 引用(如 UINT)。
|
||||
"""
|
||||
if not td.value:
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
return
|
||||
|
||||
# 优先处理 BinOp(_find_base_type 无法解析 Name 引用)
|
||||
if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr):
|
||||
left_type: str = self._resolve_type_expr(td.value.left)
|
||||
right_type: str = self._resolve_type_expr(td.value.right)
|
||||
is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr'
|
||||
if is_ptr_type:
|
||||
base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '')
|
||||
original_type: str = (base_name + ' *') if base_name else 'void *'
|
||||
td.original_class = original_type
|
||||
td.original_type_kind = 'typedef'
|
||||
elif left_type:
|
||||
td.original_class = left_type
|
||||
td.original_type_kind = 'typedef'
|
||||
elif right_type:
|
||||
td.original_class = right_type
|
||||
td.original_type_kind = 'typedef'
|
||||
else:
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
return
|
||||
|
||||
# 非 BinOp:使用 _find_base_type
|
||||
value_base_type: str | None = self._find_base_type(td.value)
|
||||
_PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'})
|
||||
|
||||
if value_base_type and value_base_type not in _PTR_MODIFIERS:
|
||||
cname: str | None = CTypeHelper.GetCName(value_base_type)
|
||||
if cname:
|
||||
td.original_class = cname
|
||||
else:
|
||||
td.original_class = value_base_type
|
||||
td.original_type_kind = 'typedef'
|
||||
return
|
||||
|
||||
if isinstance(td.value, ast.Name):
|
||||
ref_name: str = td.value.id
|
||||
# 先查本模块已解析的 typedef
|
||||
if ref_name in self._resolved_typedefs:
|
||||
ref_class: str | None = self._resolved_typedefs[ref_name]
|
||||
if ref_class:
|
||||
td.original_class = ref_class
|
||||
td.original_type_kind = 'typedef'
|
||||
return
|
||||
# 再查 symtab(跨模块)
|
||||
if ref_name in self._symtab:
|
||||
ref_info: CTypeInfo = self._symtab[ref_name]
|
||||
if ref_info and ref_info.IsTypedef and ref_info.OriginalType:
|
||||
td.original_class = ref_info.OriginalType
|
||||
td.original_type_kind = 'typedef'
|
||||
return
|
||||
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
|
||||
def _resolve_type_expr(self, node: ast.AST) -> str:
|
||||
"""解析类型表达式为 C 类型名字符串,优先查本模块已解析的 typedef
|
||||
|
||||
解决同模块 typedef 间引用(如 UINTPTR = UINT | t.CPtr 中的 UINT)
|
||||
在 TypeResolver 阶段尚未插入 symtab 的问题。
|
||||
"""
|
||||
if isinstance(node, ast.Name):
|
||||
if node.id in self._resolved_typedefs:
|
||||
return self._resolved_typedefs[node.id] or ''
|
||||
return self._type_mapper.resolve_typedef_value_type(node)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 函数签名解析
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _resolve_function(self, func: FuncSymbolData):
|
||||
"""解析函数的返回类型和参数类型"""
|
||||
func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node)
|
||||
# 同时解析为 CTypeInfo,保留符号性(LLVM 类型字符串 'i64' 不区分有无符号)
|
||||
if func.returns_node is not None:
|
||||
try:
|
||||
func.ret_ctype = CTypeInfo.FromNode(func.returns_node, self._symtab)
|
||||
except Exception:
|
||||
func.ret_ctype = None
|
||||
func.param_types = []
|
||||
_arg_name: str
|
||||
annotation: ast.expr | None
|
||||
for _arg_name, annotation in func.params:
|
||||
if annotation:
|
||||
func.param_types.append(self._type_mapper.get_func_param_type_str(annotation))
|
||||
else:
|
||||
func.param_types.append('i8*')
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Define 值解析
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _resolve_define(self, define: DefineSymbolData):
|
||||
"""解析 define 常量值"""
|
||||
if define.value_node:
|
||||
define.value = self._symtab._eval_const_expr(define.value_node)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 静态工具方法(原 _LoadSymbolsFromFile 中的闭包)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _find_base_type(node: ast.AST | None) -> str | None:
|
||||
"""从注解 AST 节点中查找基础类型名称"""
|
||||
if isinstance(node, ast.Attribute):
|
||||
if hasattr(node.value, 'id') and IsTModule(node.value.id):
|
||||
if node.attr == 'CPtr':
|
||||
return 'ptr'
|
||||
return node.attr
|
||||
elif isinstance(node, ast.Subscript):
|
||||
if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and IsTModule(node.value.value.id) and node.value.attr == 'Callable':
|
||||
return 'Callable'
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
left_result: str | None = TypeResolver._find_base_type(node.left)
|
||||
if left_result == 'ptr':
|
||||
right_result: str | None = TypeResolver._find_base_type(node.right)
|
||||
return (right_result if right_result and right_result != 'ptr' else 'void') + ' *'
|
||||
if left_result == 'Callable':
|
||||
return 'Callable'
|
||||
right_result: str | None = TypeResolver._find_base_type(node.right)
|
||||
if right_result == 'ptr':
|
||||
return (left_result if left_result and left_result != 'ptr' else 'void') + ' *'
|
||||
if right_result == 'Callable':
|
||||
return 'Callable'
|
||||
# 类型拼接语义:CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong
|
||||
long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'})
|
||||
if left_result in long_types and right_result in long_types:
|
||||
if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong':
|
||||
return 'CUnsignedLongLong'
|
||||
return 'CLongLong'
|
||||
if left_result:
|
||||
return left_result
|
||||
if right_result:
|
||||
return right_result
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _find_postdef_arg(node: ast.AST | None) -> str | None:
|
||||
"""从注解 AST 节点中查找 Postdefinition 参数"""
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id) and node.func.attr == 'Postdefinition':
|
||||
if node.args and isinstance(node.args[0], ast.Name):
|
||||
return node.args[0].id
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
left_result: str | None = TypeResolver._find_postdef_arg(node.left)
|
||||
if left_result:
|
||||
return left_result
|
||||
right_result: str | None = TypeResolver._find_postdef_arg(node.right)
|
||||
if right_result:
|
||||
return right_result
|
||||
return None
|
||||
"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值"""
|
||||
from __future__ import annotations
|
||||
import vast as ast
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.SymbolTable import SymbolTable
|
||||
|
||||
from lib.core.SymbolData import (
|
||||
ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData
|
||||
)
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
|
||||
from lib.core.LLVMTypeMapper import LLVMTypeMapper
|
||||
from lib.core.SymbolUtils import IsTModule
|
||||
from lib.includes import t
|
||||
|
||||
|
||||
class TypeResolver:
|
||||
"""解析从 AST 提取的原始符号中的类型信息"""
|
||||
|
||||
def __init__(self, symbol_table: SymbolTable):
|
||||
self._symtab = symbol_table
|
||||
self._type_mapper = LLVMTypeMapper(symbol_table)
|
||||
# 本模块内已解析的 typedef: name → original_class(供同模块 typedef 间引用解析)
|
||||
self._resolved_typedefs: dict[str, str | None] = {}
|
||||
|
||||
def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols:
|
||||
"""解析所有类型信息,就地更新 ModuleSymbols"""
|
||||
# 构建 class_members 查找表(typedef Postdefinition 需要)
|
||||
class_members: dict[str, dict[str, CTypeInfo]] = {cls.name: cls.members for cls in module_symbols.classes}
|
||||
|
||||
# 解析 typedef(按顺序记录,供后续 typedef 引用同模块已解析的 typedef)
|
||||
td: TypedefSymbolData
|
||||
for td in module_symbols.typedefs:
|
||||
self._resolve_typedef(td, class_members)
|
||||
self._resolved_typedefs[td.name] = td.original_class
|
||||
|
||||
# 解析函数签名
|
||||
func: FuncSymbolData
|
||||
for func in module_symbols.functions:
|
||||
self._resolve_function(func)
|
||||
|
||||
# 解析 define 值
|
||||
define: DefineSymbolData
|
||||
for define in module_symbols.defines:
|
||||
self._resolve_define(define)
|
||||
|
||||
return module_symbols
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Typedef 解析
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
|
||||
"""解析单个 typedef 的类型信息"""
|
||||
is_postdef_with_typedef: bool = td.has_postdef and td.has_ctypedef
|
||||
|
||||
if is_postdef_with_typedef:
|
||||
self._resolve_postdef_typedef(td, class_members)
|
||||
elif td.has_ctypedef:
|
||||
self._resolve_ctypedef_typedef(td)
|
||||
else:
|
||||
# 无特殊注解的 typedef
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
|
||||
def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
|
||||
"""解析 Postdefinition + CTypedef 组合注解"""
|
||||
original_class: str | None = self._find_postdef_arg(td.annotation)
|
||||
if original_class and original_class in class_members:
|
||||
members_info: dict[str, CTypeInfo] = class_members[original_class]
|
||||
original_type_kind: str = 'struct'
|
||||
if original_class in self._symtab:
|
||||
orig_type_info: CTypeInfo = self._symtab[original_class]
|
||||
if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion):
|
||||
if orig_type_info.type_cls is t.CStruct:
|
||||
original_type_kind = 'struct'
|
||||
elif orig_type_info.type_cls is t.CEnum:
|
||||
original_type_kind = 'enum'
|
||||
elif orig_type_info.type_cls is t.CUnion:
|
||||
original_type_kind = 'union'
|
||||
td.original_type_kind = original_type_kind
|
||||
td.original_class = original_class
|
||||
td.members = members_info
|
||||
else:
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
|
||||
def _resolve_ctypedef_typedef(self, td: TypedefSymbolData):
|
||||
"""解析 CTypedef 注解"""
|
||||
base_type_name: str | None = self._find_base_type(td.annotation)
|
||||
_TYPE_QUALIFIERS: frozenset[str] = frozenset({'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'})
|
||||
|
||||
if base_type_name == 'Callable':
|
||||
original_type: CTypeInfo = CTypeInfo()
|
||||
original_type.IsFuncPtr = True
|
||||
original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
|
||||
original_type.FuncPtrParams = []
|
||||
td.original_type_kind = 'typedef'
|
||||
td.original_class = original_type
|
||||
elif base_type_name and base_type_name not in _TYPE_QUALIFIERS:
|
||||
cname: str | None = CTypeHelper.GetCName(base_type_name)
|
||||
if cname:
|
||||
td.original_class = cname
|
||||
else:
|
||||
td.original_class = base_type_name
|
||||
td.original_type_kind = 'typedef'
|
||||
else:
|
||||
# 尝试从值表达式解析
|
||||
self._resolve_typedef_from_value(td)
|
||||
|
||||
def _resolve_typedef_from_value(self, td: TypedefSymbolData):
|
||||
"""从值表达式解析 typedef 类型
|
||||
|
||||
BinOp(如 UINT | t.CPtr)优先于 _find_base_type 处理,
|
||||
因为 _find_base_type 是静态方法无法解析 Name 引用(如 UINT)。
|
||||
"""
|
||||
if not td.value:
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
return
|
||||
|
||||
# 优先处理 BinOp(_find_base_type 无法解析 Name 引用)
|
||||
if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr):
|
||||
left_type: str = self._resolve_type_expr(td.value.left)
|
||||
right_type: str = self._resolve_type_expr(td.value.right)
|
||||
is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr'
|
||||
if is_ptr_type:
|
||||
base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '')
|
||||
original_type: str = (base_name + ' *') if base_name else 'void *'
|
||||
td.original_class = original_type
|
||||
td.original_type_kind = 'typedef'
|
||||
elif left_type:
|
||||
td.original_class = left_type
|
||||
td.original_type_kind = 'typedef'
|
||||
elif right_type:
|
||||
td.original_class = right_type
|
||||
td.original_type_kind = 'typedef'
|
||||
else:
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
return
|
||||
|
||||
# 非 BinOp:使用 _find_base_type
|
||||
value_base_type: str | None = self._find_base_type(td.value)
|
||||
_PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'})
|
||||
|
||||
if value_base_type and value_base_type not in _PTR_MODIFIERS:
|
||||
cname: str | None = CTypeHelper.GetCName(value_base_type)
|
||||
if cname:
|
||||
td.original_class = cname
|
||||
else:
|
||||
td.original_class = value_base_type
|
||||
td.original_type_kind = 'typedef'
|
||||
return
|
||||
|
||||
if isinstance(td.value, ast.Name):
|
||||
ref_name: str = td.value.id
|
||||
# 先查本模块已解析的 typedef
|
||||
if ref_name in self._resolved_typedefs:
|
||||
ref_class: str | None = self._resolved_typedefs[ref_name]
|
||||
if ref_class:
|
||||
td.original_class = ref_class
|
||||
td.original_type_kind = 'typedef'
|
||||
return
|
||||
# 再查 symtab(跨模块)
|
||||
if ref_name in self._symtab:
|
||||
ref_info: CTypeInfo = self._symtab[ref_name]
|
||||
if ref_info and ref_info.IsTypedef and ref_info.OriginalType:
|
||||
td.original_class = ref_info.OriginalType
|
||||
td.original_type_kind = 'typedef'
|
||||
return
|
||||
|
||||
td.original_type_kind = None
|
||||
td.original_class = None
|
||||
|
||||
def _resolve_type_expr(self, node: ast.AST) -> str:
|
||||
"""解析类型表达式为 C 类型名字符串,优先查本模块已解析的 typedef
|
||||
|
||||
解决同模块 typedef 间引用(如 UINTPTR = UINT | t.CPtr 中的 UINT)
|
||||
在 TypeResolver 阶段尚未插入 symtab 的问题。
|
||||
"""
|
||||
if isinstance(node, ast.Name):
|
||||
if node.id in self._resolved_typedefs:
|
||||
return self._resolved_typedefs[node.id] or ''
|
||||
return self._type_mapper.resolve_typedef_value_type(node)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 函数签名解析
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _resolve_function(self, func: FuncSymbolData):
|
||||
"""解析函数的返回类型和参数类型"""
|
||||
func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node)
|
||||
# 同时解析为 CTypeInfo,保留符号性(LLVM 类型字符串 'i64' 不区分有无符号)
|
||||
if func.returns_node is not None:
|
||||
try:
|
||||
func.ret_ctype = CTypeInfo.FromNode(func.returns_node, self._symtab)
|
||||
except Exception:
|
||||
func.ret_ctype = None
|
||||
func.param_types = []
|
||||
_arg_name: str
|
||||
annotation: ast.expr | None
|
||||
for _arg_name, annotation in func.params:
|
||||
if annotation:
|
||||
func.param_types.append(self._type_mapper.get_func_param_type_str(annotation))
|
||||
else:
|
||||
func.param_types.append('i8*')
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Define 值解析
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _resolve_define(self, define: DefineSymbolData):
|
||||
"""解析 define 常量值"""
|
||||
if define.value_node:
|
||||
define.value = self._symtab._eval_const_expr(define.value_node)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 静态工具方法(原 _LoadSymbolsFromFile 中的闭包)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def _find_base_type(node: ast.AST | None) -> str | None:
|
||||
"""从注解 AST 节点中查找基础类型名称"""
|
||||
if isinstance(node, ast.Attribute):
|
||||
if hasattr(node.value, 'id') and IsTModule(node.value.id):
|
||||
if node.attr == 'CPtr':
|
||||
return 'ptr'
|
||||
return node.attr
|
||||
elif isinstance(node, ast.Subscript):
|
||||
if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and IsTModule(node.value.value.id) and node.value.attr == 'Callable':
|
||||
return 'Callable'
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
left_result: str | None = TypeResolver._find_base_type(node.left)
|
||||
if left_result == 'ptr':
|
||||
right_result: str | None = TypeResolver._find_base_type(node.right)
|
||||
return (right_result if right_result and right_result != 'ptr' else 'void') + ' *'
|
||||
if left_result == 'Callable':
|
||||
return 'Callable'
|
||||
right_result: str | None = TypeResolver._find_base_type(node.right)
|
||||
if right_result == 'ptr':
|
||||
return (left_result if left_result and left_result != 'ptr' else 'void') + ' *'
|
||||
if right_result == 'Callable':
|
||||
return 'Callable'
|
||||
# 类型拼接语义:CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong
|
||||
long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'})
|
||||
if left_result in long_types and right_result in long_types:
|
||||
if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong':
|
||||
return 'CUnsignedLongLong'
|
||||
return 'CLongLong'
|
||||
if left_result:
|
||||
return left_result
|
||||
if right_result:
|
||||
return right_result
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _find_postdef_arg(node: ast.AST | None) -> str | None:
|
||||
"""从注解 AST 节点中查找 Postdefinition 参数"""
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id) and node.func.attr == 'Postdefinition':
|
||||
if node.args and isinstance(node.args[0], ast.Name):
|
||||
return node.args[0].id
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
left_result: str | None = TypeResolver._find_postdef_arg(node.left)
|
||||
if left_result:
|
||||
return left_result
|
||||
right_result: str | None = TypeResolver._find_postdef_arg(node.right)
|
||||
if right_result:
|
||||
return right_result
|
||||
return None
|
||||
+233
-233
@@ -1,233 +1,233 @@
|
||||
"""共享工具函数:符号表处理中使用的 AST 分析工具"""
|
||||
from __future__ import annotations
|
||||
import ast
|
||||
import re
|
||||
from lib.includes import t
|
||||
|
||||
_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__})
|
||||
|
||||
# Viper 软关键字 fn/fun/func/function 是 def 的别名(行首 + 空白 + 标识符才算函数定义,
|
||||
# 变量名/调用/注解中的 fn 不受影响)。展开为 def 后行号不变,供 ast.parse 使用。
|
||||
_SOFT_KEYWORD_RE: re.Pattern[str] = re.compile(
|
||||
r'^(\s*)(function|func|fun|fn)(\s+)(?=[A-Za-z_])', re.MULTILINE
|
||||
)
|
||||
|
||||
|
||||
def ExpandSoftKeywords(Code: str) -> str:
|
||||
"""将 Viper 软关键字 fn/fun/func/function 展开为 def(函数定义行)。
|
||||
|
||||
仅在"行首缩进 + 关键字 + 空白 + 标识符"的函数定义形态匹配,
|
||||
变量名(fn = 5)、调用(fn(x))、注解(x: fn)与字符串内容不受影响。
|
||||
展开为 def 与关键字等宽或更短,行号不变,AST 行号映射保持有效。
|
||||
"""
|
||||
if not Code:
|
||||
return Code
|
||||
return _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code)
|
||||
|
||||
|
||||
def IsTModule(module_id: str, symtable: object | None = None) -> bool:
|
||||
"""检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)"""
|
||||
if module_id in _T_MODULE_NAMES:
|
||||
return True
|
||||
if symtable is not None and hasattr(symtable, 'import_aliases'):
|
||||
resolved: str = symtable.import_aliases.get(module_id, module_id)
|
||||
if resolved in _T_MODULE_NAMES:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def IsTModulePath(module_path: str) -> bool:
|
||||
"""检查模块路径是否指向 t 类型模块"""
|
||||
if module_path in _T_MODULE_NAMES:
|
||||
return True
|
||||
if module_path:
|
||||
t_name: str
|
||||
for t_name in _T_MODULE_NAMES:
|
||||
if module_path == t_name or module_path.startswith(t_name + '.'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool:
|
||||
"""检测 AST 节点中是否包含指定名称的 t 模块类型"""
|
||||
if isinstance(node, ast.Attribute):
|
||||
if (hasattr(node.value, 'id') and IsTModule(node.value.id) and
|
||||
node.attr == TypeName):
|
||||
return True
|
||||
elif isinstance(node, ast.BinOp):
|
||||
return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName)
|
||||
elif isinstance(node, ast.Call):
|
||||
if AnnotationContainsTType(node.func, TypeName):
|
||||
return True
|
||||
for arg in node.args:
|
||||
if AnnotationContainsTType(arg, TypeName):
|
||||
return True
|
||||
elif isinstance(node, ast.Subscript):
|
||||
if AnnotationContainsTType(node.value, TypeName):
|
||||
return True
|
||||
if AnnotationContainsTType(node.slice, TypeName):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def IsListAnnotation(annotation: ast.expr) -> bool:
|
||||
"""检查注解是否为栈上固定数组类型(t.CArray[...] 或 list[type, count])"""
|
||||
if not isinstance(annotation, ast.Subscript):
|
||||
return False
|
||||
value = annotation.value
|
||||
# t.CArray[...]
|
||||
if (isinstance(value, ast.Attribute)
|
||||
and isinstance(value.value, ast.Name)
|
||||
and value.value.id == 't'
|
||||
and value.attr == 'CArray'):
|
||||
return True
|
||||
# list[type, count] — 仅匹配双参数 Tuple 切片(固定数组),
|
||||
# 单参数 list[type] 不匹配(走泛型类 list[T] 路径)
|
||||
if (isinstance(value, ast.Name)
|
||||
and value.id == 'list'
|
||||
and isinstance(annotation.slice, ast.Tuple)
|
||||
and len(annotation.slice.elts) == 2):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None:
|
||||
"""从 BinOp(BitOr) 注解中提取 list[...] 部分,如 list[i32] | t.CPtr"""
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
for side in (annotation.left, annotation.right):
|
||||
if IsListAnnotation(side):
|
||||
return side
|
||||
return None
|
||||
|
||||
|
||||
class ListAnnotationParseResult:
|
||||
"""list[...] 注解解析结果。
|
||||
|
||||
is_pointer=True 表示单参数 list[type] → 指针模式;
|
||||
is_pointer=False 表示 Tuple(2) 模式 list[type, count]。
|
||||
"""
|
||||
__slots__ = ('elem_type_node', 'count_node', 'is_pointer')
|
||||
|
||||
def __init__(self, elem_type_node: ast.expr, count_node: ast.expr | None, is_pointer: bool) -> None:
|
||||
self.elem_type_node: ast.expr = elem_type_node
|
||||
self.count_node: ast.expr | None = count_node
|
||||
self.is_pointer: bool = is_pointer
|
||||
|
||||
|
||||
def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None:
|
||||
"""解析 list[...] 注解,统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。
|
||||
|
||||
自动处理 BinOp(BitOr) 包裹(如 list[i32, N] | t.CPtr)。
|
||||
返回 None 表示不是 list 注解。
|
||||
"""
|
||||
list_node: ast.expr = annotation
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
extracted: ast.Subscript | None = ExtractListFromBinOp(annotation)
|
||||
if extracted is None:
|
||||
return None
|
||||
list_node = extracted
|
||||
if not IsListAnnotation(list_node):
|
||||
return None
|
||||
slice_node: ast.AST = list_node.slice
|
||||
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
|
||||
return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False)
|
||||
# 单参数 list[type] → 指针模式
|
||||
return ListAnnotationParseResult(slice_node, None, is_pointer=True)
|
||||
|
||||
|
||||
def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool:
|
||||
"""检测注解节点中是否包含 CInline"""
|
||||
if annotation_node is None:
|
||||
return False
|
||||
if isinstance(annotation_node, ast.Attribute):
|
||||
if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline':
|
||||
return True
|
||||
if isinstance(annotation_node, ast.Name):
|
||||
if annotation_node.id == 'CInline':
|
||||
return True
|
||||
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
|
||||
return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right)
|
||||
return False
|
||||
|
||||
|
||||
def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None:
|
||||
"""从 BinOp(BitOr) 注解左侧提取类型名(如 TypeA | TypeB → TypeA)。
|
||||
|
||||
返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。
|
||||
"""
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
left: ast.expr = annotation.left
|
||||
if isinstance(left, ast.Name):
|
||||
return left.id
|
||||
if isinstance(left, ast.Attribute):
|
||||
return left.attr
|
||||
return None
|
||||
|
||||
|
||||
def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None:
|
||||
"""递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。
|
||||
|
||||
检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。
|
||||
支持泛型特化类型(如 GSList[Param]),构造特化名后检查是否在 struct_names 中。
|
||||
"""
|
||||
if isinstance(node, ast.Name) and node.id in struct_names:
|
||||
return node.id
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names:
|
||||
return node.value
|
||||
if isinstance(node, ast.Attribute) and node.attr in struct_names:
|
||||
return node.attr
|
||||
if isinstance(node, ast.Subscript):
|
||||
base_name: str | None = None
|
||||
if isinstance(node.value, ast.Name):
|
||||
base_name = node.value.id
|
||||
elif isinstance(node.value, ast.Attribute):
|
||||
base_name = node.value.attr
|
||||
if base_name:
|
||||
slice_node: ast.AST = node.slice
|
||||
if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index):
|
||||
slice_node = slice_node.value
|
||||
type_args: list[str] = []
|
||||
if isinstance(slice_node, ast.Name):
|
||||
type_args.append(slice_node.id)
|
||||
elif isinstance(slice_node, ast.Attribute):
|
||||
type_args.append(slice_node.attr)
|
||||
elif isinstance(slice_node, ast.Tuple):
|
||||
for elt in slice_node.elts:
|
||||
if isinstance(elt, ast.Name):
|
||||
type_args.append(elt.id)
|
||||
elif isinstance(elt, ast.Attribute):
|
||||
type_args.append(elt.attr)
|
||||
if type_args:
|
||||
spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
|
||||
if spec_name in struct_names:
|
||||
return spec_name
|
||||
if base_name in struct_names:
|
||||
return base_name
|
||||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
result: str | None = FindStructNameInAnnotation(node.left, struct_names)
|
||||
if result:
|
||||
return result
|
||||
return FindStructNameInAnnotation(node.right, struct_names)
|
||||
return None
|
||||
|
||||
|
||||
def AnnotationContainsName(annotation: ast.AST, name: str) -> bool:
|
||||
"""检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。
|
||||
|
||||
同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。
|
||||
"""
|
||||
if isinstance(annotation, ast.Attribute):
|
||||
return annotation.attr == name
|
||||
if isinstance(annotation, ast.Name):
|
||||
return annotation.id == name
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name)
|
||||
return False
|
||||
|
||||
|
||||
def IsCPtrNode(node: ast.AST) -> bool:
|
||||
"""检查节点是否为 t.CPtr 属性引用。"""
|
||||
return (isinstance(node, ast.Attribute)
|
||||
and isinstance(node.value, ast.Name)
|
||||
and node.value.id == 't'
|
||||
and node.attr == 'CPtr')
|
||||
"""共享工具函数:符号表处理中使用的 AST 分析工具"""
|
||||
from __future__ import annotations
|
||||
import vast as ast
|
||||
import re
|
||||
from lib.includes import t
|
||||
|
||||
_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__})
|
||||
|
||||
# Viper 软关键字 fn/fun/func/function 是 def 的别名(行首 + 空白 + 标识符才算函数定义,
|
||||
# 变量名/调用/注解中的 fn 不受影响)。展开为 def 后行号不变,供 ast.parse 使用。
|
||||
_SOFT_KEYWORD_RE: re.Pattern[str] = re.compile(
|
||||
r'^(\s*)(function|func|fun|fn)(\s+)(?=[A-Za-z_])', re.MULTILINE
|
||||
)
|
||||
|
||||
|
||||
def ExpandSoftKeywords(Code: str) -> str:
|
||||
"""将 Viper 软关键字 fn/fun/func/function 展开为 def(函数定义行)。
|
||||
|
||||
仅在"行首缩进 + 关键字 + 空白 + 标识符"的函数定义形态匹配,
|
||||
变量名(fn = 5)、调用(fn(x))、注解(x: fn)与字符串内容不受影响。
|
||||
展开为 def 与关键字等宽或更短,行号不变,AST 行号映射保持有效。
|
||||
"""
|
||||
if not Code:
|
||||
return Code
|
||||
return _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code)
|
||||
|
||||
|
||||
def IsTModule(module_id: str, symtable: object | None = None) -> bool:
|
||||
"""检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)"""
|
||||
if module_id in _T_MODULE_NAMES:
|
||||
return True
|
||||
if symtable is not None and hasattr(symtable, 'import_aliases'):
|
||||
resolved: str = symtable.import_aliases.get(module_id, module_id)
|
||||
if resolved in _T_MODULE_NAMES:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def IsTModulePath(module_path: str) -> bool:
|
||||
"""检查模块路径是否指向 t 类型模块"""
|
||||
if module_path in _T_MODULE_NAMES:
|
||||
return True
|
||||
if module_path:
|
||||
t_name: str
|
||||
for t_name in _T_MODULE_NAMES:
|
||||
if module_path == t_name or module_path.startswith(t_name + '.'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool:
|
||||
"""检测 AST 节点中是否包含指定名称的 t 模块类型"""
|
||||
if isinstance(node, ast.Attribute):
|
||||
if (hasattr(node.value, 'id') and IsTModule(node.value.id) and
|
||||
node.attr == TypeName):
|
||||
return True
|
||||
elif isinstance(node, ast.BinOp):
|
||||
return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName)
|
||||
elif isinstance(node, ast.Call):
|
||||
if AnnotationContainsTType(node.func, TypeName):
|
||||
return True
|
||||
for arg in node.args:
|
||||
if AnnotationContainsTType(arg, TypeName):
|
||||
return True
|
||||
elif isinstance(node, ast.Subscript):
|
||||
if AnnotationContainsTType(node.value, TypeName):
|
||||
return True
|
||||
if AnnotationContainsTType(node.slice, TypeName):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def IsListAnnotation(annotation: ast.expr) -> bool:
|
||||
"""检查注解是否为栈上固定数组类型(t.CArray[...] 或 list[type, count])"""
|
||||
if not isinstance(annotation, ast.Subscript):
|
||||
return False
|
||||
value = annotation.value
|
||||
# t.CArray[...]
|
||||
if (isinstance(value, ast.Attribute)
|
||||
and isinstance(value.value, ast.Name)
|
||||
and value.value.id == 't'
|
||||
and value.attr == 'CArray'):
|
||||
return True
|
||||
# list[type, count] — 仅匹配双参数 Tuple 切片(固定数组),
|
||||
# 单参数 list[type] 不匹配(走泛型类 list[T] 路径)
|
||||
if (isinstance(value, ast.Name)
|
||||
and value.id == 'list'
|
||||
and isinstance(annotation.slice, ast.Tuple)
|
||||
and len(annotation.slice.elts) == 2):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None:
|
||||
"""从 BinOp(BitOr) 注解中提取 list[...] 部分,如 list[i32] | t.CPtr"""
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
for side in (annotation.left, annotation.right):
|
||||
if IsListAnnotation(side):
|
||||
return side
|
||||
return None
|
||||
|
||||
|
||||
class ListAnnotationParseResult:
|
||||
"""list[...] 注解解析结果。
|
||||
|
||||
is_pointer=True 表示单参数 list[type] → 指针模式;
|
||||
is_pointer=False 表示 Tuple(2) 模式 list[type, count]。
|
||||
"""
|
||||
__slots__ = ('elem_type_node', 'count_node', 'is_pointer')
|
||||
|
||||
def __init__(self, elem_type_node: ast.expr, count_node: ast.expr | None, is_pointer: bool) -> None:
|
||||
self.elem_type_node: ast.expr = elem_type_node
|
||||
self.count_node: ast.expr | None = count_node
|
||||
self.is_pointer: bool = is_pointer
|
||||
|
||||
|
||||
def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None:
|
||||
"""解析 list[...] 注解,统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。
|
||||
|
||||
自动处理 BinOp(BitOr) 包裹(如 list[i32, N] | t.CPtr)。
|
||||
返回 None 表示不是 list 注解。
|
||||
"""
|
||||
list_node: ast.expr = annotation
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
extracted: ast.Subscript | None = ExtractListFromBinOp(annotation)
|
||||
if extracted is None:
|
||||
return None
|
||||
list_node = extracted
|
||||
if not IsListAnnotation(list_node):
|
||||
return None
|
||||
slice_node: ast.AST = list_node.slice
|
||||
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
|
||||
return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False)
|
||||
# 单参数 list[type] → 指针模式
|
||||
return ListAnnotationParseResult(slice_node, None, is_pointer=True)
|
||||
|
||||
|
||||
def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool:
|
||||
"""检测注解节点中是否包含 CInline"""
|
||||
if annotation_node is None:
|
||||
return False
|
||||
if isinstance(annotation_node, ast.Attribute):
|
||||
if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline':
|
||||
return True
|
||||
if isinstance(annotation_node, ast.Name):
|
||||
if annotation_node.id == 'CInline':
|
||||
return True
|
||||
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
|
||||
return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right)
|
||||
return False
|
||||
|
||||
|
||||
def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None:
|
||||
"""从 BinOp(BitOr) 注解左侧提取类型名(如 TypeA | TypeB → TypeA)。
|
||||
|
||||
返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。
|
||||
"""
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
left: ast.expr = annotation.left
|
||||
if isinstance(left, ast.Name):
|
||||
return left.id
|
||||
if isinstance(left, ast.Attribute):
|
||||
return left.attr
|
||||
return None
|
||||
|
||||
|
||||
def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None:
|
||||
"""递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。
|
||||
|
||||
检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。
|
||||
支持泛型特化类型(如 GSList[Param]),构造特化名后检查是否在 struct_names 中。
|
||||
"""
|
||||
if isinstance(node, ast.Name) and node.id in struct_names:
|
||||
return node.id
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names:
|
||||
return node.value
|
||||
if isinstance(node, ast.Attribute) and node.attr in struct_names:
|
||||
return node.attr
|
||||
if isinstance(node, ast.Subscript):
|
||||
base_name: str | None = None
|
||||
if isinstance(node.value, ast.Name):
|
||||
base_name = node.value.id
|
||||
elif isinstance(node.value, ast.Attribute):
|
||||
base_name = node.value.attr
|
||||
if base_name:
|
||||
slice_node: ast.AST = node.slice
|
||||
if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index):
|
||||
slice_node = slice_node.value
|
||||
type_args: list[str] = []
|
||||
if isinstance(slice_node, ast.Name):
|
||||
type_args.append(slice_node.id)
|
||||
elif isinstance(slice_node, ast.Attribute):
|
||||
type_args.append(slice_node.attr)
|
||||
elif isinstance(slice_node, ast.Tuple):
|
||||
for elt in slice_node.elts:
|
||||
if isinstance(elt, ast.Name):
|
||||
type_args.append(elt.id)
|
||||
elif isinstance(elt, ast.Attribute):
|
||||
type_args.append(elt.attr)
|
||||
if type_args:
|
||||
spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
|
||||
if spec_name in struct_names:
|
||||
return spec_name
|
||||
if base_name in struct_names:
|
||||
return base_name
|
||||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
result: str | None = FindStructNameInAnnotation(node.left, struct_names)
|
||||
if result:
|
||||
return result
|
||||
return FindStructNameInAnnotation(node.right, struct_names)
|
||||
return None
|
||||
|
||||
|
||||
def AnnotationContainsName(annotation: ast.AST, name: str) -> bool:
|
||||
"""检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。
|
||||
|
||||
同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。
|
||||
"""
|
||||
if isinstance(annotation, ast.Attribute):
|
||||
return annotation.attr == name
|
||||
if isinstance(annotation, ast.Name):
|
||||
return annotation.id == name
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name)
|
||||
return False
|
||||
|
||||
|
||||
def IsCPtrNode(node: ast.AST) -> bool:
|
||||
"""检查节点是否为 t.CPtr 属性引用。"""
|
||||
return (isinstance(node, ast.Attribute)
|
||||
and isinstance(node.value, ast.Name)
|
||||
and node.value.id == 't'
|
||||
and node.attr == 'CPtr')
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import vast as ast
|
||||
import os
|
||||
import importlib
|
||||
import types
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import vast as ast
|
||||
from typing import Any, Callable, Dict, TYPE_CHECKING
|
||||
|
||||
from lib.core.Exportable import Exportable
|
||||
@@ -25,9 +25,9 @@ from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
from lib.core.SymbolTable import SymbolTable
|
||||
from lib.core.SymbolNode import SymbolNode
|
||||
from lib.constants.config import mode as _ConfigMode
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
|
||||
def _StrictLog(logger: Callable[[str], None], msg: str) -> None:
|
||||
"""在 strict 模式下记录异常日志"""
|
||||
if _ConfigMode == "strict":
|
||||
@@ -66,14 +66,14 @@ class BaseTranslatorMixin:
|
||||
self.InClass: bool = False # 是否正在处理 class 定义
|
||||
self._UserTypeModules: dict = {}
|
||||
self._source_module_sig_files: dict = {}
|
||||
self._global_function_default_args: dict = {}
|
||||
self._global_function_default_args: dict = {}
|
||||
self._global_function_param_names: dict = {}
|
||||
self.exception_registry: dict = {}
|
||||
self.exception_parents: dict = {}
|
||||
self._next_exception_code: int = 100
|
||||
# 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射
|
||||
self.config: Any = None
|
||||
self._ImportedModules: set[str] | None = None
|
||||
self._next_exception_code: int = 100
|
||||
# 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射
|
||||
self.config: Any = None
|
||||
self._ImportedModules: set[str] | None = None
|
||||
self._t_c_imported_names: dict = {}
|
||||
|
||||
# 导出表
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import vast as ast
|
||||
from typing import TYPE_CHECKING
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import vast as ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import vast as ast
|
||||
import json
|
||||
import struct
|
||||
|
||||
|
||||
+762
-762
File diff suppressed because it is too large.
Load diff
+722
-722
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,348 @@
|
||||
"""vast.nodes - 与 CPython 3.12 ast 完全同构的 AST 节点类
|
||||
|
||||
vast 是自研 Viper/Python 语法解析器,产出与标准库 ast 模块结构完全一致的
|
||||
AST 树,从而使编译器侧 ``import vast as ast`` 后原有代码零修改。
|
||||
|
||||
本模块定义全部 131 个 AST 节点类(含遗留兼容类),字段/属性与 CPython
|
||||
3.12 的 ``ast`` 模块逐一对应:
|
||||
|
||||
- ``_fields``:节点结构字段(顺序与位置参数构造一致)
|
||||
- ``_attributes``:dump(include_attributes=True) 时随节点输出的位置属性
|
||||
|
||||
构造语义与 CPython 一致:
|
||||
- 位置参数按 ``_fields`` 顺序赋值,超出字段数抛 TypeError
|
||||
- 关键字参数全部 setattr(包括未知字段,与 CPython 行为一致)
|
||||
- 未传入的字段不设置属性(访问时 AttributeError,与 CPython 一致)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class AST:
|
||||
"""所有 AST 节点的基类(与 ast.AST 同构)。"""
|
||||
|
||||
_fields: tuple[str, ...] = ()
|
||||
_attributes: tuple[str, ...] = ()
|
||||
|
||||
def __init__(self, *args: object, **kwargs: object) -> None:
|
||||
fields: tuple[str, ...] = self._fields
|
||||
if len(args) > len(fields):
|
||||
raise TypeError(
|
||||
f'{type(self).__name__} constructor takes at most '
|
||||
f'{len(fields)} positional arguments'
|
||||
)
|
||||
for name, val in zip(fields, args):
|
||||
setattr(self, name, val)
|
||||
for k, v in kwargs.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
"""AST 节点按对象身份比较(与 CPython ast 一致)。"""
|
||||
return self is other
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 节点定义表:字段表(含位置属性表),数据驱动生成全部节点类
|
||||
# =============================================================================
|
||||
|
||||
_POS_ATTRS: tuple[str, ...] = ('lineno', 'col_offset', 'end_lineno', 'end_col_offset')
|
||||
|
||||
_NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = {
|
||||
# ---- 模块/交互/表达式顶层 ----
|
||||
'Module': (('body', 'type_ignores'), ()),
|
||||
'Interactive': (('body',), ()),
|
||||
'Expression': (('body',), ()),
|
||||
'FunctionType': (('argtypes', 'returns'), ()),
|
||||
'Suite': ((), ()),
|
||||
|
||||
# ---- 语句 ----
|
||||
'FunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _POS_ATTRS),
|
||||
'AsyncFunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _POS_ATTRS),
|
||||
'ClassDef': (('name', 'bases', 'keywords', 'body', 'decorator_list', 'type_params'), _POS_ATTRS),
|
||||
'Return': (('value',), _POS_ATTRS),
|
||||
'Delete': (('targets',), _POS_ATTRS),
|
||||
'Assign': (('targets', 'value', 'type_comment'), _POS_ATTRS),
|
||||
'AugAssign': (('target', 'op', 'value'), _POS_ATTRS),
|
||||
'AnnAssign': (('target', 'annotation', 'value', 'simple'), _POS_ATTRS),
|
||||
'For': (('target', 'iter', 'body', 'orelse', 'type_comment'), _POS_ATTRS),
|
||||
'AsyncFor': (('target', 'iter', 'body', 'orelse', 'type_comment'), _POS_ATTRS),
|
||||
'While': (('test', 'body', 'orelse'), _POS_ATTRS),
|
||||
'If': (('test', 'body', 'orelse'), _POS_ATTRS),
|
||||
'With': (('items', 'body', 'type_comment'), _POS_ATTRS),
|
||||
'AsyncWith': (('items', 'body', 'type_comment'), _POS_ATTRS),
|
||||
'Match': (('subject', 'cases'), _POS_ATTRS),
|
||||
'Raise': (('exc', 'cause'), _POS_ATTRS),
|
||||
'Try': (('body', 'handlers', 'orelse', 'finalbody'), _POS_ATTRS),
|
||||
'TryStar': (('body', 'handlers', 'orelse', 'finalbody'), _POS_ATTRS),
|
||||
'Assert': (('test', 'msg'), _POS_ATTRS),
|
||||
'Import': (('names',), _POS_ATTRS),
|
||||
'ImportFrom': (('module', 'names', 'level'), _POS_ATTRS),
|
||||
'Global': (('names',), _POS_ATTRS),
|
||||
'Nonlocal': (('names',), _POS_ATTRS),
|
||||
'Expr': (('value',), _POS_ATTRS),
|
||||
'Pass': ((), _POS_ATTRS),
|
||||
'Break': ((), _POS_ATTRS),
|
||||
'Continue': ((), _POS_ATTRS),
|
||||
|
||||
# ---- 表达式 ----
|
||||
'BoolOp': (('op', 'values'), _POS_ATTRS),
|
||||
'NamedExpr': (('target', 'value'), _POS_ATTRS),
|
||||
'BinOp': (('left', 'op', 'right'), _POS_ATTRS),
|
||||
'UnaryOp': (('op', 'operand'), _POS_ATTRS),
|
||||
'Lambda': (('args', 'body'), _POS_ATTRS),
|
||||
'IfExp': (('test', 'body', 'orelse'), _POS_ATTRS),
|
||||
'Dict': (('keys', 'values'), _POS_ATTRS),
|
||||
'Set': (('elts',), _POS_ATTRS),
|
||||
'ListComp': (('elt', 'generators'), _POS_ATTRS),
|
||||
'SetComp': (('elt', 'generators'), _POS_ATTRS),
|
||||
'DictComp': (('key', 'value', 'generators'), _POS_ATTRS),
|
||||
'GeneratorExp': (('elt', 'generators'), _POS_ATTRS),
|
||||
'Await': (('value',), _POS_ATTRS),
|
||||
'Yield': (('value',), _POS_ATTRS),
|
||||
'YieldFrom': (('value',), _POS_ATTRS),
|
||||
'Compare': (('left', 'ops', 'comparators'), _POS_ATTRS),
|
||||
'Call': (('func', 'args', 'keywords'), _POS_ATTRS),
|
||||
'FormattedValue': (('value', 'conversion', 'format_spec'), _POS_ATTRS),
|
||||
'JoinedStr': (('values',), _POS_ATTRS),
|
||||
'Constant': (('value', 'kind'), _POS_ATTRS),
|
||||
'Attribute': (('value', 'attr', 'ctx'), _POS_ATTRS),
|
||||
'Subscript': (('value', 'slice', 'ctx'), _POS_ATTRS),
|
||||
'Starred': (('value', 'ctx'), _POS_ATTRS),
|
||||
'Name': (('id', 'ctx'), _POS_ATTRS),
|
||||
'List': (('elts', 'ctx'), _POS_ATTRS),
|
||||
'Tuple': (('elts', 'ctx'), _POS_ATTRS),
|
||||
'Slice': (('lower', 'upper', 'step'), _POS_ATTRS),
|
||||
|
||||
# ---- match 模式(PEP 634) ----
|
||||
'MatchValue': (('value',), _POS_ATTRS),
|
||||
'MatchSingleton': (('value',), _POS_ATTRS),
|
||||
'MatchSequence': (('patterns',), _POS_ATTRS),
|
||||
'MatchMapping': (('keys', 'patterns', 'rest'), _POS_ATTRS),
|
||||
'MatchClass': (('cls', 'patterns', 'kwd_attrs', 'kwd_patterns'), _POS_ATTRS),
|
||||
'MatchStar': (('name',), _POS_ATTRS),
|
||||
'MatchAs': (('pattern', 'name'), _POS_ATTRS),
|
||||
'MatchOr': (('patterns',), _POS_ATTRS),
|
||||
|
||||
# ---- 类型参数(PEP 695,仅声明性支持) ----
|
||||
'TypeVar': (('name', 'bound'), _POS_ATTRS),
|
||||
'TypeVarTuple': (('name',), _POS_ATTRS),
|
||||
'ParamSpec': (('name',), _POS_ATTRS),
|
||||
'TypeAlias': (('name', 'type_params', 'value'), _POS_ATTRS),
|
||||
|
||||
# ---- 复合辅助节点 ----
|
||||
'comprehension': (('target', 'iter', 'ifs', 'is_async'), ()),
|
||||
'ExceptHandler': (('type', 'name', 'body'), _POS_ATTRS),
|
||||
'arguments': (('posonlyargs', 'args', 'vararg', 'kwonlyargs', 'kw_defaults', 'kwarg', 'defaults'), ()),
|
||||
'arg': (('arg', 'annotation', 'type_comment'), _POS_ATTRS),
|
||||
'keyword': (('arg', 'value'), _POS_ATTRS),
|
||||
'alias': (('name', 'asname'), _POS_ATTRS),
|
||||
'withitem': (('context_expr', 'optional_vars'), ()),
|
||||
'match_case': (('pattern', 'guard', 'body'), ()),
|
||||
'TypeIgnore': (('lineno', 'tag'), ()),
|
||||
|
||||
# ---- 运算符 / 上下文(无字段单例类) ----
|
||||
'Add': ((), ()),
|
||||
'Sub': ((), ()),
|
||||
'Mult': ((), ()),
|
||||
'MatMult': ((), ()),
|
||||
'Div': ((), ()),
|
||||
'Mod': ((), ()),
|
||||
'Pow': ((), ()),
|
||||
'LShift': ((), ()),
|
||||
'RShift': ((), ()),
|
||||
'BitOr': ((), ()),
|
||||
'BitXor': ((), ()),
|
||||
'BitAnd': ((), ()),
|
||||
'FloorDiv': ((), ()),
|
||||
'Invert': ((), ()),
|
||||
'Not': ((), ()),
|
||||
'UAdd': ((), ()),
|
||||
'USub': ((), ()),
|
||||
'Eq': ((), ()),
|
||||
'NotEq': ((), ()),
|
||||
'Lt': ((), ()),
|
||||
'LtE': ((), ()),
|
||||
'Gt': ((), ()),
|
||||
'GtE': ((), ()),
|
||||
'Is': ((), ()),
|
||||
'IsNot': ((), ()),
|
||||
'In': ((), ()),
|
||||
'NotIn': ((), ()),
|
||||
'And': ((), ()),
|
||||
'Or': ((), ()),
|
||||
'Load': ((), ()),
|
||||
'Store': ((), ()),
|
||||
'Del': ((), ()),
|
||||
'AugLoad': ((), ()),
|
||||
'AugStore': ((), ()),
|
||||
'Param': ((), ()),
|
||||
'Ellipsis': ((), _POS_ATTRS),
|
||||
|
||||
# ---- 遗留兼容类(已废弃但保留,供 hasattr 检查) ----
|
||||
'Index': ((), ()),
|
||||
'ExtSlice': ((), ()),
|
||||
|
||||
# ---- 抽象类型占位(纯类型标注用,不实例化) ----
|
||||
'mod': ((), ()),
|
||||
'stmt': ((), ()),
|
||||
'expr': ((), ()),
|
||||
'expr_context': ((), ()),
|
||||
'boolop': ((), ()),
|
||||
'operator': ((), ()),
|
||||
'unaryop': ((), ()),
|
||||
'cmpop': ((), ()),
|
||||
'slice': ((), ()),
|
||||
'pattern': ((), ()),
|
||||
'type_ignore': ((), ()),
|
||||
'type_param': ((), ()),
|
||||
'excepthandler': ((), ()),
|
||||
}
|
||||
|
||||
_DOCS: dict[str, str] = {
|
||||
'FunctionDef': '函数定义节点(对应 def 语句)。',
|
||||
'AsyncFunctionDef': '异步函数定义节点(对应 async def)。',
|
||||
'ClassDef': '类定义节点(对应 class 语句)。',
|
||||
'AnnAssign': '带注解的赋值节点(x: T = v)。',
|
||||
'Constant': '常量节点(数字/字符串/bool/None/Ellipsis)。',
|
||||
'Name': '名称节点(标识符引用,含 Load/Store/Del 上下文)。',
|
||||
'Call': '函数调用节点。',
|
||||
'BinOp': '二元运算节点。',
|
||||
'Attribute': '属性访问节点(obj.attr)。',
|
||||
'Subscript': '下标访问节点(obj[idx])。',
|
||||
'arguments': '函数参数列表节点(含默认值、*args、**kwargs)。',
|
||||
'alias': 'import 别名节点。',
|
||||
'keyword': '关键字实参节点(f(x=1))。',
|
||||
'withitem': 'with 语句上下文节点。',
|
||||
}
|
||||
|
||||
# 类属性默认值(与 CPython 3.12 ast 节点一致):
|
||||
# dump 时"实例值为 None 且类默认值为 None"的字段会被跳过;
|
||||
# 无类默认值的字段(如 Constant.value)即使为 None 也会显示。
|
||||
_CLASS_DEFAULTS: dict[str, dict[str, object]] = {
|
||||
'AnnAssign': {'value': None},
|
||||
'Assert': {'msg': None},
|
||||
'Assign': {'type_comment': None},
|
||||
'AsyncFor': {'type_comment': None},
|
||||
'AsyncFunctionDef': {'returns': None, 'type_comment': None},
|
||||
'AsyncWith': {'type_comment': None},
|
||||
'Constant': {'kind': None},
|
||||
'ExceptHandler': {'type': None, 'name': None},
|
||||
'For': {'type_comment': None},
|
||||
'FormattedValue': {'format_spec': None},
|
||||
'FunctionDef': {'returns': None, 'type_comment': None},
|
||||
'ImportFrom': {'module': None, 'level': None},
|
||||
'match_case': {'guard': None},
|
||||
'MatchAs': {'pattern': None, 'name': None},
|
||||
'MatchMapping': {'rest': None},
|
||||
'MatchStar': {'name': None},
|
||||
'Raise': {'exc': None, 'cause': None},
|
||||
'Return': {'value': None},
|
||||
'Slice': {'lower': None, 'upper': None, 'step': None},
|
||||
'TypeVar': {'bound': None},
|
||||
'With': {'type_comment': None},
|
||||
'Yield': {'value': None},
|
||||
'alias': {'asname': None},
|
||||
'arg': {'annotation': None, 'type_comment': None},
|
||||
'arguments': {'vararg': None, 'kwarg': None},
|
||||
'keyword': {'arg': None},
|
||||
'withitem': {'optional_vars': None},
|
||||
}
|
||||
|
||||
|
||||
# 节点抽象基类映射(与 CPython 3.12 一致:expr/stmt/mod/operator/cmpop/...)
|
||||
# 节点类继承对应的抽象基类,使 isinstance(node, ast.expr) 等判断可用
|
||||
_BASE_CLASS: dict[str, str] = {
|
||||
# stmt
|
||||
'AnnAssign': 'stmt', 'Assert': 'stmt', 'Assign': 'stmt', 'AsyncFor': 'stmt',
|
||||
'AsyncFunctionDef': 'stmt', 'AsyncWith': 'stmt', 'AugAssign': 'stmt',
|
||||
'Break': 'stmt', 'ClassDef': 'stmt', 'Continue': 'stmt', 'Delete': 'stmt',
|
||||
'Expr': 'stmt', 'For': 'stmt', 'FunctionDef': 'stmt', 'Global': 'stmt',
|
||||
'If': 'stmt', 'Import': 'stmt', 'ImportFrom': 'stmt', 'Match': 'stmt',
|
||||
'Nonlocal': 'stmt', 'Pass': 'stmt', 'Raise': 'stmt', 'Return': 'stmt',
|
||||
'Try': 'stmt', 'TryStar': 'stmt', 'TypeAlias': 'stmt', 'While': 'stmt',
|
||||
'With': 'stmt',
|
||||
# expr
|
||||
'Attribute': 'expr', 'Await': 'expr', 'BinOp': 'expr', 'BoolOp': 'expr',
|
||||
'Call': 'expr', 'Compare': 'expr', 'Constant': 'expr', 'Dict': 'expr',
|
||||
'DictComp': 'expr', 'FormattedValue': 'expr', 'GeneratorExp': 'expr',
|
||||
'IfExp': 'expr', 'JoinedStr': 'expr', 'Lambda': 'expr', 'List': 'expr',
|
||||
'ListComp': 'expr', 'Name': 'expr', 'NamedExpr': 'expr', 'Set': 'expr',
|
||||
'SetComp': 'expr', 'Slice': 'expr', 'Starred': 'expr', 'Subscript': 'expr',
|
||||
'Tuple': 'expr', 'UnaryOp': 'expr', 'Yield': 'expr', 'YieldFrom': 'expr',
|
||||
# mod
|
||||
'Module': 'mod', 'Interactive': 'mod', 'Expression': 'mod',
|
||||
'FunctionType': 'mod', 'Suite': 'mod',
|
||||
# operator
|
||||
'Add': 'operator', 'Sub': 'operator', 'Mult': 'operator', 'MatMult': 'operator',
|
||||
'Div': 'operator', 'Mod': 'operator', 'Pow': 'operator', 'LShift': 'operator',
|
||||
'RShift': 'operator', 'BitOr': 'operator', 'BitXor': 'operator',
|
||||
'BitAnd': 'operator', 'FloorDiv': 'operator',
|
||||
# unaryop
|
||||
'Invert': 'unaryop', 'Not': 'unaryop', 'UAdd': 'unaryop', 'USub': 'unaryop',
|
||||
# boolop
|
||||
'And': 'boolop', 'Or': 'boolop',
|
||||
# cmpop
|
||||
'Eq': 'cmpop', 'NotEq': 'cmpop', 'Lt': 'cmpop', 'LtE': 'cmpop',
|
||||
'Gt': 'cmpop', 'GtE': 'cmpop', 'Is': 'cmpop', 'IsNot': 'cmpop',
|
||||
'In': 'cmpop', 'NotIn': 'cmpop',
|
||||
# expr_context
|
||||
'Load': 'expr_context', 'Store': 'expr_context', 'Del': 'expr_context',
|
||||
'AugLoad': 'expr_context', 'AugStore': 'expr_context', 'Param': 'expr_context',
|
||||
# slice
|
||||
'Index': 'slice', 'ExtSlice': 'slice',
|
||||
# pattern
|
||||
'MatchValue': 'pattern', 'MatchSingleton': 'pattern', 'MatchSequence': 'pattern',
|
||||
'MatchMapping': 'pattern', 'MatchClass': 'pattern', 'MatchStar': 'pattern',
|
||||
'MatchAs': 'pattern', 'MatchOr': 'pattern',
|
||||
# type_param / type_ignore
|
||||
'TypeVar': 'type_param', 'TypeVarTuple': 'type_param', 'ParamSpec': 'type_param',
|
||||
'TypeIgnore': 'type_ignore',
|
||||
# excepthandler
|
||||
'ExceptHandler': 'excepthandler',
|
||||
}
|
||||
|
||||
|
||||
def _MakeNodeClass(name: str, fields: tuple[str, ...], attrs: tuple[str, ...]) -> type:
|
||||
"""按字段表生成节点类(继承对应抽象基类)。"""
|
||||
|
||||
def _Init(self: AST, *args: object, **kwargs: object) -> None:
|
||||
if len(args) > len(fields):
|
||||
raise TypeError(
|
||||
f'{name} constructor takes at most {len(fields)} positional arguments'
|
||||
)
|
||||
for fname, val in zip(fields, args):
|
||||
setattr(self, fname, val)
|
||||
for k, v in kwargs.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
base_name: str | None = _BASE_CLASS.get(name)
|
||||
base_cls: type = globals()[base_name] if base_name else AST
|
||||
ns: dict[str, object] = {
|
||||
'__init__': _Init,
|
||||
'_fields': fields,
|
||||
'_attributes': attrs,
|
||||
'__module__': __name__,
|
||||
'__doc__': _DOCS.get(name, f'{name} AST 节点(与 ast.{name} 同构)。'),
|
||||
}
|
||||
# 类默认值(None 字段在 dump 时跳过)
|
||||
for fname, fdefault in _CLASS_DEFAULTS.get(name, {}).items():
|
||||
ns[fname] = fdefault
|
||||
cls: type = type(name, (base_cls,), ns)
|
||||
return cls
|
||||
|
||||
|
||||
# 动态生成全部节点类到本模块命名空间
|
||||
# 抽象基类(mod/stmt/expr/...)在 _NODE_DEFS 末尾定义,但需先生成
|
||||
_ABSTRACT_BASES: tuple[str, ...] = (
|
||||
'mod', 'stmt', 'expr', 'expr_context', 'boolop', 'operator', 'unaryop',
|
||||
'cmpop', 'slice', 'pattern', 'type_ignore', 'type_param', 'excepthandler',
|
||||
)
|
||||
for _name in _ABSTRACT_BASES:
|
||||
_fields, _attrs = _NODE_DEFS[_name]
|
||||
globals()[_name] = _MakeNodeClass(_name, _fields, _attrs)
|
||||
for _name, (_fields, _attrs) in _NODE_DEFS.items():
|
||||
if _name in _ABSTRACT_BASES:
|
||||
continue
|
||||
globals()[_name] = _MakeNodeClass(_name, _fields, _attrs)
|
||||
|
||||
# 显式别名:AnnAssign 已在表内;这里保证模块级 __all__ 完整性
|
||||
__all__: list[str] = list(_NODE_DEFS.keys()) + ['AST']
|
||||
+1044
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,490 @@
|
||||
"""vast.tokenizer - Viper/Python 词法分析器
|
||||
|
||||
将源码字符串切分为 token 流,与 CPython 3.12 ``tokenize`` 语义对齐:
|
||||
|
||||
- 支持缩进 INDENT/DEDENT、逻辑行 NEWLINE、括号内续行
|
||||
- 支持字符串字面量(单引号/双引号/三引号、r/b/u/f 前缀与组合前缀)
|
||||
- f-string 作为整体 FSTRING token 输出,内部表达式由 Parser 递归解析
|
||||
- 数字字面量(十进制/十六进制/八进制/二进制/浮点/复数 j/下划线分隔)
|
||||
- 运算符最长匹配
|
||||
|
||||
位置信息与 CPython 一致:``col_offset`` 为 UTF-8 字节偏移(非字符偏移),
|
||||
行号为 1-based。行列信息通过行起始索引表 + bisect 统一换算,保证跨行
|
||||
token(字符串/三引号)的行列准确。
|
||||
|
||||
软关键字 fn/fun/func/function 不作为独立 token 类型处理(并入解析器),
|
||||
tokenizer 产出普通 NAME,由 Parser 在语句首识别为函数定义关键字。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import bisect
|
||||
|
||||
# =============================================================================
|
||||
# Token 类型常量
|
||||
# =============================================================================
|
||||
ENDMARKER = 'ENDMARKER'
|
||||
NAME = 'NAME'
|
||||
NUMBER = 'NUMBER'
|
||||
STRING = 'STRING'
|
||||
FSTRING = 'FSTRING'
|
||||
OP = 'OP'
|
||||
NEWLINE = 'NEWLINE'
|
||||
INDENT = 'INDENT'
|
||||
DEDENT = 'DEDENT'
|
||||
COMMENT = 'COMMENT'
|
||||
NL = 'NL'
|
||||
|
||||
# 多字符运算符(最长优先,含 Python 3.12 全部运算符)
|
||||
_OPERATORS: tuple[str, ...] = (
|
||||
'**=', '//=', '<<=', '>>=', '**', '//', '<<', '>>', '<=', '>=', '==', '!=',
|
||||
':=', '->', '+=', '-=', '*=', '/=', '%=', '@=', '&=', '|=', '^=', '...',
|
||||
'(', ')', '[', ']', '{', '}', ',', ':', '.', ';', '+', '-', '*', '/', '%',
|
||||
'@', '&', '|', '^', '~', '<', '>', '=', '!',
|
||||
)
|
||||
|
||||
# 行首空白 + 关键字 + 空白 + 标识符 → 软关键字函数定义(Parser 层处理)
|
||||
SOFT_KEYWORDS: frozenset[str] = frozenset({'fn', 'fun', 'func', 'function'})
|
||||
|
||||
# 字符串前缀字母集合(允许任意顺序/大小写组合,如 fr、Rb、BF)
|
||||
_STRING_PREFIX_CHARS: frozenset[str] = frozenset('rRbBuUfF')
|
||||
_F_PREFIX = frozenset('fF')
|
||||
_R_PREFIX = frozenset('rR')
|
||||
_B_PREFIX = frozenset('bB')
|
||||
|
||||
|
||||
class Token:
|
||||
"""词法 token。
|
||||
|
||||
Attributes:
|
||||
Type: token 类型(NAME/NUMBER/STRING/FSTRING/OP/NEWLINE/...)
|
||||
Value: token 原始文本
|
||||
Line: 1-based 行号
|
||||
Col: UTF-8 字节偏移(0-based)
|
||||
EndLine: 结束行号
|
||||
EndCol: 结束列(UTF-8 字节偏移)
|
||||
Start: 源码字符偏移(含 UTF-8 字节偏移换算依赖,供 f-string 内部定位)
|
||||
End: 源码字符偏移(exclusive)
|
||||
"""
|
||||
__slots__ = ('Type', 'Value', 'Line', 'Col', 'EndLine', 'EndCol', 'Start', 'End')
|
||||
|
||||
def __init__(self, tok_type: str, value: str, line: int, col: int,
|
||||
end_line: int, end_col: int) -> None:
|
||||
self.Type: str = tok_type
|
||||
self.Value: str = value
|
||||
self.Line: int = line
|
||||
self.Col: int = col
|
||||
self.EndLine: int = end_line
|
||||
self.EndCol: int = end_col
|
||||
self.Start: int = -1
|
||||
self.End: int = -1
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (f'Token({self.Type}, {self.Value!r}, '
|
||||
f'{self.Line}:{self.Col}-{self.EndLine}:{self.EndCol})')
|
||||
|
||||
|
||||
def _IsIdentStart(ch: str) -> bool:
|
||||
"""标识符起始字符:字母或下划线(兼容非 ASCII)。"""
|
||||
return ch == '_' or ch.isalpha() or ord(ch) > 127
|
||||
|
||||
|
||||
def _IsIdentPart(ch: str) -> bool:
|
||||
"""标识符组成部分:字母/数字/下划线。"""
|
||||
return ch == '_' or ch.isalnum() or ord(ch) > 127
|
||||
|
||||
|
||||
class Tokenizer:
|
||||
"""Viper/Python 源码 → token 流。
|
||||
|
||||
Usage::
|
||||
|
||||
toks: list[Token] = Tokenizer(source).Tokenize()
|
||||
"""
|
||||
|
||||
def __init__(self, source: str) -> None:
|
||||
self.Source: str = source
|
||||
self.Length: int = len(source)
|
||||
self.Pos: int = 0 # 当前字符索引
|
||||
self.Tokens: list[Token] = []
|
||||
# 括号深度:>0 表示在括号内(逻辑行不结束)
|
||||
self.BracketDepth: int = 0
|
||||
# 缩进栈:0 为根
|
||||
self.Indents: list[int] = [0]
|
||||
# 行首标志(决定是否进行缩进分析)
|
||||
self.AtLineStart: bool = True
|
||||
# 反斜杠续行延续标志:续行后的物理行行首空白不产生 INDENT
|
||||
self.ContinuationLine: bool = False
|
||||
# 空行/注释行标志:本物理行无实质内容,行尾换行产 NL 而非 NEWLINE
|
||||
self.BlankLine: bool = False
|
||||
# 注释 token 收集(Parser 忽略,但保留供诊断)
|
||||
self.Comments: list[Token] = []
|
||||
# 行起始字符索引表(索引 0 对应第 1 行),用于行列换算
|
||||
self._LineStarts: list[int] = [0]
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 位置换算
|
||||
# ------------------------------------------------------------------
|
||||
def _PosInfo(self, pos: int) -> tuple[int, int]:
|
||||
"""将字符索引换算为 (1-based 行号, UTF-8 字节列偏移)。"""
|
||||
idx: int = bisect.bisect_right(self._LineStarts, pos) - 1
|
||||
line: int = idx + 1
|
||||
col_bytes: int = len(self.Source[self._LineStarts[idx]:pos].encode('utf-8'))
|
||||
return line, col_bytes
|
||||
|
||||
def _Make(self, tok_type: str, start: int, end: int) -> Token:
|
||||
"""以 [start, end) 源码区间构造 token。"""
|
||||
start_line, start_col = self._PosInfo(start)
|
||||
end_line, end_col = self._PosInfo(end)
|
||||
tok: Token = Token(tok_type, self.Source[start:end], start_line, start_col,
|
||||
end_line, end_col)
|
||||
tok.Start = start
|
||||
tok.End = end
|
||||
return tok
|
||||
|
||||
def _RegisterNewline(self, pos_after_nl: int) -> None:
|
||||
"""登记换行:pos_after_nl 是换行序列之后的字符索引(即新行行首)。"""
|
||||
self._LineStarts.append(pos_after_nl)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 主入口
|
||||
# ------------------------------------------------------------------
|
||||
def Tokenize(self) -> list[Token]:
|
||||
"""执行词法分析,返回完整 token 流(以 ENDMARKER 结尾)。"""
|
||||
while self.Pos < self.Length:
|
||||
ch: str = self.Source[self.Pos]
|
||||
if (self.AtLineStart and self.BracketDepth == 0
|
||||
and not self.ContinuationLine and ch not in '\r\n'):
|
||||
self._HandleIndent()
|
||||
if self.Pos >= self.Length:
|
||||
break
|
||||
continue
|
||||
if ch in ' \t\f':
|
||||
self.Pos += 1
|
||||
continue
|
||||
if ch == '\r':
|
||||
self.Pos += 1
|
||||
if self.Pos < self.Length and self.Source[self.Pos] == '\n':
|
||||
self.Pos += 1
|
||||
self._HandleNewline(self.Pos)
|
||||
continue
|
||||
if ch == '\n':
|
||||
self.Pos += 1
|
||||
self._HandleNewline(self.Pos)
|
||||
continue
|
||||
if ch == '#':
|
||||
self._ScanComment()
|
||||
continue
|
||||
if ch == '\\':
|
||||
self._ScanContinuation()
|
||||
continue
|
||||
if ch in '([{':
|
||||
self.BracketDepth += 1
|
||||
self._EmitOp()
|
||||
continue
|
||||
if ch in ')]}':
|
||||
if self.BracketDepth > 0:
|
||||
self.BracketDepth -= 1
|
||||
self._EmitOp()
|
||||
continue
|
||||
if ch == "'" or ch == '"' or _IsIdentStart(ch):
|
||||
if self._TryScanString():
|
||||
continue
|
||||
if ch.isdigit():
|
||||
self._ScanNumber()
|
||||
continue
|
||||
if _IsIdentStart(ch):
|
||||
self._ScanName()
|
||||
continue
|
||||
if ch.isdigit() or (ch == '.' and self.Pos + 1 < self.Length
|
||||
and self.Source[self.Pos + 1].isdigit()):
|
||||
self._ScanNumber()
|
||||
continue
|
||||
self._EmitOp()
|
||||
self._FinishFile()
|
||||
return self.Tokens
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 换行 / 缩进 / 续行 / 注释
|
||||
# ------------------------------------------------------------------
|
||||
def _HandleNewline(self, pos_after_nl: int) -> None:
|
||||
"""处理物理换行:括号外为 NEWLINE,括号内为 NL。
|
||||
|
||||
Args:
|
||||
pos_after_nl: 换行序列之后的字符索引(新行行首)。
|
||||
"""
|
||||
# 找换行序列起点(\n 或 \r\n)
|
||||
nl_start: int = self.Pos - 1
|
||||
if nl_start > 0 and self.Source[nl_start] == '\n' and self.Source[nl_start - 1] == '\r':
|
||||
nl_start -= 1
|
||||
if self.BracketDepth > 0 or self.BlankLine or (self.AtLineStart and not self.ContinuationLine):
|
||||
self.Tokens.append(self._Make(NL, nl_start, self.Pos))
|
||||
else:
|
||||
self.Tokens.append(self._Make(NEWLINE, nl_start, self.Pos))
|
||||
self._RegisterNewline(pos_after_nl)
|
||||
self.AtLineStart = True
|
||||
self.ContinuationLine = False
|
||||
self.BlankLine = False
|
||||
|
||||
def _HandleIndent(self) -> None:
|
||||
"""行首缩进分析:产出 INDENT/DEDENT 或忽略。"""
|
||||
start: int = self.Pos
|
||||
col: int = 0
|
||||
while self.Pos < self.Length:
|
||||
ch: str = self.Source[self.Pos]
|
||||
if ch == ' ':
|
||||
col += 1
|
||||
self.Pos += 1
|
||||
elif ch == '\t':
|
||||
col = (col // 8 + 1) * 8
|
||||
self.Pos += 1
|
||||
elif ch == '\f':
|
||||
self.Pos += 1
|
||||
else:
|
||||
break
|
||||
self.AtLineStart = False
|
||||
# 空行/注释行不产生缩进 token,且行尾换行应产 NL(逻辑行不结束)
|
||||
if self.Pos >= self.Length or self.Source[self.Pos] in '\r\n#':
|
||||
self.BlankLine = True
|
||||
return
|
||||
cur: int = self.Indents[-1]
|
||||
if col > cur:
|
||||
self.Indents.append(col)
|
||||
self.Tokens.append(self._Make(INDENT, start, self.Pos))
|
||||
elif col < cur:
|
||||
while self.Indents and self.Indents[-1] > col:
|
||||
self.Indents.pop()
|
||||
self.Tokens.append(self._Make(DEDENT, self.Pos, self.Pos))
|
||||
|
||||
def _ScanContinuation(self) -> None:
|
||||
"""反斜杠续行:跳过 \\ + 换行(逻辑行内,不产生 NEWLINE)。"""
|
||||
if self.Pos + 1 < self.Length and self.Source[self.Pos + 1] in '\r\n':
|
||||
self.Pos += 1
|
||||
if self.Pos < self.Length and self.Source[self.Pos] == '\r':
|
||||
self.Pos += 1
|
||||
if self.Pos < self.Length and self.Source[self.Pos] == '\n':
|
||||
self.Pos += 1
|
||||
self._RegisterNewline(self.Pos)
|
||||
self.AtLineStart = True
|
||||
self.ContinuationLine = True
|
||||
else:
|
||||
self.Pos += 1
|
||||
|
||||
def _ScanComment(self) -> None:
|
||||
"""扫描注释到行尾(不产出 COMMENT token,仅保留)。"""
|
||||
start: int = self.Pos
|
||||
while self.Pos < self.Length and self.Source[self.Pos] not in '\r\n':
|
||||
self.Pos += 1
|
||||
tok: Token = self._Make(COMMENT, start, self.Pos)
|
||||
self.Comments.append(tok)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 基础 token
|
||||
# ------------------------------------------------------------------
|
||||
def _EmitOp(self) -> None:
|
||||
"""运算符最长匹配(含 ... 与增强赋值运算符)。"""
|
||||
start: int = self.Pos
|
||||
for op in _OPERATORS:
|
||||
if self.Source.startswith(op, self.Pos):
|
||||
self.Pos += len(op)
|
||||
self.Tokens.append(self._Make(OP, start, self.Pos))
|
||||
self.AtLineStart = False
|
||||
return
|
||||
# 未知字符:单字符 OP 兜底
|
||||
self.Pos += 1
|
||||
self.Tokens.append(self._Make(OP, start, self.Pos))
|
||||
self.AtLineStart = False
|
||||
|
||||
def _ScanName(self) -> None:
|
||||
"""扫描标识符。"""
|
||||
start: int = self.Pos
|
||||
while self.Pos < self.Length and _IsIdentPart(self.Source[self.Pos]):
|
||||
self.Pos += 1
|
||||
self.Tokens.append(self._Make(NAME, start, self.Pos))
|
||||
self.AtLineStart = False
|
||||
|
||||
def _ScanNumber(self) -> None:
|
||||
"""扫描数字字面量:进制前缀/十进制/浮点/指数/复数 j/下划线。"""
|
||||
start: int = self.Pos
|
||||
# 进制前缀 0x/0o/0b
|
||||
if self.Source[self.Pos] == '0' and self.Pos + 1 < self.Length:
|
||||
nxt: str = self.Source[self.Pos + 1]
|
||||
if nxt in 'xXoObB':
|
||||
self.Pos += 2
|
||||
while self.Pos < self.Length and (self.Source[self.Pos].isalnum()
|
||||
or self.Source[self.Pos] == '_'):
|
||||
self.Pos += 1
|
||||
self.Tokens.append(self._Make(NUMBER, start, self.Pos))
|
||||
self.AtLineStart = False
|
||||
return
|
||||
# 整数部分
|
||||
while self.Pos < self.Length and (self.Source[self.Pos].isdigit()
|
||||
or self.Source[self.Pos] == '_'):
|
||||
self.Pos += 1
|
||||
# 浮点小数点
|
||||
if self.Pos < self.Length and self.Source[self.Pos] == '.':
|
||||
self.Pos += 1
|
||||
while self.Pos < self.Length and (self.Source[self.Pos].isdigit()
|
||||
or self.Source[self.Pos] == '_'):
|
||||
self.Pos += 1
|
||||
# 指数
|
||||
if self.Pos < self.Length and self.Source[self.Pos] in 'eE':
|
||||
save: int = self.Pos
|
||||
self.Pos += 1
|
||||
if self.Pos < self.Length and self.Source[self.Pos] in '+-':
|
||||
self.Pos += 1
|
||||
if self.Pos < self.Length and (self.Source[self.Pos].isdigit()
|
||||
or self.Source[self.Pos] == '_'):
|
||||
while self.Pos < self.Length and (self.Source[self.Pos].isdigit()
|
||||
or self.Source[self.Pos] == '_'):
|
||||
self.Pos += 1
|
||||
else:
|
||||
self.Pos = save # 不是指数,回退
|
||||
# 复数 j
|
||||
if self.Pos < self.Length and self.Source[self.Pos] in 'jJ':
|
||||
self.Pos += 1
|
||||
self.Tokens.append(self._Make(NUMBER, start, self.Pos))
|
||||
self.AtLineStart = False
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 字符串
|
||||
# ------------------------------------------------------------------
|
||||
def _TryScanString(self) -> bool:
|
||||
"""尝试从当前位置扫描字符串字面量(含 r/b/u/f 前缀)。
|
||||
|
||||
- 前缀字母序列后紧跟引号 → 按字符串扫描,返回 True
|
||||
- 否则回退位置,返回 False(由调用方走标识符/数字路径)
|
||||
"""
|
||||
start: int = self.Pos
|
||||
# 收集前缀字母
|
||||
while self.Pos < self.Length and self.Source[self.Pos] in _STRING_PREFIX_CHARS:
|
||||
self.Pos += 1
|
||||
# 前缀后必须是引号,否则回退
|
||||
if self.Pos >= self.Length or self.Source[self.Pos] not in '\'"':
|
||||
self.Pos = start
|
||||
return False
|
||||
prefix: str = self.Source[start:self.Pos]
|
||||
is_fstring: bool = any(c in _F_PREFIX for c in prefix)
|
||||
quote: str = self.Source[self.Pos]
|
||||
triple: bool = self.Source.startswith(quote * 3, self.Pos)
|
||||
if triple:
|
||||
self.Pos += 3
|
||||
else:
|
||||
self.Pos += 1
|
||||
self._ScanStringBody(quote, triple, is_fstring)
|
||||
end: int = self.Pos
|
||||
tok_type: str = FSTRING if is_fstring else STRING
|
||||
self.Tokens.append(self._Make(tok_type, start, end))
|
||||
self.AtLineStart = False
|
||||
return True
|
||||
|
||||
def _ScanStringBody(self, quote: str, triple: bool, is_fstring: bool) -> None:
|
||||
"""扫描字符串主体直到结束引号(处理转义、f-string 花括号、跨行登记)。"""
|
||||
while self.Pos < self.Length:
|
||||
ch: str = self.Source[self.Pos]
|
||||
if ch == '\\':
|
||||
# 反斜杠转义:\{{ 中反斜杠只转义自身,后续 {{ 仍需按花括号转义处理
|
||||
if self.Pos + 1 < self.Length and self.Source[self.Pos + 1] in '{}':
|
||||
self.Pos += 1
|
||||
else:
|
||||
self.Pos += 2
|
||||
continue
|
||||
if ch == '\n':
|
||||
# 三引号字符串跨行:登记行起始,保证后续行列换算准确
|
||||
self.Pos += 1
|
||||
self._RegisterNewline(self.Pos)
|
||||
continue
|
||||
if is_fstring and ch == '{':
|
||||
if self.Source.startswith('{{', self.Pos):
|
||||
self.Pos += 2
|
||||
continue
|
||||
self._ScanFStringExpr()
|
||||
continue
|
||||
if is_fstring and ch == '}':
|
||||
if self.Source.startswith('}}', self.Pos):
|
||||
self.Pos += 2
|
||||
continue
|
||||
self.Pos += 1
|
||||
continue
|
||||
if ch == quote:
|
||||
if triple:
|
||||
if self.Source.startswith(quote * 3, self.Pos):
|
||||
self.Pos += 3
|
||||
return
|
||||
self.Pos += 1
|
||||
else:
|
||||
self.Pos += 1
|
||||
return
|
||||
self.Pos += 1
|
||||
# 未闭合字符串:直接结束(Parser 层报语法错误)
|
||||
|
||||
def _ScanFStringExpr(self) -> None:
|
||||
"""跳过 f-string 的 {expr[!conv][:spec]} 表达式段。
|
||||
|
||||
表达式内可含字符串字面量(含嵌套 f-string)与括号嵌套,需整体跳过;
|
||||
跨行时登记行起始(三引号 f-string)。
|
||||
"""
|
||||
self.Pos += 1 # 跳过 {
|
||||
depth: int = 1
|
||||
while self.Pos < self.Length:
|
||||
ch: str = self.Source[self.Pos]
|
||||
if ch == '\\':
|
||||
self.Pos += 2
|
||||
continue
|
||||
if ch == '\n':
|
||||
self.Pos += 1
|
||||
self._RegisterNewline(self.Pos)
|
||||
continue
|
||||
if ch in '\'"':
|
||||
self._SkipInnerString()
|
||||
continue
|
||||
if ch == '(' or ch == '[' or ch == '{':
|
||||
depth += 1
|
||||
self.Pos += 1
|
||||
continue
|
||||
if ch == ')' or ch == ']':
|
||||
depth -= 1
|
||||
self.Pos += 1
|
||||
continue
|
||||
if ch == '}':
|
||||
if depth == 1:
|
||||
self.Pos += 1
|
||||
return
|
||||
depth -= 1
|
||||
self.Pos += 1
|
||||
continue
|
||||
self.Pos += 1
|
||||
|
||||
def _SkipInnerString(self) -> None:
|
||||
"""跳过 f-string 表达式内部的字符串字面量(含前缀与三引号)。"""
|
||||
save: int = self.Pos
|
||||
while self.Pos < self.Length and self.Source[self.Pos] in _STRING_PREFIX_CHARS:
|
||||
self.Pos += 1
|
||||
if self.Pos >= self.Length or self.Source[self.Pos] not in '\'"':
|
||||
self.Pos = save
|
||||
self.Pos += 1
|
||||
return
|
||||
inner_quote: str = self.Source[self.Pos]
|
||||
triple: bool = self.Source.startswith(inner_quote * 3, self.Pos)
|
||||
if triple:
|
||||
self.Pos += 3
|
||||
self._ScanStringBody(inner_quote, True, False)
|
||||
else:
|
||||
self.Pos += 1
|
||||
self._ScanStringBody(inner_quote, False, False)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 文件尾
|
||||
# ------------------------------------------------------------------
|
||||
def _FinishFile(self) -> None:
|
||||
"""文件末尾:补 NEWLINE、DEDENT、ENDMARKER。"""
|
||||
if self.Tokens and self.Tokens[-1].Type not in (NEWLINE, DEDENT, INDENT):
|
||||
self.Tokens.append(self._Make(NEWLINE, self.Pos, self.Pos))
|
||||
while len(self.Indents) > 1:
|
||||
self.Indents.pop()
|
||||
self.Tokens.append(self._Make(DEDENT, self.Pos, self.Pos))
|
||||
self.Tokens.append(self._Make(ENDMARKER, self.Pos, self.Pos))
|
||||
|
||||
|
||||
def TokenizeSource(source: str) -> list[Token]:
|
||||
"""便捷入口:源码 → token 流。"""
|
||||
return Tokenizer(source).Tokenize()
|
||||
@@ -0,0 +1,533 @@
|
||||
"""vast.unparser - AST 还原为源码字符串(与 ast.unparse 语义一致)
|
||||
|
||||
TPC 编译器多处用 ``ast.unparse`` 提取类型注解字符串(如 ``t.CArray[...]``、
|
||||
``list[i32, N]``、数组维度、默认值文本等)。本模块实现全部节点类型的
|
||||
源码还原,保证 ``import vast as ast`` 后这些调用零修改。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from lib.vast import Nodes as N
|
||||
|
||||
|
||||
class Unparser:
|
||||
"""递归将 vast 节点还原为源码文本。"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._Depth: int = 0
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 顶层
|
||||
# ------------------------------------------------------------------
|
||||
def Unparse(self, node: N.AST) -> str:
|
||||
if isinstance(node, N.Module):
|
||||
return '\n'.join(self._stmt(s) for s in node.body)
|
||||
if isinstance(node, N.Expression):
|
||||
return self._expr(node.body)
|
||||
return self._expr(node) if isinstance(node, N.expr) else self._stmt(node) # type: ignore[arg-type]
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 语句
|
||||
# ------------------------------------------------------------------
|
||||
def _stmt(self, node: N.AST) -> str:
|
||||
name: str = type(node).__name__
|
||||
m: dict[str, object] = {
|
||||
'FunctionDef': self._FunctionDef,
|
||||
'AsyncFunctionDef': self._FunctionDef,
|
||||
'ClassDef': self._ClassDef,
|
||||
'Return': self._Return,
|
||||
'Delete': self._Delete,
|
||||
'Assign': self._Assign,
|
||||
'AugAssign': self._AugAssign,
|
||||
'AnnAssign': self._AnnAssign,
|
||||
'For': self._For,
|
||||
'AsyncFor': self._For,
|
||||
'While': self._While,
|
||||
'If': self._If,
|
||||
'With': self._With,
|
||||
'AsyncWith': self._With,
|
||||
'Raise': self._Raise,
|
||||
'Try': self._Try,
|
||||
'TryStar': self._Try,
|
||||
'Assert': self._Assert,
|
||||
'Import': self._Import,
|
||||
'ImportFrom': self._ImportFrom,
|
||||
'Global': self._Global,
|
||||
'Nonlocal': self._Global,
|
||||
'Expr': self._ExprStmt,
|
||||
'Pass': self._Pass,
|
||||
'Break': lambda n: 'break',
|
||||
'Continue': lambda n: 'continue',
|
||||
'Match': self._Match,
|
||||
}
|
||||
fn = m.get(name)
|
||||
if fn is not None:
|
||||
return fn(node) # type: ignore[operator]
|
||||
raise NotImplementedError(f'unparse stmt: {name}')
|
||||
|
||||
def _Block(self, body: list[N.stmt]) -> str:
|
||||
self._Depth += 1
|
||||
pad: str = ' ' * self._Depth
|
||||
lines: list[str] = [f'{pad}{self._stmt(s)}' for s in body]
|
||||
self._Depth -= 1
|
||||
return '\n'.join(lines)
|
||||
|
||||
def _FunctionDef(self, node: N.FunctionDef) -> str:
|
||||
kw: str = 'async def' if isinstance(node, N.AsyncFunctionDef) else 'def'
|
||||
decos: str = ''.join(f'@{self._expr(d)}\n' for d in node.decorator_list)
|
||||
params: str = self._Arguments(node.args)
|
||||
ret: str = ''
|
||||
if node.returns is not None:
|
||||
ret = f' -> {self._expr(node.returns)}'
|
||||
body: str = self._Block(node.body)
|
||||
return f'{decos}{kw} {node.name}({params}){ret}:\n{body}'
|
||||
|
||||
def _ClassDef(self, node: N.ClassDef) -> str:
|
||||
decos: str = ''.join(f'@{self._expr(d)}\n' for d in node.decorator_list)
|
||||
args: list[str] = [self._expr(b) for b in node.bases]
|
||||
for kw in node.keywords:
|
||||
args.append(f'{kw.arg}={self._expr(kw.value)}' if kw.arg else f'**{self._expr(kw.value)}')
|
||||
header: str = f'class {node.name}' + (f'({", ".join(args)})' if args else '') + ':'
|
||||
return f'{decos}{header}\n{self._Block(node.body)}'
|
||||
|
||||
def _Return(self, node: N.Return) -> str:
|
||||
return 'return' if node.value is None else f'return {self._expr(node.value)}'
|
||||
|
||||
def _Delete(self, node: N.Delete) -> str:
|
||||
return 'del ' + ', '.join(self._expr(t) for t in node.targets)
|
||||
|
||||
def _Assign(self, node: N.Assign) -> str:
|
||||
return ', '.join(self._expr(t) for t in node.targets) + f' = {self._expr(node.value)}'
|
||||
|
||||
def _AugAssign(self, node: N.AugAssign) -> str:
|
||||
ops: dict[type, str] = {
|
||||
N.Add: '+', N.Sub: '-', N.Mult: '*', N.Div: '/', N.FloorDiv: '//',
|
||||
N.Mod: '%', N.Pow: '**', N.LShift: '<<', N.RShift: '>>',
|
||||
N.BitOr: '|', N.BitXor: '^', N.BitAnd: '&', N.MatMult: '@',
|
||||
}
|
||||
op: str = ops.get(type(node.op), '?')
|
||||
return f'{self._expr(node.target)} {op}= {self._expr(node.value)}'
|
||||
|
||||
def _AnnAssign(self, node: N.AnnAssign) -> str:
|
||||
val: str = f' = {self._expr(node.value)}' if node.value is not None else ''
|
||||
return f'{self._expr(node.target)}: {self._expr(node.annotation)}{val}'
|
||||
|
||||
def _For(self, node: N.For) -> str:
|
||||
kw: str = 'async for' if isinstance(node, N.AsyncFor) else 'for'
|
||||
orelse: str = f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}' if node.orelse else ''
|
||||
return f'{kw} {self._expr(node.target)} in {self._expr(node.iter)}:\n{self._Block(node.body)}{orelse}'
|
||||
|
||||
def _While(self, node: N.While) -> str:
|
||||
orelse: str = f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}' if node.orelse else ''
|
||||
return f'while {self._expr(node.test)}:\n{self._Block(node.body)}{orelse}'
|
||||
|
||||
def _If(self, node: N.If) -> str:
|
||||
out: str = f'if {self._expr(node.test)}:\n{self._Block(node.body)}'
|
||||
if node.orelse:
|
||||
if len(node.orelse) == 1 and isinstance(node.orelse[0], N.If):
|
||||
out += f'\n{" " * self._Depth}elif {self._expr(node.orelse[0].test)}:\n{self._Block(node.orelse[0].body)}'
|
||||
out += self._IfTail(node.orelse[0])
|
||||
else:
|
||||
out += f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}'
|
||||
return out
|
||||
|
||||
def _IfTail(self, node: N.If) -> str:
|
||||
out: str = ''
|
||||
if node.orelse:
|
||||
if len(node.orelse) == 1 and isinstance(node.orelse[0], N.If):
|
||||
out += f'\n{" " * self._Depth}elif {self._expr(node.orelse[0].test)}:\n{self._Block(node.orelse[0].body)}'
|
||||
out += self._IfTail(node.orelse[0])
|
||||
else:
|
||||
out += f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}'
|
||||
return out
|
||||
|
||||
def _With(self, node: N.With) -> str:
|
||||
kw: str = 'async with' if isinstance(node, N.AsyncWith) else 'with'
|
||||
items: list[str] = []
|
||||
for item in node.items:
|
||||
s: str = self._expr(item.context_expr)
|
||||
if item.optional_vars is not None:
|
||||
s += f' as {self._expr(item.optional_vars)}'
|
||||
items.append(s)
|
||||
return f'{kw} {", ".join(items)}:\n{self._Block(node.body)}'
|
||||
|
||||
def _Raise(self, node: N.Raise) -> str:
|
||||
if node.exc is None:
|
||||
return 'raise'
|
||||
out: str = f'raise {self._expr(node.exc)}'
|
||||
if node.cause is not None:
|
||||
out += f' from {self._expr(node.cause)}'
|
||||
return out
|
||||
|
||||
def _Try(self, node: N.Try) -> str:
|
||||
out: str = f'try:\n{self._Block(node.body)}'
|
||||
for h in node.handlers:
|
||||
hdr: str = 'except*' if isinstance(node, N.TryStar) else 'except'
|
||||
if h.type is not None:
|
||||
hdr += f' {self._expr(h.type)}'
|
||||
if h.name:
|
||||
hdr += f' as {h.name}'
|
||||
out += f'\n{" " * self._Depth}{hdr}:\n{self._Block(h.body)}'
|
||||
if node.orelse:
|
||||
out += f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}'
|
||||
if node.finalbody:
|
||||
out += f'\n{" " * self._Depth}finally:\n{self._Block(node.finalbody)}'
|
||||
return out
|
||||
|
||||
def _Assert(self, node: N.Assert) -> str:
|
||||
out: str = f'assert {self._expr(node.test)}'
|
||||
if node.msg is not None:
|
||||
out += f', {self._expr(node.msg)}'
|
||||
return out
|
||||
|
||||
def _Import(self, node: N.Import) -> str:
|
||||
names: list[str] = []
|
||||
for a in node.names:
|
||||
s: str = a.name
|
||||
if a.asname:
|
||||
s += f' as {a.asname}'
|
||||
names.append(s)
|
||||
return 'import ' + ', '.join(names)
|
||||
|
||||
def _ImportFrom(self, node: N.ImportFrom) -> str:
|
||||
dots: str = '.' * node.level
|
||||
mod: str = node.module or ''
|
||||
names: list[str] = []
|
||||
for a in node.names:
|
||||
s: str = a.name
|
||||
if a.asname:
|
||||
s += f' as {a.asname}'
|
||||
names.append(s)
|
||||
return f'from {dots}{mod} import {", ".join(names)}'
|
||||
|
||||
def _Global(self, node: N.AST) -> str:
|
||||
kw: str = 'global' if isinstance(node, N.Global) else 'nonlocal'
|
||||
return f'{kw} {", ".join(node.names)}'
|
||||
|
||||
def _ExprStmt(self, node: N.Expr) -> str:
|
||||
return self._expr(node.value)
|
||||
|
||||
def _Pass(self, node: N.Pass) -> str:
|
||||
return 'pass'
|
||||
|
||||
def _Match(self, node: N.Match) -> str:
|
||||
out: str = f'match {self._expr(node.subject)}:\n'
|
||||
self._Depth += 1
|
||||
pad: str = ' ' * self._Depth
|
||||
for case in node.cases:
|
||||
guard: str = f' if {self._expr(case.guard)}' if case.guard else ''
|
||||
out += f'{pad}case {self._Pattern(case.pattern)}{guard}:\n'
|
||||
self._Depth += 1
|
||||
out += self._Block(case.body)
|
||||
self._Depth -= 1
|
||||
self._Depth -= 1
|
||||
return out
|
||||
|
||||
def _Pattern(self, node: N.pattern) -> str:
|
||||
name: str = type(node).__name__
|
||||
if isinstance(node, N.MatchValue):
|
||||
return self._expr(node.value)
|
||||
if isinstance(node, N.MatchSingleton):
|
||||
return repr(node.value)
|
||||
if isinstance(node, N.MatchSequence):
|
||||
return '[' + ', '.join(self._Pattern(p) for p in node.patterns) + ']'
|
||||
if isinstance(node, N.MatchMapping):
|
||||
parts: list[str] = []
|
||||
for k, p in zip(node.keys, node.patterns):
|
||||
parts.append(f'{self._expr(k)}: {self._Pattern(p)}')
|
||||
if node.rest:
|
||||
parts.append(f'**{node.rest}')
|
||||
return '{' + ', '.join(parts) + '}'
|
||||
if isinstance(node, N.MatchClass):
|
||||
pos: list[str] = [self._Pattern(p) for p in node.patterns]
|
||||
kw: list[str] = [f'{a}={self._Pattern(p)}' for a, p in zip(node.kwd_attrs, node.kwd_patterns)]
|
||||
return f'{self._expr(node.cls)}({", ".join(pos + kw)})'
|
||||
if isinstance(node, N.MatchStar):
|
||||
return f'*{node.name}' if node.name else '*_'
|
||||
if isinstance(node, N.MatchAs):
|
||||
if node.pattern is not None:
|
||||
return f'{self._Pattern(node.pattern)} as {node.name}'
|
||||
return node.name or '_'
|
||||
if isinstance(node, N.MatchOr):
|
||||
return ' | '.join(self._Pattern(p) for p in node.patterns)
|
||||
raise NotImplementedError(f'unparse pattern: {name}')
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 表达式
|
||||
# ------------------------------------------------------------------
|
||||
def _expr(self, node: N.AST) -> str:
|
||||
name: str = type(node).__name__
|
||||
m: dict[str, object] = {
|
||||
'Name': self._Name,
|
||||
'Constant': self._Constant,
|
||||
'Attribute': self._Attribute,
|
||||
'Call': self._Call,
|
||||
'BinOp': self._BinOp,
|
||||
'UnaryOp': self._UnaryOp,
|
||||
'BoolOp': self._BoolOp,
|
||||
'Compare': self._Compare,
|
||||
'Subscript': self._Subscript,
|
||||
'Slice': self._Slice,
|
||||
'Tuple': self._Tuple,
|
||||
'List': self._List,
|
||||
'Set': self._Set,
|
||||
'Dict': self._Dict,
|
||||
'JoinedStr': self._JoinedStr,
|
||||
'FormattedValue': self._FormattedValue,
|
||||
'Lambda': self._Lambda,
|
||||
'IfExp': self._IfExp,
|
||||
'Starred': self._Starred,
|
||||
'ListComp': self._ListComp,
|
||||
'SetComp': self._ListComp,
|
||||
'GeneratorExp': self._ListComp,
|
||||
'DictComp': self._DictComp,
|
||||
'NamedExpr': self._NamedExpr,
|
||||
'Await': self._Await,
|
||||
'Yield': self._Yield,
|
||||
'YieldFrom': self._YieldFrom,
|
||||
}
|
||||
fn = m.get(name)
|
||||
if fn is not None:
|
||||
return fn(node) # type: ignore[operator]
|
||||
raise NotImplementedError(f'unparse expr: {name}')
|
||||
|
||||
def _Name(self, node: N.Name) -> str:
|
||||
return node.id
|
||||
|
||||
def _Constant(self, node: N.Constant) -> str:
|
||||
v = node.value
|
||||
if v is Ellipsis:
|
||||
return '...'
|
||||
if v is None:
|
||||
return 'None'
|
||||
if v is True:
|
||||
return 'True'
|
||||
if v is False:
|
||||
return 'False'
|
||||
if isinstance(v, str):
|
||||
return repr(v)
|
||||
if isinstance(v, bytes):
|
||||
return repr(v)
|
||||
if isinstance(v, complex):
|
||||
# 复数文本
|
||||
return repr(v)
|
||||
return repr(v)
|
||||
|
||||
def _Attribute(self, node: N.Attribute) -> str:
|
||||
return f'{self._expr(node.value)}.{node.attr}'
|
||||
|
||||
def _Call(self, node: N.Call) -> str:
|
||||
args: list[str] = [self._expr(a) for a in node.args]
|
||||
for kw in node.keywords:
|
||||
if kw.arg is None:
|
||||
args.append(f'**{self._expr(kw.value)}')
|
||||
else:
|
||||
args.append(f'{kw.arg}={self._expr(kw.value)}')
|
||||
return f'{self._expr(node.func)}({", ".join(args)})'
|
||||
|
||||
_BINOP_OPS: dict[type, str] = {
|
||||
N.Add: '+', N.Sub: '-', N.Mult: '*', N.Div: '/', N.FloorDiv: '//',
|
||||
N.Mod: '%', N.Pow: '**', N.LShift: '<<', N.RShift: '>>',
|
||||
N.BitOr: '|', N.BitXor: '^', N.BitAnd: '&', N.MatMult: '@',
|
||||
}
|
||||
|
||||
def _BinOp(self, node: N.BinOp) -> str:
|
||||
op: str = self._BINOP_OPS.get(type(node.op), '?')
|
||||
return f'{self._expr(node.left)} {op} {self._expr(node.right)}'
|
||||
|
||||
def _UnaryOp(self, node: N.UnaryOp) -> str:
|
||||
ops: dict[type, str] = {N.USub: '-', N.UAdd: '+', N.Not: 'not ', N.Invert: '~'}
|
||||
op: str = ops.get(type(node.op), '?')
|
||||
return f'{op}{self._expr(node.operand)}'
|
||||
|
||||
def _BoolOp(self, node: N.BoolOp) -> str:
|
||||
kw: str = 'or' if isinstance(node.op, N.Or) else 'and'
|
||||
return f' {kw} '.join(self._expr(v) for v in node.values)
|
||||
|
||||
_CMPOPS: dict[type, str] = {
|
||||
N.Eq: '==', N.NotEq: '!=', N.Lt: '<', N.LtE: '<=', N.Gt: '>', N.GtE: '>=',
|
||||
N.Is: 'is', N.IsNot: 'is not', N.In: 'in', N.NotIn: 'not in',
|
||||
}
|
||||
|
||||
def _Compare(self, node: N.Compare) -> str:
|
||||
parts: list[str] = [self._expr(node.left)]
|
||||
for op, comp in zip(node.ops, node.comparators):
|
||||
parts.append(self._CMPOPS.get(type(op), '?'))
|
||||
parts.append(self._expr(comp))
|
||||
return ' '.join(parts)
|
||||
|
||||
def _Subscript(self, node: N.Subscript) -> str:
|
||||
return f'{self._expr(node.value)}[{self._SliceLike(node.slice)}]'
|
||||
|
||||
def _SliceLike(self, node: N.AST) -> str:
|
||||
if isinstance(node, N.Slice):
|
||||
return self._Slice(node)
|
||||
if isinstance(node, N.Tuple):
|
||||
# 切片元组:a[1, 2] / a[i, j:k] 元素按需渲染
|
||||
return ', '.join(self._SliceLike(e) for e in node.elts)
|
||||
return self._expr(node)
|
||||
|
||||
def _Slice(self, node: N.Slice) -> str:
|
||||
"""渲染切片:a[1:2] / a[::2] / a[:2] / a[1:2:3]。"""
|
||||
parts: list[str] = []
|
||||
if node.lower is not None:
|
||||
parts.append(self._expr(node.lower))
|
||||
# 冒号:upper 或 step 存在时才需要第一个冒号
|
||||
if node.upper is not None or node.step is not None:
|
||||
if len(parts) < 1:
|
||||
parts.append('')
|
||||
parts.append(self._expr(node.upper) if node.upper is not None else '')
|
||||
if node.step is not None:
|
||||
if len(parts) < 2:
|
||||
parts.append('')
|
||||
parts.append('')
|
||||
parts.append(self._expr(node.step))
|
||||
return ':'.join(parts)
|
||||
|
||||
def _Tuple(self, node: N.Tuple) -> str:
|
||||
if len(node.elts) == 1:
|
||||
return f'({self._expr(node.elts[0])},)'
|
||||
return '(' + ', '.join(self._expr(e) for e in node.elts) + ')'
|
||||
|
||||
def _List(self, node: N.List) -> str:
|
||||
return '[' + ', '.join(self._expr(e) for e in node.elts) + ']'
|
||||
|
||||
def _Set(self, node: N.Set) -> str:
|
||||
return '{' + ', '.join(self._expr(e) for e in node.elts) + '}'
|
||||
|
||||
def _Dict(self, node: N.Dict) -> str:
|
||||
parts: list[str] = []
|
||||
for k, v in zip(node.keys, node.values):
|
||||
if k is None:
|
||||
parts.append(f'**{self._expr(v)}')
|
||||
else:
|
||||
parts.append(f'{self._expr(k)}: {self._expr(v)}')
|
||||
return '{' + ', '.join(parts) + '}'
|
||||
|
||||
def _JoinedStr(self, node: N.JoinedStr) -> str:
|
||||
out: list[str] = []
|
||||
for v in node.values:
|
||||
if isinstance(v, N.Constant):
|
||||
# 字面量段:转义内部引号与花括号
|
||||
lit: str = str(v.value)
|
||||
lit = lit.replace('{', '{{').replace('}', '}}')
|
||||
lit = lit.replace("'", "\\'")
|
||||
out.append(lit)
|
||||
else:
|
||||
out.append('{' + self._FormattedValueRaw(v) + '}')
|
||||
inner: str = ''.join(out)
|
||||
# 优先单引号(与 CPython unparse 一致)
|
||||
return "f'" + inner + "'"
|
||||
|
||||
def _FormattedValue(self, node: N.FormattedValue) -> str:
|
||||
return "f'{" + self._FormattedValueRaw(node) + "}'"
|
||||
|
||||
def _FormattedValueRaw(self, node: N.FormattedValue) -> str:
|
||||
s: str = self._expr(node.value)
|
||||
if node.conversion >= 0:
|
||||
s += f'!{chr(node.conversion)}'
|
||||
if node.format_spec is not None:
|
||||
if isinstance(node.format_spec, N.JoinedStr):
|
||||
spec: str = ''
|
||||
for v in node.format_spec.values:
|
||||
if isinstance(v, N.Constant):
|
||||
spec += str(v.value)
|
||||
else:
|
||||
spec += '{' + self._FormattedValueRaw(v) + '}'
|
||||
else:
|
||||
spec = self._expr(node.format_spec)
|
||||
s += f':{spec}'
|
||||
return s
|
||||
|
||||
def _Lambda(self, node: N.Lambda) -> str:
|
||||
return f'lambda {self._Arguments(node.args)}: {self._expr(node.body)}'
|
||||
|
||||
def _IfExp(self, node: N.IfExp) -> str:
|
||||
return f'{self._expr(node.body)} if {self._expr(node.test)} else {self._expr(node.orelse)}'
|
||||
|
||||
def _Starred(self, node: N.Starred) -> str:
|
||||
return f'*{self._expr(node.value)}'
|
||||
|
||||
def _ComprehensionClauses(self, gens: list[N.comprehension]) -> str:
|
||||
out: list[str] = []
|
||||
for g in gens:
|
||||
kw: str = 'async for' if g.is_async else 'for'
|
||||
s: str = f' {kw} {self._expr(g.target)} in {self._expr(g.iter)}'
|
||||
for cond in g.ifs:
|
||||
s += f' if {self._expr(cond)}'
|
||||
out.append(s)
|
||||
return ''.join(out)
|
||||
|
||||
def _ListComp(self, node: N.AST) -> str:
|
||||
cls_name: str = type(node).__name__
|
||||
if isinstance(node, N.SetComp):
|
||||
fmt: str = '{'
|
||||
close: str = '}'
|
||||
elt: str = self._expr(node.elt)
|
||||
elif isinstance(node, N.GeneratorExp):
|
||||
fmt, close, elt = '(', ')', self._expr(node.elt)
|
||||
elif isinstance(node, N.DictComp):
|
||||
return '{' + f'{self._expr(node.key)}: {self._expr(node.value)}' + self._ComprehensionClauses(node.generators) + '}'
|
||||
else:
|
||||
fmt, close, elt = '[', ']', self._expr(node.elt)
|
||||
return fmt + elt + self._ComprehensionClauses(node.generators) + close
|
||||
|
||||
def _DictComp(self, node: N.DictComp) -> str:
|
||||
return '{' + f'{self._expr(node.key)}: {self._expr(node.value)}' + \
|
||||
self._ComprehensionClauses(node.generators) + '}'
|
||||
|
||||
def _NamedExpr(self, node: N.NamedExpr) -> str:
|
||||
return f'{self._expr(node.target)} := {self._expr(node.value)}'
|
||||
|
||||
def _Await(self, node: N.Await) -> str:
|
||||
return f'await {self._expr(node.value)}'
|
||||
|
||||
def _Yield(self, node: N.Yield) -> str:
|
||||
return 'yield' if node.value is None else f'yield {self._expr(node.value)}'
|
||||
|
||||
def _YieldFrom(self, node: N.YieldFrom) -> str:
|
||||
return f'yield from {self._expr(node.value)}'
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 参数列表
|
||||
# ------------------------------------------------------------------
|
||||
def _Arguments(self, args: N.arguments) -> str:
|
||||
parts: list[str] = []
|
||||
n_args: int = len(args.posonlyargs) + len(args.args)
|
||||
n_defaults: int = len(args.defaults)
|
||||
# 合并 posonly + 普通参数,defaults 尾部对齐
|
||||
all_args: list[N.arg] = list(args.posonlyargs) + list(args.args)
|
||||
all_defaults: list[N.expr | None] = [None] * (n_args - n_defaults) + list(args.defaults)
|
||||
for i, a in enumerate(all_args):
|
||||
s: str = a.arg
|
||||
if a.annotation is not None:
|
||||
s += f': {self._expr(a.annotation)}'
|
||||
if all_defaults[i] is not None:
|
||||
s += f'={self._expr(all_defaults[i])}'
|
||||
parts.append(s)
|
||||
if args.posonlyargs and i == len(args.posonlyargs) - 1:
|
||||
parts.append('/')
|
||||
if args.vararg is not None:
|
||||
s = f'*{args.vararg.arg}'
|
||||
if args.vararg.annotation is not None:
|
||||
s += f': {self._expr(args.vararg.annotation)}'
|
||||
parts.append(s)
|
||||
elif args.kwonlyargs:
|
||||
parts.append('*')
|
||||
for a, d in zip(args.kwonlyargs, args.kw_defaults):
|
||||
s = a.arg
|
||||
if a.annotation is not None:
|
||||
s += f': {self._expr(a.annotation)}'
|
||||
if d is not None:
|
||||
s += f'={self._expr(d)}'
|
||||
parts.append(s)
|
||||
if args.kwarg is not None:
|
||||
s = f'**{args.kwarg.arg}'
|
||||
if args.kwarg.annotation is not None:
|
||||
s += f': {self._expr(args.kwarg.annotation)}'
|
||||
parts.append(s)
|
||||
return ', '.join(parts)
|
||||
|
||||
|
||||
def Unparse(node: N.AST) -> str:
|
||||
"""便捷入口。"""
|
||||
return Unparser().Unparse(node)
|
||||
@@ -0,0 +1,281 @@
|
||||
"""vast.utils - AST 遍历与序列化工具
|
||||
|
||||
与 CPython ``ast`` 模块辅助函数同构:
|
||||
|
||||
- ``iter_fields`` / ``iter_child_nodes`` / ``walk``
|
||||
- ``dump``(含 annotate_fields / include_attributes / indent)
|
||||
- ``copy_location`` / ``fix_missing_locations`` / ``get_source_segment``
|
||||
- ``literal_eval``(常量求值)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from lib.vast.Nodes import AST
|
||||
from lib.vast.Tokenizer import Token
|
||||
|
||||
|
||||
def iter_fields(node: AST):
|
||||
"""按 _fields 顺序产出 (字段名, 值)。"""
|
||||
for field in node._fields:
|
||||
try:
|
||||
yield field, getattr(node, field)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def iter_child_nodes(node: AST):
|
||||
"""产出全部子节点(递归扁平,跳过 None 与空列表)。"""
|
||||
for _name, field in iter_fields(node):
|
||||
if isinstance(field, AST):
|
||||
yield field
|
||||
elif isinstance(field, list):
|
||||
for item in field:
|
||||
if isinstance(item, AST):
|
||||
yield item
|
||||
|
||||
|
||||
def walk(node: AST):
|
||||
"""深度优先遍历,产出自身与全部后代节点。"""
|
||||
from collections import deque
|
||||
|
||||
todo: deque[AST] = deque([node])
|
||||
while todo:
|
||||
n: AST = todo.popleft()
|
||||
yield n
|
||||
todo.extend(iter_child_nodes(n))
|
||||
|
||||
|
||||
def dump(node: AST, annotate_fields: bool = True, include_attributes: bool = False,
|
||||
indent: int | str | None = None) -> str:
|
||||
"""将 AST 节点格式化为字符串(精确复刻 CPython 3.12 ast.dump)。
|
||||
|
||||
- annotate_fields: 是否显示字段名(默认 True)
|
||||
- include_attributes: 是否附加 lineno/col_offset 等位置属性
|
||||
- indent: 缩进(int 或字符串),None 为单行紧凑输出
|
||||
|
||||
与 CPython 一致的行为:
|
||||
- 值为 None 且类默认值为 None 的字段跳过(如 FunctionDef.returns)
|
||||
- 节点字段全部为"简单值"且 ≤3 个时单行输出
|
||||
"""
|
||||
if not isinstance(node, AST):
|
||||
raise TypeError(f'expected AST, got {type(node).__name__!r}')
|
||||
|
||||
if indent is not None and not isinstance(indent, str):
|
||||
indent = ' ' * indent
|
||||
|
||||
def _format(node: object, level: int = 0):
|
||||
if indent is not None:
|
||||
level += 1
|
||||
prefix: str = '\n' + indent * level # type: ignore[operator]
|
||||
sep: str = ',\n' + indent * level # type: ignore[operator]
|
||||
else:
|
||||
prefix = ''
|
||||
sep = ', '
|
||||
if isinstance(node, AST):
|
||||
cls: type = type(node)
|
||||
args: list[str] = []
|
||||
allsimple: bool = True
|
||||
keywords: bool = annotate_fields
|
||||
for name in node._fields:
|
||||
try:
|
||||
value = getattr(node, name)
|
||||
except AttributeError:
|
||||
keywords = True
|
||||
continue
|
||||
if value is None and getattr(cls, name, ...) is None:
|
||||
keywords = True
|
||||
continue
|
||||
value, simple = _format(value, level)
|
||||
allsimple = allsimple and simple
|
||||
if keywords:
|
||||
args.append(f'{name}={value}')
|
||||
else:
|
||||
args.append(value)
|
||||
if include_attributes and node._attributes:
|
||||
for name in node._attributes:
|
||||
try:
|
||||
value = getattr(node, name)
|
||||
except AttributeError:
|
||||
continue
|
||||
if value is None and getattr(cls, name, ...) is None:
|
||||
continue
|
||||
value, simple = _format(value, level)
|
||||
allsimple = allsimple and simple
|
||||
args.append(f'{name}={value}')
|
||||
if allsimple and len(args) <= 3:
|
||||
return f'{type(node).__name__}({", ".join(args)})', not args
|
||||
return f'{type(node).__name__}({prefix}{sep.join(args)})', False
|
||||
elif isinstance(node, list):
|
||||
if not node:
|
||||
return '[]', True
|
||||
return f'[{prefix}{sep.join(_format(x, level)[0] for x in node)}]', False
|
||||
return repr(node), True
|
||||
|
||||
return _format(node)[0]
|
||||
|
||||
|
||||
def copy_location(new_node: AST, old_node: AST) -> AST:
|
||||
"""复制 old_node 的位置属性到 new_node(与 ast.copy_location 一致)。"""
|
||||
for attr in ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'):
|
||||
try:
|
||||
setattr(new_node, attr, getattr(old_node, attr))
|
||||
except AttributeError:
|
||||
pass
|
||||
return new_node
|
||||
|
||||
|
||||
def fix_missing_locations(node: AST) -> AST:
|
||||
"""为缺失位置的节点补全(从最近的祖先复制;递归处理)。"""
|
||||
def _fix(n: AST, parent_loc: dict[str, int] | None) -> None:
|
||||
has_loc: bool = hasattr(n, 'lineno') and getattr(n, 'lineno', None) is not None
|
||||
if hasattr(n, 'lineno') and getattr(n, 'lineno', None) is None and parent_loc:
|
||||
for attr, val in parent_loc.items():
|
||||
setattr(n, attr, val)
|
||||
loc: dict[str, int] | None = None
|
||||
if hasattr(n, 'lineno') and getattr(n, 'lineno', None) is not None:
|
||||
loc = {a: getattr(n, a) for a in
|
||||
('lineno', 'col_offset', 'end_lineno', 'end_col_offset')
|
||||
if getattr(n, a, None) is not None}
|
||||
for child in iter_child_nodes(n):
|
||||
_fix(child, loc)
|
||||
|
||||
_fix(node, None)
|
||||
return node
|
||||
|
||||
|
||||
def get_source_segment(source: str, node: AST, padded: bool = False) -> str | None:
|
||||
"""提取节点对应的源码片段(与 ast.get_source_segment 一致)。"""
|
||||
try:
|
||||
lineno: int | None = getattr(node, 'lineno', None)
|
||||
end_lineno: int | None = getattr(node, 'end_lineno', None)
|
||||
col_offset: int | None = getattr(node, 'col_offset', None)
|
||||
end_col_offset: int | None = getattr(node, 'end_col_offset', None)
|
||||
if lineno is None or end_lineno is None or col_offset is None or end_col_offset is None:
|
||||
return None
|
||||
lines: list[str] = source.splitlines(keepends=True)
|
||||
if lineno < 1 or lineno > len(lines):
|
||||
return None
|
||||
first: str = lines[lineno - 1]
|
||||
# col_offset 是 UTF-8 字节偏移 → 转字符偏移
|
||||
start_char: int = _ByteToChar(first, col_offset)
|
||||
if lineno == end_lineno:
|
||||
end_char: int = _ByteToChar(first, end_col_offset)
|
||||
segment: str = first[start_char:end_char]
|
||||
else:
|
||||
last: str = lines[end_lineno - 1]
|
||||
end_char = _ByteToChar(last, end_col_offset)
|
||||
middle: list[str] = lines[lineno:end_lineno - 1]
|
||||
segment = first[start_char:] + ''.join(middle) + last[:end_char]
|
||||
if padded:
|
||||
return segment
|
||||
return segment
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _ByteToChar(line: str, byte_offset: int) -> int:
|
||||
"""UTF-8 字节偏移 → 字符偏移。"""
|
||||
b: bytes = line.encode('utf-8')
|
||||
return len(b[:byte_offset].decode('utf-8', errors='replace')) if byte_offset > 0 else 0
|
||||
|
||||
|
||||
def literal_eval(node_or_string: AST | str):
|
||||
"""安全求值常量表达式(与 ast.literal_eval 语义一致)。
|
||||
|
||||
支持常量、元组/列表/集合/字典、一元 +/-、BinOp 算术、切片。
|
||||
"""
|
||||
if isinstance(node_or_string, str):
|
||||
from lib.vast.Tokenizer import Tokenizer
|
||||
|
||||
toks: list[Token] = Tokenizer(node_or_string).Tokenize()
|
||||
if toks and toks[0].Type == 'NEWLINE':
|
||||
raise ValueError('malformed node or string')
|
||||
from lib.vast.Parser import _ComputeLineStarts
|
||||
|
||||
from lib.vast.ExprParser import ExprParserMixin
|
||||
|
||||
class _EV(ExprParserMixin):
|
||||
def __init__(self) -> None:
|
||||
super().__init__(toks, node_or_string, _ComputeLineStarts(node_or_string))
|
||||
|
||||
parser = _EV()
|
||||
node: AST = parser.ParseExpr()
|
||||
elif isinstance(node_or_string, AST):
|
||||
node = node_or_string
|
||||
else:
|
||||
raise TypeError('bad argument type')
|
||||
|
||||
return _EvalLiteral(node)
|
||||
|
||||
|
||||
def _EvalLiteral(node: AST):
|
||||
"""递归常量求值核心。"""
|
||||
if isinstance(node, AST):
|
||||
pass
|
||||
name: str = type(node).__name__
|
||||
# 常量
|
||||
if name == 'Constant':
|
||||
value = node.value
|
||||
if isinstance(value, (int, float, complex, str, bool, bytes, type(None), Ellipsis)): # type: ignore[comparison-overlap]
|
||||
return value
|
||||
raise ValueError('malformed node or string: unsupported constant')
|
||||
if name == 'Tuple':
|
||||
return tuple(_EvalLiteral(e) for e in node.elts)
|
||||
if name == 'List':
|
||||
return [_EvalLiteral(e) for e in node.elts]
|
||||
if name == 'Set':
|
||||
return {_EvalLiteral(e) for e in node.elts}
|
||||
if name == 'Dict':
|
||||
if len(node.keys) != len(node.values):
|
||||
raise ValueError('malformed node or string: Dict')
|
||||
out: dict = {}
|
||||
for k, v in zip(node.keys, node.values):
|
||||
if k is None:
|
||||
raise ValueError('malformed node or string: ** in Dict')
|
||||
out[_EvalLiteral(k)] = _EvalLiteral(v)
|
||||
return out
|
||||
if name == 'UnaryOp':
|
||||
operand = _EvalLiteral(node.operand)
|
||||
if isinstance(node.op, (__import__('lib.vast.Nodes', fromlist=['USub']).USub,)):
|
||||
return -operand
|
||||
if isinstance(node.op, (__import__('lib.vast.Nodes', fromlist=['UAdd']).UAdd,)):
|
||||
return +operand
|
||||
if isinstance(node.op, (__import__('lib.vast.Nodes', fromlist=['Not']).Not,)):
|
||||
return not operand
|
||||
raise ValueError('malformed node or string: unary op')
|
||||
if name == 'BinOp':
|
||||
from lib.vast.Nodes import Add, Sub, Mult, Div, FloorDiv, Mod, Pow, LShift, RShift, BitOr, BitXor, BitAnd
|
||||
|
||||
left = _EvalLiteral(node.left)
|
||||
right = _EvalLiteral(node.right)
|
||||
op = node.op
|
||||
if isinstance(op, Add):
|
||||
return left + right
|
||||
if isinstance(op, Sub):
|
||||
return left - right
|
||||
if isinstance(op, Mult):
|
||||
return left * right
|
||||
if isinstance(op, Div):
|
||||
return left / right
|
||||
if isinstance(op, FloorDiv):
|
||||
return left // right
|
||||
if isinstance(op, Mod):
|
||||
return left % right
|
||||
if isinstance(op, Pow):
|
||||
return left ** right
|
||||
if isinstance(op, LShift):
|
||||
return left << right
|
||||
if isinstance(op, RShift):
|
||||
return left >> right
|
||||
if isinstance(op, BitOr):
|
||||
return left | right
|
||||
if isinstance(op, BitXor):
|
||||
return left ^ right
|
||||
if isinstance(op, BitAnd):
|
||||
return left & right
|
||||
raise ValueError('malformed node or string: bin op')
|
||||
if name == 'Slice':
|
||||
lower = _EvalLiteral(node.lower) if node.lower is not None else None
|
||||
upper = _EvalLiteral(node.upper) if node.upper is not None else None
|
||||
step = _EvalLiteral(node.step) if node.step is not None else None
|
||||
return slice(lower, upper, step)
|
||||
raise ValueError(f'malformed node or string: {name}')
|
||||
@@ -0,0 +1,69 @@
|
||||
"""vast - Viper/Python 自研语法解析器(ast 替代品)
|
||||
|
||||
vast 提供与 CPython 3.12 标准库 ``ast`` 完全一致的 API:
|
||||
|
||||
- 节点类:``AST`` 及全部 131 个节点类(Name/Call/BinOp/FunctionDef/...)
|
||||
- 解析入口:``parse(source, filename, mode, ...)`` 产出 ``Module``
|
||||
- 辅助函数:``dump`` / ``walk`` / ``iter_child_nodes`` / ``iter_fields`` /
|
||||
``unparse`` / ``copy_location`` / ``fix_missing_locations`` /
|
||||
``get_source_segment`` / ``literal_eval``
|
||||
- 类型标注占位:``expr`` / ``stmt`` / ``operator`` / ``cmpop`` 等
|
||||
|
||||
编译器侧替换方式(零修改其余代码)::
|
||||
|
||||
import vast as ast
|
||||
|
||||
vast 原生支持 Viper 软关键字 fn/fun/func/function(并入解析器),无需
|
||||
ExpandSoftKeywords 预处理。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys as _sys
|
||||
|
||||
from lib.vast.Nodes import AST
|
||||
from lib.vast.Nodes import _NODE_DEFS
|
||||
|
||||
# 将全部节点类提升到包命名空间
|
||||
for _name in _NODE_DEFS:
|
||||
globals()[_name] = getattr(_sys.modules['lib.vast.Nodes'], _name)
|
||||
|
||||
from lib.vast.Parser import Parse # noqa: E402
|
||||
from lib.vast.Utils import ( # noqa: E402
|
||||
iter_fields, iter_child_nodes, walk, dump, copy_location,
|
||||
fix_missing_locations, get_source_segment, literal_eval,
|
||||
)
|
||||
from lib.vast.Unparser import Unparse as unparse # noqa: E402
|
||||
from lib.vast.Tokenizer import SOFT_KEYWORDS # noqa: E402
|
||||
|
||||
|
||||
def parse(source: str, filename: str = '<unknown>', mode: str = 'exec', *,
|
||||
type_comments: bool = False, feature_version: tuple[int, int] | int | None = None) -> AST:
|
||||
"""解析源码字符串为 AST(与 ast.parse 同签名、同结构)。
|
||||
|
||||
Args:
|
||||
source: 源码文本
|
||||
filename: 文件名(仅用于错误报告,vast 保留)
|
||||
mode: 'exec'(模块)/ 'eval'(单表达式)/ 'single'(交互式)
|
||||
type_comments: 是否解析 # type: 注释(vast 暂返回 None 字段)
|
||||
feature_version: 目标 Python 版本(vast 忽略,保持兼容)
|
||||
"""
|
||||
tree: AST = Parse(source)
|
||||
if mode == 'exec':
|
||||
return tree
|
||||
if mode == 'eval':
|
||||
if len(tree.body) != 1 or not isinstance(tree.body[0], _sys.modules['lib.vast.Nodes'].Expr):
|
||||
raise SyntaxError('invalid syntax for eval mode')
|
||||
expr_node: AST = _sys.modules['lib.vast.Nodes'].Expression(
|
||||
body=tree.body[0].value)
|
||||
return expr_node
|
||||
if mode == 'single':
|
||||
interactive: AST = _sys.modules['lib.vast.Nodes'].Interactive(body=tree.body)
|
||||
return interactive
|
||||
raise ValueError(f"invalid mode {mode!r}")
|
||||
|
||||
|
||||
__all__: list[str] = [
|
||||
'AST', 'parse', 'dump', 'walk', 'iter_fields', 'iter_child_nodes',
|
||||
'unparse', 'copy_location', 'fix_missing_locations',
|
||||
'get_source_segment', 'literal_eval', 'SOFT_KEYWORDS',
|
||||
] + list(_NODE_DEFS.keys())
|
||||
Reference in new issue
Block a user