修正了种子编译器的错误
This commit is contained in:
@@ -69,8 +69,17 @@ def resolve_paths(config: dict[str, Any], project_file: str) -> dict[str, Any]:
|
||||
resolved_sources.append(resolve(src))
|
||||
result['sources'] = [s for s in resolved_sources if os.path.isfile(s)]
|
||||
|
||||
result['temp_dir'] = resolve(config.get('temp_dir'))
|
||||
result['output_dir'] = resolve(config.get('output_dir'))
|
||||
# build_dir: 统一构建目录(默认 ./.tpv_build),temp 和 output 作为其子目录
|
||||
# 不再单独读取 temp_dir/output_dir,由 build_dir 自动计算
|
||||
build_dir: str = config.get('build_dir', './.tpv_build')
|
||||
build_dir = resolve(build_dir)
|
||||
result['build_dir'] = build_dir
|
||||
if build_dir is not None:
|
||||
result['temp_dir'] = os.path.join(build_dir, 'temp')
|
||||
result['output_dir'] = os.path.join(build_dir, 'output')
|
||||
else:
|
||||
result['temp_dir'] = None
|
||||
result['output_dir'] = None
|
||||
|
||||
if 'includes' in result:
|
||||
result['includes'] = [resolve(inc) for inc in result['includes']]
|
||||
|
||||
@@ -110,8 +110,9 @@ class DeclarationGenerator:
|
||||
if decl:
|
||||
lines.append(decl)
|
||||
elif isinstance(node, ast.ClassDef):
|
||||
if hasattr(node, 'type_params') and node.type_params:
|
||||
continue
|
||||
# PEP 695 泛型类不再完全跳过:子类(如 Value(GSListNode[Value]))的
|
||||
# 继承字段展平需要从泛型基类的 stub 中读取字段(如 GSListNode.Next)。
|
||||
# _generate_class_decl 内部会跳过泛型类的方法声明(T 参数 → opaque struct)。
|
||||
decls: list[str] = self._generate_class_decl(node)
|
||||
lines.extend(decls)
|
||||
|
||||
@@ -625,37 +626,42 @@ class DeclarationGenerator:
|
||||
else:
|
||||
new_func_decl = f'declare void @{new_func_name}({struct_type_name}*)'
|
||||
decls.append(new_func_decl)
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.FunctionDef):
|
||||
if hasattr(item, 'type_params') and item.type_params:
|
||||
continue
|
||||
method_name: str = f'{class_name}.{item.name}'
|
||||
if self.module_sha1:
|
||||
method_name = f"{self.module_sha1}.{method_name}"
|
||||
ret_type: str = self._get_type_str(item.returns) if item.returns else 'void'
|
||||
if not ret_type:
|
||||
ret_type = 'void'
|
||||
params: list[str] = []
|
||||
for arg_idx, arg in enumerate(item.args.args):
|
||||
arg_type: str
|
||||
if arg.annotation:
|
||||
arg_type = self._get_type_str(arg.annotation)
|
||||
elif arg_idx == 0 and arg.arg == 'self':
|
||||
arg_type = f'{struct_type_name}*'
|
||||
# PEP 695 泛型类跳过方法声明生成:方法参数类型 T 会被解析为 opaque struct,
|
||||
# LLVM 报 "invalid type for function argument"。字段(AnnAssign)仍正常生成,
|
||||
# 确保子类(如 Value(GSListNode[Value]))能从 stub 中读取继承字段(如 Next)。
|
||||
IsGenericClass: bool = hasattr(node, 'type_params') and bool(node.type_params)
|
||||
if not IsGenericClass:
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.FunctionDef):
|
||||
if hasattr(item, 'type_params') and item.type_params:
|
||||
continue
|
||||
method_name: str = f'{class_name}.{item.name}'
|
||||
if self.module_sha1:
|
||||
method_name = f"{self.module_sha1}.{method_name}"
|
||||
ret_type: str = self._get_type_str(item.returns) if item.returns else 'void'
|
||||
if not ret_type:
|
||||
ret_type = 'void'
|
||||
params: list[str] = []
|
||||
for arg_idx, arg in enumerate(item.args.args):
|
||||
arg_type: str
|
||||
if arg.annotation:
|
||||
arg_type = self._get_type_str(arg.annotation)
|
||||
elif arg_idx == 0 and arg.arg == 'self':
|
||||
arg_type = f'{struct_type_name}*'
|
||||
else:
|
||||
arg_type = 'i8*'
|
||||
# C 语言中数组参数退化为指针:[N x elem_type] → elem_type*
|
||||
arg_type = self._decay_array_to_ptr(arg_type)
|
||||
params.append(arg_type)
|
||||
param_str: str = ', '.join(params) if params else ''
|
||||
if method_name[0].isdigit():
|
||||
decls.append(f'declare {ret_type} @"{method_name}"({param_str})')
|
||||
else:
|
||||
arg_type = 'i8*'
|
||||
# C 语言中数组参数退化为指针:[N x elem_type] → elem_type*
|
||||
arg_type = self._decay_array_to_ptr(arg_type)
|
||||
params.append(arg_type)
|
||||
param_str: str = ', '.join(params) if params else ''
|
||||
if method_name[0].isdigit():
|
||||
decls.append(f'declare {ret_type} @"{method_name}"({param_str})')
|
||||
else:
|
||||
decls.append(f'declare {ret_type} @{method_name}({param_str})')
|
||||
# 为继承但未覆写的方法生成包装声明
|
||||
# 这些声明让跨模块调用能正确解析子类包装函数的签名,
|
||||
# 避免 stub 缺失导致默认 i32 返回类型 → 64 位指针截断
|
||||
decls.extend(self._generate_inherited_method_decls(node, class_name, struct_type_name))
|
||||
decls.append(f'declare {ret_type} @{method_name}({param_str})')
|
||||
# 为继承但未覆写的方法生成包装声明
|
||||
# 这些声明让跨模块调用能正确解析子类包装函数的签名,
|
||||
# 避免 stub 缺失导致默认 i32 返回类型 → 64 位指针截断
|
||||
decls.extend(self._generate_inherited_method_decls(node, class_name, struct_type_name))
|
||||
return decls
|
||||
|
||||
def _generate_inherited_method_decls(self, node: ast.ClassDef, child_class_name: str, child_struct_type: str) -> list[str]:
|
||||
|
||||
@@ -59,6 +59,10 @@ class Phase1Generator:
|
||||
self._manifest: dict[str, dict] = {}
|
||||
self._typedef_map_cache: dict[str, ast.AST] | None = None
|
||||
self._manifest_path: str = os.path.join(self.temp_dir, '_phase1_manifest.json')
|
||||
# includes 依赖图:{module_name: set[dep_module_name]},用于 .stub.ll 缓存依赖校验
|
||||
self._include_dep_graph: dict[str, set[str]] = {}
|
||||
# include 文件映射:{module_name: (src_path, rel_from_inc, includes_dir)}
|
||||
self._include_file_map: dict[str, tuple[str, str, str]] = {}
|
||||
self._load_manifest()
|
||||
|
||||
def _load_manifest(self) -> None:
|
||||
@@ -174,6 +178,7 @@ class Phase1Generator:
|
||||
pass
|
||||
|
||||
needed: set[str] = set()
|
||||
dep_graph: dict[str, set[str]] = {}
|
||||
queue: list[str] = list(imported_from_src)
|
||||
while queue:
|
||||
mod_name: str = queue.pop(0)
|
||||
@@ -184,6 +189,7 @@ class Phase1Generator:
|
||||
src_path: str = include_file_map[mod_name][0]
|
||||
includes_dir: str = include_file_map[mod_name][2]
|
||||
deps: set[str] = get_file_dependencies(src_path, includes_dir)
|
||||
dep_graph[mod_name] = deps
|
||||
for dep in deps:
|
||||
if dep in include_file_map and dep not in needed:
|
||||
queue.append(dep)
|
||||
@@ -195,6 +201,10 @@ class Phase1Generator:
|
||||
if info not in needed_infos:
|
||||
needed_infos.append(info)
|
||||
|
||||
# 存储依赖图和文件映射,供 .stub.ll 缓存依赖校验使用
|
||||
self._include_dep_graph = dep_graph
|
||||
self._include_file_map = include_file_map
|
||||
|
||||
return needed_infos
|
||||
|
||||
def run(self) -> None:
|
||||
@@ -356,6 +366,58 @@ class Phase1Generator:
|
||||
_vlog().warning(f"收集 typedef 映射失败: {_e}", "Exception")
|
||||
return typedef_map
|
||||
|
||||
def _ComputeDepSha1Signature(self, module_name: str) -> str:
|
||||
"""计算 module_name 的所有传递依赖的 SHA1 签名。
|
||||
|
||||
用于 .stub.ll 缓存依赖校验:当依赖的 include SHA1 变化时,
|
||||
当前 include 的 .stub.ll 缓存应失效(因为类型引用的 SHA1 前缀会变化)。
|
||||
"""
|
||||
if not self._include_dep_graph or not self._include_file_map:
|
||||
return ''
|
||||
Result: set[str] = set()
|
||||
Visited: set[str] = set()
|
||||
Queue: list[str] = list(self._include_dep_graph.get(module_name, set()))
|
||||
while Queue:
|
||||
DepMod: str = Queue.pop(0)
|
||||
if DepMod in Visited:
|
||||
continue
|
||||
Visited.add(DepMod)
|
||||
if DepMod in self._include_file_map:
|
||||
DepSrc: str = self._include_file_map[DepMod][0]
|
||||
DepSha1: str = self._get_sha1(DepSrc)
|
||||
if DepSha1:
|
||||
Result.add(DepSha1)
|
||||
Queue.extend(self._include_dep_graph.get(DepMod, set()))
|
||||
return '|'.join(sorted(Result))
|
||||
|
||||
def _ReadStubDep(self, stub_path: str) -> str:
|
||||
"""读取 .stub.ll 的依赖签名 sidecar,不存在返回空字符串。"""
|
||||
DepPath: str = stub_path + '.dep'
|
||||
try:
|
||||
with open(DepPath, 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
def _WriteStubDep(self, stub_path: str, dep_sig: str) -> None:
|
||||
"""写入 .stub.ll 的依赖签名 sidecar 到 temp_dir 和全局缓存。"""
|
||||
# temp_dir
|
||||
DepPath: str = stub_path + '.dep'
|
||||
try:
|
||||
with open(DepPath, 'w', encoding='utf-8') as f:
|
||||
f.write(dep_sig)
|
||||
except Exception:
|
||||
pass
|
||||
# 全局缓存
|
||||
Sha1: str = os.path.basename(stub_path).replace('.stub.ll', '')
|
||||
GlobalDepPath: str = os.path.join(_GLOBAL_CACHE_DIR, f"{Sha1}.stub.ll.dep")
|
||||
try:
|
||||
os.makedirs(_GLOBAL_CACHE_DIR, exist_ok=True)
|
||||
with open(GlobalDepPath, 'w', encoding='utf-8') as f:
|
||||
f.write(dep_sig)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _process_include_py_files_stub(self, struct_names: set[str], needed_includes: list[tuple[str, str, str]] | None = None, enum_names: set[str] | None = None, struct_sha1_map: dict[str, str] | None = None, exception_names: set[str] | None = None, class_def_map: dict[str, ast.ClassDef] | None = None) -> None:
|
||||
include_py_files: list[tuple[str, str, str]]
|
||||
if needed_includes is not None:
|
||||
@@ -374,15 +436,43 @@ class Phase1Generator:
|
||||
if not sha1:
|
||||
continue
|
||||
|
||||
# 计算依赖签名(用于 .stub.ll 缓存依赖校验)
|
||||
# 当依赖的 include SHA1 变化时,.stub.ll 中类型引用的 SHA1 前缀会变化,缓存应失效
|
||||
DepSig: str = self._ComputeDepSha1Signature(module_name)
|
||||
|
||||
stub_path: str = os.path.join(self.temp_dir, f"{sha1}.stub.ll")
|
||||
if os.path.isfile(stub_path):
|
||||
_vlog().info(f" 缓存命中: {rel_from_inc} -> {sha1}.stub.ll")
|
||||
continue
|
||||
# 依赖校验:temp_dir 中的 .stub.ll 可能是上次编译残留,引用旧 SHA1
|
||||
if self._ReadStubDep(stub_path) == DepSig:
|
||||
_vlog().info(f" 缓存命中: {rel_from_inc} -> {sha1}.stub.ll")
|
||||
continue
|
||||
else:
|
||||
_vlog().info(f" 缓存失效(依赖变更): {rel_from_inc} -> {sha1}.stub.ll")
|
||||
try:
|
||||
os.remove(stub_path)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 全局缓存检查(不被 --clean 清除)
|
||||
if _TryGlobalCache(sha1, 'stub.ll', stub_path):
|
||||
_vlog().info(f" 缓存命中(全局): {rel_from_inc} -> {sha1}.stub.ll")
|
||||
continue
|
||||
# 从全局缓存复制 sidecar .dep 文件
|
||||
GlobalDepPath: str = os.path.join(_GLOBAL_CACHE_DIR, f"{sha1}.stub.ll.dep")
|
||||
TempDepPath: str = stub_path + '.dep'
|
||||
if os.path.isfile(GlobalDepPath):
|
||||
try:
|
||||
shutil.copy2(GlobalDepPath, TempDepPath)
|
||||
except Exception:
|
||||
pass
|
||||
# 依赖校验:全局缓存中的 .stub.ll 可能引用旧 SHA1
|
||||
if self._ReadStubDep(stub_path) == DepSig:
|
||||
_vlog().info(f" 缓存命中(全局): {rel_from_inc} -> {sha1}.stub.ll")
|
||||
continue
|
||||
else:
|
||||
_vlog().info(f" 缓存失效(依赖变更): {rel_from_inc} -> {sha1}.stub.ll")
|
||||
try:
|
||||
os.remove(stub_path)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi")
|
||||
if not os.path.isfile(sig_path):
|
||||
@@ -392,6 +482,8 @@ class Phase1Generator:
|
||||
|
||||
self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map, class_def_map=class_def_map)
|
||||
_SaveToGlobalCache(sha1, 'stub.ll', stub_path)
|
||||
# 写入依赖签名 sidecar(temp_dir 和全局缓存)
|
||||
self._WriteStubDep(stub_path, DepSig)
|
||||
_vlog().info(f" 生成声明: {rel_from_inc} -> {sha1}.stub.ll")
|
||||
except Exception as e:
|
||||
_vlog().error(f"处理 include 文件失败 {rel_from_inc}: {e}")
|
||||
|
||||
@@ -458,7 +458,10 @@ class Phase2Translator:
|
||||
raise
|
||||
|
||||
if errors:
|
||||
_vlog().error(f"\n{len(errors)} 个文件翻译失败,继续编译 includes")
|
||||
_vlog().error(f"\n{len(errors)} 个文件翻译失败,立即终止编译")
|
||||
for rel, err in errors:
|
||||
_vlog().error(f" {rel}: {err}")
|
||||
raise RuntimeError(f"{len(errors)} 个文件翻译失败,已终止编译")
|
||||
else:
|
||||
for idx, (i, src_path, out_path, sha1, msm) in enumerate(need_translate):
|
||||
rel = os.path.relpath(src_path, self.src_root)
|
||||
@@ -470,6 +473,7 @@ class Phase2Translator:
|
||||
except Exception as e:
|
||||
_vlog().error(f" {rel}: {e}")
|
||||
traceback.print_exc()
|
||||
raise RuntimeError(f"翻译 {rel} 失败,已终止编译: {e}") from e
|
||||
t_end = time.time()
|
||||
_vlog().info(f" 翻译总耗时: {t_end-t_start:.1f}s")
|
||||
|
||||
|
||||
@@ -521,6 +521,11 @@ class AnnAssignHandle(BaseHandle):
|
||||
InitValue: ir.Value | None = None
|
||||
if Node.value:
|
||||
InitValue = self.HandleExprLlvm(Node.value, VarType=VarType)
|
||||
# 闭包变量追踪:当赋值右侧是返回闭包的函数调用时,记录变量为闭包类型
|
||||
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name):
|
||||
CalledName: str = Node.value.func.id
|
||||
if CalledName in Gen._closure_return_types:
|
||||
Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName]
|
||||
if VarName in Gen._reg_values:
|
||||
del Gen._reg_values[VarName]
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
|
||||
@@ -163,6 +163,11 @@ class AssignHandle(BaseHandle):
|
||||
if type_info.get('type') == 'CArray':
|
||||
var_type_for_list = type_info.get('full_type')
|
||||
Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=var_type_for_list)
|
||||
# 闭包变量追踪:当赋值右侧是返回闭包的函数调用时,记录变量为闭包类型
|
||||
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name):
|
||||
CalledName: str = Node.value.func.id
|
||||
if CalledName in Gen._closure_return_types:
|
||||
Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName]
|
||||
if not Value:
|
||||
return
|
||||
if isinstance(Value.type, ir.VoidType):
|
||||
|
||||
@@ -327,6 +327,52 @@ class ExprCallHandle(BaseHandle):
|
||||
if ArgVal:
|
||||
args.append(ArgVal)
|
||||
return Gen.builder.call(fn_ptr, args, name=f"call_{FuncName}")
|
||||
# 处理 t.CPtr (i8*) 函数指针调用
|
||||
# 当函数被赋值给 t.CPtr 变量时,原始函数类型退化为 i8*
|
||||
# 检查是否是闭包变量(通过 _closure_var_types 追踪)
|
||||
if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.IntType) and closure_ptr.type.pointee.width == 8:
|
||||
ClosureInfo: tuple[ir.Type, list[ir.Type]] | None = Gen._closure_var_types.get(FuncName)
|
||||
if ClosureInfo is not None:
|
||||
# 闭包结构体解包:{i8* env, i8* fn} -> 加载 env 和 fn,构造正确函数签名
|
||||
FnRetType: ir.Type = ClosureInfo[0]
|
||||
NonlocalArgTypes: list[ir.Type] = ClosureInfo[1]
|
||||
I8PtrType: ir.PointerType = ir.IntType(8).as_pointer()
|
||||
ClosureStructType: ir.LiteralStructType = ir.LiteralStructType([I8PtrType, I8PtrType])
|
||||
ClosureStructPtr: ir.Value = Gen.builder.bitcast(closure_ptr, ir.PointerType(ClosureStructType), name=f"cast_closure_{FuncName}")
|
||||
# 加载 env(field 0)和 fn(field 1)
|
||||
EnvGep: ir.Value = Gen.builder.gep(ClosureStructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"env_gep_{FuncName}")
|
||||
EnvVal: ir.Value = Gen._load(EnvGep, name=f"env_{FuncName}")
|
||||
FnGep: ir.Value = Gen.builder.gep(ClosureStructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name=f"fn_gep_{FuncName}")
|
||||
FnVal: ir.Value = Gen._load(FnGep, name=f"fn_{FuncName}")
|
||||
# 收集用户调用参数
|
||||
UserArgTypes: list[ir.Type] = []
|
||||
UserCallArgs: list[ir.Value] = []
|
||||
for arg in Node.args:
|
||||
ArgVal = self.HandleExprLlvm(arg)
|
||||
if ArgVal:
|
||||
UserCallArgs.append(ArgVal)
|
||||
UserArgTypes.append(ArgVal.type)
|
||||
# 构造完整函数类型:[nonlocal_types..., user_arg_types...]
|
||||
FullArgTypes: list[ir.Type] = list(NonlocalArgTypes) + UserArgTypes
|
||||
FullFnType: ir.FunctionType = ir.FunctionType(FnRetType, FullArgTypes)
|
||||
FullFnPtr: ir.Value = Gen.builder.bitcast(FnVal, ir.PointerType(FullFnType), name=f"cast_fn_{FuncName}")
|
||||
# 调用参数:env 对应 nonlocal 参数,bitcast 到正确类型
|
||||
CallArgs: list[ir.Value] = []
|
||||
if NonlocalArgTypes:
|
||||
CallArgs.append(Gen.builder.bitcast(EnvVal, NonlocalArgTypes[0], name=f"cast_env_{FuncName}"))
|
||||
CallArgs.extend(UserCallArgs)
|
||||
return Gen.builder.call(FullFnPtr, CallArgs, name=f"call_{FuncName}")
|
||||
# 普通函数指针调用(无闭包):从调用参数构造函数类型,默认返回 i32
|
||||
cptr_arg_types: list[ir.Type] = []
|
||||
cptr_call_args: list[ir.Value] = []
|
||||
for arg in Node.args:
|
||||
ArgVal = self.HandleExprLlvm(arg)
|
||||
if ArgVal:
|
||||
cptr_call_args.append(ArgVal)
|
||||
cptr_arg_types.append(ArgVal.type)
|
||||
cptr_fn_type = ir.FunctionType(ir.IntType(32), cptr_arg_types)
|
||||
cptr_fn_ptr = Gen.builder.bitcast(closure_ptr, ir.PointerType(cptr_fn_type), name=f"cast_fn_{FuncName}")
|
||||
return Gen.builder.call(cptr_fn_ptr, cptr_call_args, name=f"call_{FuncName}")
|
||||
if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.LiteralStructType):
|
||||
st = closure_ptr.type.pointee
|
||||
if len(st.elements) == 2 and isinstance(st.elements[1], ir.PointerType) and isinstance(st.elements[1].pointee, ir.FunctionType):
|
||||
@@ -352,11 +398,16 @@ class ExprCallHandle(BaseHandle):
|
||||
raise Exception(f"Undefined function: '{FuncName}'")
|
||||
if isinstance(Node.func, ast.Subscript):
|
||||
# Handle list[int](mb) syntax — generic class constructor with explicit type args
|
||||
# Handle xxx[T](x) syntax — generic function call with explicit type args
|
||||
sub: ast.Subscript = Node.func
|
||||
if isinstance(sub.value, ast.Name):
|
||||
ClassName: str = sub.value.id
|
||||
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates:
|
||||
return self._HandleGenericClassNewLlvm(Node, ClassName, explicit_slice=sub.slice)
|
||||
FuncName: str = sub.value.id
|
||||
# 优先检查泛型类模板
|
||||
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncName in self.Trans.ClassHandler._generic_class_templates:
|
||||
return self._HandleGenericClassNewLlvm(Node, FuncName, explicit_slice=sub.slice)
|
||||
# 检查泛型函数模板(如 xxx[T](x))
|
||||
if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates:
|
||||
return self._HandleGenericCallExplicitLlvm(Node, FuncName, explicit_slice=sub.slice)
|
||||
if isinstance(Node.func, ast.Attribute):
|
||||
if Node.func.attr in ('update', 'final', 'transform'):
|
||||
pass
|
||||
@@ -489,6 +540,42 @@ class ExprCallHandle(BaseHandle):
|
||||
if (is_instance_var or _is_chained_instance) and not is_class_name:
|
||||
return self._HandleMethodCallLlvm(Node)
|
||||
FuncAttr = Node.func.attr
|
||||
# c 模块的特殊语法设施(Addr/Deref/DerefAs/Set/Load/Asm 等)必须优先处理,
|
||||
# 即使它们在 Gen.structs 中(c.py 的类会被声明为结构体但不应被实例化)。
|
||||
# c.py 是语法部分,不应被编译,其中的类是编译器语法设施。
|
||||
# 必须在 Gen.structs 检查之前处理,否则 c.Deref/c.DerefAs 会被
|
||||
# _HandleClassNewLlvm 当成普通类实例化(根因:HandlesExprCall.py:497)。
|
||||
if ModulePath == 'c':
|
||||
if FuncAttr == 'Asm':
|
||||
return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
|
||||
elif FuncAttr == 'Addr':
|
||||
return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node)
|
||||
elif FuncAttr == 'Set':
|
||||
return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node)
|
||||
elif FuncAttr == 'Load':
|
||||
return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node)
|
||||
elif FuncAttr == 'Deref':
|
||||
return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
|
||||
elif FuncAttr == 'DerefAs':
|
||||
return self._HandleCDerefAsLlvm(Node)
|
||||
elif FuncAttr == 'PtrToInt':
|
||||
return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
|
||||
elif FuncAttr in ('CIf', 'CElif'):
|
||||
return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node)
|
||||
elif FuncAttr == 'CError':
|
||||
msg = "compile-time error"
|
||||
if Node.args:
|
||||
arg = Node.args[0]
|
||||
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
||||
msg = arg.value
|
||||
lineno = getattr(Node, 'lineno', 0)
|
||||
raise Exception(f"#error: {msg} (line {lineno})")
|
||||
elif FuncAttr in ('AsmInp', 'AsmOut'):
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncAttr == 'LLVMIR':
|
||||
return self._HandleLLVMIRLlvm(Node)
|
||||
elif FuncAttr in ('LInp', 'LOut'):
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
if FuncAttr in Gen.structs:
|
||||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||||
if result is not None:
|
||||
@@ -572,40 +659,6 @@ class ExprCallHandle(BaseHandle):
|
||||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||||
if result is not None:
|
||||
return result
|
||||
# c 模块的特殊语法设施(Addr/Deref/DerefAs/Set/Load/Asm 等)必须优先处理,
|
||||
# 即使它们在 Gen.structs 中(c.py 的类会被声明为结构体但不应被实例化)。
|
||||
# c.py 是语法部分,不应被编译,其中的类是编译器语法设施。
|
||||
if ModulePath == 'c':
|
||||
if FuncAttr == 'Asm':
|
||||
return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
|
||||
elif FuncAttr == 'Addr':
|
||||
return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node)
|
||||
elif FuncAttr == 'Set':
|
||||
return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node)
|
||||
elif FuncAttr == 'Load':
|
||||
return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node)
|
||||
elif FuncAttr == 'Deref':
|
||||
return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
|
||||
elif FuncAttr == 'DerefAs':
|
||||
return self._HandleCDerefAsLlvm(Node)
|
||||
elif FuncAttr == 'PtrToInt':
|
||||
return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
|
||||
elif FuncAttr in ('CIf', 'CElif'):
|
||||
return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node)
|
||||
elif FuncAttr == 'CError':
|
||||
msg = "compile-time error"
|
||||
if Node.args:
|
||||
arg = Node.args[0]
|
||||
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
||||
msg = arg.value
|
||||
lineno = getattr(Node, 'lineno', 0)
|
||||
raise Exception(f"#error: {msg} (line {lineno})")
|
||||
elif FuncAttr in ('AsmInp', 'AsmOut'):
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
elif FuncAttr == 'LLVMIR':
|
||||
return self._HandleLLVMIRLlvm(Node)
|
||||
elif FuncAttr in ('LInp', 'LOut'):
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
if FuncAttr in Gen.structs:
|
||||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||||
if result is not None:
|
||||
@@ -1037,21 +1090,55 @@ class ExprCallHandle(BaseHandle):
|
||||
|
||||
icmp_match = re.match(r'icmp\s+(\w+)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template)
|
||||
if icmp_match:
|
||||
pred = icmp_match.group(1)
|
||||
pred: str = icmp_match.group(1)
|
||||
op1 = resolve_op(int(icmp_match.group(3)))
|
||||
op2 = resolve_op(int(icmp_match.group(4)))
|
||||
if op1 and op2:
|
||||
result = Gen.builder.icmp_signed(pred, op1, op2, name="llvmir_result")
|
||||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||||
# LLVM IR 谓词(eq/ne/sgt/sge/slt/sle/ugt/uge/ult/ule)映射到 llvmlite
|
||||
# llvmlite 的 icmp_signed/icmp_unsigned 只接受 '=='/'!='/'<'/'<='/'>'/>='
|
||||
_ICMP_PRED_MAP: dict[str, tuple[str, str]] = {
|
||||
'eq': ('==', 'signed'), 'ne': ('!=', 'signed'),
|
||||
'sgt': ('>', 'signed'), 'sge': ('>=', 'signed'),
|
||||
'slt': ('<', 'signed'), 'sle': ('<=', 'signed'),
|
||||
'ugt': ('>', 'unsigned'), 'uge': ('>=', 'unsigned'),
|
||||
'ult': ('<', 'unsigned'), 'ule': ('<=', 'unsigned'),
|
||||
}
|
||||
pred_info: tuple[str, str] | None = _ICMP_PRED_MAP.get(pred)
|
||||
if pred_info:
|
||||
llvmlite_pred: str
|
||||
cmp_kind: str
|
||||
llvmlite_pred, cmp_kind = pred_info
|
||||
icmp_method: Any = Gen.builder.icmp_signed if cmp_kind == 'signed' else Gen.builder.icmp_unsigned
|
||||
result = icmp_method(llvmlite_pred, op1, op2, name="llvmir_result")
|
||||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||||
|
||||
fcmp_match = re.match(r'fcmp\s+(\w+(?:\s+fast)?)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template)
|
||||
fcmp_match = re.match(r'fcmp\s+([\w\s]+?)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template)
|
||||
if fcmp_match:
|
||||
pred = fcmp_match.group(1)
|
||||
pred_raw: str = fcmp_match.group(1).strip()
|
||||
# 分离 fast 修饰符(可能是 "oeq fast" 或 "fast oeq")
|
||||
is_fast: bool = 'fast' in pred_raw
|
||||
pred: str = pred_raw.replace('fast', '').strip()
|
||||
op1 = resolve_op(int(fcmp_match.group(3)))
|
||||
op2 = resolve_op(int(fcmp_match.group(4)))
|
||||
if op1 and op2:
|
||||
result = Gen.builder.fcmp_ordered(pred, op1, op2, name="llvmir_result")
|
||||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||||
# LLVM IR fcmp 谓词(oeq/ogt/olt/ord/uno/ueq 等)映射到 llvmlite
|
||||
_FCMP_PRED_MAP: dict[str, tuple[str, str]] = {
|
||||
'oeq': ('==', 'ordered'), 'ogt': ('>', 'ordered'),
|
||||
'oge': ('>=', 'ordered'), 'olt': ('<', 'ordered'),
|
||||
'ole': ('<=', 'ordered'), 'one': ('!=', 'ordered'),
|
||||
'ord': ('ord', 'ordered'), 'uno': ('uno', 'unordered'),
|
||||
'ueq': ('==', 'unordered'), 'ugt': ('>', 'unordered'),
|
||||
'uge': ('>=', 'unordered'), 'ult': ('<', 'unordered'),
|
||||
'ule': ('<=', 'unordered'), 'une': ('!=', 'unordered'),
|
||||
}
|
||||
fcmp_info: tuple[str, str] | None = _FCMP_PRED_MAP.get(pred)
|
||||
if fcmp_info:
|
||||
llvmlite_pred: str
|
||||
cmp_kind: str
|
||||
llvmlite_pred, cmp_kind = fcmp_info
|
||||
fcmp_method: Any = Gen.builder.fcmp_ordered if cmp_kind == 'ordered' else Gen.builder.fcmp_unordered
|
||||
result = fcmp_method(llvmlite_pred, op1, op2, name="llvmir_result")
|
||||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||||
|
||||
for op_name, method_name in binop_map.items():
|
||||
pattern = re.compile(
|
||||
@@ -3547,6 +3634,10 @@ class ExprCallHandle(BaseHandle):
|
||||
|
||||
def _HandleClassNewLlvm(self, Node: ast.Call, ClassName: str, module_sha1: str | None = None) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
# DEBUG: 追踪 Asm 类的构造
|
||||
if ClassName == 'Asm':
|
||||
import sys as _dbg_sys
|
||||
print(f"[DEBUG_CLASSNEW] _HandleClassNewLlvm called for Asm, module_sha1={module_sha1}", file=_dbg_sys.stderr)
|
||||
# 跨模块类型引用:优先用 {module_sha1}.{ClassName} 查找 struct
|
||||
_struct_full_key: str | None = f"{module_sha1}.{ClassName}" if module_sha1 else None
|
||||
|
||||
@@ -3562,6 +3653,9 @@ class ExprCallHandle(BaseHandle):
|
||||
InitFuncName = f'{ClassName}.__init__'
|
||||
NewMethodFuncName = f'{ClassName}.__new__'
|
||||
has_new_method = Gen._find_function(NewMethodFuncName) is not None
|
||||
if ClassName == 'Asm':
|
||||
import sys as _dbg_sys
|
||||
print(f"[DEBUG_CLASSNEW] Asm: has_before_init={Gen._has_function(NewFuncName)}, has_new={has_new_method}, struct_in_gen={ClassName in Gen.structs}", file=_dbg_sys.stderr)
|
||||
if Gen._has_function(NewFuncName):
|
||||
NewFunc = Gen._get_function(NewFuncName)
|
||||
StructType = _get_struct_type(ClassName)
|
||||
@@ -3873,6 +3967,59 @@ class ExprCallHandle(BaseHandle):
|
||||
return ElemPtr
|
||||
return None
|
||||
|
||||
def _HandleGenericCallExplicitLlvm(self, Node: ast.Call, FuncName: str, explicit_slice: ast.AST) -> ir.Value | None:
|
||||
"""处理泛型函数手动传类型参数的调用 xxx[T](x)。
|
||||
|
||||
与自动推导的 _HandleGenericCallLlvm 不同,这里从 explicit_slice
|
||||
提取类型参数,而不是从参数值推导。
|
||||
"""
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
template: dict = self.Trans.FunctionHandler._generic_templates[FuncName]
|
||||
type_param_names: list[str] = template['type_params']
|
||||
# 从 slice 提取类型参数
|
||||
type_args: list[str] = []
|
||||
slice_nodes: list[ast.AST] = []
|
||||
if isinstance(explicit_slice, ast.Tuple):
|
||||
slice_nodes = list(explicit_slice.elts)
|
||||
else:
|
||||
slice_nodes = [explicit_slice]
|
||||
for sn in slice_nodes:
|
||||
result = self._resolve_generic_slice_type(sn)
|
||||
if result is not None:
|
||||
type_args.append(result[0])
|
||||
# 补齐缺少的类型参数
|
||||
while len(type_args) < len(type_param_names):
|
||||
type_args.append('int')
|
||||
type_args = type_args[:len(type_param_names)]
|
||||
# 特化
|
||||
spec_name = self.Trans.FunctionHandler._specialize_generic_function(FuncName, type_args, Gen)
|
||||
if spec_name is None:
|
||||
return None
|
||||
mangled_spec = Gen._mangle_func_name(spec_name)
|
||||
func = None
|
||||
if mangled_spec in Gen.functions:
|
||||
func = Gen.functions[mangled_spec]
|
||||
elif spec_name in Gen.functions:
|
||||
func = Gen.functions[spec_name]
|
||||
else:
|
||||
for fname, fobj in Gen.functions.items():
|
||||
if spec_name in fname or fname.endswith(spec_name):
|
||||
func = fobj
|
||||
break
|
||||
if func is None:
|
||||
return None
|
||||
# 处理调用参数
|
||||
CallArgs: list[ir.Value] = []
|
||||
for arg_node in Node.args:
|
||||
arg_val = self.HandleExprLlvm(arg_node)
|
||||
if arg_val:
|
||||
CallArgs.append(arg_val)
|
||||
if not CallArgs:
|
||||
CallArgs = [ir.Constant(ir.IntType(32), 0) for _ in func.args]
|
||||
CallArgs = Gen._apply_auto_addr(spec_name, CallArgs)
|
||||
adjusted = Gen._adjust_args(CallArgs, func)
|
||||
return Gen.builder.call(func, adjusted, name=f"call_{spec_name}")
|
||||
|
||||
def _HandleGenericCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
template: dict = self.Trans.FunctionHandler._generic_templates[FuncName]
|
||||
|
||||
@@ -21,10 +21,12 @@ class ExprOpsHandle(BaseHandle):
|
||||
Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
|
||||
if not Op:
|
||||
return None
|
||||
OP_OVERLOAD_MAP: dict[str, str] = {
|
||||
'+': '__add__', '-': '__sub__', '*': '__mul__',
|
||||
'/': '__truediv__', '//': '__floordiv__', '%': '__mod__',
|
||||
'**': '__pow__',
|
||||
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
|
||||
@@ -47,10 +49,11 @@ class ExprOpsHandle(BaseHandle):
|
||||
TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
|
||||
LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
|
||||
if LeftClassName:
|
||||
op_name: str = OP_OVERLOAD_MAP[Op]
|
||||
result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
|
||||
if result is not None:
|
||||
return result
|
||||
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:
|
||||
@@ -282,6 +285,36 @@ class ExprOpsHandle(BaseHandle):
|
||||
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
|
||||
|
||||
@@ -330,6 +330,33 @@ class ForHandle(BaseHandle):
|
||||
for name in implicit_names:
|
||||
if name not in nonlocal_var_names:
|
||||
nonlocal_var_names.append(name)
|
||||
# 堆分配 nonlocal 变量:避免外层函数返回后栈帧释放导致悬垂指针
|
||||
# 闭包返回模式(return nested_fn)要求捕获变量在堆上存活
|
||||
malloc_fn_type: ir.FunctionType = ir.FunctionType(ir.IntType(8).as_pointer(), [ir.IntType(64)])
|
||||
malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_fn_type)
|
||||
for var_name in nonlocal_var_names:
|
||||
if var_name in Gen.variables and Gen.variables[var_name] is not None:
|
||||
old_var: ir.Value = Gen.variables[var_name]
|
||||
if isinstance(old_var.type, ir.PointerType):
|
||||
elem_type: ir.Type = old_var.type.pointee
|
||||
# 计算元素大小(字节)
|
||||
elem_size: int = 8 # 默认指针大小
|
||||
if isinstance(elem_type, ir.IntType):
|
||||
elem_size = max(1, elem_type.width // 8)
|
||||
elif isinstance(elem_type, ir.FloatType):
|
||||
elem_size = 4
|
||||
elif isinstance(elem_type, ir.DoubleType):
|
||||
elem_size = 8
|
||||
elif isinstance(elem_type, ir.PointerType):
|
||||
elem_size = 8
|
||||
# malloc 堆存储
|
||||
heap_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), elem_size)], name=f"heap_{var_name}")
|
||||
heap_ptr: ir.Value = Gen.builder.bitcast(heap_raw, ir.PointerType(elem_type), name=f"heap_{var_name}_ptr")
|
||||
# 复制栈值到堆
|
||||
old_val: ir.Value = Gen._load(old_var, name=f"load_old_{var_name}")
|
||||
Gen._store(old_val, heap_ptr)
|
||||
# 更新 Gen.variables 使外层和嵌套函数都使用堆指针
|
||||
Gen.variables[var_name] = heap_ptr
|
||||
extra_params: list[tuple[str, ir.Type]] = []
|
||||
for var_name in nonlocal_var_names:
|
||||
if var_name in Gen.variables and Gen.variables[var_name] is not None:
|
||||
|
||||
@@ -652,7 +652,17 @@ class FunctionHandle(BaseHandle):
|
||||
ParamTypeInfo.ArrayDims = []
|
||||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||||
ParamType: ir.Type = Gen._ctype_to_llvm(ParamTypeInfo)
|
||||
# 参数类型不能是 VoidType:C 语言不允许 void 参数,
|
||||
# VoidType 说明类型注解无法识别(如跨模块 ast.expr),直接报错终止
|
||||
if isinstance(ParamType, ir.VoidType):
|
||||
AnnStr: str = ast.unparse(Arg.annotation) if hasattr(ast, 'unparse') else str(Arg.annotation)
|
||||
raise SyntaxError(
|
||||
f"无法识别的参数类型注解: '{AnnStr}'(在函数 '{Node.name}' 的参数 '{Arg.arg}' 上)。"
|
||||
f"请使用有效的 TPV 类型(如 t.CPtr、ast.AST 或已注册的结构体)。"
|
||||
)
|
||||
ParamTypeStr: Any = ParamTypeInfo
|
||||
except SyntaxError:
|
||||
raise
|
||||
except Exception as e:
|
||||
ParamType = ir.IntType(32)
|
||||
ParamTypeStr = CTypeInfo()
|
||||
@@ -1402,9 +1412,19 @@ class FunctionHandle(BaseHandle):
|
||||
ParamTypeInfo.ArrayDims = []
|
||||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||||
ParamType = Gen._ctype_to_llvm(ParamTypeInfo)
|
||||
# 参数类型不能是 VoidType:C 语言不允许 void 参数,
|
||||
# VoidType 说明类型注解无法识别(如跨模块 ast.expr),直接报错终止
|
||||
if isinstance(ParamType, ir.VoidType):
|
||||
AnnStr: str = ast.unparse(Arg.annotation) if hasattr(ast, 'unparse') else str(Arg.annotation)
|
||||
raise SyntaxError(
|
||||
f"无法识别的参数类型注解: '{AnnStr}'(在函数 '{Node.name}' 的参数 '{Arg.arg}' 上)。"
|
||||
f"请使用有效的 TPV 类型(如 t.CPtr、ast.AST 或已注册的结构体)。"
|
||||
)
|
||||
if ParamTypeInfo and ParamTypeInfo.IsFuncPtr:
|
||||
ParamType = ir.IntType(8).as_pointer()
|
||||
ParamIsUnsigned = ParamTypeInfo.IsUInt
|
||||
except SyntaxError:
|
||||
raise
|
||||
except Exception: # 回退:参数类型解析失败时使用默认 i32
|
||||
ParamType = ir.IntType(32)
|
||||
ParamTypeInfo = CTypeInfo()
|
||||
|
||||
@@ -1323,8 +1323,12 @@ class ImportHandle(BaseHandle):
|
||||
|
||||
def _EmitExternalClassDeclLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin, module_name: str | None = None, actual_module_name: str | None = None, source_sha1: str | None = None) -> None:
|
||||
ClassName = Node.name
|
||||
if hasattr(Node, 'type_params') and Node.type_params:
|
||||
return
|
||||
# PEP 695 泛型类(如 GSListNode[T])不再完全跳过:跨模块继承展平需要从泛型基类
|
||||
# 获取字段(如 Next),否则子类(如 Value(GSListNode[Value]))的 class_members
|
||||
# 会缺少继承字段,导致 struct body 字段数不正确 → GEP 索引错位 → 崩溃。
|
||||
# 但泛型类的方法声明必须跳过:方法参数类型 T 会被解析为 opaque struct,
|
||||
# LLVM 不允许 opaque struct 作为值参数(invalid type for function argument)。
|
||||
IsGenericClass: bool = hasattr(Node, 'type_params') and bool(Node.type_params)
|
||||
IsCenum = False
|
||||
IsRenum = False
|
||||
IsCpythonObject = False
|
||||
@@ -1579,19 +1583,23 @@ class ImportHandle(BaseHandle):
|
||||
# 此时 MemManager 尚未注册到虚表,导致直接调用返回 NULL → 段错误。
|
||||
# 修复:在 _TryLoadStructFromStub 之前预扫描方法列表并提前注册虚表。
|
||||
_has_methods_prescan = False
|
||||
for _item in Node.body:
|
||||
if isinstance(_item, ast.FunctionDef):
|
||||
_has_methods_prescan = True
|
||||
_MethodName = _item.name
|
||||
# 构造函数(__new__/__init__/__before_init__)不放入 vtable,
|
||||
# 避免子类与基类 vtable 大小不一致导致虚分派索引偏移
|
||||
# (如 Module 有 __new__/__init__ 使 vtable=7,AST 无它们 vtable=5,
|
||||
# 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。
|
||||
if _MethodName in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
_FuncFullName = f"{ClassName}.__init__" if _MethodName == "__init__" else f"{ClassName}.__call__" if _MethodName == "__call__" else f"{ClassName}.{_MethodName}"
|
||||
if _FuncFullName not in Gen.class_methods[ClassName]:
|
||||
Gen.class_methods[ClassName].append(_FuncFullName)
|
||||
# PEP 695 泛型类的方法声明必须跳过:方法参数类型 T(如 list[T].append(item: T))
|
||||
# 会被解析为 opaque struct,LLVM 报 "invalid type for function argument"。
|
||||
# 字段(AnnAssign)仍正常加载,确保继承字段(如 GSListNode.Next)可被展平。
|
||||
if not IsGenericClass:
|
||||
for _item in Node.body:
|
||||
if isinstance(_item, ast.FunctionDef):
|
||||
_has_methods_prescan = True
|
||||
_MethodName = _item.name
|
||||
# 构造函数(__new__/__init__/__before_init__)不放入 vtable,
|
||||
# 避免子类与基类 vtable 大小不一致导致虚分派索引偏移
|
||||
# (如 Module 有 __new__/__init__ 使 vtable=7,AST 无它们 vtable=5,
|
||||
# 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。
|
||||
if _MethodName in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
_FuncFullName = f"{ClassName}.__init__" if _MethodName == "__init__" else f"{ClassName}.__call__" if _MethodName == "__call__" else f"{ClassName}.{_MethodName}"
|
||||
if _FuncFullName not in Gen.class_methods[ClassName]:
|
||||
Gen.class_methods[ClassName].append(_FuncFullName)
|
||||
if _has_methods_prescan and IsCVTable:
|
||||
Gen._cross_module_vtable_classes.add(ClassName)
|
||||
Gen.class_vtable.add(ClassName)
|
||||
@@ -1651,7 +1659,10 @@ class ImportHandle(BaseHandle):
|
||||
const = self._BuildScalarConstant(item.value, MemberType, Gen)
|
||||
if const:
|
||||
Gen.class_member_defaults[ClassName][VarName] = const
|
||||
elif isinstance(item, ast.FunctionDef):
|
||||
elif isinstance(item, ast.FunctionDef) and not IsGenericClass:
|
||||
# PEP 695 泛型类跳过方法声明:T 参数会变成 opaque struct 触发
|
||||
# "invalid type for function argument"。字段已由上面的 AnnAssign
|
||||
# 分支加载,继承字段(如 GSListNode.Next)由后面的展平逻辑补充。
|
||||
has_methods = True
|
||||
MethodName = item.name
|
||||
FuncFullName = f"{ClassName}.__init__" if MethodName == "__init__" else f"{ClassName}.__call__" if MethodName == "__call__" else f"{ClassName}.{MethodName}"
|
||||
|
||||
@@ -16,6 +16,58 @@ class ReturnHandle(BaseHandle):
|
||||
|
||||
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] = [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] = []
|
||||
|
||||
@@ -166,6 +166,11 @@ class BaseGenMixin:
|
||||
self._current_tree: Any = None
|
||||
self._DefineConstants: dict = {}
|
||||
self._all_define_constants: dict = {}
|
||||
# 闭包追踪:记录返回闭包的函数和变量
|
||||
# _closure_return_types: func_name -> (fn_return_type, nonlocal_arg_types)
|
||||
self._closure_return_types: dict[str, tuple[Any, list[Any]]] = {}
|
||||
# _closure_var_types: var_name -> (fn_return_type, nonlocal_arg_types)
|
||||
self._closure_var_types: dict[str, tuple[Any, list[Any]]] = {}
|
||||
pi: dict[str, bool | int] = self._platform_info
|
||||
# 根据目标平台设置宏(声明式,从三元组推导)
|
||||
if pi['is_windows']:
|
||||
@@ -328,11 +333,17 @@ class BaseGenMixin:
|
||||
# _parse_llvm_type 先通过此路径创建 opaque 结构体,_TryLoadStructFromStub 再 set_body。
|
||||
elif Entry and Entry.IsEnum and clean_name not in self.class_methods:
|
||||
return ir.IntType(32)
|
||||
if Entry and Entry.IsExceptionClass:
|
||||
# 治本修复:当 clean_name 是已注册的类(在 class_methods 或 class_members 中)时,
|
||||
# 不应走 IsExceptionClass/IsFunction/IsVariable 分支返回非结构体类型。
|
||||
# 否则 _get_or_create_struct 返回指针类型(如 _TypedPointerType)而非 IdentifiedStructType,
|
||||
# 导致 _TryLoadStructFromStub 的 set_body 被跳过(isinstance 检查失败),
|
||||
# struct 保持不完整字段数,引发跨模块 GEP 越界崩溃。
|
||||
_is_class_name: bool = clean_name in self.class_methods or clean_name in self.class_members
|
||||
if Entry and Entry.IsExceptionClass and not _is_class_name:
|
||||
return ir.IntType(32)
|
||||
if Entry and Entry.IsFunction:
|
||||
if Entry and Entry.IsFunction and not _is_class_name:
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
if Entry and Entry.IsVariable:
|
||||
if Entry and Entry.IsVariable and not _is_class_name:
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
if Entry and Entry.BaseType:
|
||||
if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum):
|
||||
|
||||
@@ -386,11 +386,27 @@ class StructGenMixin:
|
||||
continue
|
||||
# struct body 不完整,清除 _elements 和 stub 缓存以便重新加载
|
||||
existing_st._elements = None
|
||||
# 同时清除 sha1 全名 key 的 _elements:
|
||||
# self.structs 中可能同时存在 'Value'(短名) 和 'f9e36e2cd6fa659f.Value'(sha1全名) 两个 key,
|
||||
# _TryLoadStructFromStub 调用 _get_or_create_struct 时会返回 sha1全名 key 的 struct。
|
||||
# 若只清除短名 key 的 _elements,sha1全名 key 的 struct 仍保持错误 body(is_opaque=False),
|
||||
# 导致 _TryLoadStructFromStub 跳过 set_body,struct 保持不完整字段数。
|
||||
_imported_sha1_pre: str = self.class_sha1_map.get(ClassName, '')
|
||||
if _imported_sha1_pre:
|
||||
_full_key_pre: str = f"{_imported_sha1_pre}.{ClassName}"
|
||||
_full_st_pre: ir.IdentifiedStructType | None = self.structs.get(_full_key_pre)
|
||||
if _full_st_pre is not None and isinstance(_full_st_pre, ir.IdentifiedStructType):
|
||||
_full_st_pre._elements = None
|
||||
_import_handler_pre: Any = self._import_handler_ref
|
||||
if _import_handler_pre is not None:
|
||||
_cache_key_pre: tuple = (id(self), ClassName)
|
||||
if _cache_key_pre in _import_handler_pre._struct_Load_cache:
|
||||
del _import_handler_pre._struct_Load_cache[_cache_key_pre]
|
||||
# 同时清除 sha1全名 key 的 stub 缓存
|
||||
if _imported_sha1_pre:
|
||||
_cache_key_full_pre: tuple = (id(self), f"{_imported_sha1_pre}.{ClassName}")
|
||||
if _cache_key_full_pre in _import_handler_pre._struct_Load_cache:
|
||||
del _import_handler_pre._struct_Load_cache[_cache_key_full_pre]
|
||||
has_vtable: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
|
||||
if not has_vtable:
|
||||
p: str | None = self.class_parent.get(ClassName)
|
||||
|
||||
@@ -191,9 +191,18 @@ class Logger:
|
||||
prefix: str = self._colorize("SUCCESS", Colors.BRIGHT_GREEN)
|
||||
if category:
|
||||
prefix += f"[{self._colorize(category, Colors.CYAN)}]"
|
||||
|
||||
|
||||
msg: str = f"{self._colorize('├', Colors.GREEN)} {prefix}: {message}"
|
||||
self._write(msg, "SUCCESS")
|
||||
|
||||
def banner(self, message: str, category: str = "") -> None:
|
||||
"""输出醒目的横幅标题"""
|
||||
header: str = self._colorize(message, Colors.BRIGHT_BLUE + Colors.BOLD)
|
||||
line: str = self._colorize('═' * 60, Colors.BLUE)
|
||||
msg: str = f"\n{self._colorize('╔', Colors.BLUE)}{line}{self._colorize('╗', Colors.BLUE)}\n"
|
||||
msg += f"{self._colorize('║', Colors.BLUE)} {header}\n"
|
||||
msg += f"{self._colorize('╚', Colors.BLUE)}{line}{self._colorize('╝', Colors.BLUE)}"
|
||||
self._write(msg, "BANNER")
|
||||
|
||||
def compile_error(self, message: str, file: str = "", line: int = 0, code: str = "") -> None:
|
||||
"""编译错误格式化输出"""
|
||||
|
||||
Reference in New Issue
Block a user