import t, c from stdint import * import ast import llvmlite import memhub import string import viperlib import stdio import stdlib import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.Handles.HandlesType as HandlesType import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesBody as HandlesBody import lib.core.Handles.HandlesNonlocal as HandlesNonlocal import lib.core.Handles.HandlesImports as HandlesImports # ============================================================ # extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性 # # 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式 # 也支持 @c.Attribute(t.attr.llvm.xxx) 形式 # # 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None # ============================================================ def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr, decorator_list: list[ast.AST | t.CPtr] | t.CPtr, imported_modules: str) -> t.CChar | t.CPtr: """从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串""" if decorator_list is None: return None dn: t.CSizeT = decorator_list.__len__() if dn == 0: return None attrs_buf: t.CChar | t.CPtr = pool.alloc(256) if attrs_buf is None: return None attrs_buf[0] = '\0' found_any: int = 0 for di in range(dn): deco: ast.AST | t.CPtr = decorator_list.get(di) if deco is None or deco.kind() != ast.ASTKind.Call: continue call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco) if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute: continue # 检测 c.Attribute func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func) if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0: continue if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name: continue c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value) if c_name.id is None or string.strcmp(c_name.id, "c") != 0: continue if HandlesImports.is_module_imported(imported_modules, "c") == 0: continue # 遍历参数提取属性 if call_node.args is None: continue args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args an: t.CSizeT = args_list.__len__() for ai in range(an): arg_node: ast.AST | t.CPtr = args_list.get(ai) if arg_node is None: continue # 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx) attr_name: str = _get_attr_name_from_node(arg_node) if attr_name is None: continue # 映射到 LLVM 属性名并追加 if _append_llvm_attr(attrs_buf, attr_name) != 0: found_any = 1 # 追加成功后,如果不是最后一个属性,添加空格分隔 # 在下一次追加前由 _append_str 处理 if found_any == 0: return None return attrs_buf def _get_attr_name_from_node(node: ast.AST | t.CPtr) -> str: """从 AST 节点提取属性名 支持: - Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline" - Attribute: t.attr.packed -> "packed" - Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind" """ if node is None: return None k: int = node.kind() # Call 节点: t.attr.always_inline() if k == ast.ASTKind.Call: call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) if call.func is None or call.func.kind() != ast.ASTKind.Attribute: return None at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func) return at.attr # Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind if k == ast.ASTKind.Attribute: at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) return at2.attr return None def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int: """将属性名映射到 LLVM 属性名并追加到缓冲区 返回 1 表示已追加,0 表示不支持该属性 """ if attrs_buf is None or attr_name is None: return 0 # 先确定映射的 LLVM 属性名 llvm_name: str = None if string.strcmp(attr_name, "always_inline") == 0: llvm_name = "alwaysinline" elif string.strcmp(attr_name, "noinline") == 0: llvm_name = "noinline" elif string.strcmp(attr_name, "noreturn") == 0: llvm_name = "noreturn" elif string.strcmp(attr_name, "pure") == 0: llvm_name = "readonly" elif string.strcmp(attr_name, "const") == 0: llvm_name = "readnone" elif string.strcmp(attr_name, "nounwind") == 0: llvm_name = "nounwind" elif string.strcmp(attr_name, "noredzone") == 0: llvm_name = "noredzone" elif string.strcmp(attr_name, "willreturn") == 0: llvm_name = "willreturn" elif string.strcmp(attr_name, "mustprogress") == 0: llvm_name = "mustprogress" else: # packed/aligned/section/visibility/weak 等不支持作为函数内联属性 return 0 # 支持的属性:如果缓冲区非空,先追加空格分隔 if attrs_buf[0] != '\0': _append_str(attrs_buf, " ") _append_str(attrs_buf, llvm_name) return 1 def _append_str(buf: t.CChar | t.CPtr, s: str) -> None: """将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)""" if buf is None or s is None: return cur_len: t.CSizeT = string.strlen(buf) string.strcpy(buf + cur_len, s) # ============================================================ # HandlesFunctions - 函数定义处理(trans 单参模式) # # 参考 Python 版 TransPyC FunctionHandle # # 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope # 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。 # ============================================================ # ============================================================ # _mangle_name - 为名称添加 SHA1 前缀 # # 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带 # SHA1 前缀(16 hex + '.'),则原样返回。 # ============================================================ def _mangle_name(trans: HT.Translator | t.CPtr, name: str) -> str: """为任意名称添加 SHA1 前缀(不做 main/export 检查)""" if trans is None or name is None: return name if trans.ModuleSha1 is None: return name name_len: t.CSizeT = string.strlen(name) # 已带 SHA1 前缀(16 hex + '.')则跳过 if name_len > 17: is_sha1: int = 1 for i in range(16): c: t.CChar = name[i] if not (('0' <= c <= '9') or ('a' <= c <= 'f')): is_sha1 = 0 break if is_sha1 != 0 and name[16] == '.': return name sha1: str = trans.ModuleSha1 sha1_len: t.CSizeT = string.strlen(sha1) mangled: str = stdlib.malloc(sha1_len + name_len + 2) if mangled is None: return name string.strcpy(mangled, sha1) mangled[sha1_len] = '.' string.strcpy(mangled + sha1_len + 1, name) return mangled # ============================================================ # _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀 # # 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling, # 而非当前模块的 SHA1。 # ============================================================ def _mangle_name_with_sha1(sha1: str, name: str) -> str: """用指定 SHA1 为名称添加前缀(不做 main/export 检查)""" if sha1 is None or name is None: return name name_len: t.CSizeT = string.strlen(name) # 已带 SHA1 前缀(16 hex + '.')则跳过 if name_len > 17: is_sha1: int = 1 for i in range(16): c2: t.CChar = name[i] if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')): is_sha1 = 0 break if is_sha1 != 0 and name[16] == '.': return name sha1_len: t.CSizeT = string.strlen(sha1) mangled: str = stdlib.malloc(sha1_len + name_len + 2) if mangled is None: return name string.strcpy(mangled, sha1) mangled[sha1_len] = '.' string.strcpy(mangled + sha1_len + 1, name) return mangled # ============================================================ # _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查) # # 规则: # - main 函数不加前缀(程序入口点) # - has_export 非 0 时不加前缀(t.CExport 导出函数) # - 已带 SHA1 前缀的不再加 # - ModuleSha1 为 None 时不加前缀 # ============================================================ def _mangle_func_name(trans: HT.Translator | t.CPtr, name: str, has_export: int) -> str: """为函数名添加 SHA1 前缀(检查 main/export)""" if trans is None or name is None: return name if has_export != 0: return name if string.strcmp(name, "main") == 0: return name return _mangle_name(trans, name) # ============================================================ # forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明 # # 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用 # vsnprintf(行41),但 vsnprintf 定义在后面。 # # 对每个顶层 FunctionDef: # 1. 推断返回类型和参数类型 # 2. 计算 mangled name(含 SHA1 前缀) # 3. 创建 declare(IsDeclared=1) # 4. 添加参数 # 5. 注册到函数表 # # 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare, # 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。 # ============================================================ def forward_declare_functions(trans: HT.Translator | t.CPtr, tree: ast.AST | t.CPtr) -> int: """预扫描所有顶层 FunctionDef,创建前向声明""" if trans is None or tree is None: return 0 pool: memhub.MemBuddy | t.CPtr = trans.Pool mod: llvmlite.LLVMModule | t.CPtr = trans.Module if pool is None or mod is None: return 0 imported_modules: str = trans._imported_modules from_imports: str = trans._from_imports funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children if ch is None: return 0 cn_count: t.CSizeT = ch.__len__() for ci in range(cn_count): child: ast.AST | t.CPtr = ch.get(ci) if child is None: continue if child.kind() != ast.ASTKind.FunctionDef: continue fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child) if fd is None or fd.name is None: continue # 推断返回类型 ret_ty: llvmlite.LLVMType | t.CPtr = None if fd.returns is not None: ret_ty = HandlesType.resolve_annotation_type( pool, fd.returns, imported_modules, from_imports) if ret_ty is None and fd.returns is not None: if HandlesType.has_decorator_marker(fd.returns, "State") != 0: ret_ty = llvmlite.Void(pool) if ret_ty is None: ret_ty = i32_ty # 检测 CExtern/State/CExport has_extern: int = 0 has_state: int = 0 has_export: int = 0 if fd.returns is not None: has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") has_state = HandlesType.has_decorator_marker(fd.returns, "State") has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") is_extern_decl: int = 0 if has_extern != 0 or has_state != 0: is_extern_decl = 1 # 计算 mangled name if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main": mangled_name: str = fd.name else: mangled_name = _mangle_func_name(trans, fd.name, 0) # 如果函数已存在(如重复定义),跳过 existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) if existing is not None: continue # 创建 declare func: llvmlite.Function | t.CPtr = llvmlite.create_declare( pool, mod, mangled_name, ret_ty) if func is None: continue # 注册到函数表(用裸名 fd.name,不是 mangled_name) max_funcs: int = 256 cur_count: int = trans._func_count if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs) == 0: trans._func_count = cur_count + 1 # 注册 CExport 函数到全局表 if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) # 添加参数 args_node: ast.Arguments | t.CPtr = fd.args if args_node is not None: ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) if ags.args is not None: alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args an: t.CSizeT = alist.__len__() for ai in range(an): arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) if arg is None or arg.arg is None: continue # t.CVoid 表示空参:跳过 if arg.annotation is not None: if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: continue param_ty: llvmlite.LLVMType | t.CPtr = i32_ty if arg.annotation is not None: resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg.annotation, imported_modules, from_imports) if resolved is not None: param_ty = resolved pname: t.CChar | t.CPtr = pool.alloc(32) if pname is not None: viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) return 0 # ============================================================ # 翻译函数定义 FunctionDef(name, args, body, ...) # # trans 单参模式:所有共享状态从 trans 获取 # 函数局部作用域通过 enter_scope/exit_scope 管理 # ============================================================ def translate_function_def(trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: """翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)""" fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) if fd is None or fd.name is None: return 0 pool: memhub.MemBuddy | t.CPtr = trans.Pool mod: llvmlite.LLVMModule | t.CPtr = trans.Module imported_modules: str = trans._imported_modules from_imports: str = trans._from_imports funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs func_count: int = trans._func_count i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) # 推断返回类型:优先使用返回类型注解 ret_ty: llvmlite.LLVMType | t.CPtr = None if fd.returns is not None: ret_ty = HandlesType.resolve_annotation_type( pool, fd.returns, imported_modules, from_imports) # 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void # 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32 if ret_ty is None and fd.returns is not None: if HandlesType.has_decorator_marker(fd.returns, "State") != 0: ret_ty = llvmlite.Void(pool) # 如果仍然为 None,扫描 return 语句推断(至少返回 i32) if ret_ty is None: param_types_str: str = HandlesType.build_param_types_str(pool, fd.args) ret_ty = HandlesType.infer_return_type( pool, fd.children, param_types_str) # 检测是否为外部声明函数(t.CExtern 或 t.State) # 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号) # t.State = t.CExtern + t.CExport(既是声明又是导出) # t.CExport 导出函数不加 SHA1 前缀 # t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名 is_extern_decl: int = 0 has_export: int = 0 has_extern: int = 0 has_state: int = 0 if fd.returns is not None: has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern") has_state = HandlesType.has_decorator_marker(fd.returns, "State") has_export = HandlesType.has_decorator_marker(fd.returns, "CExport") # t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass) if has_extern != 0 or has_state != 0: is_extern_decl = 1 # SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名 # (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference) # main 函数也不加前缀(程序入口点) if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main": mangled_name: str = fd.name else: mangled_name: str = _mangle_func_name(trans, fd.name, 0) # 注册 CExport 函数到全局表(供跨模块调用查表) # t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name) if is_extern_decl != 0: # 外部声明函数:生成 declare(仅声明,不定义) # 先检查是否已由 forward_declare_functions 创建,避免重复 declare existing_extern: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) if existing_extern is not None: # 已存在前向声明,复用之,不再重复创建 return 0 func: llvmlite.Function | t.CPtr = llvmlite.create_declare( pool, mod, mangled_name, ret_ty) if func is None: return 0 # 注册到函数表 max_funcs_extern: int = 256 if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern) == 0: trans._func_count = func_count + 1 # 添加参数(支持类型注解) args_node_extern: ast.Arguments | t.CPtr = fd.args if args_node_extern is not None: ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern) if ags_e.args is not None: alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args an_e: t.CSizeT = alist_e.__len__() for ai_e in range(an_e): arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e)) if arg_e is not None and arg_e.arg is not None: # t.CVoid 表示空参:跳过,不添加到函数签名 if arg_e.annotation is not None: if HandlesType._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0: continue param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty if arg_e.annotation is not None: resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg_e.annotation, imported_modules, from_imports) if resolved_e is not None: param_ty_e = resolved_e pname_e: t.CChar | t.CPtr = pool.alloc(32) if pname_e is not None: viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg) llvmlite.add_param(pool, func, param_ty_e, pname_e) # 提取 @c.Attribute 装饰器属性并设置到函数 func_attrs_e: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) if func_attrs_e is not None: llvmlite.function_set_attrs(func, func_attrs_e) return 0 # args_node 用于后续 alloca 创建,提前赋值 args_node: ast.Arguments | t.CPtr = fd.args # 检查是否已有前向声明(由 forward_declare_functions 创建) func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name) if func is not None and llvmlite.function_is_declared(func) != 0: # 复用前向声明:清除 IsDeclared 标记,转为 define func.IsDeclared = 0 # 装饰器属性设置(前向声明时未设置) func_attrs_reuse: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) if func_attrs_reuse is not None: llvmlite.function_set_attrs(func, func_attrs_reuse) else: # 创建新的 LLVM 函数(使用 SHA1 混淆名) func = llvmlite.create_function(pool, mod, mangled_name, ret_ty) if func is None: stdio.printf("[FUNC] create_function %s failed\n", fd.name) return 0 # 提取 @c.Attribute 装饰器属性并设置到函数 func_attrs: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules) if func_attrs is not None: llvmlite.function_set_attrs(func, func_attrs) # 注册到函数表 max_funcs: int = 256 if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs) == 0: trans._func_count = func_count + 1 # 添加参数(支持类型注解) if args_node is not None: ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) if ags.args is not None: alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args an: t.CSizeT = alist.__len__() for ai in range(an): arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) if arg is not None and arg.arg is not None: # t.CVoid 表示空参:跳过,不添加到函数签名 if arg.annotation is not None: if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: continue param_ty: llvmlite.LLVMType | t.CPtr = i32_ty if arg.annotation is not None: resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg.annotation, imported_modules, from_imports) if resolved is not None: param_ty = resolved pname: t.CChar | t.CPtr = pool.alloc(32) if pname is not None: viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) # 创建 entry 块 entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") if entry_blk is None: return 0 # 创建函数专属 builder func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) if func_builder is None: return 0 llvmlite.position_at_end(func_builder, entry_blk) # 进入函数作用域(嵌套符号表) HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION) # 为参数创建 alloca if args_node is not None: ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) if ags2.args is not None: alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args an2: t.CSizeT = alist2.__len__() for ai2 in range(an2): arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2)) if arg2 is not None and arg2.arg is not None: # t.CVoid 表示空参:跳过,不创建 alloca if arg2.annotation is not None: if HandlesType._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0: continue param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty if arg2.annotation is not None: resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg2.annotation, imported_modules, from_imports) if resolved2 is not None: param_ty2 = resolved2 alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2) if alloca is not None: HandlesVar.define_var(trans.SymTab, arg2.arg, alloca) # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) if arg2.annotation is not None: cls_nm: str = HandlesType.extract_class_name_from_annotation( arg2.annotation, imported_modules) if cls_nm is not None: HandlesVar.set_var_annot_class_name( trans.SymTab, arg2.arg, cls_nm) pname2: t.CChar | t.CPtr = pool.alloc(32) if pname2 is not None: viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue( pool, param_ty2, pname2) llvmlite.build_store(func_builder, param_val, alloca) # 保存模块级作用域状态(仅非变量表相关) old_func: llvmlite.Function | t.CPtr = trans._cur_func old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder old_global_count: int = trans._global_name_count old_nonlocal_count: int = trans._nonlocal_name_count old_env_count: int = trans._closure_env_count trans._cur_func = func trans._cur_builder = func_builder # 清空 global/nonlocal 名称集合(新函数作用域) HT.clear_scope_names(trans) # 预扫描函数体:为局部变量提前创建 alloca body: list[ast.AST | t.CPtr] | t.CPtr = fd.children if body is not None: bn: t.CSizeT = body.__len__() for bi in range(bn): stmt: ast.AST | t.CPtr = body.get(bi) if stmt is not None: HandlesBody.pre_scan_allocas(trans, stmt) # 翻译函数体 if body is not None: bn2: t.CSizeT = body.__len__() for bi2 in range(bn2): stmt2: ast.AST | t.CPtr = body.get(bi2) if stmt2 is not None: HandlesBody.translate_stmt(trans, stmt2) # 如果函数体最后一条语句不是 Return,添加隐式 ret last_is_return: int = 0 if body is not None: bn3: t.CSizeT = body.__len__() if bn3 > 0: last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: last_is_return = 1 if last_is_return == 0: zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) llvmlite.build_ret(func_builder, zero_val) # 恢复模块级作用域(退出函数作用域) HandlesVar.exit_scope(trans.SymTab) trans._cur_func = old_func trans._cur_builder = old_builder trans._global_name_count = old_global_count trans._nonlocal_name_count = old_nonlocal_count trans._closure_env_count = old_env_count return 0 # ============================================================ # translate_nested_function_def - 嵌套函数提升 + 闭包创建 # # 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32, # 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到 # 以函数名命名的局部变量中。 # # 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配) # Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节) # ============================================================ def translate_nested_function_def(trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: """翻译嵌套函数定义:提升为顶层函数 + 创建闭包""" fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node) if fd is None or fd.name is None: return 0 pool: memhub.MemBuddy | t.CPtr = trans.Pool mod: llvmlite.LLVMModule | t.CPtr = trans.Module func_name: str = fd.name i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) # 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突) promoted_name: t.CChar | t.CPtr = pool.alloc(64) if promoted_name is not None: viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name) mangled_promoted: str = _mangle_name(trans, promoted_name) # 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env) func: llvmlite.Function | t.CPtr = llvmlite.create_function( pool, mod, mangled_promoted, i32_ty) if func is None: return 0 llvmlite.add_param(pool, func, i8_ptr_ty, "%env") # 3. 创建 entry 块 + builder entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry") if entry_blk is None: return 0 func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func) if func_builder is None: return 0 llvmlite.position_at_end(func_builder, entry_blk) # 4. 进入嵌套函数作用域(嵌套符号表) HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION) # 5. 创建 _env_ptr alloca 并存储 %env 参数 env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty) if env_alloca is not None: HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca) env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env") llvmlite.build_store(func_builder, env_param_val, env_alloca) # 6. 保存父函数作用域状态(仅非变量表相关) old_func: llvmlite.Function | t.CPtr = trans._cur_func old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder old_func_name: str = trans._cur_func_name old_global_count: int = trans._global_name_count old_nonlocal_count: int = trans._nonlocal_name_count old_env_count: int = trans._closure_env_count # 7. 切换到嵌套函数作用域 + 清空 scope names trans._cur_func = func trans._cur_builder = func_builder trans._cur_func_name = func_name HT.clear_scope_names(trans) # 8. 预扫描函数体:为局部变量提前创建 alloca body: list[ast.AST | t.CPtr] | t.CPtr = fd.children if body is not None: bn: t.CSizeT = body.__len__() for bi in range(bn): stmt: ast.AST | t.CPtr = body.get(bi) if stmt is not None: HandlesBody.pre_scan_allocas(trans, stmt) # 9. 翻译函数体(Nonlocal 语句会填充 _nonlocal_names) if body is not None: bn2: t.CSizeT = body.__len__() for bi2 in range(bn2): stmt2: ast.AST | t.CPtr = body.get(bi2) if stmt2 is not None: HandlesBody.translate_stmt(trans, stmt2) # 10. 隐式 ret last_is_return: int = 0 if body is not None: bn3: t.CSizeT = body.__len__() if bn3 > 0: last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1) if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return: last_is_return = 1 if last_is_return == 0: zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) llvmlite.build_ret(func_builder, zero_val) # 11. 保存嵌套函数的 nonlocal 信息 nested_nonlocal_count: int = trans._nonlocal_name_count # 12. 退出嵌套函数作用域,回到父函数作用域(保留 _nonlocal_names 用于 env 创建) HandlesVar.exit_scope(trans.SymTab) trans._cur_func = old_func trans._cur_builder = old_builder # NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值 # 13. 在父函数中创建闭包对象 parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder if parent_builder is None: # 无 builder(模块级嵌套函数?)→ 无法创建闭包,仅恢复状态 trans._cur_func_name = old_func_name trans._global_name_count = old_global_count trans._nonlocal_name_count = old_nonlocal_count trans._closure_env_count = old_env_count return 0 # 13a. 创建 env: malloc(4 * nested_nonlocal_count) — env 直接存储 i32 值 env_ptr: llvmlite.Value | t.CPtr = None if nested_nonlocal_count > 0: env_size: t.CInt64T = nested_nonlocal_count * 4 env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size) if env_size_val is not None: env_size_val.Next = None env_ptr = llvmlite.build_call( parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) # 为每个 nonlocal 变量存储值到 env if env_ptr is not None: i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) for ni in range(nested_nonlocal_count): # 从 _nonlocal_names 缓冲区读取名称 name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8 nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr) nl_name: str = nl_slot[0] if nl_name is not None: # 在父函数作用域中查找(Current 已回到父作用域) var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( trans.SymTab, nl_name) if var_alloca is not None: # 加载变量值 var_ty: llvmlite.LLVMType | t.CPtr = None if var_alloca.Ty is not None: var_ty = var_alloca.Ty.Pointee if var_ty is None: var_ty = i32_ty var_val: llvmlite.Value | t.CPtr = llvmlite.build_load( parent_builder, var_ty, var_alloca) if var_val is not None: # GEP to env[ni*4] offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 4) slot: llvmlite.Value | t.CPtr = llvmlite.build_gep( parent_builder, i8_ty, env_ptr, offset_val) if slot is not None: # bitcast to i32* and store value slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( parent_builder, slot, i32_ptr_ty) if slot_typed is not None: # 类型转换(确保 var_val 是 i32) coerced_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( parent_builder, var_val, i32_ty) if coerced_val is not None: llvmlite.build_store(parent_builder, coerced_val, slot_typed) # 13b. 创建闭包结构: malloc(16) closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16) if closure_size_val is not None: closure_size_val.Next = None closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0) if closure_ptr is None: # malloc 失败,恢复状态 trans._cur_func_name = old_func_name trans._global_name_count = old_global_count trans._nonlocal_name_count = old_nonlocal_count trans._closure_env_count = old_env_count return 0 # 13c. 存储 fn_ptr 到 offset 0 # 创建函数指针类型 i32(i8*)* fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty) fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1) fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty) # 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名) fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64) if fn_ptr_name is not None: # SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func") if string.strchr(mangled_promoted, '.') is not None: viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted) else: viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted) fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name) # bitcast 函数指针到 i8*(闭包存储 i8* 类型) fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( parent_builder, fn_ptr_val, i8_ptr_ty) fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( parent_builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty)) if fn_slot is not None and fn_as_i8ptr is not None: llvmlite.build_store(parent_builder, fn_as_i8ptr, fn_slot) # 13d. 存储 env_ptr 到 offset 8 eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8) env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( parent_builder, i8_ty, closure_ptr, eight_val) if env_slot_addr is not None: env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( parent_builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty)) if env_slot is not None: if env_ptr is not None: llvmlite.build_store(parent_builder, env_ptr, env_slot) else: # 无 nonlocal 变量,存储 null null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null") llvmlite.build_store(parent_builder, null_val, env_slot) # 13e. 将闭包指针存储到父函数的局部变量 {func_name} closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty) if closure_alloca is not None: llvmlite.build_store(parent_builder, closure_ptr, closure_alloca) HandlesVar.define_var(trans.SymTab, func_name, closure_alloca) # 14. 恢复 scope names trans._cur_func_name = old_func_name trans._global_name_count = old_global_count trans._nonlocal_name_count = old_nonlocal_count trans._closure_env_count = old_env_count return 1 # ============================================================ # 创建 LLVM 函数(简单版本,仅声明) # ============================================================ def create_function(pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, name: str, args_node: ast.AST | t.CPtr, ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr: """创建 LLVM 函数并添加参数""" if name is None or mod is None: return None func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty) if func is None: return None if args_node is not None: ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node) if ags.args is not None: alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args an: t.CSizeT = alist.__len__() i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) for ai in range(an): arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai)) if arg is not None and arg.arg is not None: # t.CVoid 表示空参:跳过 if arg.annotation is not None: if arg.annotation.kind() == ast.ASTKind.Attribute: at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation) if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0: continue param_ty: llvmlite.LLVMType | t.CPtr = i32_ty if arg.annotation is not None: resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( pool, arg.annotation, None, None) if resolved is not None: param_ty = resolved pname: t.CChar | t.CPtr = pool.alloc(32) if pname is not None: viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) return func