Files
ViperC/App/lib/core/Gen/GenApi.vp
T
TermiNexus d921dcd9e7 fix(gen): willFree 形参表访问先转 Arguments*,修复 TPC 侧 MemberLookupFailFast
FunctionDef.args 的字段静态类型是 AST*,直接写 fn.args.args 会在 AST 类上查 args(class_members=7 不含 args)。改为先 ast.Arguments*(fn.args) 再取 .args 列表,与 VpiReader / FuncGenMixin / ClassGenVTable 等既有写法一致。
2026-10-08 21:34:14 +08:00

733 lines
36 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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