FunctionDef.args 的字段静态类型是 AST*,直接写 fn.args.args 会在 AST 类上查 args(class_members=7 不含 args)。改为先 ast.Arguments*(fn.args) 再取 .args 列表,与 VpiReader / FuncGenMixin / ClassGenVTable 等既有写法一致。
733 lines
36 KiB
Plaintext
733 lines
36 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import mlirlite
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Generator as Generator
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.Gen.Generator as Generator
|
||
|
||
# GenApi - module-level delegate entry for pipeline/reserved-file access to Gen
|
||
# (drops the Handles layer); generated from Gen sub-object methods via _g_gen.
|
||
|
||
|
||
# Global gen singleton (injected by main/BuildPipeline after creating gen)
|
||
_g_gen: Generator.Generator* = None
|
||
|
||
|
||
# ---------------- set_temp_dir (delegates to TypeGenBase.set_temp_dir) ----------------
|
||
def set_temp_dir(temp_dir: str) -> None:
|
||
"""Delegate to gen.set_temp_dir"""
|
||
if _g_gen is not None: _g_gen.TypeGenBase.set_temp_dir(temp_dir)
|
||
|
||
|
||
# ---------------- set_current_file_imports (delegates to ImportsGenMixin.set_current_file) ----------------
|
||
def set_current_file_imports(file_path: str) -> None:
|
||
"""Delegate to gen.set_current_file"""
|
||
if _g_gen is not None: _g_gen.ImportsGen.set_current_file(file_path)
|
||
|
||
|
||
# ---------------- set_current_file_type (delegates to TypeGenResolve.set_current_file) ----------------
|
||
def set_current_file_type(file_path: str) -> None:
|
||
"""Set the current file for attribution via gen, falling back to the Generator singleton."""
|
||
if _g_gen is not None:
|
||
_g_gen.TypeGenResolve.set_current_file(file_path)
|
||
return
|
||
gg: Generator.Generator* = Generator._g_gen
|
||
if gg is not None: gg.TypeGenResolve.set_current_file(file_path)
|
||
|
||
|
||
# ---------------- set_current_module_sha1 (delegates to TypeGenBase.set_current_module_sha1) ----------------
|
||
def set_current_module_sha1(sha1: str) -> None:
|
||
"""Delegate to gen.set_current_module_sha1"""
|
||
if _g_gen is not None: _g_gen.TypeGenBase.set_current_module_sha1(sha1)
|
||
|
||
|
||
# ---------------- clear_trace (delegates to TypeGenBase.clear_trace) ----------------
|
||
def clear_trace() -> None:
|
||
"""Delegate to gen.clear_trace"""
|
||
if _g_gen is not None: _g_gen.TypeGenBase.clear_trace()
|
||
|
||
|
||
# ---------------- clear_cdefine_constants (delegates to TypeGenCDef.clear_cdefine_constants) ----------------
|
||
def clear_cdefine_constants() -> None:
|
||
"""Delegate to gen.clear_cdefine_constants"""
|
||
if _g_gen is not None: _g_gen.TypeGenCDef.clear_cdefine_constants()
|
||
|
||
|
||
# ---------------- clear_ctypedefs (delegates to TypeGenCType.clear_ctypedefs) ----------------
|
||
def clear_ctypedefs() -> None:
|
||
"""Delegate to gen.clear_ctypedefs"""
|
||
if _g_gen is not None: _g_gen.TypeGenCType.clear_ctypedefs()
|
||
|
||
|
||
# ---------------- RegisterCTypedefFromSource (delegates to TypeGenCType.register_ctypedef_from_source) ----------------
|
||
def RegisterCTypedefFromSource(pool: memhub.MemBuddy*, src: str) -> int:
|
||
"""Delegate to gen.register_ctypedef_from_source"""
|
||
if _g_gen is not None: _g_gen.TypeGenCType.register_ctypedef_from_source(pool, src)
|
||
return 0
|
||
|
||
|
||
# ---------------- dump_parse_traceback (delegates to TypeGenErr.dump_parse_traceback) ----------------
|
||
def dump_parse_traceback(file_path: str) -> None:
|
||
"""Delegate to gen.dump_parse_traceback"""
|
||
if _g_gen is not None: _g_gen.TypeGenErr.dump_parse_traceback(file_path)
|
||
|
||
|
||
# ---------------- fatal_error (delegates to TypeGenErr.fatal_error) ----------------
|
||
def fatal_error(node: ast.AST*, msg: str, err_type: str = "SyntaxError") -> None:
|
||
"""Report an error through gen.TypeGenErr, falling back to the Generator singleton."""
|
||
if _g_gen is not None:
|
||
_g_gen.TypeGenErr.fatal_error(node, msg, err_type)
|
||
return
|
||
gg: Generator.Generator* = Generator._g_gen
|
||
if gg is not None: gg.TypeGenErr.fatal_error(node, msg, err_type)
|
||
|
||
|
||
# ---------------- map_t_type (delegates to TypeGenResolve.map_t_type) ----------------
|
||
def map_t_type(pool: memhub.MemBuddy*, type_name: str) -> mlirlite.LLVMType*:
|
||
"""Delegate to gen.map_t_type"""
|
||
if _g_gen is not None: _g_gen.TypeGenResolve.map_t_type(pool, type_name)
|
||
return None
|
||
|
||
|
||
# ---------------- resolve_typedef_or_map (delegates to TypeGenResolve.resolve_typedef_or_map) ----------------
|
||
def resolve_typedef_or_map(pool: memhub.MemBuddy*, name: str, imported_modules: str, from_imports: str, trans: HT.Translator* = None) -> mlirlite.LLVMType*:
|
||
"""Delegate to gen.resolve_typedef_or_map: CTypedef table first, then map_t_type."""
|
||
if _g_gen is not None: return _g_gen.TypeGenResolve.resolve_typedef_or_map(pool, name, imported_modules, from_imports, trans)
|
||
return None
|
||
|
||
|
||
# ---------------- infer_external_func_ret_ty (delegates to CallGenLib._infer_external_func_ret_ty) ----------------
|
||
def infer_external_func_ret_ty(pool: memhub.MemBuddy*, func_name: str) -> mlirlite.LLVMType*:
|
||
"""Infer an external function return type from the whitelist, defaulting to i32."""
|
||
if _g_gen is not None: return _g_gen.CallGenLib._infer_external_func_ret_ty(pool, func_name, None, 0)
|
||
return None
|
||
|
||
|
||
# ---------------- get_current_file (delegates to TypeGenResolve.get_current_file) ----------------
|
||
def get_current_file() -> str:
|
||
"""Delegate to gen.get_current_file"""
|
||
if _g_gen is not None: return _g_gen.TypeGenResolve.get_current_file()
|
||
return None
|
||
|
||
|
||
# ---------------- _is_ctypedef_annotation (delegates to TypeGenCType._is_ctypedef_annotation) ----------------
|
||
def _is_ctypedef_annotation(annotation: ast.AST*) -> int:
|
||
"""Delegate to gen._is_ctypedef_annotation"""
|
||
if _g_gen is not None: return _g_gen.TypeGenCType._is_ctypedef_annotation(annotation)
|
||
return 0
|
||
|
||
|
||
# ---------------- resolve_annotation_type (delegates to TypeGenResolve.resolve_annotation_type) ----------------
|
||
def resolve_annotation_type(pool: memhub.MemBuddy*, node: ast.AST*, imported_modules: str, from_imports: str, trans: HT.Translator* = None, depth: int = 0) -> mlirlite.LLVMType*:
|
||
"""Delegate to gen.resolve_annotation_type"""
|
||
if _g_gen is not None: return _g_gen.TypeGenResolve.resolve_annotation_type(pool, node, imported_modules, from_imports, trans, depth)
|
||
return None
|
||
|
||
|
||
# ---------------- has_decorator_marker (delegates to TypeGenErr.has_decorator_marker) ----------------
|
||
def has_decorator_marker(node: ast.AST*, marker_name: str, depth: int = 0) -> int:
|
||
"""Delegate to gen.has_decorator_marker"""
|
||
if _g_gen is not None: return _g_gen.TypeGenErr.has_decorator_marker(node, marker_name, depth)
|
||
return 0
|
||
|
||
|
||
# ---------------- _get_type_name_from_annotation (delegates to TypeGenResolve._get_type_name_from_annotation) ----------------
|
||
def _get_type_name_from_annotation(pool: memhub.MemBuddy*, node: ast.AST*) -> str:
|
||
"""Delegate to gen._get_type_name_from_annotation"""
|
||
if _g_gen is not None: return _g_gen.TypeGenResolve._get_type_name_from_annotation(pool, node)
|
||
return None
|
||
|
||
|
||
# ---------------- register_ctypedef (delegates to TypeGenCType.register_ctypedef) ----------------
|
||
def register_ctypedef(pool: memhub.MemBuddy*, name: str, type_str: str):
|
||
"""Delegate to gen.register_ctypedef"""
|
||
if _g_gen is not None: _g_gen.TypeGenCType.register_ctypedef(pool, name, type_str)
|
||
|
||
|
||
# ---------------- lookup_cdefine_constant (delegates to TypeGenCDef.lookup_cdefine_constant) ----------------
|
||
def lookup_cdefine_constant(name: str) -> int64:
|
||
"""Delegate to gen.lookup_cdefine_constant"""
|
||
if _g_gen is not None: return _g_gen.TypeGenCDef.lookup_cdefine_constant(name)
|
||
return 0
|
||
|
||
|
||
# ---------------- is_cdefine_found (delegates to TypeGenCDef.is_cdefine_found) ----------------
|
||
def is_cdefine_found() -> int:
|
||
"""Delegate to gen.is_cdefine_found"""
|
||
if _g_gen is not None: return _g_gen.TypeGenCDef.is_cdefine_found()
|
||
return 0
|
||
|
||
|
||
# ---------------- register_cdefine_constant (delegates to TypeGenCDef.register_cdefine_constant) ----------------
|
||
def register_cdefine_constant(pool: memhub.MemBuddy*, name: str, value: int64):
|
||
"""Delegate to gen.register_cdefine_constant"""
|
||
if _g_gen is not None: _g_gen.TypeGenCDef.register_cdefine_constant(pool, name, value)
|
||
|
||
|
||
# ---------------- register_cdefine_double (delegates to TypeGenCDef.register_cdefine_double) ----------------
|
||
def register_cdefine_double(pool: memhub.MemBuddy*, name: str, value: double):
|
||
"""Delegate to gen.register_cdefine_double"""
|
||
if _g_gen is not None: _g_gen.TypeGenCDef.register_cdefine_double(pool, name, value)
|
||
|
||
|
||
# ---------------- is_cdefine_annotation (delegates to AssignGenMixin.is_cdefine_annotation) ----------------
|
||
def is_cdefine_annotation(annot: ast.AST*) -> int:
|
||
"""Delegate to gen.is_cdefine_annotation"""
|
||
if _g_gen is not None: return _g_gen.AssignGen.is_cdefine_annotation(annot)
|
||
return 0
|
||
|
||
|
||
# ---------------- extract_cdefine_int_value (delegates to AssignGenMixin.extract_cdefine_int_value) ----------------
|
||
def extract_cdefine_int_value(val_node: ast.AST*) -> int64:
|
||
"""Delegate to gen.extract_cdefine_int_value"""
|
||
if _g_gen is not None: return _g_gen.AssignGen.extract_cdefine_int_value(val_node)
|
||
return 0
|
||
|
||
|
||
# ---------------- push_trace (delegates to TypeGenBase.push_trace) ----------------
|
||
def push_trace(file_name: str, lineno: int, col_start: int = 0, col_end: int = 0):
|
||
"""Delegate to gen.push_trace"""
|
||
if _g_gen is not None: _g_gen.TypeGenBase.push_trace(file_name, lineno, col_start, col_end)
|
||
|
||
|
||
# ---------------- pop_trace (delegates to TypeGenBase.pop_trace) ----------------
|
||
def pop_trace():
|
||
"""Delegate to gen.pop_trace"""
|
||
if _g_gen is not None: _g_gen.TypeGenBase.pop_trace()
|
||
|
||
|
||
# ---------------- get_temp_dir (delegates to TypeGenBase.get_temp_dir) ----------------
|
||
def get_temp_dir() -> str:
|
||
"""Delegate to gen.get_temp_dir"""
|
||
if _g_gen is not None: return _g_gen.TypeGenBase.get_temp_dir()
|
||
return None
|
||
|
||
|
||
# ---------------- reset_visible_structs (delegates to StructGenMixin.reset_visible_structs) ----------------
|
||
def reset_visible_structs(pool: memhub.MemBuddy*, strict: int):
|
||
"""Delegate to gen.reset_visible_structs"""
|
||
if _g_gen is not None: _g_gen.StructGen.reset_visible_structs(pool, strict)
|
||
|
||
|
||
# ---------------- set_stdlib_alloc (delegates to StructGenMixin.set_stdlib_alloc) ----------------
|
||
def set_stdlib_alloc(flag: int):
|
||
"""Delegate to gen.set_stdlib_alloc"""
|
||
if _g_gen is not None: _g_gen.StructGen.set_stdlib_alloc(flag)
|
||
|
||
|
||
# ---------------- get_struct_count (delegates to StructGenMixin.get_struct_count) ----------------
|
||
def get_struct_count() -> int:
|
||
"""Delegate to gen.get_struct_count"""
|
||
if _g_gen is not None: return _g_gen.StructGen.get_struct_count()
|
||
return 0
|
||
|
||
|
||
# ---------------- reset_module_methods_emitted (delegates to StructGenMixin.reset_module_methods_emitted) ----------------
|
||
def reset_module_methods_emitted(sha1: str) -> int:
|
||
"""Delegate to gen.reset_module_methods_emitted"""
|
||
if _g_gen is not None: return _g_gen.StructGen.reset_module_methods_emitted(sha1)
|
||
return 0
|
||
|
||
|
||
# ---------------- get_struct_type (delegates to StructGenMixin.get_struct_type) ----------------
|
||
def get_struct_type(class_name: str) -> mlirlite.LLVMType*:
|
||
"""Delegate to gen.get_struct_type"""
|
||
if _g_gen is not None: return _g_gen.StructGen.get_struct_type(class_name)
|
||
return None
|
||
|
||
|
||
# ---------------- get_enum_base_type (delegates to StmtGenDeclMixin.get_enum_base_type) ----------------
|
||
def get_enum_base_type(enum_name: str) -> mlirlite.LLVMType*:
|
||
"""Delegate to gen.get_enum_base_type, falling back to the enum table's base type."""
|
||
if _g_gen is not None: return _g_gen.StmtGenDecl.get_enum_base_type(enum_name)
|
||
return None
|
||
|
||
|
||
# ---------------- add_visible_struct (delegates to StructGenMixin.add_visible_struct) ----------------
|
||
def add_visible_struct(pool: memhub.MemBuddy*, name: str):
|
||
"""Delegate to gen.add_visible_struct"""
|
||
if _g_gen is not None: _g_gen.StructGen.add_visible_struct(pool, name)
|
||
|
||
|
||
# ---------------- find_struct_by_module (delegates to StructGenMixin.find_struct_by_module) ----------------
|
||
def find_struct_by_module(name: str, sha1: str) -> GenTypes.StructEntry*:
|
||
"""Delegate to gen.find_struct_by_module"""
|
||
if _g_gen is not None: return _g_gen.StructGen.find_struct_by_module(name, sha1)
|
||
return None
|
||
|
||
|
||
# ---------------- mark_module_class (delegates to StructGenMixin.mark_module_class) ----------------
|
||
def mark_module_class(pool: memhub.MemBuddy*, sha1: str, name: str) -> None:
|
||
"""Register "{sha1}.{class}" for this module and point the current definition fields at it."""
|
||
if _g_gen is not None: _g_gen.StructGen.mark_module_class(pool, sha1, name)
|
||
|
||
|
||
# ---------------- register_file_classes (delegates to StructGenMixin.register_file_classes) ----------------
|
||
def register_file_classes(pool: memhub.MemBuddy*, sha1: str, tree: ast.AST*) -> None:
|
||
"""Pre-register top-level ClassDef names with this file's module SHA1."""
|
||
if _g_gen is not None: _g_gen.StructGen.register_file_classes(pool, sha1, tree)
|
||
|
||
|
||
# ---------------- register_file_funcs / is_file_func (delegates to StructGenMixin) ----------------
|
||
def register_file_funcs(pool: memhub.MemBuddy*, tree: ast.AST*) -> None:
|
||
"""Pre-register this file's top-level FunctionDef names to guard its own extern declarations."""
|
||
if _g_gen is not None: _g_gen.StructGen.register_file_funcs(pool, tree)
|
||
|
||
|
||
def is_file_func(name: str) -> int:
|
||
"""Return 1 if name is a top-level function declared in this file, else 0."""
|
||
if _g_gen is not None: return _g_gen.StructGen.is_file_func(name)
|
||
return 0
|
||
|
||
|
||
def is_file_var(name: str) -> int:
|
||
"""本文件是否顶层声明过该模块级变量名(AnnAssign/Assign 目标);1=是 / 0=否。"""
|
||
if _g_gen is not None: return _g_gen.StructGen.is_file_var(name)
|
||
return 0
|
||
|
||
|
||
# ---------------- 生命期摘要查询(M2.3 v1b, delegates to StructGenMixin) ----------------
|
||
def get_param_escapes(name: str) -> int:
|
||
"""形参逃逸掩码(第 k 位=第 k 个形参逃逸);无记录返回 0"""
|
||
if _g_gen is not None: return _g_gen.StructGen.get_param_escapes(name)
|
||
return 0
|
||
|
||
|
||
def get_ret_borrow(name: str) -> int:
|
||
"""返回借用标记(1=该函数直接返回某形参);无记录返回 0"""
|
||
if _g_gen is not None: return _g_gen.StructGen.get_ret_borrow(name)
|
||
return 0
|
||
|
||
|
||
def get_param_escapes_method(pool: memhub.MemBuddy*, class_name: str, method_name: str) -> int:
|
||
"""方法形参逃逸掩码:查 "Class.method" 并沿 MRO 回退;无记录返回 0"""
|
||
if _g_gen is not None: return _g_gen.StructGen.get_param_escapes_method(pool, class_name, method_name)
|
||
return 0
|
||
|
||
|
||
def compute_escape_summary(pool: memhub.MemBuddy*, fd: ast.AST*, gset: sizet*, box: sizet*) -> int:
|
||
"""计算函数逃逸摘要(box[0]=形参逃逸掩码,box[1]=返回借用位);.vpi 生成时落盘用"""
|
||
if _g_gen is not None: return _g_gen.StructGen.compute_escape_summary(pool, ast.FunctionDef*(fd), gset, box)
|
||
return 1
|
||
|
||
|
||
# ---------------- 生命期标注 @life(willFree(...)) / @willFree(...)(P2) ----------------
|
||
# 返回值 = 形参位掩码:第 k 位 = 第 k 个形参所指对象在**本调用返回后失效**(被调用者释放/接管)。
|
||
# 语义见 includes/stdlib.vp 的 free 与 Debugger/ownership-and-new.md §12-P2。
|
||
# 非法标注一律 fail-fast(LifetimeError),不静默忽略。
|
||
def compute_willfree_mask(fd: ast.AST*) -> int:
|
||
"""解析函数定义的 @life(willFree(...)) / @willFree(...) 标注并返回形参位掩码(0=无标注)"""
|
||
fn: ast.FunctionDef* = ast.FunctionDef*(fd)
|
||
if fn is None or fn.decorator_list is None: return 0
|
||
dl: list[ast.AST*]* = fn.decorator_list
|
||
dn: sizet = len(dl)
|
||
if dn == 0: return 0
|
||
mask: int = 0
|
||
for i in range(dn):
|
||
deco: ast.AST* = dl.get(i)
|
||
if deco is None or deco.kind() != ast.ASTKind.Call: continue
|
||
dc: ast.Call* = ast.Call*(deco)
|
||
if dc.func is None or dc.func.kind() != ast.ASTKind.Name: continue
|
||
fname: ast.Name* = ast.Name*(dc.func)
|
||
if fname.id is None: continue
|
||
if string.strcmp(fname.id, "life") == 0:
|
||
# @life(<tag>, <tag>, ...):逐个标签并入
|
||
if dc.args is not None:
|
||
an: sizet = len(dc.args)
|
||
for j in range(an):
|
||
mask = _WillFreeMergeTag(fn, dc.args.get(j), mask)
|
||
elif string.strcmp(fname.id, "willFree") == 0:
|
||
# 兼容形式:@willFree(0) 直接叠加(与 @life 等价、可混用)
|
||
mask = _WillFreeMergeTag(fn, deco, mask)
|
||
return mask
|
||
|
||
|
||
def _WillFreeMergeTag(fn: ast.FunctionDef*, tag: ast.AST*, mask: int) -> int:
|
||
"""校验一个标签调用 willFree(<int>|<name>) 并并入掩码;未知标签/非法实参 → fail-fast"""
|
||
if tag is None or tag.kind() != ast.ASTKind.Call:
|
||
fatal_error(tag, "@life(...) accepts only tag calls such as willFree(0) or willFree(p)", "LifetimeError")
|
||
return mask
|
||
tc: ast.Call* = ast.Call*(tag)
|
||
tnm: str = None
|
||
if tc.func is not None:
|
||
if tc.func.kind() == ast.ASTKind.Name:
|
||
tn: ast.Name* = ast.Name*(tc.func)
|
||
tnm = tn.id
|
||
elif tc.func.kind() == ast.ASTKind.Attribute:
|
||
ta: ast.Attribute* = ast.Attribute*(tc.func)
|
||
tnm = ta.attr
|
||
if tnm is None or string.strcmp(tnm, "willFree") != 0:
|
||
fatal_error(tag, "unknown lifetime tag: only `willFree(<param>)` is defined for @life(...)", "LifetimeError")
|
||
return mask
|
||
if tc.args is None or len(tc.args) != 1:
|
||
fatal_error(tag, "@willFree(...) requires exactly one argument: a parameter name or its 0-based position", "LifetimeError")
|
||
return mask
|
||
idx: int = _WillFreeArgIndex(fn, tc.args.get(0))
|
||
if idx < 0: return mask
|
||
return mask | (1 << idx)
|
||
|
||
|
||
def _WillFreeArgIndex(fn: ast.FunctionDef*, arg: ast.AST*) -> int:
|
||
"""标签实参 → 形参下标(0 起,self/cls 计入);非法即报错并返回 -1"""
|
||
if arg is None:
|
||
fatal_error(arg, "@willFree(...) requires a parameter name or its 0-based position", "LifetimeError")
|
||
return -1
|
||
# FunctionDef.args 的字段静态类型是 AST*(见 includes/ast/stmts.vp),必须先转成 Arguments*
|
||
# 才能再取 .args 列表;直接写 fn.args.args 会去 AST 类查 'args' 触发 MemberLookupFailFast。
|
||
if fn.args is None:
|
||
fatal_error(arg, "@willFree(...) cannot be used here: the definition has no parameter list", "LifetimeError")
|
||
return -1
|
||
fargs: ast.Arguments* = ast.Arguments*(fn.args)
|
||
if fargs is None or fargs.args is None:
|
||
fatal_error(arg, "@willFree(...) cannot be used here: the definition has no parameter list", "LifetimeError")
|
||
return -1
|
||
pl: list[ast.AST*]* = fargs.args
|
||
pn: sizet = len(pl)
|
||
if arg.kind() == ast.ASTKind.Name:
|
||
nma: ast.Name* = ast.Name*(arg)
|
||
if nma.id is None: return -1
|
||
for k in range(pn):
|
||
pa: ast.AST* = pl.get(k)
|
||
if pa is None or pa.kind() != ast.ASTKind.Arg: continue
|
||
aa: ast.Arg* = ast.Arg*(pa)
|
||
if aa.arg is not None and string.strcmp(aa.arg, nma.id) == 0: return int(k)
|
||
fatal_error(arg, f"@willFree({nma.id}): '{nma.id}' is not a parameter of this function", "LifetimeError")
|
||
return -1
|
||
if arg.kind() != ast.ASTKind.Constant:
|
||
fatal_error(arg, "@willFree(...) accepts only a parameter name or an integer position", "LifetimeError")
|
||
return -1
|
||
ca: ast.Constant* = ast.Constant*(arg)
|
||
if ca.const_kind != ast.CONST_INT:
|
||
fatal_error(arg, "@willFree(...) accepts only a parameter name or an integer position", "LifetimeError")
|
||
return -1
|
||
idx: int = int(ca.int_val)
|
||
if idx < 0 or idx >= int(pn):
|
||
fatal_error(arg, f"@willFree({idx}): parameter position out of range (the function has {int(pn)} parameter(s))", "LifetimeError")
|
||
return -1
|
||
return idx
|
||
|
||
|
||
def get_param_willfree(name: str) -> int:
|
||
"""本文件函数的 willFree 形参掩码(第 k 位=第 k 个形参在本调用后失效);无记录返回 0"""
|
||
if _g_gen is not None: return _g_gen.StructGen.get_param_willfree(name)
|
||
return 0
|
||
|
||
|
||
# ---------------- find_struct_by_type (delegates to StructGenMixin.find_struct_by_type) ----------------
|
||
def find_struct_by_type(struct_ty: mlirlite.LLVMType*) -> GenTypes.StructEntry*:
|
||
"""Delegate to gen.find_struct_by_type"""
|
||
if _g_gen is not None: return _g_gen.StructGen.find_struct_by_type(struct_ty)
|
||
return None
|
||
|
||
|
||
# ---------------- register_struct (delegates to StructGenMixin.register_struct) ----------------
|
||
def register_struct(pool: memhub.MemBuddy*, name: str, struct_ty: mlirlite.LLVMType*, sha1: str = None) -> GenTypes.StructEntry*:
|
||
"""Delegate to gen.register_struct"""
|
||
if _g_gen is not None: return _g_gen.StructGen.register_struct(pool, name, struct_ty, sha1)
|
||
return None
|
||
|
||
|
||
# ---------------- add_field (delegates to StructGenMixin.add_field) ----------------
|
||
def add_field(pool: memhub.MemBuddy*, struct_entry: GenTypes.StructEntry*, field_name: str, field_ty: mlirlite.LLVMType*) -> int:
|
||
"""Delegate to gen.add_field"""
|
||
if _g_gen is not None: return _g_gen.StructGen.add_field(pool, struct_entry, field_name, field_ty)
|
||
return -1
|
||
|
||
|
||
# ---------------- register_struct_alias (delegates to StructGenMixin.register_struct_alias) ----------------
|
||
def register_struct_alias(pool: memhub.MemBuddy*, name: str, sha1: str, src_entry: GenTypes.StructEntry*) -> GenTypes.StructEntry*:
|
||
"""Delegate to gen.StructGen.register_struct_alias for package re-export aliases."""
|
||
if _g_gen is not None: return _g_gen.StructGen.register_struct_alias(pool, name, sha1, src_entry)
|
||
return None
|
||
|
||
|
||
# ---------------- get_stdlib_alloc (delegates to StructGenMixin.get_stdlib_alloc) ----------------
|
||
def get_stdlib_alloc() -> int:
|
||
"""Delegate to gen.get_stdlib_alloc"""
|
||
if _g_gen is not None: return _g_gen.StructGen.get_stdlib_alloc()
|
||
return 0
|
||
|
||
|
||
|
||
# ---------------- compute_package_from_relpath (delegates to ImportsGenMixin.compute_package_from_relpath) ----------------
|
||
def compute_package_from_relpath(pool: memhub.MemBuddy*, rel_path: str) -> str:
|
||
"""Delegate to gen.compute_package_from_relpath"""
|
||
if _g_gen is not None: return _g_gen.ImportsGen.compute_package_from_relpath(pool, rel_path)
|
||
return None
|
||
|
||
|
||
# ---------------- is_module_imported (delegates to ImportsGenMixin.is_module_imported) ----------------
|
||
def is_module_imported(imported_modules: str, name: str) -> int:
|
||
"""Delegate to gen.is_module_imported"""
|
||
if _g_gen is not None: return _g_gen.ImportsGen.is_module_imported(imported_modules, name)
|
||
return 0
|
||
|
||
|
||
# Single source of truth for SHA1-prefix recognition: sha1_prefix_len(name) returns
|
||
# 17 for "{16 lowercase hex}.Class", else 0; is_sha1_hex16(seg) checks a bare segment.
|
||
def sha1_prefix_len(name: str) -> int:
|
||
"""Return 17 if name starts with "{16 lowercase hex}.", otherwise 0."""
|
||
if name is None: return 0
|
||
if string.strlen(name) < 17: return 0
|
||
if name[16] != '.': return 0
|
||
i: sizet
|
||
for i in range(16):
|
||
c: int = name[i]
|
||
# 48-57 = '0'-'9', 97-102 = 'a'-'f'
|
||
if not ((c >= 48 and c <= 57) or (c >= 97 and c <= 102)): return 0
|
||
return 17
|
||
|
||
|
||
def is_sha1_hex16(seg: str) -> int:
|
||
"""Return 1 if seg is exactly 16 lowercase hex chars, else 0."""
|
||
if seg is None: return 0
|
||
if string.strlen(seg) != 16: return 0
|
||
i: sizet
|
||
for i in range(16):
|
||
c: int = seg[i]
|
||
if not ((c >= 48 and c <= 57) or (c >= 97 and c <= 102)): return 0
|
||
return 1
|
||
|
||
|
||
# ---------------- add_imported_module (delegates to ImportsGenMixin.add_imported_module) ----------------
|
||
def add_imported_module(pool: memhub.MemBuddy*, imported_modules: str, name: str) -> str:
|
||
"""Delegate to gen.add_imported_module"""
|
||
if _g_gen is not None: return _g_gen.ImportsGen.add_imported_module(pool, imported_modules, name)
|
||
return None
|
||
|
||
|
||
# ---------------- translate_import (delegates to ImportsGenMixin.translate_import) ----------------
|
||
def translate_import(trans: HT.Translator*, node: ast.AST*) -> int:
|
||
"""Delegate to gen.translate_import"""
|
||
if _g_gen is not None: return _g_gen.ImportsGen.translate_import(trans, node)
|
||
return 0
|
||
|
||
|
||
# ---------------- translate_import_from_module (delegates to ImportsGenMixin.translate_import_from_module) ----------------
|
||
def translate_import_from_module(trans: HT.Translator*, node: ast.AST*) -> int:
|
||
"""Delegate to gen.translate_import_from_module"""
|
||
if _g_gen is not None: return _g_gen.ImportsGen.translate_import_from_module(trans, node)
|
||
return 0
|
||
|
||
|
||
# ---------------- translate_import_from_names (delegates to ImportsGenMixin.translate_import_from_names) ----------------
|
||
def translate_import_from_names(trans: HT.Translator*, node: ast.AST*) -> int:
|
||
"""Delegate to gen.translate_import_from_names"""
|
||
if _g_gen is not None: return _g_gen.ImportsGen.translate_import_from_names(trans, node)
|
||
return 0
|
||
|
||
|
||
# ---------------- _get_parent_class (delegates to ClassGenBase._get_parent_class) ----------------
|
||
def _get_parent_class(cd: ast.ClassDef*, trans: HT.Translator* = None) -> str:
|
||
"""Delegate to gen._get_parent_class"""
|
||
if _g_gen is not None: return _g_gen.ClassGenBase._get_parent_class(cd, trans)
|
||
return None
|
||
|
||
|
||
# ---------------- _register_generic_template (delegates to ClassGenGeneric._register_generic_template) ----------------
|
||
def _register_generic_template(pool: memhub.MemBuddy*, cd: ast.ClassDef*, module_sha1: str):
|
||
"""Delegate to gen._register_generic_template"""
|
||
if _g_gen is not None: _g_gen.ClassGenGeneric._register_generic_template(pool, cd, module_sha1)
|
||
|
||
|
||
# ---------------- _register_generic_func_template (delegates to ClassGenGeneric._register_generic_func_template) ----------------
|
||
def _register_generic_func_template(pool: memhub.MemBuddy*, fd: ast.FunctionDef*, module_sha1: str):
|
||
"""Delegate to gen.ClassGenGeneric._register_generic_func_template for scan pre-registration."""
|
||
if _g_gen is not None: _g_gen.ClassGenGeneric._register_generic_func_template(pool, fd, module_sha1)
|
||
|
||
|
||
# ---------------- _mangle_name_with_sha1 (delegates to FuncGenBase._mangle_name_with_sha1) ----------------
|
||
def _mangle_name_with_sha1(sha1: str, name: str) -> str:
|
||
"""Delegate to gen._mangle_name_with_sha1"""
|
||
if _g_gen is not None: return _g_gen.FuncGenBase._mangle_name_with_sha1(sha1, name)
|
||
return None
|
||
|
||
|
||
# ---------------- forward_declare_functions (delegates to FuncGenDef.forward_declare_functions) ----------------
|
||
def forward_declare_functions(trans: HT.Translator*, tree: ast.AST*) -> int:
|
||
"""Delegate to gen.forward_declare_functions"""
|
||
if _g_gen is not None: return _g_gen.FuncGenDef.forward_declare_functions(trans, tree)
|
||
return 0
|
||
|
||
|
||
# f-string escape rules: results point at the current function's stack buffer, so
|
||
# escaping positions fail-fast; use escape_fstring_copy to copy explicitly.
|
||
def fail_if_fstring_escape(node: ast.AST*, where: str) -> int:
|
||
"""Fail fast when an f-string sits in an escaping position such as a return value."""
|
||
if node is None: return 0
|
||
hit: int = 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.JoinedStr or k == ast.ASTKind.FormattedValue: hit = 1
|
||
elif k == ast.ASTKind.Tuple:
|
||
tp: ast.Tuple* = ast.Tuple*(node)
|
||
if tp.elts is not None:
|
||
en: sizet = len(tp.elts)
|
||
for i in range(en):
|
||
e: ast.AST* = tp.elts.get(i)
|
||
if e is not None:
|
||
ek: int = e.kind()
|
||
if ek == ast.ASTKind.JoinedStr or ek == ast.ASTKind.FormattedValue:
|
||
hit = 1
|
||
break
|
||
if hit == 0: return 0
|
||
if _g_gen is not None:
|
||
_g_gen.TypeGenErr.fatal_error(node, f"f-string result cannot be used in {where} (escape): f-string points at **the stack buffer of the current function**, " f"which becomes invalid once the function returns; carrying this pointer out of the function reads an already-popped frame" f"(historical incident: ASan stack-buffer-underflow in vsnprintf). " f"when the value must outlive the function, allocate and copy explicitly: " f"tmp: str = f\"...\"; out: str = GenApi.escape_fstring_copy(tmp); return out.", "TypeError")
|
||
return 0
|
||
|
||
|
||
def escape_fstring_copy(src: str) -> str:
|
||
"""Copy an f-string result onto the stdlib heap and return it; the only escape path."""
|
||
if src is None: return None
|
||
n: sizet = string.strlen(src)
|
||
out: str = stdlib.malloc(n + 1)
|
||
if out is None: return None
|
||
string.strcpy(out, src)
|
||
return out
|
||
|
||
|
||
# Stack-escape rule: the address of a stack object must not outlive the current frame.
|
||
# The judgement is now the unified **life-tag** mechanism (GenTypes define LIFE_*); the
|
||
# implementation lives in AssignGen.fail_if_life_escapes. It covers:
|
||
# (a) `&name` — explicit address of a local variable / parameter;
|
||
# (b) `name` — a bare local ARRAY used where a pointer is expected (array decay);
|
||
# (c) propagated borrows — `s: str = l` gives Life(s)=FRAME, so `return s` is caught.
|
||
# A bare name with a matching aggregate target is a value copy, never an escape.
|
||
def fail_if_stack_addr_escape(node: ast.AST*, where: str, trans: HT.Translator*, target_ty: mlirlite.LLVMType* = None) -> int:
|
||
"""Fail fast (LifetimeError) when the address of a stack object escapes the frame."""
|
||
if node is None or trans is None or _g_gen is None: return 0
|
||
return _g_gen.AssignGen.fail_if_life_escapes(node, where, trans, target_ty)
|
||
|
||
|
||
|
||
|
||
# ---------------- create_wrapper_main (delegates to TranslatorGenMixin.create_wrapper_main) ----------------
|
||
def create_wrapper_main(trans: HT.Translator*, tree: ast.AST*, i32_ty: mlirlite.LLVMType*) -> int:
|
||
"""Delegate to gen.create_wrapper_main"""
|
||
if _g_gen is not None: return _g_gen.TranslatorGen.create_wrapper_main(trans, tree, i32_ty)
|
||
return 0
|
||
|
||
|
||
# ---------------- handle_module_level_var (delegates to TranslatorGenMixin.handle_module_level_var) ----------------
|
||
def handle_module_level_var(trans: HT.Translator*, node: ast.AST*) -> int:
|
||
"""Delegate to gen.handle_module_level_var"""
|
||
if _g_gen is not None: return _g_gen.TranslatorGen.handle_module_level_var(trans, node)
|
||
return 0
|
||
|
||
|
||
# ---------------- translate_children (delegates to TranslatorGenMixin.translate_children) ----------------
|
||
def translate_children(trans: HT.Translator*, tree: ast.AST*) -> int:
|
||
"""Delegate to gen.translate_children"""
|
||
if _g_gen is not None: return _g_gen.TranslatorGen.translate_children(trans, tree)
|
||
return 0
|
||
|
||
|
||
# ---------------- init_symbol_table (delegates to VarGenMixin.init_symbol_table) ----------------
|
||
def init_symbol_table(pool: memhub.MemBuddy*) -> GenTypes.SymbolTable*:
|
||
"""Delegate to gen.init_symbol_table"""
|
||
if _g_gen is not None: return _g_gen.VarGen.init_symbol_table(pool)
|
||
return None
|
||
|
||
|
||
# ---------------- SetTempDir (delegates to CallGenBase.SetTempDir) ----------------
|
||
def SetTempDir(temp_dir: str):
|
||
"""Delegate to gen.SetTempDir"""
|
||
if _g_gen is not None: _g_gen.CallGenBase.SetTempDir(temp_dir)
|
||
|
||
|
||
# ---------------- find_func_in_module (delegates to CallGenBase.find_func_in_module) ----------------
|
||
def find_func_in_module(mod: mlirlite.LLVMModule*, name: str) -> mlirlite.Function*:
|
||
"""Delegate to gen.find_func_in_module"""
|
||
if _g_gen is not None: return _g_gen.CallGenBase.find_func_in_module(mod, name)
|
||
return None
|
||
|
||
|
||
# ---------------- add_func_to_table (delegates to CallGenLeafKit.add_func_to_table) ----------------
|
||
def add_func_to_table(funcs: GenTypes.FuncEntry*, func_count: int, name: str, func: mlirlite.Function*, max_count: int, defaults: t.CPtr = None, default_count: int = 0, param_count: int = 0, pool: memhub.MemBuddy* = None, def_sha1: str = None) -> int:
|
||
"""Delegate to gen.add_func_to_table; def_sha1 is the defining module's SHA1."""
|
||
if _g_gen is not None: return _g_gen.CallGenLeafKit.add_func_to_table(funcs, func_count, name, func, max_count, defaults, default_count, param_count, pool, def_sha1)
|
||
return 0
|
||
|
||
|
||
# ---------------- init_func_table (delegates to CallGenLeafKit.init_func_table) ----------------
|
||
def init_func_table(pool: memhub.MemBuddy*, max_count: int) -> GenTypes.FuncEntry*:
|
||
"""Delegate to gen.init_func_table"""
|
||
if _g_gen is not None: return _g_gen.CallGenLeafKit.init_func_table(pool, max_count)
|
||
return None
|
||
|
||
|
||
# ---------------- translate_call (delegates to CallGenMixin.translate_call) ----------------
|
||
def translate_call(pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator* = None) -> mlirlite.Value*:
|
||
"""Delegate to gen.translate_call"""
|
||
if _g_gen is not None: return _g_gen.CallGen.translate_call(pool, builder, mod, node, funcs_ptr, func_count, trans)
|
||
return None
|
||
|
||
|
||
# ---------------- translate_printf_call (delegates to CallGenLeafKit.translate_printf_call) ----------------
|
||
def translate_printf_call(pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, trans: HT.Translator* = None):
|
||
"""Delegate to gen.translate_printf_call"""
|
||
if _g_gen is not None: _g_gen.CallGenLeafKit.translate_printf_call(pool, builder, mod, cl, trans)
|
||
|
||
|
||
# ---------------- translate_print_call (delegates to CallGenLeafKit.translate_print_call) ----------------
|
||
def translate_print_call(pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, trans: HT.Translator* = None):
|
||
"""Delegate to gen.translate_print_call"""
|
||
if _g_gen is not None: _g_gen.CallGenLeafKit.translate_print_call(pool, builder, mod, cl, trans)
|
||
|
||
|
||
# ---------------- add_global_name (delegates to TranslatorGenMixin.add_global_name) ----------------
|
||
def add_global_name(trans: HT.Translator*, name: str):
|
||
"""Delegate to gen.TranslatorGen.add_global_name"""
|
||
if _g_gen is not None: _g_gen.TranslatorGen.add_global_name(trans, name)
|
||
|
||
|
||
# ---------------- is_global_name (delegates to TranslatorGenMixin.is_global_name) ----------------
|
||
def is_global_name(trans: HT.Translator*, name: str) -> int:
|
||
"""Delegate to gen.TranslatorGen.is_global_name"""
|
||
if _g_gen is not None: return _g_gen.TranslatorGen.is_global_name(trans, name)
|
||
return 0
|
||
|
||
|
||
# ---------------- add_nonlocal_name (delegates to TranslatorGenMixin.add_nonlocal_name) ----------------
|
||
def add_nonlocal_name(trans: HT.Translator*, name: str, var_ty: mlirlite.LLVMType* = None):
|
||
"""Delegate to gen.TranslatorGen.add_nonlocal_name"""
|
||
if _g_gen is not None: _g_gen.TranslatorGen.add_nonlocal_name(trans, name, var_ty)
|
||
|
||
|
||
# ---------------- get_nonlocal_type (delegates to TranslatorGenMixin.get_nonlocal_type) ----------------
|
||
def get_nonlocal_type(trans: HT.Translator*, name: str) -> mlirlite.LLVMType*:
|
||
"""Delegate to gen.TranslatorGen.get_nonlocal_type"""
|
||
if _g_gen is not None: return _g_gen.TranslatorGen.get_nonlocal_type(trans, name)
|
||
return None
|
||
|
||
|
||
# ---------------- is_nonlocal_name (delegates to TranslatorGenMixin.is_nonlocal_name) ----------------
|
||
def is_nonlocal_name(trans: HT.Translator*, name: str) -> int:
|
||
"""Delegate to gen.TranslatorGen.is_nonlocal_name"""
|
||
if _g_gen is not None: return _g_gen.TranslatorGen.is_nonlocal_name(trans, name)
|
||
return 0
|
||
|
||
|
||
# ---------------- get_nonlocal_index (delegates to TranslatorGenMixin.get_nonlocal_index) ----------------
|
||
def get_nonlocal_index(trans: HT.Translator*, name: str) -> int:
|
||
"""Delegate to gen.TranslatorGen.get_nonlocal_index"""
|
||
if _g_gen is not None: return _g_gen.TranslatorGen.get_nonlocal_index(trans, name)
|
||
return 0
|
||
|
||
|
||
# ---------------- clear_scope_names (delegates to TranslatorGenMixin.clear_scope_names) ----------------
|
||
def clear_scope_names(trans: HT.Translator*):
|
||
"""Delegate to gen.TranslatorGen.clear_scope_names"""
|
||
if _g_gen is not None: _g_gen.TranslatorGen.clear_scope_names(trans)
|
||
|
||
|
||
# ---------------- update_global_func_spec (delegates to CallGenLeafKit.update_global_func_spec) ----------------
|
||
def update_global_func_spec(name: str, func: mlirlite.Function*) -> int:
|
||
"""Delegate to gen.CallGenLeafKit.update_global_func_spec."""
|
||
if _g_gen is not None: return _g_gen.CallGenLeafKit.update_global_func_spec(name, func)
|
||
return 0
|