refactor(callgen): annotate string values as char* (mechanical pass)
One-token annotation change across the call generators: str -> char*. No logic changes; the same pass also rewrote literal "string" in comments, which is why this is committed as a checkpoint rather than as behaviour.
This commit is contained in:
1 parent
cd78edd702
commit
84f11a69e7
8 files changed
+570
-570
No files matched your search
@@ -273,7 +273,7 @@ novirtual class CallGenBase:
|
||||
# appended by the caller) are preserved. Idempotent: _apply_auto_addr_arg passes an already-pointer
|
||||
# argument through, so a caller that also ran translate_call_arg does not double-address.
|
||||
def _apply_auto_addr_to_call_args(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*,
|
||||
trans: HT.Translator*, callee_name: str, arg_nodes: list[ast.AST*]*,
|
||||
trans: HT.Translator*, callee_name: char*, arg_nodes: list[ast.AST*]*,
|
||||
head: mlirlite.Value*, count: int, start_idx: int) -> mlirlite.Value*:
|
||||
"""Apply value-reference auto-address (&T / &temp T) to a call's user args; returns the chain head."""
|
||||
if head is None or count <= 0: return head
|
||||
@@ -305,7 +305,7 @@ novirtual class CallGenBase:
|
||||
mlirlite.value_set_next(new_tail, cur)
|
||||
return new_head
|
||||
|
||||
def _lookup_module_sha1(self, mod_name: str) -> str:
|
||||
def _lookup_module_sha1(self, mod_name: char*) -> str:
|
||||
"""Resolve a module name (or an already-resolved SHA1) to a SHA1; None if absent.
|
||||
|
||||
Re-export entries may store the defining SHA1 directly, so a 16-hex input is
|
||||
@@ -323,11 +323,11 @@ novirtual class CallGenBase:
|
||||
if is_hex != 0: return mod_name
|
||||
return StubMergerStore.LookupSha1ByModName(mod_name)
|
||||
|
||||
def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str:
|
||||
def _lookup_module_sha1_suffix(self, mod_suffix: char*) -> str:
|
||||
"""Look up a module SHA1 by suffix (e.g. "__types" matches "mlirlite.__types") for relative imports, via StubMerger.LookupSha1ByModNameSuffix."""
|
||||
return StubMergerStore.LookupSha1ByModNameSuffix(mod_suffix)
|
||||
|
||||
def _module_package_from_sha1(self, pool: memhub.MemBuddy*, mod_sha1: str) -> str:
|
||||
def _module_package_from_sha1(self, pool: memhub.MemBuddy*, mod_sha1: char*) -> str:
|
||||
"""Compute the module's package name (directory part, '/' to '.') from the SHA1 store's rel_path"""
|
||||
if pool is None or mod_sha1 is None: return None
|
||||
rel_arr_ptr: bytes = StubMergerStore.GetSha1StoreRelArrPtr()
|
||||
@@ -338,7 +338,7 @@ novirtual class CallGenBase:
|
||||
sidx: sizet = sizet(i) * 17
|
||||
if string.strcmp(sha1_arr_ptr + sidx, mod_sha1) != 0: continue
|
||||
ridx: sizet = sizet(i) * StubMerger.MAX_REL_PATH_LEN
|
||||
rel: str = rel_arr_ptr + ridx
|
||||
rel: char* = rel_arr_ptr + ridx
|
||||
# Includes are registered with a workspace-relative path ("includes/ast/__init__.vp")
|
||||
# because the scan root is the workspace, while the module name drops that prefix
|
||||
# ("ast", "ast.lexer"). Dropping it here too keeps re-export resolution (`from .lexer
|
||||
@@ -346,11 +346,11 @@ novirtual class CallGenBase:
|
||||
rel_off: sizet = 0
|
||||
if string.strncmp(rel, "includes/", 9) == 0: rel_off = 9
|
||||
rel = rel + rel_off
|
||||
last_slash: str = string.strrchr(rel, 47) # 47 = ord('/')
|
||||
last_slash: char* = string.strrchr(rel, 47) # 47 = ord('/')
|
||||
if last_slash is None: return None
|
||||
pkg_len: sizet = sizet(uint64(last_slash) - uint64(rel))
|
||||
if pkg_len == 0: return None
|
||||
pkg_buf: str = pool.alloc(pkg_len + 1)
|
||||
pkg_buf: char* = pool.alloc(pkg_len + 1)
|
||||
if pkg_buf is None: return None
|
||||
for pi in range(int(pkg_len)):
|
||||
if rel[pi] == '/': pkg_buf[pi] = '.'
|
||||
@@ -360,7 +360,7 @@ novirtual class CallGenBase:
|
||||
return None
|
||||
|
||||
|
||||
def _lookup_reexport_from_vpi(self, pool: memhub.MemBuddy*, mod_sha1: str, func_name: str, allow_star: int = 1) -> str:
|
||||
def _lookup_reexport_from_vpi(self, pool: memhub.MemBuddy*, mod_sha1: char*, func_name: char*, allow_star: int = 1) -> str:
|
||||
"""On a re-export table miss, parse the module's .vpi from-import statements to locate the defining module (the table may be empty since it is only populated during full translation).
|
||||
allow_star=0 skips `from X import *` candidates: they are unverified hints (the caller must
|
||||
check them), and a CLASS owner must never be taken from one -- nearly every file star-imports
|
||||
@@ -368,12 +368,12 @@ novirtual class CallGenBase:
|
||||
forward-declared as "stdint.TypeGenErr" this way, then every vpi/text.ll lookup missed)."""
|
||||
if pool is None or mod_sha1 is None or func_name is None: return None
|
||||
# accumulate star-import candidates (space-separated); caller validates each
|
||||
star_cands: str = None
|
||||
star_cands: char* = None
|
||||
star_cands_len: sizet = 0
|
||||
temp_dir: str = self.Gen.TypeGenBase.get_temp_dir()
|
||||
temp_dir: char* = self.Gen.TypeGenBase.get_temp_dir()
|
||||
if temp_dir is None: return None
|
||||
td_len: sizet = string.strlen(temp_dir)
|
||||
vpi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, mod_sha1, "vpi")
|
||||
vpi_path: char* = StubMergerCollect._sliced_path(temp_dir, td_len, mod_sha1, "vpi")
|
||||
if vpi_path is None: return None
|
||||
READ_SZ: sizet = 1048576
|
||||
buf: bytes = stdlib.malloc(READ_SZ)
|
||||
@@ -436,7 +436,7 @@ novirtual class CallGenBase:
|
||||
if allow_star == 0: continue
|
||||
star_dot: int = 0
|
||||
if buf[mod_start] == '.': star_dot = 1
|
||||
star_buf: str = pool.alloc(mod_end - mod_start + 1)
|
||||
star_buf: char* = pool.alloc(mod_end - mod_start + 1)
|
||||
if star_buf is not None:
|
||||
si2: sizet = 0
|
||||
while mod_start + si2 < mod_end:
|
||||
@@ -446,16 +446,16 @@ novirtual class CallGenBase:
|
||||
while star_buf[0] == '.': star_buf = star_buf + 1
|
||||
if string.strlen(star_buf) > 0:
|
||||
if star_dot != 0:
|
||||
spkg: str = self._module_package_from_sha1(pool, mod_sha1)
|
||||
spkg: char* = self._module_package_from_sha1(pool, mod_sha1)
|
||||
if spkg is not None:
|
||||
srl: sizet = string.strlen(spkg) + string.strlen(star_buf) + 2
|
||||
sres: str = pool.alloc(srl)
|
||||
sres: char* = pool.alloc(srl)
|
||||
if sres is not None:
|
||||
viperlib.snprintf(sres, srl, "%s.%s", spkg, star_buf)
|
||||
star_buf = sres
|
||||
# accumulate candidates (space-separated)
|
||||
sbl: sizet = string.strlen(star_buf)
|
||||
new_cands: str = pool.alloc(star_cands_len + sbl + 2)
|
||||
new_cands: char* = pool.alloc(star_cands_len + sbl + 2)
|
||||
if new_cands is not None:
|
||||
if star_cands is not None and star_cands_len > 0:
|
||||
string.strcpy(new_cands, star_cands)
|
||||
@@ -492,7 +492,7 @@ novirtual class CallGenBase:
|
||||
# hit: parse module name (leading dot -> relative, add pkg prefix)
|
||||
has_dot: int = 0
|
||||
if buf[mod_start] == '.': has_dot = 1
|
||||
mod_buf: str = pool.alloc(mod_end - mod_start + 1)
|
||||
mod_buf: char* = pool.alloc(mod_end - mod_start + 1)
|
||||
if mod_buf is None:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
@@ -506,12 +506,12 @@ novirtual class CallGenBase:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
if has_dot != 0:
|
||||
pkg: str = self._module_package_from_sha1(pool, mod_sha1)
|
||||
pkg: char* = self._module_package_from_sha1(pool, mod_sha1)
|
||||
if pkg is None:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
rl: sizet = string.strlen(pkg) + string.strlen(mod_buf) + 2
|
||||
res: str = pool.alloc(rl)
|
||||
res: char* = pool.alloc(rl)
|
||||
if res is None:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
@@ -530,7 +530,7 @@ novirtual class CallGenBase:
|
||||
return None
|
||||
|
||||
|
||||
def register_cexport_func(self, sha1: str, func_name: str) -> int:
|
||||
def register_cexport_func(self, sha1: char*, func_name: char*) -> int:
|
||||
"""Register a ExportT function into the global table (single source of truth in Gen.CallGenBase)"""
|
||||
if self.Gen is None or sha1 is None or func_name is None: return 0
|
||||
if self.Gen.CallGenBase.CexportSha1Arr is None:
|
||||
@@ -552,7 +552,7 @@ novirtual class CallGenBase:
|
||||
return 0
|
||||
|
||||
|
||||
def is_cexport_func(self, sha1: str, func_name: str) -> int:
|
||||
def is_cexport_func(self, sha1: char*, func_name: char*) -> int:
|
||||
"""Whether (sha1, func_name) is a ExportT function (reads the Gen.CallGenBase source of truth), falling back to the vpi return annotation on a registry miss."""
|
||||
if self.Gen is None or sha1 is None or func_name is None: return 0
|
||||
if self.Gen.CallGenBase.CexportSha1Arr is not None:
|
||||
@@ -566,7 +566,7 @@ novirtual class CallGenBase:
|
||||
|
||||
# RegisterStaticSymbol / IsStaticSymbol - static symbol registry: the four
|
||||
# syntaxes all normalize to t.StaticT; meaning = no cross-module use.
|
||||
def RegisterStaticSymbol(self, sha1: str, name: str) -> int:
|
||||
def RegisterStaticSymbol(self, sha1: char*, name: char*) -> int:
|
||||
"""Register a static symbol (defining module SHA1 + symbol name); 1=registered (idempotent) / 0=failure"""
|
||||
if self.Gen is None or sha1 is None or name is None: return 0
|
||||
if self.Gen.CallGenBase.StaticSha1Arr is None:
|
||||
@@ -594,7 +594,7 @@ novirtual class CallGenBase:
|
||||
return 0
|
||||
|
||||
|
||||
def IsStaticSymbol(self, sha1: str, name: str) -> int:
|
||||
def IsStaticSymbol(self, sha1: char*, name: char*) -> int:
|
||||
"""Whether (sha1, name) is a registered static symbol, the cross-module reference blocker; pairs (sha1, name) exactly to avoid same-name mistakes."""
|
||||
if self.Gen is None or sha1 is None or name is None: return 0
|
||||
if self.Gen.CallGenBase.StaticSha1Arr is None: return 0
|
||||
@@ -606,7 +606,7 @@ novirtual class CallGenBase:
|
||||
return 0
|
||||
|
||||
|
||||
def _is_cexport_func_from_vpi(self, sha1: str, func_name: str) -> int:
|
||||
def _is_cexport_func_from_vpi(self, sha1: char*, func_name: char*) -> int:
|
||||
"""Whether the vpi declares a bare-name function (`export def` / `extern def` / legacy ExportT)."""
|
||||
if sha1 is None or func_name is None: return 0
|
||||
if self.Gen is None or self.Gen.CallGenBase.TempDir is None or self.Gen.CallGenBase.TempDirLen <= 0: return 0
|
||||
@@ -614,45 +614,45 @@ novirtual class CallGenBase:
|
||||
# New vpi carries the storage marker as the `export`/`extern` prefix, not in the
|
||||
# return annotation; without this, cross-module calls mangle the name and link fails.
|
||||
if VpiReader._lookup_vpi_bare(sha1, None, func_name) != 0: return 1
|
||||
cexp_annot: str = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name)
|
||||
cexp_annot: char* = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name)
|
||||
if cexp_annot is None: return 0
|
||||
if string.strstr(cexp_annot, "ExportT") is not None: return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _is_state_func_from_vpi(self, pool: memhub.MemBuddy*, sha1: str, func_name: str) -> int:
|
||||
def _is_state_func_from_vpi(self, pool: memhub.MemBuddy*, sha1: char*, func_name: char*) -> int:
|
||||
"""Whether the vpi declares a bare-name external C function (`extern def` / legacy State)."""
|
||||
if pool is None or sha1 is None or func_name is None: return 0
|
||||
if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0: VpiReader._ensure_vpi_ret_annot_loaded(sha1, self.Gen.CallGenBase.TempDir)
|
||||
# `extern def` prefix (current vpi) => bare C symbol name.
|
||||
if VpiReader._lookup_vpi_bare(sha1, None, func_name) != 0: return 1
|
||||
state_annot: str = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name)
|
||||
state_annot: char* = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name)
|
||||
if state_annot is None: return 0
|
||||
# ret annotation contains "State" -> external C function
|
||||
if string.strstr(state_annot, "State") is not None: return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _lookup_mod_sha1(self, pool: memhub.MemBuddy*, from_imports: str, class_name: str, allow_star_fallback: int = 1) -> str:
|
||||
def _lookup_mod_sha1(self, pool: memhub.MemBuddy*, from_imports: char*, class_name: char*, allow_star_fallback: int = 1) -> str:
|
||||
"""Look up the SHA1 of the module owning a class found in from_imports; None if not found. allow_star_fallback=0 disables star-import fallback."""
|
||||
mod_name_raw: str = self.Gen.ImportsGen.lookup_from_import(from_imports, class_name, allow_star_fallback)
|
||||
mod_name_raw: char* = self.Gen.ImportsGen.lookup_from_import(from_imports, class_name, allow_star_fallback)
|
||||
if mod_name_raw is None: return None
|
||||
return self._lookup_sha1_from_modname_raw(pool, mod_name_raw)
|
||||
|
||||
|
||||
def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy*, mod_name_raw: str) -> str:
|
||||
def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy*, mod_name_raw: char*) -> str:
|
||||
"""Look up SHA1 from a raw module name; None if not found"""
|
||||
# find module-name end (space/null/':' alias sep), copy into a new buffer
|
||||
mod_len: sizet = 0
|
||||
while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':': mod_len += 1
|
||||
mod_name_buf: str = pool.alloc(mod_len + 1)
|
||||
mod_name_buf: char* = pool.alloc(mod_len + 1)
|
||||
if mod_name_buf is None: return None
|
||||
for mi in range(int(mod_len)): mod_name_buf[mi] = mod_name_raw[mi]
|
||||
mod_name_buf[mod_len] = '\0'
|
||||
# strip leading dots of relative import
|
||||
base_mod: str = mod_name_buf
|
||||
base_mod: char* = mod_name_buf
|
||||
while base_mod[0] == '.': base_mod = base_mod + 1
|
||||
sha1: str = self._lookup_module_sha1(base_mod)
|
||||
sha1: char* = self._lookup_module_sha1(base_mod)
|
||||
if sha1 is None: sha1 = self._lookup_module_sha1_suffix(base_mod)
|
||||
return sha1
|
||||
|
||||
@@ -675,7 +675,7 @@ novirtual class CallGenBase:
|
||||
p_cur = mlirlite.param_get_next(p_cur)
|
||||
return mlirlite.Func(pool, f_ref.RetTy, pn_head, p_cnt)
|
||||
|
||||
def find_func_in_module(self, mod: mlirlite.LLVMModule*, name: str, owner_sha1: str = None) -> mlirlite.Function*:
|
||||
def find_func_in_module(self, mod: mlirlite.LLVMModule*, name: char*, owner_sha1: char* = None) -> mlirlite.Function*:
|
||||
"""Find a function by name in the module's function list: exact then suffix match, honoring owner_sha1 for same-module priority."""
|
||||
if mod is None or name is None: return None
|
||||
name_len: sizet = string.strlen(name)
|
||||
@@ -686,7 +686,7 @@ novirtual class CallGenBase:
|
||||
declare_hit: mlirlite.Function* = None
|
||||
any_hit: mlirlite.Function* = None
|
||||
while cur is not None:
|
||||
cur_name: str = mlirlite.function_get_name(cur)
|
||||
cur_name: char* = mlirlite.function_get_name(cur)
|
||||
if cur_name is not None:
|
||||
# fast path: skip strcmp when first chars differ (mangled names start
|
||||
# with sha1 hex, bare names with letters/underscore)
|
||||
@@ -725,7 +725,7 @@ novirtual class CallGenBase:
|
||||
|
||||
|
||||
# _ensure_method_declare: create a declare in the current module when the stub is missing
|
||||
def _ensure_method_declare(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, call_name: str, ret_ty: mlirlite.LLVMType*, param_head: mlirlite.Value*, param_count: int):
|
||||
def _ensure_method_declare(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, call_name: char*, ret_ty: mlirlite.LLVMType*, param_head: mlirlite.Value*, param_count: int):
|
||||
"""Create a declare for a cross-module method call, appending missing params to an existing shorter declare (defines are left untouched)."""
|
||||
if pool is None or mod is None or call_name is None: return
|
||||
# list-walk sentinel (fail-fast): an unbounded walk would loop forever if a
|
||||
@@ -786,9 +786,9 @@ novirtual class CallGenBase:
|
||||
func.IsDeclared = 1
|
||||
# Prefer definition-side param types (from {sha1}.{cls}.{method} vpi
|
||||
# annotations): wider ints win, pointers always use the definition side.
|
||||
sha1_d: str = None
|
||||
cls_d: str = None
|
||||
meth_d: str = None
|
||||
sha1_d: char* = None
|
||||
cls_d: char* = None
|
||||
meth_d: char* = None
|
||||
if call_name is not None:
|
||||
# SHA1 prefix via single source GenApi.sha1_prefix_len (no hardcoded 17/16)
|
||||
sha1_pfx_d: int = GenApi.sha1_prefix_len(call_name)
|
||||
@@ -799,9 +799,9 @@ novirtual class CallGenBase:
|
||||
string.strncpy(sha1_buf_d, call_name, pfx_len_d - 1)
|
||||
sha1_buf_d[pfx_len_d - 1] = '\0'
|
||||
sha1_d = sha1_buf_d
|
||||
rest_d: str = call_name + pfx_len_d
|
||||
rest_d: char* = call_name + pfx_len_d
|
||||
# take the last '.': method has no dot; the first would truncate module-qualified args
|
||||
dot2_d: str = string.strrchr(rest_d, '.')
|
||||
dot2_d: char* = string.strrchr(rest_d, '.')
|
||||
if dot2_d is not None:
|
||||
cls_len_d: sizet = uint64(dot2_d) - uint64(rest_d)
|
||||
if cls_len_d > 0:
|
||||
@@ -812,7 +812,7 @@ novirtual class CallGenBase:
|
||||
cls_d = cls_buf_d
|
||||
meth_d = dot2_d + 1
|
||||
else: meth_d = rest_d
|
||||
prm_annots_d: str = None
|
||||
prm_annots_d: char* = None
|
||||
if sha1_d is not None and meth_d is not None: prm_annots_d = self._vpi_method_param_annot(pool, sha1_d, cls_d, meth_d)
|
||||
i32_ty_d: mlirlite.LLVMType* = mlirlite.Int32(pool)
|
||||
i8_ptr_d: mlirlite.LLVMType* = mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
@@ -853,8 +853,8 @@ novirtual class CallGenBase:
|
||||
def _call_ty_equal(self, pool: memhub.MemBuddy*, a: mlirlite.LLVMType*, b: mlirlite.LLVMType*) -> int:
|
||||
"""1 when both types have the same LLVM text (the canonical form used for emission)."""
|
||||
if a is None or b is None: return 0
|
||||
ta: str = self.Gen.ExprGenBase._type_text(pool, a)
|
||||
tb: str = self.Gen.ExprGenBase._type_text(pool, b)
|
||||
ta: char* = self.Gen.ExprGenBase._type_text(pool, a)
|
||||
tb: char* = self.Gen.ExprGenBase._type_text(pool, b)
|
||||
if ta is None or tb is None: return 0
|
||||
if string.strcmp(ta, tb) == 0: return 1
|
||||
return 0
|
||||
@@ -862,11 +862,11 @@ novirtual class CallGenBase:
|
||||
# _path_tail_is - 1 when the last `.`-separated segment of path equals name.
|
||||
# Discriminates `mod.Class.func()` (path tail = the class) from `mod.func()` (path tail = the
|
||||
# module) when a suffix lookup finds a dotted method symbol.
|
||||
def _path_tail_is(self, path: str, name: str) -> int:
|
||||
def _path_tail_is(self, path: char*, name: char*) -> int:
|
||||
"""1 when the last segment of path equals name."""
|
||||
if path is None or name is None: return 0
|
||||
dot: str = string.strrchr(path, 46)
|
||||
tail: str = path
|
||||
dot: char* = string.strrchr(path, 46)
|
||||
tail: char* = path
|
||||
if dot is not None: tail = dot + 1
|
||||
if tail[0] == '\0': return 0
|
||||
if string.strcmp(tail, name) == 0: return 1
|
||||
@@ -880,7 +880,7 @@ novirtual class CallGenBase:
|
||||
if func is None: return 0
|
||||
p: mlirlite.Param* = mlirlite.function_get_param_head(func)
|
||||
if p is None: return 0
|
||||
nm: str = mlirlite.param_get_name(p)
|
||||
nm: char* = mlirlite.param_get_name(p)
|
||||
if nm is None: return 1
|
||||
if string.strcmp(nm, "self") == 0: return 1
|
||||
if string.strcmp(nm, "cls") == 0: return 1
|
||||
@@ -894,7 +894,7 @@ novirtual class CallGenBase:
|
||||
# not accept, and only the MLIR verifier notices. Once the declare/definition exists it is
|
||||
# the authority: coerce each argument to its parameter type, use its return type, and fail
|
||||
# fast when a cross-module call site resolved a conflicting return type.
|
||||
def _call_symbol_ret_ty(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, call_name: str,
|
||||
def _call_symbol_ret_ty(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, call_name: char*,
|
||||
ret_ty: mlirlite.LLVMType*, node: ast.AST* = None) -> mlirlite.LLVMType*:
|
||||
"""Return type to emit for this call: the callee symbol's, validated against ret_ty."""
|
||||
if mod is None or call_name is None: return ret_ty
|
||||
@@ -922,7 +922,7 @@ novirtual class CallGenBase:
|
||||
# Positional alignment over the fixed params; a variadic callee's extra arguments (already
|
||||
# promoted to the C ABI) are left untouched.
|
||||
def _conform_call_args(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*,
|
||||
call_name: str, head: mlirlite.Value*, node: ast.AST* = None,
|
||||
call_name: char*, head: mlirlite.Value*, node: ast.AST* = None,
|
||||
trans: HT.Translator* = None) -> mlirlite.Value*:
|
||||
"""Rebuild the argument chain with every fixed argument coerced to its parameter type."""
|
||||
if head is None or call_name is None or mod is None: return head
|
||||
@@ -962,7 +962,7 @@ novirtual class CallGenBase:
|
||||
# `X*` / `X**` / `module.Class` / 裸类名 / 内建名 / typedef。
|
||||
# 只用最基础的字符串操作,不依赖 VpiReader 的多分支分段解析器:自举时该解析器可能
|
||||
# 误编译,让一个已注册的类解析失败。无法判定时返回 None,由后续完整解析器继续处理。
|
||||
def _resolve_vpi_annot_direct(self, pool: memhub.MemBuddy*, annot: str) -> mlirlite.LLVMType*:
|
||||
def _resolve_vpi_annot_direct(self, pool: memhub.MemBuddy*, annot: char*) -> mlirlite.LLVMType*:
|
||||
"""解析 vpi 注解里的指针写法:`X*` / `X**` / `const X*` / `module.Class`。
|
||||
不递归:先把 `const` / `volatile` 前缀剥掉,再统计尾部 `*` 的层数,
|
||||
最后只做一次类/枚举/typedef 查找并按层数包 Ptr。"""
|
||||
@@ -991,8 +991,8 @@ novirtual class CallGenBase:
|
||||
if nm_buf is None: return None
|
||||
string.strncpy(nm_buf, annot + st_i, end_i - st_i)
|
||||
nm_buf[end_i - st_i] = '\0'
|
||||
dot_n: str = string.strrchr(nm_buf, '.')
|
||||
cls_n: str = nm_buf
|
||||
dot_n: char* = string.strrchr(nm_buf, '.')
|
||||
cls_n: char* = nm_buf
|
||||
if dot_n is not None: cls_n = dot_n + 1
|
||||
base_ty: mlirlite.LLVMType* = GenApi.get_struct_type(cls_n)
|
||||
if base_ty is None: base_ty = GenApi.get_enum_base_type(cls_n)
|
||||
@@ -1006,7 +1006,7 @@ novirtual class CallGenBase:
|
||||
# (`GSList[Param]*`, `dict[str, X]*`) by specializing it on demand. VpiReader's string
|
||||
# resolver handles markers/named types only, so without this a generic return type falls
|
||||
# through to the i32 placeholder (现场: mlirlite.function_get_params -> GSList[Param]*).
|
||||
def _resolve_generic_annot_str(self, trans: HT.Translator*, pool: memhub.MemBuddy*, annot: str) -> mlirlite.LLVMType*:
|
||||
def _resolve_generic_annot_str(self, trans: HT.Translator*, pool: memhub.MemBuddy*, annot: char*) -> mlirlite.LLVMType*:
|
||||
"""Specialize `Base[Arg, ...]` (+ trailing '*') from an annotation string; None if not applicable."""
|
||||
if trans is None or pool is None or annot is None: return None
|
||||
a_len: sizet = string.strlen(annot)
|
||||
@@ -1031,7 +1031,7 @@ novirtual class CallGenBase:
|
||||
if lb >= end_i - 1: return None
|
||||
base_len: sizet = lb - st_i
|
||||
if base_len == 0: return None
|
||||
base_buf: str = pool.alloc(base_len + 1)
|
||||
base_buf: char* = pool.alloc(base_len + 1)
|
||||
if base_buf is None: return None
|
||||
string.strncpy(base_buf, annot + st_i, base_len)
|
||||
base_buf[base_len] = '\0'
|
||||
@@ -1047,7 +1047,7 @@ novirtual class CallGenBase:
|
||||
while seg_s < seg_e and annot[seg_s] == ' ': seg_s += 1
|
||||
while seg_e > seg_s and annot[seg_e - 1] == ' ': seg_e -= 1
|
||||
if seg_e > seg_s:
|
||||
ab: str = pool.alloc(seg_e - seg_s + 1)
|
||||
ab: char* = pool.alloc(seg_e - seg_s + 1)
|
||||
if ab is None: return None
|
||||
string.strncpy(ab, annot + seg_s, seg_e - seg_s)
|
||||
ab[seg_e - seg_s] = '\0'
|
||||
@@ -1057,7 +1057,7 @@ novirtual class CallGenBase:
|
||||
elif annot[ai] == ']': depth_g -= 1
|
||||
ai += 1
|
||||
if len(ta_list) == 0: return None
|
||||
spec: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, base_buf, ta_list)
|
||||
spec: char* = self.Gen.ClassGenGeneric._specialize_generic_class(trans, base_buf, ta_list)
|
||||
if spec is None: return None
|
||||
ty: mlirlite.LLVMType* = GenApi.get_struct_type(spec)
|
||||
if ty is None: ty = GenApi.get_enum_base_type(spec)
|
||||
@@ -1068,7 +1068,7 @@ novirtual class CallGenBase:
|
||||
k_l += 1
|
||||
return ty
|
||||
|
||||
def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: str, cls_name: str, method_name: str, trans: HT.Translator* = None, depth: int = 0) -> mlirlite.LLVMType*:
|
||||
def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: char*, cls_name: char*, method_name: char*, trans: HT.Translator* = None, depth: int = 0) -> mlirlite.LLVMType*:
|
||||
"""Get a method return type from the vpi stub annotation cache; None on miss"""
|
||||
if pool is None or cls_sha1 is None or method_name is None: return None
|
||||
# lazy import inside the function: VpiReader imports HandlesExprCall, a top-level import would cycle
|
||||
@@ -1077,7 +1077,7 @@ novirtual class CallGenBase:
|
||||
# on-demand load: read {temp_dir}/{sha1[0:2]}/{sha1}.vpi on cache miss,
|
||||
# covering method calls whose stub is not yet injected.
|
||||
if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0: VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, self.Gen.CallGenBase.TempDir)
|
||||
annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name)
|
||||
annot: char* = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name)
|
||||
# A re-export facade such as `io.vp` (`from _io import *`) has no own `def`;
|
||||
# the annotation is stored in the defining module's vpi. Follow the re-export
|
||||
# entry to that module before giving up.
|
||||
@@ -1098,7 +1098,7 @@ novirtual class CallGenBase:
|
||||
if ret_ty is None: ret_ty = self._resolve_generic_annot_str(trans, pool, annot)
|
||||
return ret_ty
|
||||
|
||||
def _vpi_module_defines(self, mod_sha1: str, func_name: str) -> int:
|
||||
def _vpi_module_defines(self, mod_sha1: char*, func_name: char*) -> int:
|
||||
"""Return 1 when the module's .vpi declares a module-level function with this name."""
|
||||
if mod_sha1 is None or func_name is None: return 0
|
||||
if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0:
|
||||
@@ -1106,7 +1106,7 @@ novirtual class CallGenBase:
|
||||
if VpiReader._lookup_vpi_ret_annot(mod_sha1, None, func_name) is not None: return 1
|
||||
return 0
|
||||
|
||||
def _is_reexport_owner(self, pool: memhub.MemBuddy*, mod_sha1: str, func_name: str, owner_full_name: str) -> int:
|
||||
def _is_reexport_owner(self, pool: memhub.MemBuddy*, mod_sha1: char*, func_name: char*, owner_full_name: char*) -> int:
|
||||
"""Return 1 when owner_full_name belongs to a re-export source of mod_sha1.
|
||||
|
||||
A module-qualified call on a facade (e.g. `io.ExpandEnvironmentPath`)
|
||||
@@ -1122,7 +1122,7 @@ novirtual class CallGenBase:
|
||||
osuf: sizet = own_len - fn_len
|
||||
if owner_full_name[osuf - 1] != '.': return 0
|
||||
if string.strcmp(owner_full_name + osuf, func_name) != 0: return 0
|
||||
rr_src: str = self.Gen.ImportsGen.lookup_reexport_call(mod_sha1, func_name)
|
||||
rr_src: char* = self.Gen.ImportsGen.lookup_reexport_call(mod_sha1, func_name)
|
||||
if rr_src is None: rr_src = self._lookup_reexport_from_vpi(pool, mod_sha1, func_name)
|
||||
if rr_src is None: return 0
|
||||
total: sizet = string.strlen(rr_src)
|
||||
@@ -1134,17 +1134,17 @@ novirtual class CallGenBase:
|
||||
while ri < total and rr_src[ri] != ' ': ri += 1
|
||||
seg_len: sizet = ri - seg_start
|
||||
if seg_len == 0: continue
|
||||
seg_buf: str = pool.alloc(seg_len + 1)
|
||||
seg_buf: char* = pool.alloc(seg_len + 1)
|
||||
if seg_buf is None: continue
|
||||
string.strncpy(seg_buf, rr_src + seg_start, seg_len)
|
||||
seg_buf[seg_len] = '\0'
|
||||
cand_sha1: str = self._lookup_module_sha1(seg_buf)
|
||||
cand_sha1: char* = self._lookup_module_sha1(seg_buf)
|
||||
if cand_sha1 is None: cand_sha1 = self._lookup_module_sha1_suffix(seg_buf)
|
||||
if cand_sha1 is not None:
|
||||
if string.strncmp(owner_full_name, cand_sha1, 16) == 0 and own_len > 17 and owner_full_name[16] == '.': return 1
|
||||
return 0
|
||||
|
||||
def _lookup_reexport_ret_ty(self, pool: memhub.MemBuddy*, cls_sha1: str, cls_name: str, method_name: str, trans: HT.Translator* = None, depth: int = 0) -> mlirlite.LLVMType*:
|
||||
def _lookup_reexport_ret_ty(self, pool: memhub.MemBuddy*, cls_sha1: char*, cls_name: char*, method_name: char*, trans: HT.Translator* = None, depth: int = 0) -> mlirlite.LLVMType*:
|
||||
"""Resolve a module-level function's return type through re-export entries.
|
||||
|
||||
The facade vpi has no `def`; the annotation belongs to the defining module.
|
||||
@@ -1154,7 +1154,7 @@ novirtual class CallGenBase:
|
||||
"""
|
||||
if depth >= 4 or pool is None or cls_sha1 is None or method_name is None: return None
|
||||
if cls_name is not None: return None
|
||||
rr_src: str = self.Gen.ImportsGen.lookup_reexport_call(cls_sha1, method_name)
|
||||
rr_src: char* = self.Gen.ImportsGen.lookup_reexport_call(cls_sha1, method_name)
|
||||
if rr_src is None: rr_src = self._lookup_reexport_from_vpi(pool, cls_sha1, method_name)
|
||||
if rr_src is None: return None
|
||||
total: sizet = string.strlen(rr_src)
|
||||
@@ -1166,18 +1166,18 @@ novirtual class CallGenBase:
|
||||
while ri < total and rr_src[ri] != ' ': ri += 1
|
||||
seg_len: sizet = ri - seg_start
|
||||
if seg_len == 0: continue
|
||||
seg_buf: str = pool.alloc(seg_len + 1)
|
||||
seg_buf: char* = pool.alloc(seg_len + 1)
|
||||
if seg_buf is None: continue
|
||||
string.strncpy(seg_buf, rr_src + seg_start, seg_len)
|
||||
seg_buf[seg_len] = '\0'
|
||||
rr_sha1: str = self._lookup_module_sha1(seg_buf)
|
||||
rr_sha1: char* = self._lookup_module_sha1(seg_buf)
|
||||
if rr_sha1 is None: rr_sha1 = self._lookup_module_sha1_suffix(seg_buf)
|
||||
if rr_sha1 is not None:
|
||||
ty: mlirlite.LLVMType* = self._lookup_method_ret_ty_via_vpi(pool, rr_sha1, cls_name, method_name, trans, depth + 1)
|
||||
if ty is not None: return ty
|
||||
return None
|
||||
|
||||
def _vpi_escape_packed(self, sha1: str, cls_name: str, method_name: str) -> int:
|
||||
def _vpi_escape_packed(self, sha1: char*, cls_name: char*, method_name: char*) -> int:
|
||||
"""跨模块逃逸摘要查询(v3):按 (定义模块 sha1, Class?, method) 查 .vpi 缓存;0=无摘要。
|
||||
|
||||
用"本模块已加载"备忘包住 _ensure_vpi_ret_annot_loaded(其内部是 O(N) 前缀判定):
|
||||
@@ -1194,7 +1194,7 @@ novirtual class CallGenBase:
|
||||
# lookup_escape_dir_via_vpi - 跨模块声明式指令契约(@life(escape(...)) / @life(noescape(...)))。
|
||||
# 本文件指令表按文件重置,跨模块调用点必为空,只能靠 .vpi 行尾的 esce=/escn= 传递;
|
||||
# noescape != 0 取"强制不逃逸位",否则取"强制逃逸位"。0 = 无该标注(含该模块未加载过)。
|
||||
def lookup_escape_dir_via_vpi(self, cls_sha1: str, class_name: str, func_name: str, noescape: int) -> int:
|
||||
def lookup_escape_dir_via_vpi(self, cls_sha1: char*, class_name: char*, func_name: char*, noescape: int) -> int:
|
||||
"""对方模块 .vpi 里落的契约掩码;0 = 无该标注"""
|
||||
if func_name is None or cls_sha1 is None: return 0
|
||||
return VpiReader._lookup_vpi_escape_dir(cls_sha1, class_name, func_name, noescape)
|
||||
@@ -1203,7 +1203,7 @@ novirtual class CallGenBase:
|
||||
# 与 escape/noescape 同一条 .vpi 通道(行尾 escr=);0 = 无声明(含该模块未加载过)。
|
||||
# 注意:本查询可能在调用点**之前**(life_of_expr 判右值生命期)发生,不能假定调用点的
|
||||
# 逃逸查询已把对方 vpi 载入,故这里自己走一次"本模块已加载"备忘 + 按需加载。
|
||||
def lookup_ret_kind_via_vpi(self, cls_sha1: str, class_name: str, func_name: str) -> int:
|
||||
def lookup_ret_kind_via_vpi(self, cls_sha1: char*, class_name: char*, func_name: char*) -> int:
|
||||
"""对方模块 .vpi 里落的 ret_kind;0 = 无声明"""
|
||||
if func_name is None or cls_sha1 is None: return 0
|
||||
if VpiReader._vpi_escape_module_loaded(cls_sha1) == 0:
|
||||
@@ -1217,7 +1217,7 @@ novirtual class CallGenBase:
|
||||
VpiReader._vpi_escape_mark_module(cls_sha1)
|
||||
return VpiReader._lookup_vpi_escape_dir(cls_sha1, class_name, func_name, 2)
|
||||
|
||||
def lookup_escape_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: str, cls_name: str, method_name: str) -> int:
|
||||
def lookup_escape_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: char*, cls_name: char*, method_name: char*) -> int:
|
||||
"""跨模块逃逸摘要(v3):本类 + MRO 祖先各自的模块 sha1 依次查 .vpi,返回打包值(0=无摘要)。
|
||||
|
||||
本文件的摘要表按文件重置,跨模块调用点上必为空,只能靠 .vpi 传递;
|
||||
@@ -1230,16 +1230,16 @@ novirtual class CallGenBase:
|
||||
mro: sizet* = self.Gen.StructGen.get_mro_chain(pool, cls_name)
|
||||
mi: int = 1
|
||||
while mro is not None and mro[mi] != 0:
|
||||
anc: str = rawptr(mro[mi])
|
||||
anc: char* = rawptr(mro[mi])
|
||||
if anc is not None and string.strcmp(anc, cls_name) != 0:
|
||||
sha_a: str = self.Gen.StructGen.get_struct_sha1(anc)
|
||||
sha_a: char* = self.Gen.StructGen.get_struct_sha1(anc)
|
||||
if sha_a is not None:
|
||||
pa: int = self._vpi_escape_packed(sha_a, anc, method_name)
|
||||
if pa != 0: return pa
|
||||
mi += 1
|
||||
return 0
|
||||
|
||||
def _vpi_willfree(self, sha1: str, cls_name: str, method_name: str) -> int:
|
||||
def _vpi_willfree(self, sha1: char*, cls_name: char*, method_name: char*) -> int:
|
||||
"""跨模块 willFree 标注查询(P2):按 (定义模块 sha1, Class?, method) 查 .vpi 缓存;0=无标注。
|
||||
|
||||
与逃逸摘要共用"本模块已加载"备忘:_ensure_vpi_ret_annot_loaded 的单一入口会把
|
||||
@@ -1251,7 +1251,7 @@ novirtual class CallGenBase:
|
||||
VpiReader._vpi_escape_mark_module(sha1)
|
||||
return VpiReader._lookup_vpi_willfree(sha1, cls_name, method_name)
|
||||
|
||||
def lookup_escape_clears_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: str, class_name: str, func_name: str, cargs: list[ast.AST*]*, can: sizet, param_base: int) -> int:
|
||||
def lookup_escape_clears_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: char*, class_name: char*, func_name: char*, cargs: list[ast.AST*]*, can: sizet, param_base: int) -> int:
|
||||
"""跨模块常量特化:把实参字面量装进常量环境,再向 vpi 缓存要"该清掉的位掩码";0 = 无命中
|
||||
|
||||
跨模块拿不到被调者函数体(只有 .vpi),所以用落盘的守卫表(`escg=`)而不是重算摘要。
|
||||
@@ -1262,7 +1262,7 @@ novirtual class CallGenBase:
|
||||
if fenv is None: return 0
|
||||
return VpiReader._lookup_vpi_escape_clears(cls_sha1, class_name, func_name, fenv)
|
||||
|
||||
def lookup_willfree_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: str, cls_name: str, method_name: str) -> int:
|
||||
def lookup_willfree_via_vpi(self, pool: memhub.MemBuddy*, cls_sha1: char*, cls_name: char*, method_name: char*) -> int:
|
||||
"""跨模块 willFree 掩码(P2):本类 + MRO 祖先各自的模块 sha1 依次查 .vpi;0=无标注"""
|
||||
if method_name is None: return 0
|
||||
if cls_sha1 is not None:
|
||||
@@ -1272,9 +1272,9 @@ novirtual class CallGenBase:
|
||||
mro: sizet* = self.Gen.StructGen.get_mro_chain(pool, cls_name)
|
||||
mi: int = 1
|
||||
while mro is not None and mro[mi] != 0:
|
||||
anc: str = rawptr(mro[mi])
|
||||
anc: char* = rawptr(mro[mi])
|
||||
if anc is not None and string.strcmp(anc, cls_name) != 0:
|
||||
sha_a: str = self.Gen.StructGen.get_struct_sha1(anc)
|
||||
sha_a: char* = self.Gen.StructGen.get_struct_sha1(anc)
|
||||
if sha_a is not None:
|
||||
pa: int = self._vpi_willfree(sha_a, anc, method_name)
|
||||
if pa != 0: return pa
|
||||
@@ -1282,7 +1282,7 @@ novirtual class CallGenBase:
|
||||
return 0
|
||||
|
||||
# _vpi_method_param_annot: on-demand lookup of the vpi param annotation string
|
||||
def _vpi_method_param_annot(self, pool: memhub.MemBuddy*, cls_sha1: str, cls_name: str, method_name: str) -> str:
|
||||
def _vpi_method_param_annot(self, pool: memhub.MemBuddy*, cls_sha1: char*, cls_name: char*, method_name: char*) -> str:
|
||||
"""Load and query the vpi parameter annotation string on demand; None on miss"""
|
||||
if pool is None or cls_sha1 is None or cls_name is None or method_name is None: return None
|
||||
# on-demand load: read {temp_dir}/{sha1[0:2]}/{sha1}.vpi on cache miss
|
||||
@@ -1290,7 +1290,7 @@ novirtual class CallGenBase:
|
||||
return VpiReader._lookup_vpi_param_annots(cls_sha1, cls_name, method_name)
|
||||
|
||||
# _vpi_resolve_param_annot_ty: parse a vpi param annotation segment into LLVMType
|
||||
def _vpi_resolve_param_annot_ty(self, pool: memhub.MemBuddy*, seg: str, src_sha1: str = None) -> mlirlite.LLVMType*:
|
||||
def _vpi_resolve_param_annot_ty(self, pool: memhub.MemBuddy*, seg: char*, src_sha1: char* = None) -> mlirlite.LLVMType*:
|
||||
"""Parse a single vpi parameter annotation segment into an LLVMType; None on failure"""
|
||||
if pool is None or seg is None: return None
|
||||
i32_ty: mlirlite.LLVMType* = mlirlite.Int32(pool)
|
||||
@@ -1301,7 +1301,7 @@ novirtual class CallGenBase:
|
||||
# _special_method_ret_ty: fixed return types for compiler built-in special methods
|
||||
|
||||
# ============================================================
|
||||
def _special_method_ret_ty(self, pool: memhub.MemBuddy*, class_name: str, method_name: str) -> mlirlite.LLVMType*:
|
||||
def _special_method_ret_ty(self, pool: memhub.MemBuddy*, class_name: char*, method_name: char*) -> mlirlite.LLVMType*:
|
||||
"""Fixed return type for compiler builtin special methods; None for non-special ones"""
|
||||
if pool is None or method_name is None: return None
|
||||
if string.strcmp(method_name, "__before_init__") == 0 or string.strcmp(method_name, "__init__") == 0: return mlirlite.Void(pool)
|
||||
@@ -1315,7 +1315,7 @@ novirtual class CallGenBase:
|
||||
# _fail_method_ret_ty: ERROR + abort when the method return type cannot be resolved
|
||||
|
||||
# ============================================================
|
||||
def _fail_method_ret_ty(self, method_name: str, node: ast.AST* = None, cls: str = None, anc: str = None, sha1: str = None, pool: memhub.MemBuddy* = None) -> mlirlite.LLVMType*:
|
||||
def _fail_method_ret_ty(self, method_name: char*, node: ast.AST* = None, cls: char* = None, anc: char* = None, sha1: char* = None, pool: memhub.MemBuddy* = None) -> mlirlite.LLVMType*:
|
||||
"""Fail fast when a method return type cannot be resolved precisely (module function, text.ll define, then vpi cache); never default to i32."""
|
||||
# NOTE: VLogger.error terminates the process in batch mode (sys.exit(1)), so the whole
|
||||
# report must be a SINGLE call -- anything after it is dead code (this is why a separate
|
||||
@@ -1324,30 +1324,30 @@ novirtual class CallGenBase:
|
||||
# Reports: receiver class, its registered struct sha1, the class/sha1 actually used for
|
||||
# the lookup (MRO fallback candidate), whether that module's text.ll exists, and the raw
|
||||
# vpi return-annotation string if the cache holds one.
|
||||
c_cls: str = cls
|
||||
c_cls: char* = cls
|
||||
if c_cls is None: c_cls = "?"
|
||||
c_anc: str = anc
|
||||
c_anc: char* = anc
|
||||
if c_anc is None: c_anc = "?"
|
||||
# Probe with the sha1 actually used for the lookup, falling back to the receiver class's
|
||||
# own registered sha1 when the caller passed none (so the dump is informative everywhere).
|
||||
probe_sha: str = sha1
|
||||
probe_sha: char* = sha1
|
||||
if probe_sha is None and anc is not None: probe_sha = self.Gen.StructGen.get_struct_sha1(anc)
|
||||
if probe_sha is None and cls is not None: probe_sha = self.Gen.StructGen.get_struct_sha1(cls)
|
||||
c_sha: str = probe_sha
|
||||
c_sha: char* = probe_sha
|
||||
if c_sha is None: c_sha = "?"
|
||||
c_st_sha: str = "?"
|
||||
c_st_sha: char* = "?"
|
||||
if cls is not None:
|
||||
st_sha_d: str = self.Gen.StructGen.get_struct_sha1(cls)
|
||||
st_sha_d: char* = self.Gen.StructGen.get_struct_sha1(cls)
|
||||
if st_sha_d is not None: c_st_sha = st_sha_d
|
||||
c_tll: int = 0
|
||||
c_vpi: str = "-"
|
||||
c_tail_ty: str = "-"
|
||||
c_annot_res: str = "-"
|
||||
c_vpi: char* = "-"
|
||||
c_tail_ty: char* = "-"
|
||||
c_annot_res: char* = "-"
|
||||
if probe_sha is not None:
|
||||
c_tll = self._dep_text_ll_exists(None, probe_sha)
|
||||
if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0:
|
||||
VpiReader._ensure_vpi_ret_annot_loaded(probe_sha, self.Gen.CallGenBase.TempDir)
|
||||
annot_d: str = VpiReader._lookup_vpi_ret_annot(probe_sha, cls, method_name)
|
||||
annot_d: char* = VpiReader._lookup_vpi_ret_annot(probe_sha, cls, method_name)
|
||||
if annot_d is not None:
|
||||
c_vpi = annot_d
|
||||
# Probe the string resolver here (caller's pool when available, same annotation)
|
||||
@@ -1363,12 +1363,12 @@ novirtual class CallGenBase:
|
||||
# Annotate the tail class of the raw annotation: "missing" = the class was never
|
||||
# registered (upstream bug); "struct"/"enum" = registered but the string resolver
|
||||
# still failed (resolver bug). Distinguishes the two without guessing.
|
||||
dot_d: str = string.strrchr(annot_d, '.')
|
||||
dot_d: char* = string.strrchr(annot_d, '.')
|
||||
if dot_d is not None:
|
||||
tail_len_d: sizet = string.strlen(dot_d + 1)
|
||||
tb_d: bytes = stdlib.malloc(tail_len_d + 1)
|
||||
if tb_d is not None:
|
||||
rb_d: str = string.strchr(dot_d + 1, ']')
|
||||
rb_d: char* = string.strchr(dot_d + 1, ']')
|
||||
if rb_d is not None: tail_len_d = sizet(uint64(rb_d) - uint64(dot_d + 1))
|
||||
string.strncpy(tb_d, dot_d + 1, tail_len_d)
|
||||
tb_d[tail_len_d] = '\0'
|
||||
@@ -1379,11 +1379,11 @@ novirtual class CallGenBase:
|
||||
# Same-named struct entries: find_struct returns the FIRST exact match, so an earlier bogus
|
||||
# registration (alias/forward/stale, different ModuleSha1) silently shadows the real one.
|
||||
dup_n_d: int = 0
|
||||
dup_last_d: str = "-"
|
||||
dup_last_d: char* = "-"
|
||||
# The entry's LLVM type name embeds "{sha1}.{Class}", i.e. the sha1 used when the entry
|
||||
# was first created (registration / forward-declare / stub injection) -- it reveals
|
||||
# provenance even if a later path overwrote ModuleSha1.
|
||||
dup_ty_nm_d: str = "-"
|
||||
dup_ty_nm_d: char* = "-"
|
||||
sc_n_d: int = self.Gen.StructGen.get_struct_count()
|
||||
sc_i_d: int = 0
|
||||
while sc_i_d < sc_n_d:
|
||||
@@ -1393,15 +1393,15 @@ novirtual class CallGenBase:
|
||||
dup_n_d += 1
|
||||
if e_d.ModuleSha1 is not None: dup_last_d = e_d.ModuleSha1
|
||||
if e_d.Ty is not None:
|
||||
nm_d: str = mlirlite.get_struct_name(e_d.Ty)
|
||||
nm_d: char* = mlirlite.get_struct_name(e_d.Ty)
|
||||
if nm_d is not None: dup_ty_nm_d = nm_d
|
||||
sc_i_d += 1
|
||||
# Current-file / defining-module sha1 at the moment of failure: distinguishes
|
||||
# "wrong sha1 captured during (vpi injection) forward-declare" from "correct sha1
|
||||
# overwritten later".
|
||||
cur_file_d: str = self.Gen.StructGen.get_file_module_sha1()
|
||||
cur_file_d: char* = self.Gen.StructGen.get_file_module_sha1()
|
||||
if cur_file_d is None: cur_file_d = "-"
|
||||
cur_def_d: str = self.Gen.StructGen.CurDefModuleSha1
|
||||
cur_def_d: char* = self.Gen.StructGen.CurDefModuleSha1
|
||||
if cur_def_d is None: cur_def_d = "-"
|
||||
VLogger.error(f"method return type cannot be obtained precisely (function/text.ll/vpi stub all missed): {method_name} | [diag] cls={c_cls} struct_sha1={c_st_sha} lookup_anc={c_anc} lookup_sha1={c_sha} text_ll={c_tll} vpi_annot={c_vpi} tail_ty={c_tail_ty} annot_res={c_annot_res} same_name_entries={dup_n_d} last_same_sha1={dup_last_d} entry_ty={dup_ty_nm_d} cur_file_sha1={cur_file_d} cur_def_sha1={cur_def_d}", "HandlesExprCall")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"method return type cannot be obtained precisely; defaulting to i32 would truncate pointers/i64: {method_name}", "TypeError")
|
||||
@@ -1410,7 +1410,7 @@ novirtual class CallGenBase:
|
||||
# SetTempDir: set the temp dir path (called before Phase A to read dependency text.ll)
|
||||
|
||||
# ============================================================
|
||||
def SetTempDir(self, temp_dir: str) -> None:
|
||||
def SetTempDir(self, temp_dir: char*) -> None:
|
||||
"""Set the temp directory path (single source of truth in Gen.CallGenBase)"""
|
||||
if self.Gen is None: return
|
||||
self.Gen.CallGenBase.TempDir = temp_dir
|
||||
@@ -1690,7 +1690,7 @@ novirtual class CallGenBase:
|
||||
return None
|
||||
|
||||
# _LookupCachedRetTyText: lookup the persistent "dependency text.ll return type" cache
|
||||
def _LookupCachedRetTyText(self, class_sha1: str, class_name: str, method_name: str, use_bare: int) -> str:
|
||||
def _LookupCachedRetTyText(self, class_sha1: char*, class_name: char*, method_name: char*, use_bare: int) -> str:
|
||||
"""Look up the return-type text cache: return the text on a hit, None on a miss"""
|
||||
if self.Gen is None or class_sha1 is None or method_name is None: return None
|
||||
ht: hashtable.HashTable* = self.Gen.CallGenBase.MethodRetTyMap
|
||||
@@ -1713,7 +1713,7 @@ novirtual class CallGenBase:
|
||||
return rawptr(v)
|
||||
|
||||
# _CacheModuleRetTyTexts: one pass to register all define lines and find the first match
|
||||
def _CacheModuleRetTyTexts(self, class_sha1: str, text_buf: bytes, text_len: sizet, pool: memhub.MemBuddy*, search_buf: str, search_str_len: sizet) -> mlirlite.LLVMType*:
|
||||
def _CacheModuleRetTyTexts(self, class_sha1: char*, text_buf: bytes, text_len: sizet, pool: memhub.MemBuddy*, search_buf: char*, search_str_len: sizet) -> mlirlite.LLVMType*:
|
||||
"""Single-pass register and lookup over all text.ll define lines (lookup only if table allocation fails)"""
|
||||
if text_buf is None or text_len == 0: return None
|
||||
# Merge the former two passes (register all, then scan again) into one
|
||||
@@ -1819,8 +1819,8 @@ novirtual class CallGenBase:
|
||||
rt_len = 5 # '#' + "none"
|
||||
else: rt_len = 1 + (ret_e - ret_s)
|
||||
else: rt_len = at_pos - (ls + 7)
|
||||
kcopy: str = perm.alloc(name_len + 1)
|
||||
tcopy: str = perm.alloc(rt_len + 1)
|
||||
kcopy: char* = perm.alloc(name_len + 1)
|
||||
tcopy: char* = perm.alloc(rt_len + 1)
|
||||
if kcopy is not None and tcopy is not None:
|
||||
string.strncpy(kcopy, text_buf + name_start, name_len)
|
||||
kcopy[name_len] = '\0'
|
||||
@@ -1849,7 +1849,7 @@ novirtual class CallGenBase:
|
||||
# _LookupMethodRetTyFromTextLL: read {temp_dir}/{sha1[0:2]}/{sha1}.text.ll and find the define line
|
||||
|
||||
# ============================================================
|
||||
def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy*, class_sha1: str, class_name: str, method_name: str, use_bare: int = 0) -> mlirlite.LLVMType*:
|
||||
def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy*, class_sha1: char*, class_name: char*, method_name: char*, use_bare: int = 0) -> mlirlite.LLVMType*:
|
||||
"""Look up a method return type in a dependency module's text.ll; use_bare=1 searches a module-level "{sha1}.{method_name}" define."""
|
||||
if pool is None or class_sha1 is None or method_name is None: return None
|
||||
if self.Gen.CallGenBase.TempDir is None or self.Gen.CallGenBase.TempDirLen == 0: return None
|
||||
@@ -1858,7 +1858,7 @@ novirtual class CallGenBase:
|
||||
if sha1_len < 2: return None
|
||||
|
||||
# cache hit: O(1) text retrieval, rebuilt with the caller pool; miss falls through
|
||||
cached_text: str = self._LookupCachedRetTyText(class_sha1, class_name, method_name, use_bare)
|
||||
cached_text: char* = self._LookupCachedRetTyText(class_sha1, class_name, method_name, use_bare)
|
||||
if cached_text is not None:
|
||||
# '#' prefix = MLIR type text (form marker written by _CacheModuleRetTyTexts)
|
||||
if cached_text[0] == '#': return self._ParseMlirRetTyStr(pool, cached_text, 1, string.strlen(cached_text))
|
||||
@@ -1931,7 +1931,7 @@ novirtual class CallGenBase:
|
||||
# _dep_text_ll_exists: probe whether {temp_dir}/{sha1[0:2]}/{sha1}.text.ll exists
|
||||
|
||||
# ============================================================
|
||||
def _dep_text_ll_exists(self, pool: memhub.MemBuddy*, sha1: str) -> int:
|
||||
def _dep_text_ll_exists(self, pool: memhub.MemBuddy*, sha1: char*) -> int:
|
||||
"""Probe whether {temp_dir}/{sha1[0:2]}/{sha1}.text.ll exists, 1=yes"""
|
||||
if self.Gen.CallGenBase.TempDir is None or self.Gen.CallGenBase.TempDirLen == 0 or sha1 is None: return 0
|
||||
sha1_len: sizet = string.strlen(sha1)
|
||||
|
||||
@@ -37,7 +37,7 @@ define LLVMIR_TEMPLATE_BUF = 4096
|
||||
novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
"""Translate c.* builtins, inline asm and raw LLVM IR."""
|
||||
|
||||
def _asm_append_cstr(self, dst: str, dst_size: sizet, src: str, what: str = "inline asm"):
|
||||
def _asm_append_cstr(self, dst: char*, dst_size: sizet, src: char*, what: char* = "inline asm"):
|
||||
"""Append the C string src to the end of dst; fail-fast when it does not fit.
|
||||
|
||||
Silent truncation corrupts the generated text (a template cut in the middle of an
|
||||
@@ -58,12 +58,12 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
dst[dlen + i] = '\0'
|
||||
|
||||
|
||||
def _asm_mangle_global_symbols(self, pool: memhub.MemBuddy*, asm_text: str, asm_size: sizet, mod: mlirlite.LLVMModule*) -> str:
|
||||
def _asm_mangle_global_symbols(self, pool: memhub.MemBuddy*, asm_text: char*, asm_size: sizet, mod: mlirlite.LLVMModule*) -> str:
|
||||
"""Fail-fast when inline asm references a SHA1-mangled module global by bare name."""
|
||||
if asm_text is None or mod is None: return asm_text
|
||||
src_len: sizet = string.strlen(asm_text)
|
||||
if src_len == 0: return asm_text
|
||||
out: str = pool.alloc(asm_size * 2)
|
||||
out: char* = pool.alloc(asm_size * 2)
|
||||
if out is None: return asm_text
|
||||
out[0] = '\0'
|
||||
out_pos: sizet = 0
|
||||
@@ -72,10 +72,10 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
matched: int = 0
|
||||
cur: mlirlite.GlobalVariable* = mod.GlobalHead
|
||||
while cur is not None:
|
||||
gname: str = cur.Name
|
||||
gname: char* = cur.Name
|
||||
if gname is not None and string.strchr(gname, 46) is not None:
|
||||
dot_g: str = string.strchr(gname, 46)
|
||||
bare_g: str = dot_g + 1
|
||||
dot_g: char* = string.strchr(gname, 46)
|
||||
bare_g: char* = dot_g + 1
|
||||
bare_len: sizet = string.strlen(bare_g)
|
||||
if bare_len > 0 and i + bare_len <= src_len:
|
||||
if string.strncmp(asm_text + i, bare_g, bare_len) == 0:
|
||||
@@ -108,11 +108,11 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
return out
|
||||
|
||||
|
||||
def _asm_escape_for_ir(self, pool: memhub.MemBuddy*, src: str) -> str:
|
||||
def _asm_escape_for_ir(self, pool: memhub.MemBuddy*, src: char*) -> str:
|
||||
"""Escape asm text for an LLVM IR string literal."""
|
||||
if src is None: return None
|
||||
slen: sizet = string.strlen(src)
|
||||
buf: str = pool.alloc(slen * 4 + 8)
|
||||
buf: char* = pool.alloc(slen * 4 + 8)
|
||||
if buf is None: return None
|
||||
pos: sizet = 0
|
||||
for ch in src:
|
||||
@@ -144,7 +144,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
return buf
|
||||
|
||||
|
||||
def _resolve_register(self, attr_name: str) -> str:
|
||||
def _resolve_register(self, attr_name: char*) -> str:
|
||||
"""Map an ASM_DESCR attribute name to its constraint string."""
|
||||
if attr_name is None: return ""
|
||||
|
||||
@@ -248,11 +248,11 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(node)
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
left_str: str = self._resolve_asm_descr(pool, bop.left)
|
||||
right_str: str = self._resolve_asm_descr(pool, bop.right)
|
||||
left_str: char* = self._resolve_asm_descr(pool, bop.left)
|
||||
right_str: char* = self._resolve_asm_descr(pool, bop.right)
|
||||
llen: sizet = string.strlen(left_str)
|
||||
rlen: sizet = string.strlen(right_str)
|
||||
buf: str = pool.alloc(llen + rlen + 1)
|
||||
buf: char* = pool.alloc(llen + rlen + 1)
|
||||
if buf is None: return ""
|
||||
string.strcpy(buf, left_str)
|
||||
for i in range(int(rlen)): buf[llen + i] = right_str[i]
|
||||
@@ -274,11 +274,11 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if k == ast.ASTKind.Name:
|
||||
nm_b: ast.Name* = ast.Name*(node)
|
||||
if nm_b.id is not None:
|
||||
rs_b: str = self._resolve_register(nm_b.id)
|
||||
rs_b: char* = self._resolve_register(nm_b.id)
|
||||
if rs_b is not None and rs_b[0] != '\0': return rs_b
|
||||
return ""
|
||||
|
||||
# Constant: string constant
|
||||
# Constant: char*ing constant
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant* = ast.Constant*(node)
|
||||
if cn.const_kind == ast.CONST_STR: return cn.str_val
|
||||
@@ -308,10 +308,10 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
return None
|
||||
|
||||
|
||||
def _asm_name_is_mangled(self, name: str) -> int:
|
||||
def _asm_name_is_mangled(self, name: char*) -> int:
|
||||
"""Return 1 when the LLVM name carries a SHA1-mangled prefix."""
|
||||
if name is None: return 0
|
||||
n: str = name
|
||||
n: char* = name
|
||||
nlen: sizet = string.strlen(n)
|
||||
# Strip the '@"..."' wrapper (reference name)
|
||||
if nlen >= 3 and n[0] == '@' and n[1] == '"' and n[nlen - 1] == '"': n = n + 2
|
||||
@@ -320,7 +320,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
return 0
|
||||
|
||||
|
||||
def _asm_add_operand(self, operands: GenTypes.AsmOperand*, count: int, val: mlirlite.Value*, constraint: str, is_output: int) -> int:
|
||||
def _asm_add_operand(self, operands: GenTypes.AsmOperand*, count: int, val: mlirlite.Value*, constraint: char*, is_output: int) -> int:
|
||||
"""Append an operand, dedup by value and direction, and return the new count."""
|
||||
# fail-fast: the operand array is fixed at ASM_MAX_OPERANDS slots; dropping the
|
||||
# excess operand here would silently change the generated constraint/argument lists.
|
||||
@@ -367,7 +367,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
string.memset(clobbers, 0, 8 * ASM_MAX_CLOBBERS)
|
||||
|
||||
# Allocate the asm text buffer
|
||||
asm_text: str = pool.alloc(ASM_TEXT_BUF_SIZE)
|
||||
asm_text: char* = pool.alloc(ASM_TEXT_BUF_SIZE)
|
||||
if asm_text is None: return None
|
||||
asm_text[0] = '\0'
|
||||
|
||||
@@ -409,7 +409,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
fexpr: ast.AST* = fv.value
|
||||
if fexpr is None or fexpr.kind() != ast.ASTKind.Call: continue
|
||||
fcall: ast.Call* = ast.Call*(fexpr)
|
||||
attr_nm: str = self._asm_is_c_call(fcall)
|
||||
attr_nm: char* = self._asm_is_c_call(fcall)
|
||||
if attr_nm is None: continue
|
||||
|
||||
is_out: int = 0
|
||||
@@ -421,7 +421,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if fargs is None or len(fargs) < 1: continue
|
||||
|
||||
val_node: ast.AST* = fargs.get(0)
|
||||
cons_str: str = ""
|
||||
cons_str: char* = ""
|
||||
if len(fargs) >= 2: cons_str = self._resolve_asm_descr(pool, fargs.get(1))
|
||||
|
||||
if is_out != 0:
|
||||
@@ -501,12 +501,12 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
oelt: ast.AST* = out_elts.get(oi)
|
||||
if oelt is None or oelt.kind() != ast.ASTKind.Call: continue
|
||||
ocall: ast.Call* = ast.Call*(oelt)
|
||||
oattr: str = self._asm_is_c_call(ocall)
|
||||
oattr: char* = self._asm_is_c_call(ocall)
|
||||
if oattr is None or string.strcmp(oattr, "AsmOut") != 0: continue
|
||||
oargs: list[ast.AST*]* = ocall.args
|
||||
if oargs is None or len(oargs) < 1: continue
|
||||
oval_node: ast.AST* = oargs.get(0)
|
||||
ocons: str = ""
|
||||
ocons: char* = ""
|
||||
if len(oargs) >= 2: ocons = self._resolve_asm_descr(pool, oargs.get(1))
|
||||
if oval_node is None or oval_node.kind() != ast.ASTKind.Name: continue
|
||||
onm: ast.Name* = ast.Name*(oval_node)
|
||||
@@ -530,12 +530,12 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
ielt: ast.AST* = in_elts.get(ii)
|
||||
if ielt is None or ielt.kind() != ast.ASTKind.Call: continue
|
||||
icall: ast.Call* = ast.Call*(ielt)
|
||||
iattr: str = self._asm_is_c_call(icall)
|
||||
iattr: char* = self._asm_is_c_call(icall)
|
||||
if iattr is None or string.strcmp(iattr, "AsmInp") != 0: continue
|
||||
iargs: list[ast.AST*]* = icall.args
|
||||
if iargs is None or len(iargs) < 1: continue
|
||||
ival_node: ast.AST* = iargs.get(0)
|
||||
icons: str = ""
|
||||
icons: char* = ""
|
||||
if len(iargs) >= 2: icons = self._resolve_asm_descr(pool, iargs.get(1))
|
||||
ival2: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, ival_node, None, 0, trans)
|
||||
if ival2 is None: continue
|
||||
@@ -551,7 +551,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
for ci in range(int(clen)):
|
||||
celt: ast.AST* = cl_elts.get(ci)
|
||||
if celt is None: continue
|
||||
cstr: str = self._resolve_asm_descr(pool, celt)
|
||||
cstr: char* = self._resolve_asm_descr(pool, celt)
|
||||
if cstr is None or cstr[0] == '\0': continue
|
||||
# fail-fast: the clobber slot array is fixed at ASM_MAX_CLOBBERS;
|
||||
# dropping the excess would silently weaken the clobber list.
|
||||
@@ -559,7 +559,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
self.Gen.TypeGenErr.fatal_error(celt, f"inline asm has more than {ASM_MAX_CLOBBERS} clobbers (compiler limit); remove duplicates or split the asm block", "TypeError")
|
||||
return None
|
||||
cl_addr: uint64 = uint64(clobbers) + clobber_count * 8
|
||||
cl_ptr: str* = (str*)(cl_addr)
|
||||
cl_ptr: char** = (str*)(cl_addr)
|
||||
cl_ptr[0] = cstr
|
||||
clobber_count += 1
|
||||
|
||||
@@ -574,13 +574,13 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
for pi in range(int(plen)):
|
||||
pelt: ast.AST* = pos_elts.get(pi)
|
||||
if pelt is None: continue
|
||||
pstr: str = self._resolve_asm_descr(pool, pelt)
|
||||
pstr: char* = self._resolve_asm_descr(pool, pelt)
|
||||
if pstr is None or pstr[0] == '\0': continue
|
||||
if clobber_count >= ASM_MAX_CLOBBERS:
|
||||
self.Gen.TypeGenErr.fatal_error(pelt, f"inline asm has more than {ASM_MAX_CLOBBERS} clobbers (compiler limit); remove duplicates or split the asm block", "TypeError")
|
||||
return None
|
||||
pcl_addr: uint64 = uint64(clobbers) + clobber_count * 8
|
||||
pcl_ptr: str* = (str*)(pcl_addr)
|
||||
pcl_ptr: char** = (str*)(pcl_addr)
|
||||
pcl_ptr[0] = pstr
|
||||
clobber_count += 1
|
||||
|
||||
@@ -700,7 +700,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if fv_fi < fv_count:
|
||||
orig_idx2: int = fv_orig_indices[fv_fi]
|
||||
new_idx2: int = orig_to_new[orig_idx2]
|
||||
ph_buf2: str = pool.alloc(16)
|
||||
ph_buf2: char* = pool.alloc(16)
|
||||
if ph_buf2 is not None:
|
||||
viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2)
|
||||
self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2)
|
||||
@@ -714,7 +714,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
# ~300 bytes, so the old fixed 512-byte cap could silently cut it. Overflow of this
|
||||
# (or any asm text buffer) is fail-fast in _asm_append_cstr.
|
||||
const_cap: sizet = ASM_CONST_BUF_SIZE + sizet(operand_count + clobber_count + 1) * 64
|
||||
const_buf: str = pool.alloc(const_cap)
|
||||
const_buf: char* = pool.alloc(const_cap)
|
||||
if const_buf is None: return None
|
||||
const_buf[0] = '\0'
|
||||
|
||||
@@ -722,7 +722,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
for ci2 in range(int(operand_count)):
|
||||
orig_i: int = new_order[ci2]
|
||||
cop: GenTypes.AsmOperand* = self._asm_get_operand(operands, orig_i)
|
||||
cons_val: str = cop.Constraint
|
||||
cons_val: char* = cop.Constraint
|
||||
if cons_val is None: cons_val = "r"
|
||||
|
||||
if first_const == 0: self._asm_append_cstr(const_buf, const_cap, ",")
|
||||
@@ -737,7 +737,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
# Append clobber constraints ~{name}
|
||||
for cidx in range(int(clobber_count)):
|
||||
cl_addr2: uint64 = uint64(clobbers) + cidx * 8
|
||||
cname: str = (str*)(cl_addr2)[0]
|
||||
cname: char* = (str*)(cl_addr2)[0]
|
||||
if cname is None or cname[0] == '\0': continue
|
||||
if first_const == 0: self._asm_append_cstr(const_buf, const_cap, ",")
|
||||
first_const = 0
|
||||
@@ -750,7 +750,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
# buffer from that worst case instead of underestimating it (544 bytes/operand
|
||||
# silently cut wide inlined named structs).
|
||||
asm_arg_cap: sizet = sizet(operand_count + 1) * 4224 + 64
|
||||
args_buf: str = pool.alloc(asm_arg_cap)
|
||||
args_buf: char* = pool.alloc(asm_arg_cap)
|
||||
if args_buf is None: return None
|
||||
args_buf[0] = '\0'
|
||||
|
||||
@@ -766,7 +766,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
first_arg = 0
|
||||
|
||||
# Type text
|
||||
ty_buf: str = pool.alloc_tagged(4096, memhub.DETSITE_CALLGENCBUILTIN_1150)
|
||||
ty_buf: char* = pool.alloc_tagged(4096, memhub.DETSITE_CALLGENCBUILTIN_1150)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
mlirlite.TypePrint(ty_buf, 4096, aval.Ty, pool)
|
||||
@@ -776,15 +776,15 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
|
||||
# 7. Escape the asm text. First replace bare symbols with mangled names
|
||||
# (lea rax, [rip + gdt] -> [rip + 054f5e56cbefcaa4.gdt]).
|
||||
mangled_asm: str = self._asm_mangle_global_symbols(pool, asm_text, ASM_TEXT_BUF_SIZE, mod)
|
||||
mangled_asm: char* = self._asm_mangle_global_symbols(pool, asm_text, ASM_TEXT_BUF_SIZE, mod)
|
||||
if mangled_asm is None: mangled_asm = asm_text
|
||||
escaped_asm: str = self._asm_escape_for_ir(pool, mangled_asm)
|
||||
escaped_asm: char* = self._asm_escape_for_ir(pool, mangled_asm)
|
||||
if escaped_asm is None: return None
|
||||
|
||||
# 8. Generate and emit the IR line
|
||||
# The line buffer is sized after ret_ty_buf is ready (see line_cap below)
|
||||
|
||||
ssa_name: str = None
|
||||
ssa_name: char* = None
|
||||
if is_void == 0:
|
||||
ssa_name = pool.alloc(16)
|
||||
if ssa_name is not None:
|
||||
@@ -792,7 +792,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
builder.Counter += 1
|
||||
|
||||
# Get the return type text
|
||||
ret_ty_buf: str = pool.alloc_tagged(4096, memhub.DETSITE_CALLGENCBUILTIN_1176)
|
||||
ret_ty_buf: char* = pool.alloc_tagged(4096, memhub.DETSITE_CALLGENCBUILTIN_1176)
|
||||
if ret_ty_buf is not None:
|
||||
ret_ty_buf[0] = '\0'
|
||||
mlirlite.TypePrint(ret_ty_buf, 4096, ret_ty, pool)
|
||||
@@ -801,7 +801,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
line_cap: sizet = 512 + string.strlen(escaped_asm) + string.strlen(args_buf)
|
||||
if const_buf is not None: line_cap += string.strlen(const_buf)
|
||||
if ret_ty_buf is not None: line_cap += string.strlen(ret_ty_buf)
|
||||
line: str = pool.alloc(line_cap)
|
||||
line: char* = pool.alloc(line_cap)
|
||||
if line is None: return None
|
||||
|
||||
if is_void == 1:
|
||||
@@ -823,13 +823,13 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if output_count > 1:
|
||||
# Multi-output: extractvalue index out_emit_idx, then store
|
||||
if oo.Value is not None and oo.Value.Ty is not None and oo.Value.Ty.Pointee != 0:
|
||||
ev_name: str = pool.alloc(32)
|
||||
ev_name: char* = pool.alloc(32)
|
||||
# Size the line from its actual parts: ret_ty_buf alone can be ~4096
|
||||
# bytes, so the old fixed cap could cut the instruction in half.
|
||||
ev_cap: sizet = ASM_LINE_BUF_SIZE + 64
|
||||
if ret_ty_buf is not None: ev_cap += string.strlen(ret_ty_buf)
|
||||
if ssa_name is not None: ev_cap += string.strlen(ssa_name)
|
||||
ev_line: str = pool.alloc(ev_cap)
|
||||
ev_line: char* = pool.alloc(ev_cap)
|
||||
if ev_name is not None and ev_line is not None:
|
||||
# ssa_name is "%N"; build a unique "%asm.N.e{i}" (letter-
|
||||
# initial) so %N.e{i} is not parsed as id plus a bad suffix.
|
||||
@@ -870,7 +870,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
elif tk == ast.ASTKind.Constant:
|
||||
cn_only: ast.Constant* = ast.Constant*(first_arg)
|
||||
if cn_only.str_val is not None: cap += string.strlen(cn_only.str_val)
|
||||
text: str = pool.alloc(cap)
|
||||
text: char* = pool.alloc(cap)
|
||||
if text is None: return None
|
||||
text[0] = '\0'
|
||||
|
||||
@@ -894,7 +894,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if fexpr is None: continue
|
||||
if fexpr.kind() == ast.ASTKind.Call:
|
||||
fcall: ast.Call* = ast.Call*(fexpr)
|
||||
attr_nm: str = self._asm_is_c_call(fcall)
|
||||
attr_nm: char* = self._asm_is_c_call(fcall)
|
||||
if attr_nm is not None:
|
||||
fargs: list[ast.AST*]* = fcall.args
|
||||
if fargs is None or len(fargs) < 1: continue
|
||||
@@ -909,7 +909,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
self.Gen.TypeGenErr.fatal_error(fcall, f"raw IR has more than {LLVMIR_MAX_OPS} input operands (compiler limit); split the block", "TypeError")
|
||||
return None
|
||||
in_vals[counts[0]] = sizet(inp_val)
|
||||
pname: str = pool.alloc(32)
|
||||
pname: char* = pool.alloc(32)
|
||||
if pname is not None:
|
||||
viperlib.snprintf(pname, 32, "%%in%d", counts[0])
|
||||
self._asm_append_cstr(text, cap, pname, "raw IR")
|
||||
@@ -931,7 +931,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
self.Gen.TypeGenErr.fatal_error(fcall, f"raw IR has more than {LLVMIR_MAX_OPS} output operands (compiler limit); split the block", "TypeError")
|
||||
return None
|
||||
out_vals[counts[1]] = sizet(alloca)
|
||||
rname: str = pool.alloc(32)
|
||||
rname: char* = pool.alloc(32)
|
||||
if rname is not None:
|
||||
viperlib.snprintf(rname, 32, "%%vpc_out%d", counts[1])
|
||||
self._asm_append_cstr(text, cap, rname, "raw IR")
|
||||
@@ -948,7 +948,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
|
||||
return text
|
||||
|
||||
def _raw_ir_emit_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, name: str, in_vals: sizet*, in_count: int, out_vals: sizet*, out_count: int) -> mlirlite.Value*:
|
||||
def _raw_ir_emit_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, name: char*, in_vals: sizet*, in_count: int, out_vals: sizet*, out_count: int) -> mlirlite.Value*:
|
||||
"""Emit the call to the generated raw function (inputs, then output pointers)."""
|
||||
total: int = in_count + out_count
|
||||
head: mlirlite.Value* = None
|
||||
@@ -965,14 +965,14 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
void_ty: mlirlite.LLVMType* = mlirlite.Void(pool)
|
||||
return mlirlite.build_call(builder, name, head, total, void_ty, 0)
|
||||
|
||||
def _raw_ir_func_name(self, pool: memhub.MemBuddy*, trans: HT.Translator*, tag: str) -> str:
|
||||
def _raw_ir_func_name(self, pool: memhub.MemBuddy*, trans: HT.Translator*, tag: char*) -> str:
|
||||
"""Unique symbol name for one generated raw function."""
|
||||
seq: int = self.Gen.CallGenBase.LLVMIRRegSeq + 1
|
||||
self.Gen.CallGenBase.LLVMIRRegSeq = seq
|
||||
sha1: str = trans.ModuleSha1
|
||||
sha1: char* = trans.ModuleSha1
|
||||
if sha1 is None: sha1 = "vpc"
|
||||
cap: sizet = string.strlen(sha1) + string.strlen(tag) + 48
|
||||
name: str = pool.alloc(cap)
|
||||
name: char* = pool.alloc(cap)
|
||||
if name is None: return None
|
||||
viperlib.snprintf(name, cap, "%s.%s_%d", sha1, tag, seq)
|
||||
return name
|
||||
@@ -994,19 +994,19 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
counts[0] = 0
|
||||
counts[1] = 0
|
||||
|
||||
body: str = self._raw_ir_template(pool, builder, mod, cl, trans, in_vals, out_vals, counts)
|
||||
body: char* = self._raw_ir_template(pool, builder, mod, cl, trans, in_vals, out_vals, counts)
|
||||
if body is None: return None
|
||||
in_count: int = counts[0]
|
||||
out_count: int = counts[1]
|
||||
|
||||
name: str = self._raw_ir_func_name(pool, trans, "__vpc_llvmir")
|
||||
name: char* = self._raw_ir_func_name(pool, trans, "__vpc_llvmir")
|
||||
if name is None: return None
|
||||
|
||||
# Sidecar definition: linkonce_odr + alwaysinline so llvm-link merges it with the
|
||||
# declaration and opt -passes=always-inline restores inline semantics.
|
||||
cap: sizet = string.strlen(body) + 256 + sizet(in_count + out_count) * 4352
|
||||
fn_buf: str = pool.alloc(cap)
|
||||
ty_buf: str = pool.alloc(4096)
|
||||
fn_buf: char* = pool.alloc(cap)
|
||||
ty_buf: char* = pool.alloc(4096)
|
||||
if fn_buf is None or ty_buf is None: return None
|
||||
fn_buf[0] = '\0'
|
||||
viperlib.snprintf(fn_buf, cap, "define linkonce_odr void @\"%s\"(", name)
|
||||
@@ -1082,17 +1082,17 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
counts[0] = 0
|
||||
counts[1] = 0
|
||||
|
||||
body: str = self._raw_ir_template(pool, builder, mod, cl, trans, in_vals, out_vals, counts)
|
||||
body: char* = self._raw_ir_template(pool, builder, mod, cl, trans, in_vals, out_vals, counts)
|
||||
if body is None: return None
|
||||
in_count: int = counts[0]
|
||||
out_count: int = counts[1]
|
||||
|
||||
name: str = self._raw_ir_func_name(pool, trans, "__vpc_mlir")
|
||||
name: char* = self._raw_ir_func_name(pool, trans, "__vpc_mlir")
|
||||
if name is None: return None
|
||||
|
||||
fn: mlirlite.Function* = mlirlite.create_function(pool, mod, name, mlirlite.Void(pool))
|
||||
if fn is None: return None
|
||||
pn: str = pool.alloc(32)
|
||||
pn: char* = pool.alloc(32)
|
||||
for k in range(in_count):
|
||||
v: mlirlite.Value* = mlirlite.Value*(in_vals[k])
|
||||
if v is None or v.Ty is None: return None
|
||||
@@ -1108,9 +1108,9 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
fn.Attrs = "alwaysinline"
|
||||
|
||||
cap: sizet = string.strlen(body) + 128 + sizet(out_count) * 8448
|
||||
raw: str = pool.alloc(cap)
|
||||
ty_buf: str = pool.alloc(4096)
|
||||
ptr_buf: str = pool.alloc(4096)
|
||||
raw: char* = pool.alloc(cap)
|
||||
ty_buf: char* = pool.alloc(4096)
|
||||
ptr_buf: char* = pool.alloc(4096)
|
||||
if raw is None or ty_buf is None or ptr_buf is None: return None
|
||||
string.strcpy(raw, body)
|
||||
pos: sizet = string.strlen(raw)
|
||||
|
||||
@@ -20,7 +20,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# (GEP vtable ptr -> load method slot -> bitcast -> call).
|
||||
|
||||
# ============================================================
|
||||
def _do_virtual_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, class_name: str, method_name: str, self_ptr: mlirlite.Value*, args_head: mlirlite.Value*, args_count: int, found_func: mlirlite.Function*, ret_ty: mlirlite.LLVMType*, vtable_base: mlirlite.Value* = None) -> mlirlite.Value*:
|
||||
def _do_virtual_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, class_name: char*, method_name: char*, self_ptr: mlirlite.Value*, args_head: mlirlite.Value*, args_count: int, found_func: mlirlite.Function*, ret_ty: mlirlite.LLVMType*, vtable_base: mlirlite.Value* = None) -> mlirlite.Value*:
|
||||
"""Call a virtual method indirectly through the vtable; returns None for void."""
|
||||
if pool is None or builder is None or class_name is None or method_name is None: return None
|
||||
if self_ptr is None or args_head is None: return None
|
||||
@@ -55,7 +55,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
for mi in range(int(vc_entry.VTableMethodCount)):
|
||||
mname_addr: sizet = methods_arr[mi]
|
||||
if mname_addr == 0: continue
|
||||
mname: str = rawptr(mname_addr)
|
||||
mname: char* = rawptr(mname_addr)
|
||||
if mname is not None and string.strcmp(mname, method_name) == 0:
|
||||
method_index = mi
|
||||
break
|
||||
@@ -146,7 +146,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# first argument (goes through virtual dispatch if the method is in the vtable).
|
||||
|
||||
# ============================================================
|
||||
def _call_method_on_ptr(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, class_name: str, method_name: str, self_ptr: mlirlite.Value*, extra_args: sizet*, extra_count: int, trans: HT.Translator*, node: ast.AST* = None, is_volatile: int = 0, arg_nodes: list[ast.AST*]* = None, recv_life: int = -1) -> mlirlite.Value*:
|
||||
def _call_method_on_ptr(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, class_name: char*, method_name: char*, self_ptr: mlirlite.Value*, extra_args: sizet*, extra_count: int, trans: HT.Translator*, node: ast.AST* = None, is_volatile: int = 0, arg_nodes: list[ast.AST*]* = None, recv_life: int = -1) -> mlirlite.Value*:
|
||||
"""Call a method on a struct pointer; adds a volatile barrier for constructors."""
|
||||
if pool is None or builder is None or class_name is None or method_name is None: return None
|
||||
if self_ptr is None: return None
|
||||
@@ -157,7 +157,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# `__new__` 不查:其形参与 __init__ 共享且可能被裁剪,位置对应不可靠。
|
||||
if arg_nodes is not None and string.strcmp(method_name, "__init__") == 0:
|
||||
esc_mask_ci: int = GenApi.get_param_escapes_method(pool, class_name, method_name)
|
||||
sha_ci: str = None
|
||||
sha_ci: char* = None
|
||||
if esc_mask_ci == 0:
|
||||
# 跨模块回退(v3):构造器常定义在别的模块(self.f = p 写在那边)
|
||||
sha_ci = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
@@ -201,7 +201,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if cmop_struct_ty is None and cmop_entry is not None: cmop_struct_ty = cmop_entry.Ty
|
||||
|
||||
# Build the lookup name: ClassName.method_name.
|
||||
lookup_name: str = pool.alloc(128)
|
||||
lookup_name: char* = pool.alloc(128)
|
||||
if lookup_name is None: return None
|
||||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
|
||||
|
||||
@@ -214,13 +214,13 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if arg_nodes is not None: m_argc2 = len(arg_nodes)
|
||||
ovl_m2: mlirlite.Function* = self.Gen.CallGenLeafKit.resolve_overload_call(pool, trans, trans._funcs, trans._func_count, lookup_name, trans.ModuleSha1, arg_nodes, m_argc2, node, 1, 1)
|
||||
if ovl_m2 is None: return None
|
||||
fn_sym2: str = mlirlite.function_get_name(ovl_m2)
|
||||
fn_sym2: char* = mlirlite.function_get_name(ovl_m2)
|
||||
if fn_sym2 is not None:
|
||||
pre_len2: sizet = 17 + string.strlen(lookup_name)
|
||||
if string.strlen(fn_sym2) > pre_len2:
|
||||
sfx2: str = fn_sym2 + pre_len2
|
||||
sfx2: char* = fn_sym2 + pre_len2
|
||||
short_cap2: sizet = string.strlen(method_name) + string.strlen(sfx2) + 1
|
||||
short_buf2: str = pool.alloc(short_cap2)
|
||||
short_buf2: char* = pool.alloc(short_cap2)
|
||||
if short_buf2 is not None:
|
||||
viperlib.snprintf(short_buf2, short_cap2, "%s%s", method_name, sfx2)
|
||||
method_name = short_buf2
|
||||
@@ -229,14 +229,14 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if m_ovl_done2 == 0: found_func = self.find_func_in_module(mod, lookup_name)
|
||||
|
||||
# Determine the call name.
|
||||
call_name: str = lookup_name
|
||||
call_name: char* = lookup_name
|
||||
if found_func is not None:
|
||||
found_name: str = mlirlite.function_get_name(found_func)
|
||||
found_name: char* = mlirlite.function_get_name(found_func)
|
||||
if found_name is not None: call_name = found_name
|
||||
else:
|
||||
# found_func is None (stub not injected): build the call name from the
|
||||
# class module SHA1, preferring the entry's SHA1.
|
||||
cls_sha1: str = None
|
||||
cls_sha1: char* = None
|
||||
if cmop_entry is not None: cls_sha1 = cmop_entry.ModuleSha1
|
||||
else: cls_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if cls_sha1 is None and trans is not None:
|
||||
@@ -245,15 +245,15 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if cls_sha1 is None:
|
||||
# [D6 truncation] Allocate by exact length instead of a fixed 256
|
||||
# buffer so long class/method names are not silently truncated.
|
||||
msg_fmt: str = "Class '%s' method '%s': module SHA1 not found"
|
||||
msg_fmt: char* = "Class '%s' method '%s': module SHA1 not found"
|
||||
msg_size: sizet = string.strlen(msg_fmt) + string.strlen(class_name) + string.strlen(method_name) - 4 + 1
|
||||
err_msg: str = pool.alloc(msg_size)
|
||||
err_msg: char* = pool.alloc(msg_size)
|
||||
if err_msg is not None:
|
||||
viperlib.snprintf(err_msg, msg_size, msg_fmt, class_name, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_msg)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Module SHA1 not found")
|
||||
# Build the call name: {cls_sha1}.{lookup_name}.
|
||||
mangled2: str = pool.alloc(string.strlen(cls_sha1) + string.strlen(lookup_name) + 2)
|
||||
mangled2: char* = pool.alloc(string.strlen(cls_sha1) + string.strlen(lookup_name) + 2)
|
||||
if mangled2 is not None:
|
||||
viperlib.snprintf(mangled2, string.strlen(cls_sha1) + string.strlen(lookup_name) + 2, "%s.%s", cls_sha1, lookup_name)
|
||||
call_name = mangled2
|
||||
@@ -267,9 +267,9 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0:
|
||||
# fail-fast: __getitem__/__new__ must return a pointer; a missing
|
||||
# return type means a broken stub declare (silent ptr truncation).
|
||||
msg_fmt1: str = "Cannot determine return type of method '%s' (stub declare return type missing)"
|
||||
msg_fmt1: char* = "Cannot determine return type of method '%s' (stub declare return type missing)"
|
||||
msg_size1: sizet = string.strlen(msg_fmt1) + string.strlen(method_name) - 2 + 1
|
||||
err_cm1: str = pool.alloc(msg_size1)
|
||||
err_cm1: char* = pool.alloc(msg_size1)
|
||||
if err_cm1 is not None:
|
||||
viperlib.snprintf(err_cm1, msg_size1, msg_fmt1, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_cm1)
|
||||
@@ -284,18 +284,18 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if cmop_struct_ty is not None: call_ret_ty = mlirlite.Ptr(pool, cmop_struct_ty)
|
||||
else:
|
||||
# [D6 truncation] Use exact length instead of a fixed 256 buffer.
|
||||
msg_fmt2: str = "Unknown self struct type of method '%s' (field type degraded, dependency module not preregistered?)"
|
||||
msg_fmt2: char* = "Unknown self struct type of method '%s' (field type degraded, dependency module not preregistered?)"
|
||||
msg_size2: sizet = string.strlen(msg_fmt2) + string.strlen(method_name) - 2 + 1
|
||||
err_cm2: str = pool.alloc(msg_size2)
|
||||
err_cm2: char* = pool.alloc(msg_size2)
|
||||
if err_cm2 is not None:
|
||||
viperlib.snprintf(err_cm2, msg_size2, msg_fmt2, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_cm2)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Unknown self struct type")
|
||||
elif string.strcmp(method_name, "__getitem__") == 0:
|
||||
# [D6 truncation] Use exact length instead of a fixed 256 buffer.
|
||||
msg_fmt3: str = "Method '%s.__getitem__': stub declare not injected (dependency module vpi missing or wrong topological order); cannot determine return type"
|
||||
msg_fmt3: char* = "Method '%s.__getitem__': stub declare not injected (dependency module vpi missing or wrong topological order); cannot determine return type"
|
||||
msg_size3: sizet = string.strlen(msg_fmt3) + string.strlen(class_name) - 2 + 1
|
||||
err_cm3: str = pool.alloc(msg_size3)
|
||||
err_cm3: char* = pool.alloc(msg_size3)
|
||||
if err_cm3 is not None:
|
||||
viperlib.snprintf(err_cm3, msg_size3, msg_fmt3, class_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_cm3)
|
||||
@@ -307,7 +307,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# is_local_mod exemption: when the target module is the one being
|
||||
# translated, take the return type from the current IR, not text.ll.
|
||||
if cls_sha1 is not None and trans is not None and trans.ModuleSha1 is not None and string.strncmp(cls_sha1, trans.ModuleSha1, 16) == 0:
|
||||
local_lk_cm2: str = pool.alloc(string.strlen(class_name) + string.strlen(method_name) + 2)
|
||||
local_lk_cm2: char* = pool.alloc(string.strlen(class_name) + string.strlen(method_name) + 2)
|
||||
if local_lk_cm2 is not None:
|
||||
viperlib.snprintf(local_lk_cm2, string.strlen(class_name) + string.strlen(method_name) + 2, "%s.%s", class_name, method_name)
|
||||
local_fn_cm2: mlirlite.Function* = self.find_func_in_module(mod, local_lk_cm2)
|
||||
@@ -331,7 +331,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# returns None and breaks expression translation).
|
||||
call_ret_ty = mlirlite.Int32(pool)
|
||||
else:
|
||||
err_cm4: str = pool.alloc(256)
|
||||
err_cm4: char* = pool.alloc(256)
|
||||
if err_cm4 is not None:
|
||||
viperlib.snprintf(err_cm4, 256, "Cannot determine return type of method '%s.%s' (neither text.ll nor vpi hit, cross-module stub not injected)", class_name, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_cm4)
|
||||
@@ -387,7 +387,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# depends on mdf_gd (the only holder of stdlib constant snapshots).
|
||||
# 必须带方法所属模块 SHA1:裸名跨模块会命中同名方法(`run`/`init`)的签名。
|
||||
mdf_gd: GenTypes.FuncDefaultsEntry* = None
|
||||
cmop_sha: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
cmop_sha: char* = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if cmop_sha is not None: mdf_gd = self.Gen.CallGenLeafKit.find_func_defaults(lookup_name, cmop_sha)
|
||||
if mdf_defaults is None and mdf_gd is not None:
|
||||
mdf_defaults = mdf_gd.Defaults
|
||||
@@ -396,9 +396,9 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
|
||||
# Cross-module stub fallback: when found_func is None and the table has no
|
||||
# ParamCount, fill it from the vpi cache to align declare/call with define.
|
||||
vpi_pa: str = None
|
||||
vpi_pa: char* = None
|
||||
if mdf_param_count == 0 and found_func is None:
|
||||
vpi_sha1_p: str = None
|
||||
vpi_sha1_p: char* = None
|
||||
if cmop_entry is not None and cmop_entry.ModuleSha1 is not None: vpi_sha1_p = cmop_entry.ModuleSha1
|
||||
else: vpi_sha1_p = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if vpi_sha1_p is not None:
|
||||
@@ -417,7 +417,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
ppcnt_f2: int = 0
|
||||
ppn_f2: mlirlite.Param* = mlirlite.function_get_param_head(found_func)
|
||||
while ppn_f2 is not None:
|
||||
fp_nm_f2: str = mlirlite.param_get_name(ppn_f2)
|
||||
fp_nm_f2: char* = mlirlite.param_get_name(ppn_f2)
|
||||
if fp_nm_f2 is None or (string.strcmp(fp_nm_f2, "%__eh_msg_out__") != 0 and string.strcmp(fp_nm_f2, "%__eh_code_out__") != 0):
|
||||
ppcnt_f2 += 1
|
||||
ppn_f2 = mlirlite.param_get_next(ppn_f2)
|
||||
@@ -555,7 +555,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
for cmop_mi in range(int(cmop_entry.VTableMethodCount)):
|
||||
cmop_mname_addr: sizet = cmop_methods_arr[cmop_mi]
|
||||
if cmop_mname_addr == 0: continue
|
||||
cmop_mname: str = rawptr(cmop_mname_addr)
|
||||
cmop_mname: char* = rawptr(cmop_mname_addr)
|
||||
if cmop_mname is not None and string.strcmp(cmop_mname, method_name) == 0:
|
||||
cmop_method_idx = cmop_mi
|
||||
break
|
||||
@@ -600,14 +600,14 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# land on a procedure. A generic instance (Class[T]) is emitted in this module only after all
|
||||
# bodies, so the call site cannot read its signature; the template method is the only source.
|
||||
# No return annotation = procedure = void, matching the unified body pipeline.
|
||||
def _predicted_generic_method_is_void(self, pool: memhub.MemBuddy*, class_name: str, method_name: str) -> int:
|
||||
def _predicted_generic_method_is_void(self, pool: memhub.MemBuddy*, class_name: char*, method_name: char*) -> int:
|
||||
"""1 when the template method (of a Class[T] instance) has no return annotation."""
|
||||
if class_name is None or method_name is None: return 0
|
||||
br: str = string.strchr(class_name, '[')
|
||||
br: char* = string.strchr(class_name, '[')
|
||||
if br is None: return 0
|
||||
bare_len: sizet = sizet(uint64(br) - uint64(class_name))
|
||||
if bare_len == 0: return 0
|
||||
bare: str = pool.alloc(bare_len + 1)
|
||||
bare: char* = pool.alloc(bare_len + 1)
|
||||
if bare is None: return 0
|
||||
string.strncpy(bare, class_name, bare_len)
|
||||
bare[bare_len] = '\0'
|
||||
@@ -642,7 +642,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# object pointer (obj_ptr, an alloca of Ptr(StructTy)) as the self argument.
|
||||
|
||||
# ============================================================
|
||||
def _translate_method_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, class_name: str, method_name: str, obj_ptr: mlirlite.Value*, cl: ast.Call*, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
def _translate_method_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, class_name: char*, method_name: char*, obj_ptr: mlirlite.Value*, cl: ast.Call*, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
"""Translate a method call; returns the call result Value."""
|
||||
if pool is None or builder is None or class_name is None or method_name is None: return None
|
||||
if obj_ptr is None or cl is None: return None
|
||||
@@ -653,7 +653,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
cargs_mc: list[ast.AST*]* = cl.args
|
||||
if cargs_mc is not None:
|
||||
esc_mask_mc: int = GenApi.get_param_escapes_method(pool, class_name, method_name)
|
||||
sha_mc: str = None
|
||||
sha_mc: char* = None
|
||||
if esc_mask_mc == 0:
|
||||
# 跨模块回退(v3):本文件摘要表按文件重置,跨模块只能查 .vpi 落盘的摘要
|
||||
sha_mc = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
@@ -702,19 +702,19 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if cargs_mc is not None:
|
||||
wf_mask_mc = GenApi.get_param_willfree_method(pool, class_name, method_name)
|
||||
if wf_mask_mc == 0:
|
||||
sha_wf_mc: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
sha_wf_mc: char* = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
wf_mask_mc = self.Gen.CallGenBase.lookup_willfree_via_vpi(pool, sha_wf_mc, class_name, method_name)
|
||||
|
||||
# list generic container method: dispatch to _translate_list_builtin_call inline
|
||||
# when the method is a list builtin; use the receiver's actual struct name.
|
||||
lb_src: str = class_name
|
||||
lb_src: char* = class_name
|
||||
if lb_src is None or lb_src[0] == '\0':
|
||||
lb_sty_s: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(obj_ptr)
|
||||
if lb_sty_s is not None:
|
||||
lb_nm_s: str = mlirlite.get_struct_name(lb_sty_s)
|
||||
lb_nm_s: char* = mlirlite.get_struct_name(lb_sty_s)
|
||||
if lb_nm_s is not None: lb_src = lb_nm_s
|
||||
if method_name is not None and lb_src is not None:
|
||||
lb_cls: str = lb_src
|
||||
lb_cls: char* = lb_src
|
||||
# Strip the cross-module specialization sha1 prefix "{16hex}." using
|
||||
# the single source GenApi.sha1_prefix_len.
|
||||
lb_pfx_d: int = GenApi.sha1_prefix_len(lb_cls)
|
||||
@@ -744,7 +744,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
|
||||
# [D25 fail-fast] A non-builtin method call on a bare generic template base
|
||||
# (e.g. "list") has an unknown element type; fail fast rather than assume it.
|
||||
cm_bare: str = None
|
||||
cm_bare: char* = None
|
||||
if lb_src is not None:
|
||||
cm_pfx: int = GenApi.sha1_prefix_len(lb_src)
|
||||
cm_bare = lb_src + cm_pfx if cm_pfx != 0 else lb_src
|
||||
@@ -762,13 +762,13 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
|
||||
# [D25] Generic container receivers use the actual struct name (the IR-level
|
||||
# truth); resolve via CallGenProp._resolve_generic_receiver_name.
|
||||
mc_act_d: str = self.Gen.CallGenProp._resolve_generic_receiver_name(pool, mc_struct_ty, method_name, cl)
|
||||
mc_act_d: char* = self.Gen.CallGenProp._resolve_generic_receiver_name(pool, mc_struct_ty, method_name, cl)
|
||||
if mc_act_d is not None: class_name = mc_act_d
|
||||
|
||||
# Build the lookup name; allocate by exact length ([D6]) since the
|
||||
# specialized class name can be long (e.g. list[rawptr[sha.AST]]).
|
||||
lk_cap: sizet = string.strlen(class_name) + string.strlen(method_name) + 2
|
||||
lookup_name: str = pool.alloc(lk_cap)
|
||||
lookup_name: char* = pool.alloc(lk_cap)
|
||||
if lookup_name is None: return None
|
||||
viperlib.snprintf(lookup_name, lk_cap, "%s.%s", class_name, method_name)
|
||||
|
||||
@@ -784,13 +784,13 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if m_args_o is not None: m_argc_o = len(m_args_o)
|
||||
ovl_m: mlirlite.Function* = self.Gen.CallGenLeafKit.resolve_overload_call(pool, trans, trans._funcs, trans._func_count, lookup_name, trans.ModuleSha1, m_args_o, m_argc_o, cl.func, 1, 1)
|
||||
if ovl_m is None: return None
|
||||
fn_sym_o: str = mlirlite.function_get_name(ovl_m)
|
||||
fn_sym_o: char* = mlirlite.function_get_name(ovl_m)
|
||||
if fn_sym_o is not None:
|
||||
pre_len_o: sizet = 17 + string.strlen(lookup_name)
|
||||
if string.strlen(fn_sym_o) > pre_len_o:
|
||||
sfx_o: str = fn_sym_o + pre_len_o
|
||||
sfx_o: char* = fn_sym_o + pre_len_o
|
||||
short_cap: sizet = string.strlen(method_name) + string.strlen(sfx_o) + 1
|
||||
short_buf_o: str = pool.alloc(short_cap)
|
||||
short_buf_o: char* = pool.alloc(short_cap)
|
||||
if short_buf_o is not None:
|
||||
viperlib.snprintf(short_buf_o, short_cap, "%s%s", method_name, sfx_o)
|
||||
method_name = short_buf_o
|
||||
@@ -804,20 +804,20 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# ({sha1}.list[int].get), so match by suffix using mc_entry.Name.
|
||||
if found_func is None and mc_entry is not None and mc_entry.Name is not None:
|
||||
if string.strcmp(mc_entry.Name, class_name) != 0:
|
||||
spec_lookup: str = pool.alloc(160)
|
||||
spec_lookup: char* = pool.alloc(160)
|
||||
if spec_lookup is not None:
|
||||
viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name)
|
||||
found_func = self.find_func_in_module(mod, spec_lookup)
|
||||
|
||||
# Walk the MRO ancestor chain for the parent method (first parent wins).
|
||||
mc_anc: str = None # the method's defining class (for multi-inheritance this-adjust)
|
||||
mc_anc: char* = None # the method's defining class (for multi-inheritance this-adjust)
|
||||
if found_func is None:
|
||||
mro_ptr: sizet* = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||||
mi: int = 1
|
||||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||||
anc: str = rawptr(mro_ptr[mi])
|
||||
anc: char* = rawptr(mro_ptr[mi])
|
||||
if anc is not None:
|
||||
parent_lookup: str = pool.alloc(128)
|
||||
parent_lookup: char* = pool.alloc(128)
|
||||
if parent_lookup is not None:
|
||||
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, method_name)
|
||||
parent_func: mlirlite.Function* = self.find_func_in_module(mod, parent_lookup)
|
||||
@@ -832,7 +832,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if found_func is None:
|
||||
sib_recv_local: int = 1
|
||||
if trans is not None and trans.ModuleSha1 is not None:
|
||||
sib_recv_sha1: str = None
|
||||
sib_recv_sha1: char* = None
|
||||
if mc_entry is not None and mc_entry.ModuleSha1 is not None: sib_recv_sha1 = mc_entry.ModuleSha1
|
||||
else: sib_recv_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if sib_recv_sha1 is not None:
|
||||
@@ -844,12 +844,12 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
while sc_i < sc_n and found_func is None:
|
||||
cand_entry: GenTypes.StructEntry* = self.Gen.StructGen._get_struct_entry(sc_i)
|
||||
if cand_entry is not None and cand_entry.Name is not None:
|
||||
cand_name: str = cand_entry.Name
|
||||
cand_name: char* = cand_entry.Name
|
||||
if string.strcmp(cand_name, class_name) != 0:
|
||||
# Specialized generic class name contains '[': not a Mixin candidate.
|
||||
if string.strchr(cand_name, '[') is None:
|
||||
if self._mixin_sibling_same_composite(pool, class_name, cand_name) != 0:
|
||||
cand_lookup: str = pool.alloc(128)
|
||||
cand_lookup: char* = pool.alloc(128)
|
||||
if cand_lookup is not None:
|
||||
viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name)
|
||||
cand_func: mlirlite.Function* = self.find_func_in_module(mod, cand_lookup)
|
||||
@@ -860,9 +860,9 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
|
||||
# Determine the call name (default "ClassName.method"; when not found, build
|
||||
# it along the MRO using the defining class's SHA1).
|
||||
call_name: str = lookup_name
|
||||
call_name: char* = lookup_name
|
||||
if found_func is not None:
|
||||
found_name: str = mlirlite.function_get_name(found_func)
|
||||
found_name: char* = mlirlite.function_get_name(found_func)
|
||||
if found_name is not None: call_name = found_name
|
||||
|
||||
# Determine the return type.
|
||||
@@ -878,8 +878,8 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
call_ret_ty = sp_ty2
|
||||
# Special methods (e.g. __before_init__) also need the sha1 prefix on
|
||||
# cross-module calls, else the bare name links to an undefined symbol.
|
||||
sp_anc_name: str = class_name
|
||||
sp_anc_sha1: str = None
|
||||
sp_anc_name: char* = class_name
|
||||
sp_anc_sha1: char* = None
|
||||
if mc_entry is not None: sp_anc_sha1 = mc_entry.ModuleSha1
|
||||
else: sp_anc_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if sp_anc_sha1 is None and mc_struct_ty is not None:
|
||||
@@ -889,7 +889,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# Only extract sha1 when the type name is "{16hex}.{Class}"
|
||||
# (via GenApi.sha1_prefix_len), avoiding false positives.
|
||||
if GenApi.sha1_prefix_len(type_name_sp) != 0:
|
||||
sb_sp: str = pool.alloc(17)
|
||||
sb_sp: char* = pool.alloc(17)
|
||||
if sb_sp is not None:
|
||||
string.strncpy(sb_sp, type_name_sp, 16)
|
||||
sb_sp[16] = '\0'
|
||||
@@ -898,15 +898,15 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
pass
|
||||
if sp_anc_sha1 is not None:
|
||||
ml_sp: sizet = string.strlen(sp_anc_sha1) + string.strlen(sp_anc_name) + string.strlen(method_name) + 3
|
||||
mangled_sp: str = pool.alloc(ml_sp)
|
||||
mangled_sp: char* = pool.alloc(ml_sp)
|
||||
if mangled_sp is not None:
|
||||
viperlib.snprintf(mangled_sp, ml_sp, "%s.%s.%s", sp_anc_sha1, sp_anc_name, method_name)
|
||||
call_name = mangled_sp
|
||||
else:
|
||||
# The method's defining class (source of cross-module name / return
|
||||
# type); defaults to class_name and updates on MRO fallback.
|
||||
ret_anc_name: str = class_name
|
||||
ret_anc_sha1: str = None
|
||||
ret_anc_name: char* = class_name
|
||||
ret_anc_sha1: char* = None
|
||||
if mc_entry is not None: ret_anc_sha1 = mc_entry.ModuleSha1
|
||||
else: ret_anc_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if ret_anc_sha1 is None:
|
||||
@@ -914,7 +914,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
mro_s0: sizet* = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||||
mi_s0: int = 1
|
||||
while mro_s0 is not None and mro_s0[mi_s0] != 0 and ret_anc_sha1 is None:
|
||||
anc_s0: str = rawptr(mro_s0[mi_s0])
|
||||
anc_s0: char* = rawptr(mro_s0[mi_s0])
|
||||
if anc_s0 is not None: ret_anc_sha1 = self.Gen.StructGen.get_struct_sha1(anc_s0)
|
||||
mi_s0 += 1
|
||||
|
||||
@@ -922,15 +922,15 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# registered yet; trigger it (idempotent), then re-lookup.
|
||||
gen_done: int = 0
|
||||
if class_name is not None:
|
||||
lbkt_g: str = string.strchr(class_name, '[')
|
||||
lbkt_g: char* = string.strchr(class_name, '[')
|
||||
if lbkt_g is not None:
|
||||
rbkt_g: str = string.strrchr(class_name, ']')
|
||||
rbkt_g: char* = string.strrchr(class_name, ']')
|
||||
if rbkt_g is not None and rbkt_g > lbkt_g:
|
||||
base_len_g: sizet = sizet(uint64(lbkt_g) - uint64(class_name))
|
||||
arg_len_g: sizet = sizet(uint64(rbkt_g) - uint64(lbkt_g) - 1)
|
||||
if base_len_g > 0 and arg_len_g > 0:
|
||||
base_buf_g: str = pool.alloc(base_len_g + 1)
|
||||
arg_buf_g: str = pool.alloc(arg_len_g + 1)
|
||||
base_buf_g: char* = pool.alloc(base_len_g + 1)
|
||||
arg_buf_g: char* = pool.alloc(arg_len_g + 1)
|
||||
if base_buf_g is not None and arg_buf_g is not None:
|
||||
string.strncpy(base_buf_g, class_name, base_len_g)
|
||||
base_buf_g[base_len_g] = '\0'
|
||||
@@ -939,14 +939,14 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
ta_list_g: list[str]* = list[str](pool, 8)
|
||||
if ta_list_g is not None:
|
||||
# Comma-separated multiple type args (list[X] / dict[K, V]).
|
||||
cur_arg_g: str = arg_buf_g
|
||||
cur_arg_g: char* = arg_buf_g
|
||||
while cur_arg_g is not None:
|
||||
comma_g: str = string.strchr(cur_arg_g, ',')
|
||||
comma_g: char* = string.strchr(cur_arg_g, ',')
|
||||
if comma_g is None:
|
||||
ta_list_g.append(cur_arg_g)
|
||||
break
|
||||
seg_len_g: sizet = sizet(uint64(comma_g) - uint64(cur_arg_g))
|
||||
seg_buf_g: str = pool.alloc(seg_len_g + 1)
|
||||
seg_buf_g: char* = pool.alloc(seg_len_g + 1)
|
||||
if seg_buf_g is not None:
|
||||
string.strncpy(seg_buf_g, cur_arg_g, seg_len_g)
|
||||
seg_buf_g[seg_len_g] = '\0'
|
||||
@@ -954,16 +954,16 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
cur_arg_g = comma_g + 1
|
||||
# base_buf_g may carry a template module SHA1 prefix
|
||||
# ({tpl}.GSList); strip it before template lookup.
|
||||
base_clean_g: str = base_buf_g
|
||||
base_clean_g: char* = base_buf_g
|
||||
# [C10] SHA1 prefix detection uses the single source;
|
||||
# take the cut length from its return value.
|
||||
base_pfx_g: int = GenApi.sha1_prefix_len(base_buf_g)
|
||||
if base_pfx_g != 0: base_clean_g = base_buf_g + sizet(base_pfx_g)
|
||||
spec_name_g: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, base_clean_g, ta_list_g)
|
||||
spec_name_g: char* = self.Gen.ClassGenGeneric._specialize_generic_class(trans, base_clean_g, ta_list_g)
|
||||
if spec_name_g is not None:
|
||||
# Re-lookup the specialized function after specialization;
|
||||
# find_func_in_module matches both bare and tpl-prefixed names.
|
||||
spec_lk_g: str = pool.alloc(string.strlen(class_name) + string.strlen(method_name) + 2)
|
||||
spec_lk_g: char* = pool.alloc(string.strlen(class_name) + string.strlen(method_name) + 2)
|
||||
if spec_lk_g is not None:
|
||||
viperlib.snprintf(spec_lk_g, string.strlen(class_name) + string.strlen(method_name) + 2, "%s.%s", class_name, method_name)
|
||||
spec_found_g: mlirlite.Function* = self.find_func_in_module(mod, spec_lk_g)
|
||||
@@ -977,7 +977,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# is_local_mod exemption: when the method is defined in the module
|
||||
# being translated, take the return type from the current IR.
|
||||
if trans is not None and ret_anc_sha1 is not None and trans.ModuleSha1 is not None and string.strncmp(ret_anc_sha1, trans.ModuleSha1, 16) == 0:
|
||||
local_lk_lm: str = pool.alloc(string.strlen(ret_anc_name) + string.strlen(method_name) + 2)
|
||||
local_lk_lm: char* = pool.alloc(string.strlen(ret_anc_name) + string.strlen(method_name) + 2)
|
||||
if local_lk_lm is not None:
|
||||
viperlib.snprintf(local_lk_lm, string.strlen(ret_anc_name) + string.strlen(method_name) + 2, "%s.%s", ret_anc_name, method_name)
|
||||
local_fn_lm: mlirlite.Function* = self.find_func_in_module(mod, local_lk_lm)
|
||||
@@ -999,9 +999,9 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
mro_v2: sizet* = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||||
mi_v2: int = 1
|
||||
while mro_v2 is not None and mro_v2[mi_v2] != 0 and vpi_ret_ty is None:
|
||||
anc_v2: str = rawptr(mro_v2[mi_v2])
|
||||
anc_v2: char* = rawptr(mro_v2[mi_v2])
|
||||
if anc_v2 is not None and string.strcmp(anc_v2, class_name) != 0:
|
||||
anc_sha1_v2: str = self.Gen.StructGen.get_struct_sha1(anc_v2)
|
||||
anc_sha1_v2: char* = self.Gen.StructGen.get_struct_sha1(anc_v2)
|
||||
vpi_ret_ty = self._lookup_method_ret_ty_via_vpi(pool, anc_sha1_v2, anc_v2, method_name, trans)
|
||||
if vpi_ret_ty is not None:
|
||||
ret_anc_name = anc_v2
|
||||
@@ -1018,9 +1018,9 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
mro_t2: sizet* = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||||
mi_t2: int = 1
|
||||
while mro_t2 is not None and mro_t2[mi_t2] != 0 and looked_up_ty is None:
|
||||
anc_t2: str = rawptr(mro_t2[mi_t2])
|
||||
anc_t2: char* = rawptr(mro_t2[mi_t2])
|
||||
if anc_t2 is not None and string.strcmp(anc_t2, class_name) != 0:
|
||||
anc_sha1_t2: str = self.Gen.StructGen.get_struct_sha1(anc_t2)
|
||||
anc_sha1_t2: char* = self.Gen.StructGen.get_struct_sha1(anc_t2)
|
||||
looked_up_ty = self._LookupMethodRetTyFromTextLL(pool, anc_sha1_t2, anc_t2, method_name)
|
||||
if looked_up_ty is not None:
|
||||
ret_anc_name = anc_t2
|
||||
@@ -1045,7 +1045,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# Only extract sha1 when the type name is "{16hex}.{Class}"
|
||||
# (via the single source GenApi.sha1_prefix_len).
|
||||
if GenApi.sha1_prefix_len(type_name_st) != 0:
|
||||
sha1_from_ty: str = pool.alloc(17)
|
||||
sha1_from_ty: char* = pool.alloc(17)
|
||||
if sha1_from_ty is not None:
|
||||
string.strncpy(sha1_from_ty, type_name_st, 16)
|
||||
sha1_from_ty[16] = '\0'
|
||||
@@ -1054,7 +1054,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
pass
|
||||
if ret_anc_name is not None and ret_anc_sha1 is not None:
|
||||
ml_anc: sizet = string.strlen(ret_anc_sha1) + string.strlen(ret_anc_name) + string.strlen(method_name) + 3
|
||||
mangled_anc: str = pool.alloc(ml_anc)
|
||||
mangled_anc: char* = pool.alloc(ml_anc)
|
||||
if mangled_anc is not None:
|
||||
viperlib.snprintf(mangled_anc, ml_anc, "%s.%s.%s", ret_anc_sha1, ret_anc_name, method_name)
|
||||
call_name = mangled_anc
|
||||
@@ -1082,17 +1082,17 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
is_first_parent_th: int = 0
|
||||
mro_fp_th: sizet* = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||||
if mro_fp_th is not None and mro_fp_th[1] != 0:
|
||||
first_parent_th: str = rawptr(mro_fp_th[1])
|
||||
first_parent_th: char* = rawptr(mro_fp_th[1])
|
||||
if first_parent_th is not None and string.strcmp(first_parent_th, mc_anc) == 0: is_first_parent_th = 1
|
||||
anc_entry_th: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(mc_anc)
|
||||
# Parent with no fields (FieldCount==0): the method body reads no layout
|
||||
# fields, so this needs no byte adjust; pass it through unchanged.
|
||||
if anc_entry_th is not None and anc_entry_th.FieldCount > 0:
|
||||
anc_first_name_th: str = None
|
||||
anc_first_name_th: char* = None
|
||||
for afi_th in range(int(anc_entry_th.FieldCount)):
|
||||
afe_th: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(anc_entry_th, afi_th)
|
||||
if afe_th is not None:
|
||||
afn_th: str = self.Gen.StructGen.get_field_name_ptr(afe_th)
|
||||
afn_th: char* = self.Gen.StructGen.get_field_name_ptr(afe_th)
|
||||
if afn_th is not None and string.strcmp(afn_th, "__vtable__") != 0:
|
||||
anc_first_name_th = afn_th
|
||||
break
|
||||
@@ -1174,7 +1174,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
arg_node_k: ast.AST* = None
|
||||
if pi_k < can: arg_node_k = cargs.get(pi_k)
|
||||
else:
|
||||
pname_k: str = mlirlite.param_get_name(cur_param_k)
|
||||
pname_k: char* = mlirlite.param_get_name(cur_param_k)
|
||||
if pname_k is not None:
|
||||
ki_k: int
|
||||
for ki_k in range(int(kwc)):
|
||||
@@ -1187,7 +1187,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if arg_node_k is not None:
|
||||
# Fetch the param type first (char literal -> str param needs a materialized string).
|
||||
pty_k0: mlirlite.LLVMType* = mlirlite.param_get_ty(cur_param_k)
|
||||
ao_name_k: str = None
|
||||
ao_name_k: char* = None
|
||||
if found_func is not None: ao_name_k = mlirlite.function_get_name(found_func)
|
||||
arg_val_k = self.Gen.CallGenBase.translate_call_arg(builder, pool, mod, trans, ao_name_k, pi_k, arg_node_k, pty_k0, None)
|
||||
if arg_val_k is None:
|
||||
@@ -1234,7 +1234,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
pi += 1
|
||||
if pp is not None: pty = mlirlite.param_get_ty(pp)
|
||||
# Value-reference params (&T / &temp T): auto-address (self is param 0, arg ai -> param ai+1).
|
||||
ao_name_p: str = None
|
||||
ao_name_p: char* = None
|
||||
if found_func is not None: ao_name_p = mlirlite.function_get_name(found_func)
|
||||
arg_val: mlirlite.Value* = self.Gen.CallGenBase.translate_call_arg(builder, pool, mod, trans, ao_name_p, int(ai) + 1, arg_node, pty, None)
|
||||
if arg_val is None:
|
||||
@@ -1275,7 +1275,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
mdf_param_count: int = 0
|
||||
# 方法所属模块 SHA1:后面所有 defaults 查找都必须带上它,绝不跨模块按名搜
|
||||
# (`run`/`init` 这类方法名在多个模块里都有,裸名会拿错签名去补参)。
|
||||
vpi_sha1_p: str = None
|
||||
vpi_sha1_p: char* = None
|
||||
if mc_entry is not None and mc_entry.ModuleSha1 is not None: vpi_sha1_p = mc_entry.ModuleSha1
|
||||
else: vpi_sha1_p = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if trans is not None and trans._funcs is not None:
|
||||
@@ -1304,7 +1304,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
|
||||
# Cross-module stub fallback: when the dependency's vpi is not loaded the
|
||||
# table lacks ParamCount; fill it from the vpi text cache.
|
||||
vpi_pa: str = None
|
||||
vpi_pa: char* = None
|
||||
if mdf_param_count == 0 and found_func is None:
|
||||
if vpi_sha1_p is not None:
|
||||
vpi_pa = self.Gen.CallGenBase._vpi_method_param_annot(pool, vpi_sha1_p, class_name, method_name)
|
||||
@@ -1322,7 +1322,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
ppcnt_f: int = 0
|
||||
ppn_f: mlirlite.Param* = mlirlite.function_get_param_head(found_func)
|
||||
while ppn_f is not None:
|
||||
fp_nm_f: str = mlirlite.param_get_name(ppn_f)
|
||||
fp_nm_f: char* = mlirlite.param_get_name(ppn_f)
|
||||
if fp_nm_f is None or (string.strcmp(fp_nm_f, "%__eh_msg_out__") != 0 and string.strcmp(fp_nm_f, "%__eh_code_out__") != 0):
|
||||
ppcnt_f += 1
|
||||
ppn_f = mlirlite.param_get_next(ppn_f)
|
||||
@@ -1420,7 +1420,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
for mc_mi in range(int(mc_entry.VTableMethodCount)):
|
||||
mc_mname_addr: sizet = mc_methods_arr[mc_mi]
|
||||
if mc_mname_addr == 0: continue
|
||||
mc_mname: str = rawptr(mc_mname_addr)
|
||||
mc_mname: char* = rawptr(mc_mname_addr)
|
||||
if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0:
|
||||
mc_method_idx = mc_mi
|
||||
break
|
||||
@@ -1447,7 +1447,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
|
||||
# _translate_list_builtin_call - inline translation of list builtin methods
|
||||
# (layout: __data__(0) __count__(8) __elem_size__(32) ...); lm_obj is Ptr(list-struct).
|
||||
def _translate_list_builtin_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, lm_name: str, lm_obj: mlirlite.Value*, cargs: list[ast.AST*]*, can: sizet, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
def _translate_list_builtin_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, lm_name: char*, lm_obj: mlirlite.Value*, cargs: list[ast.AST*]*, can: sizet, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
"""Translate a list builtin method call; returns None for void methods."""
|
||||
if pool is None or builder is None or lm_obj is None or lm_name is None: return None
|
||||
i64_ty: mlirlite.LLVMType* = mlirlite.Int64(pool)
|
||||
@@ -1456,7 +1456,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# Element type T parsed from the list specialization name (list[int]->i32,
|
||||
# list[str]->i8*; unknown/pointer elements -> i8*).
|
||||
lm_esty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||||
lm_ename: str = None
|
||||
lm_ename: char* = None
|
||||
if lm_esty is not None: lm_ename = mlirlite.get_struct_name(lm_esty)
|
||||
lm_elem_ty: mlirlite.LLVMType* = None
|
||||
if lm_ename is not None: lm_elem_ty = self.Gen.ExprGenName._list_elem_type_from_name(pool, lm_ename)
|
||||
@@ -1552,7 +1552,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# reallocation, so use the _list.py implementation.
|
||||
elif string.strcmp(lm_name, "append") == 0:
|
||||
if can >= 1 and cargs is not None:
|
||||
ap_sha1: str = self._lookup_module_sha1("_list")
|
||||
ap_sha1: char* = self._lookup_module_sha1("_list")
|
||||
if ap_sha1 is None:
|
||||
# Dependency module not compiled (_list not in the build chain): fail
|
||||
# fast, never silently skip append.
|
||||
@@ -1560,21 +1560,21 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if ap_sha1 is not None:
|
||||
# Extract the specialized class name: list.append's symbol is
|
||||
# {sha1}.list[AST*].append, not {sha1}.list.append.
|
||||
ap_spec_nm: str = None
|
||||
ap_spec_nm: char* = None
|
||||
ap_struct_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||||
if ap_struct_ty is not None: ap_spec_nm = self.Gen.StructGen.get_class_name_by_type(pool, ap_struct_ty)
|
||||
if ap_spec_nm is None: ap_spec_nm = "list"
|
||||
# Trigger generic specialization translation (idempotent).
|
||||
if trans is not None and ap_spec_nm is not None:
|
||||
lbkt_ap: str = string.strchr(ap_spec_nm, '[')
|
||||
lbkt_ap: char* = string.strchr(ap_spec_nm, '[')
|
||||
if lbkt_ap is not None:
|
||||
rbkt_ap: str = string.strrchr(ap_spec_nm, ']')
|
||||
rbkt_ap: char* = string.strrchr(ap_spec_nm, ']')
|
||||
if rbkt_ap is not None and rbkt_ap > lbkt_ap:
|
||||
base_len_ap: sizet = sizet(uint64(lbkt_ap) - uint64(ap_spec_nm))
|
||||
arg_len_ap: sizet = sizet(uint64(rbkt_ap) - uint64(lbkt_ap) - 1)
|
||||
if base_len_ap > 0 and arg_len_ap > 0:
|
||||
base_buf_ap: str = pool.alloc(base_len_ap + 1)
|
||||
arg_buf_ap: str = pool.alloc(arg_len_ap + 1)
|
||||
base_buf_ap: char* = pool.alloc(base_len_ap + 1)
|
||||
arg_buf_ap: char* = pool.alloc(arg_len_ap + 1)
|
||||
if base_buf_ap is not None and arg_buf_ap is not None:
|
||||
string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap)
|
||||
base_buf_ap[base_len_ap] = '\0'
|
||||
@@ -1583,14 +1583,14 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
args_ap: list[str]* = list[str](pool, 8)
|
||||
if args_ap is not None:
|
||||
# Comma-separated multiple type args (list[X] / dict[K, V]).
|
||||
cur_ap: str = arg_buf_ap
|
||||
cur_ap: char* = arg_buf_ap
|
||||
while cur_ap is not None:
|
||||
comma_ap: str = string.strchr(cur_ap, ',')
|
||||
comma_ap: char* = string.strchr(cur_ap, ',')
|
||||
if comma_ap is None:
|
||||
args_ap.append(cur_ap)
|
||||
break
|
||||
seg_len_ap: sizet = sizet(uint64(comma_ap) - uint64(cur_ap))
|
||||
seg_buf_ap: str = pool.alloc(seg_len_ap + 1)
|
||||
seg_buf_ap: char* = pool.alloc(seg_len_ap + 1)
|
||||
if seg_buf_ap is not None:
|
||||
string.strncpy(seg_buf_ap, cur_ap, seg_len_ap)
|
||||
seg_buf_ap[seg_len_ap] = '\0'
|
||||
@@ -1600,7 +1600,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# Call name "{sha1}.{spec}.append":
|
||||
# sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25
|
||||
ap_mlen: sizet = string.strlen(ap_sha1) + string.strlen(ap_spec_nm) + 26
|
||||
ap_mangled: str = pool.alloc(ap_mlen)
|
||||
ap_mangled: char* = pool.alloc(ap_mlen)
|
||||
if ap_mangled is not None:
|
||||
viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", ap_sha1, ap_spec_nm)
|
||||
ap_item_node: ast.AST* = cargs.get(0)
|
||||
@@ -1622,7 +1622,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# current class from self, first MRO ancestor defining the method, no virtual.
|
||||
|
||||
# ============================================================
|
||||
def _translate_super_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, method_name: str, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
def _translate_super_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, method_name: char*, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
"""Translate super().method(args) as a static parent-class method call."""
|
||||
if pool is None or builder is None or cl is None or method_name is None: return None
|
||||
if trans is None: return None
|
||||
@@ -1633,18 +1633,18 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if self_entry is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super(): no self variable in the current scope (unavailable inside a static method)", "TypeError")
|
||||
return None
|
||||
cur_class: str = self.Gen.VarGen.var_annot_class_name(self_entry)
|
||||
cur_class: char* = self.Gen.VarGen.var_annot_class_name(self_entry)
|
||||
if cur_class is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super() can only be used inside a class method (self has no annotated class name)")
|
||||
return None
|
||||
# 2. Walk the MRO, skipping self, for the first ancestor defining the method.
|
||||
anc: str = None
|
||||
anc: char* = None
|
||||
mro_sp: sizet* = self.Gen.StructGen.get_mro_chain(pool, cur_class)
|
||||
mi_sp: int = 1
|
||||
while mro_sp is not None and mro_sp[mi_sp] != 0:
|
||||
anc_sp: str = rawptr(mro_sp[mi_sp])
|
||||
anc_sp: char* = rawptr(mro_sp[mi_sp])
|
||||
if anc_sp is not None:
|
||||
probe_sp: str = pool.alloc(160)
|
||||
probe_sp: char* = pool.alloc(160)
|
||||
if probe_sp is not None:
|
||||
viperlib.snprintf(probe_sp, 160, "%s.%s", anc_sp, method_name)
|
||||
if self.Gen.CallGenLeafKit.find_func_global(probe_sp) is not None:
|
||||
@@ -1652,7 +1652,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
break
|
||||
mi_sp += 1
|
||||
if anc is None:
|
||||
err_sp: str = pool.alloc(256)
|
||||
err_sp: char* = pool.alloc(256)
|
||||
if err_sp is not None:
|
||||
viperlib.snprintf(err_sp, 256, "super(): the parent chain of current class %s does not define method %s", cur_class, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(cl, err_sp, "TypeError")
|
||||
@@ -1679,11 +1679,11 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if string.strcmp(anc, cur_class) != 0:
|
||||
anc_entry_sp: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(anc)
|
||||
if anc_entry_sp is not None and anc_entry_sp.FieldCount > 0:
|
||||
first_name_sp: str = None
|
||||
first_name_sp: char* = None
|
||||
for afi_sp in range(int(anc_entry_sp.FieldCount)):
|
||||
afe_sp: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(anc_entry_sp, afi_sp)
|
||||
if afe_sp is not None:
|
||||
afn_sp: str = self.Gen.StructGen.get_field_name_ptr(afe_sp)
|
||||
afn_sp: char* = self.Gen.StructGen.get_field_name_ptr(afe_sp)
|
||||
if afn_sp is not None and string.strcmp(afn_sp, "__vtable__") != 0:
|
||||
first_name_sp = afn_sp
|
||||
break
|
||||
@@ -1709,19 +1709,19 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
mlirlite.module_ensure_opaque_for_type(mod, pool, anc_ptr_sp)
|
||||
self_arg = mlirlite.build_bitcast(builder, adj_sp, anc_ptr_sp)
|
||||
# 4. Find the parent method function and build the call name (SHA1-mangled).
|
||||
anc_lookup: str = pool.alloc(160)
|
||||
anc_lookup: char* = pool.alloc(160)
|
||||
if anc_lookup is None: return None
|
||||
viperlib.snprintf(anc_lookup, 160, "%s.%s", anc, method_name)
|
||||
found_func: mlirlite.Function* = self.find_func_in_module(mod, anc_lookup)
|
||||
call_name: str = anc_lookup
|
||||
anc_sha1_sp: str = self.Gen.StructGen.get_struct_sha1(anc)
|
||||
call_name: char* = anc_lookup
|
||||
anc_sha1_sp: char* = self.Gen.StructGen.get_struct_sha1(anc)
|
||||
if anc_sha1_sp is None: anc_sha1_sp = trans.ModuleSha1
|
||||
if found_func is not None:
|
||||
fname_sp: str = mlirlite.function_get_name(found_func)
|
||||
fname_sp: char* = mlirlite.function_get_name(found_func)
|
||||
if fname_sp is not None: call_name = fname_sp
|
||||
else:
|
||||
if anc_sha1_sp is not None:
|
||||
mangled_sp: str = self.Gen.FuncGenBase._mangle_name_with_sha1(anc_sha1_sp, anc_lookup)
|
||||
mangled_sp: char* = self.Gen.FuncGenBase._mangle_name_with_sha1(anc_sha1_sp, anc_lookup)
|
||||
if mangled_sp is not None: call_name = mangled_sp
|
||||
# 5. Translate args and coerce to params (self is param 0, arg ai maps to ai+1).
|
||||
cargs_sp: list[ast.AST*]* = cl.args
|
||||
@@ -1793,7 +1793,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
return mlirlite.build_call(builder, call_name, head, arg_count_sp, ret_ty_sp, is_variadic_sp)
|
||||
# _recv_is_mixin_base - is the receiver used as a parent of a registered class?
|
||||
# Only a real direct parent can have its field area in a composite class layout.
|
||||
def _recv_is_mixin_base(self, class_name: str) -> int:
|
||||
def _recv_is_mixin_base(self, class_name: char*) -> int:
|
||||
"""Is the receiver class a direct parent of any registered class; 1=yes / 0=no."""
|
||||
if class_name is None: return 0
|
||||
if self.Gen is None: return 0
|
||||
@@ -1803,14 +1803,14 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if e is not None and e.Name is not None:
|
||||
pc: int = self.Gen.StructGen.get_parent_count(e.Name)
|
||||
for pj in range(int(pc)):
|
||||
pn: str = self.Gen.StructGen.get_parent_name_at(e.Name, pj)
|
||||
pn: char* = self.Gen.StructGen.get_parent_name_at(e.Name, pj)
|
||||
if pn is not None:
|
||||
if string.strcmp(pn, class_name) == 0: return 1
|
||||
return 0
|
||||
|
||||
# _mixin_sibling_same_composite - do both classes share a composite class's MRO?
|
||||
# A registered class K whose MRO contains both is the necessary condition.
|
||||
def _mixin_sibling_same_composite(self, pool: memhub.MemBuddy*, class_name: str, cand_name: str) -> int:
|
||||
def _mixin_sibling_same_composite(self, pool: memhub.MemBuddy*, class_name: char*, cand_name: char*) -> int:
|
||||
"""Do both classes share a registered composite class's MRO; 1=yes / 0=no."""
|
||||
if class_name is None or cand_name is None or pool is None: return 0
|
||||
if self.Gen is None: return 0
|
||||
@@ -1824,7 +1824,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
has_cand: int = 0
|
||||
mi: int = 0
|
||||
while mro[mi] != 0:
|
||||
nm: str = rawptr(mro[mi])
|
||||
nm: char* = rawptr(mro[mi])
|
||||
if nm is not None:
|
||||
if string.strcmp(nm, class_name) == 0: has_self = 1
|
||||
elif string.strcmp(nm, cand_name) == 0: has_cand = 1
|
||||
@@ -1868,7 +1868,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
return 0
|
||||
# _kwarg_name_matches - check whether a keyword arg name matches a param name.
|
||||
# Param names carry a "%" prefix in IR; compare after skipping it.
|
||||
def _kwarg_name_matches(self, kw_arg: str, param_name: str) -> int:
|
||||
def _kwarg_name_matches(self, kw_arg: char*, param_name: char*) -> int:
|
||||
"""Check whether kwarg name kw_arg matches param param_name (skips '%' prefix)."""
|
||||
if kw_arg is None or param_name is None: return 0
|
||||
start: sizet = 0
|
||||
|
||||
@@ -54,7 +54,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
|
||||
# _apply_struct_defaults - apply struct field default values after zeroinitializer and
|
||||
# before explicit args (which later override); translate + store each field with a default.
|
||||
def _apply_struct_defaults(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, struct_ty: mlirlite.LLVMType*, class_name: str, tmp: mlirlite.Value*, trans: HT.Translator*, is_volatile: int = 0):
|
||||
def _apply_struct_defaults(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, struct_ty: mlirlite.LLVMType*, class_name: char*, tmp: mlirlite.Value*, trans: HT.Translator*, is_volatile: int = 0):
|
||||
"""Apply struct field default values; is_volatile=1 keeps ctor writes volatile"""
|
||||
# locate the entry by type pointer to avoid cross-module same-name find_struct mistakes
|
||||
entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(struct_ty)
|
||||
@@ -82,9 +82,9 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
zero_arr2: mlirlite.Value* = mlirlite.ConstZero(pool, fe.Ty)
|
||||
if zero_arr2 is not None: mlirlite.build_store(builder, zero_arr2, field_ptr_arr2, is_volatile)
|
||||
# owner_ctx only serves the empty-element fail-fast message (class + field + index)
|
||||
sd_ctx: str = pool.alloc(192)
|
||||
sd_ctx: char* = pool.alloc(192)
|
||||
if sd_ctx is not None:
|
||||
fname_sd: str = fe.Name
|
||||
fname_sd: char* = fe.Name
|
||||
if fname_sd is None: fname_sd = "?"
|
||||
viperlib.snprintf(sd_ctx, 192, "Class %s field %s (struct ctor defaults):", class_name, fname_sd)
|
||||
# arr_ty_opt = fe.Ty: same reason as ClassGenVTable (the GEP value may carry no pointee type)
|
||||
@@ -108,7 +108,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# _translate_struct_ctor - struct constructor Point(10, 20): alloca, zeroinit, per-field
|
||||
# GEP + store (or __new__/__before_init__/__init__ for OOP structs), then load.
|
||||
|
||||
def _translate_struct_ctor(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, struct_ty: mlirlite.LLVMType*, class_name: str, cargs: list[ast.AST*]*, can: sizet, trans: HT.Translator*, is_volatile: int = 0) -> mlirlite.Value*:
|
||||
def _translate_struct_ctor(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, struct_ty: mlirlite.LLVMType*, class_name: char*, cargs: list[ast.AST*]*, can: sizet, trans: HT.Translator*, is_volatile: int = 0) -> mlirlite.Value*:
|
||||
"""Translate a struct constructor; stores args by field; is_volatile=1 marks writes volatile"""
|
||||
# Create the temporary alloca, ensuring the full cross-module struct definition is
|
||||
# available in this module.
|
||||
@@ -142,7 +142,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# Cross-module OOP inference: IsOOP may be unset (Phase1 cache skipped
|
||||
# _translate_oop_methods). Check for ClassName.__init__ in the module or global defaults table.
|
||||
if is_oop == 0 and class_name is not None:
|
||||
init_lookup_name: str = pool.alloc(128)
|
||||
init_lookup_name: char* = pool.alloc(128)
|
||||
if init_lookup_name is not None:
|
||||
viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name)
|
||||
# option 1: check the current module's function declarations
|
||||
@@ -205,7 +205,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if ctor_entry is not None and ctor_entry.IsOOP != 0: bi_ok = 1
|
||||
if bi_ok == 0 and ctor_entry is not None and ctor_entry.HasInit != 0: bi_ok = 1
|
||||
if bi_ok == 0 and class_name is not None:
|
||||
bi_lk: str = pool.alloc(160)
|
||||
bi_lk: char* = pool.alloc(160)
|
||||
if bi_lk is not None:
|
||||
viperlib.snprintf(bi_lk, 160, "%s.__init__", class_name)
|
||||
if self.find_func_in_module(mod, bi_lk) is not None: bi_ok = 1
|
||||
@@ -215,7 +215,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
bi_mro: sizet* = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||||
bi_mi: int = 1
|
||||
while bi_mro is not None and bi_mro[bi_mi] != 0:
|
||||
bi_anc: str = rawptr(bi_mro[bi_mi])
|
||||
bi_anc: char* = rawptr(bi_mro[bi_mi])
|
||||
if bi_anc is not None and string.strcmp(bi_anc, class_name) != 0:
|
||||
bi_ae: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(bi_anc)
|
||||
if bi_ae is not None and bi_ae.HasInit != 0:
|
||||
@@ -267,7 +267,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
for fi in range(int(ctor_entry.FieldCount)):
|
||||
cand_fe: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(ctor_entry, fi)
|
||||
if cand_fe is None: continue
|
||||
cand_name: str = self.Gen.StructGen.get_field_name_ptr(cand_fe)
|
||||
cand_name: char* = self.Gen.StructGen.get_field_name_ptr(cand_fe)
|
||||
if cand_name is not None and string.strcmp(cand_name, "__vtable__") == 0: continue
|
||||
if target_idx == ai:
|
||||
fe = cand_fe
|
||||
@@ -335,7 +335,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# _translate_renum_construct - REnum variant ctor (ClassName.Variant(args...)): alloca,
|
||||
# zeroinit, store __tag and payload fields, return the pointer.
|
||||
|
||||
def _translate_renum_construct(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, class_name: str, variant_name: str, tag_value: int, cargs: list[ast.AST*]*, can: sizet, trans: HT.Translator*, is_volatile: int = 0) -> mlirlite.Value*:
|
||||
def _translate_renum_construct(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, class_name: char*, variant_name: char*, tag_value: int, cargs: list[ast.AST*]*, can: sizet, trans: HT.Translator*, is_volatile: int = 0) -> mlirlite.Value*:
|
||||
"""Build a REnum variant instance; returns a pointer to the alloca"""
|
||||
if pool is None or builder is None or class_name is None: return None
|
||||
|
||||
@@ -369,7 +369,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
tag_field: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(renum_entry, 0)
|
||||
tag_field_ty: mlirlite.LLVMType* = mlirlite.Int32(pool)
|
||||
if tag_field is not None and tag_field.Ty is not None: tag_field_ty = tag_field.Ty
|
||||
tag_name_buf: str = pool.alloc(32)
|
||||
tag_name_buf: char* = pool.alloc(32)
|
||||
if tag_name_buf is not None: viperlib.snprintf(tag_name_buf, 32, "%d", tag_value)
|
||||
tag_const: mlirlite.Value* = mlirlite.ConstInt(pool, tag_field_ty, tag_value, tag_name_buf if tag_name_buf is not None else "0")
|
||||
tag_ptr: mlirlite.Value* = mlirlite.build_gep_struct(builder, renum_ty, tag_field_ty, tmp, 0)
|
||||
@@ -408,7 +408,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# stack(含 stack slife)→ 帧内 alloca,随帧消失,不产生 free;
|
||||
# memgr(x) slife → 归还池(D6 待定),本阶段不接管。
|
||||
# _new_is_nll_demotable - §13 NLL:可降级为"帧对象"的 `new heap`(判据见 Debugger/ownership-and-new.md §13.2)
|
||||
def _new_is_nll_demotable(self, trans: HT.Translator*, rhs: ast.AST*, var_name: str) -> int:
|
||||
def _new_is_nll_demotable(self, trans: HT.Translator*, rhs: ast.AST*, var_name: char*) -> int:
|
||||
"""1 = 该 `new` 可当帧对象处理(生命期按 FRAME、出口释放复用 slife 通道);0 = 不必/判不定。
|
||||
|
||||
只降级"堆且**未显式**指定生命期"的:显式 `hlife` 是用户对自由生命期的要求,不动;
|
||||
@@ -467,7 +467,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if src == ast.NEW_SRC_STACK and life == ast.NEW_LIFE_HLIFE:
|
||||
self.Gen.TypeGenErr.fatal_error(new_node, "`new stack hlife` is contradictory: stack storage cannot outlive its frame; use `new stack slife`, or `heap`/`memgr(x)`", "LifetimeError")
|
||||
return None
|
||||
class_name: str = self.Gen.ExprGenBase.get_func_name(new_node.func)
|
||||
class_name: char* = self.Gen.ExprGenBase.get_func_name(new_node.func)
|
||||
# REnum 变体构造:`new [desc] Qual.Variant(args)`(如 new memgr(pool) LLVMType.Int(32))。
|
||||
# callee 是 Attribute 且限定名 Qual 为已注册 REnum 类、Variant 命中该类的变体表时,把
|
||||
# class_name 归一到 **Qual(REnum 类名)**:下方 get_struct_type 命中的正是 REnum 的
|
||||
@@ -476,7 +476,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# 不归一(Qual 非 REnum / 变体缺失)时保持原样,由下方基本类型路径定夺 / fail-fast。
|
||||
if class_name is not None and new_node.func is not None and new_node.func.kind() == ast.ASTKind.Attribute:
|
||||
_rn_at: ast.Attribute* = ast.Attribute*(new_node.func)
|
||||
_rn_qual: str = None
|
||||
_rn_qual: char* = None
|
||||
if _rn_at.value is not None:
|
||||
if _rn_at.value.kind() == ast.ASTKind.Name:
|
||||
_rn_qual = ast.Name*(_rn_at.value).id
|
||||
@@ -558,7 +558,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# heap/memgr → 按 sizeof(T) 分配(复用既有 memgr 通道)
|
||||
# 有实参的标量(`new stack int(5)`)在这里 fail-fast:本路径刻意只做"取存储",
|
||||
# 不引入"标量构造"的第二套语义(要初值就 `new … int` 之后赋值)。
|
||||
def _translate_new_primitive(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, new_node: ast.New*, class_name: str, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
def _translate_new_primitive(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, new_node: ast.New*, class_name: char*, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
"""`new` 基本类型(标量):取存储 + 零初始化;返回 T*(失败返回 None,均 fail-fast)"""
|
||||
prim_ty: mlirlite.LLVMType* = None
|
||||
if new_node.func is not None:
|
||||
@@ -578,7 +578,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
elem_ty = elem_a
|
||||
case _:
|
||||
pass
|
||||
nm: str = class_name
|
||||
nm: char* = class_name
|
||||
if nm is None: nm = "?"
|
||||
if is_scalar == 0:
|
||||
if class_name is None:
|
||||
@@ -642,7 +642,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if mv is None:
|
||||
self.Gen.TypeGenErr.fatal_error(mgr_node, "`memgr(x)`: cannot translate the manager expression", "TypeError")
|
||||
return None
|
||||
mgr_cls: str = None
|
||||
mgr_cls: char* = None
|
||||
mty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(mv)
|
||||
if mty is not None: mgr_cls = self.Gen.StructGen.get_class_name_by_type(pool, mty)
|
||||
if mgr_cls is None:
|
||||
@@ -656,7 +656,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# _translate_struct_ctor_kw - struct constructor with keyword args: Point(x=10, y=20) or
|
||||
# Point(10, y=20); positional args map by field index, keywords by field name.
|
||||
|
||||
def _translate_struct_ctor_kw(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, struct_ty: mlirlite.LLVMType*, class_name: str, cargs: list[ast.AST*]*, can: sizet, keywords: list[ast.AST*]*, kw_count: sizet, trans: HT.Translator*, is_volatile: int = 0) -> mlirlite.Value*:
|
||||
def _translate_struct_ctor_kw(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, struct_ty: mlirlite.LLVMType*, class_name: char*, cargs: list[ast.AST*]*, can: sizet, keywords: list[ast.AST*]*, kw_count: sizet, trans: HT.Translator*, is_volatile: int = 0) -> mlirlite.Value*:
|
||||
"""Struct constructor for keyword arguments; is_volatile=1 marks writes volatile"""
|
||||
# Create the temporary alloca, ensuring the full cross-module struct definition is
|
||||
# available in this module.
|
||||
@@ -691,7 +691,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# Cross-module OOP inference: IsOOP may be unset (Phase1 cache skipped
|
||||
# _translate_oop_methods). Check for ClassName.__init__ in the module or global defaults table.
|
||||
if is_oop == 0 and class_name is not None:
|
||||
kw_init_lookup: str = pool.alloc(128)
|
||||
kw_init_lookup: char* = pool.alloc(128)
|
||||
if kw_init_lookup is not None:
|
||||
viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name)
|
||||
# option 1: check the current module's function declarations
|
||||
@@ -818,7 +818,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
|
||||
# Handle keyword args (lookup by field name).
|
||||
# Get the SHA1 from kw_entry (avoid cross-module same-name find_struct mistakes).
|
||||
kw_sha1: str = None
|
||||
kw_sha1: char* = None
|
||||
if kw_entry is not None: kw_sha1 = kw_entry.ModuleSha1
|
||||
for ki in range(int(kw_count)):
|
||||
kw: ast.Keyword* = ast.Keyword*(keywords.get(ki))
|
||||
@@ -897,15 +897,15 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# Generic-instantiation helper: extract type-argument names from a Subscript slice.
|
||||
# _get_type_name_from_annotation now lives in HandlesType.py (supports BinOp/Attribute).
|
||||
|
||||
def _extract_type_args_from_slice(self, pool: memhub.MemBuddy*, slice_node: ast.AST*, from_imports: str = None) -> list[str]*:
|
||||
def _extract_type_args_from_slice(self, pool: memhub.MemBuddy*, slice_node: ast.AST*, from_imports: char* = None) -> list[str]*:
|
||||
"""Extract type-argument names from a Subscript.slice; normalised when from_imports is set"""
|
||||
if slice_node is None or pool is None: return None
|
||||
# elem_size=8: str is an i8* pointer (8 bytes); with 4, append writes 8 bytes at a
|
||||
# elem_size=8: char* is an i8* pointer (8 bytes); with 4, append writes 8 bytes at a
|
||||
# 4-byte stride and the second element overwrites the first -> get returns a junk pointer.
|
||||
result: list[str]* = list[str](pool, 8)
|
||||
k: int = slice_node.kind()
|
||||
tn_raw: str = None
|
||||
tn: str = None
|
||||
tn_raw: char* = None
|
||||
tn: char* = None
|
||||
if k == ast.ASTKind.Tuple:
|
||||
tp: ast.Tuple* = ast.Tuple*(slice_node)
|
||||
elts: list[ast.AST*]* = tp.elts
|
||||
@@ -927,10 +927,10 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
|
||||
# _ptr_layer_type_arg - add the pointer layer (`*`) to inferred type args so the ctor side
|
||||
# matches the annotation-side canonical form `{sha}.Type*`; non-class names pass through.
|
||||
def _ptr_layer_type_arg(self, pool: memhub.MemBuddy*, cls_nm: str, ptr_level: int, from_imports: str) -> str:
|
||||
def _ptr_layer_type_arg(self, pool: memhub.MemBuddy*, cls_nm: char*, ptr_level: int, from_imports: char*) -> str:
|
||||
"""Map an annotation class name to a type-arg text; add `*` per PtrLevel, non-class names unchanged"""
|
||||
if cls_nm is None: return None
|
||||
res_pl: str = self.Gen.TypeGenResolve._norm_type_arg_name(pool, cls_nm, from_imports)
|
||||
res_pl: char* = self.Gen.TypeGenResolve._norm_type_arg_name(pool, cls_nm, from_imports)
|
||||
if res_pl is None: res_pl = cls_nm
|
||||
if ptr_level <= 0: return res_pl
|
||||
# non-class names (no SHA1 prefix, e.g. typedef "VOIDPTR" / bare marker "PtrT") keep the pointer layer
|
||||
@@ -944,7 +944,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
lvl_pl -= 1
|
||||
return res_pl
|
||||
|
||||
def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy*, arg_node: ast.AST*, class_name: str, trans: HT.Translator*) -> str:
|
||||
def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy*, arg_node: ast.AST*, class_name: char*, trans: HT.Translator*) -> str:
|
||||
"""Infer a generic type-arg name from a ctor arg AST (static AST only, no IR)"""
|
||||
if pool is None or arg_node is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"Cannot infer the type argument of generic class '{class_name}' from the argument; annotate explicitly, e.g. {class_name}[Type](...)", "TypeError")
|
||||
@@ -969,12 +969,12 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if cty_c is not None:
|
||||
# Signedness comes from the callee's source text (LLVM iN/uN are identical),
|
||||
# reusing spec_sign_of_annot (whitelist + TypedefT chain fallback).
|
||||
callee_txt_c: str = None
|
||||
callee_txt_c: char* = None
|
||||
if fk_c == ast.ASTKind.Name: callee_txt_c = ast.Name*(cl_f.func).id
|
||||
else: callee_txt_c = ast.Attribute*(cl_f.func).attr
|
||||
sign_c: int = TSpec.TS_SIGN_UNKNOWN
|
||||
if callee_txt_c is not None: sign_c = self.Gen.TypeGenCType.spec_sign_of_annot(callee_txt_c, 0)
|
||||
ta_c: str = self.Gen.ClassGenGeneric.infer_scalar_type_arg_from_llvm_ty(pool, cty_c, sign_c)
|
||||
ta_c: char* = self.Gen.ClassGenGeneric.infer_scalar_type_arg_from_llvm_ty(pool, cty_c, sign_c)
|
||||
if ta_c is not None: return ta_c
|
||||
# A cast call whose callee does not resolve to a scalar type: fail-fast
|
||||
# (return None -> caller fail-fasts).
|
||||
@@ -989,7 +989,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if ve_i is not None:
|
||||
# Route the annotation class name through _ptr_layer_type_arg: after
|
||||
# _norm_type_arg_name, add `*` when the value type is a pointer (Spec.PtrLevel>0).
|
||||
cn_nm_i: str = self.Gen.VarGen.var_annot_class_name(ve_i)
|
||||
cn_nm_i: char* = self.Gen.VarGen.var_annot_class_name(ve_i)
|
||||
pl_nm_i: int = 0
|
||||
if ve_i.Spec is not None: pl_nm_i = ve_i.Spec.PtrLevel
|
||||
return self._ptr_layer_type_arg(pool, cn_nm_i, pl_nm_i, trans._from_imports)
|
||||
@@ -999,16 +999,16 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if k == ast.ASTKind.Attribute:
|
||||
# Same: add `*` when the field value type is a pointer (FieldEntry.Spec.PtrLevel>0).
|
||||
# _resolve_attr_field_entry is read-only, supports one level; deeper chains keep the old behaviour.
|
||||
cn_at_i: str = self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, arg_node)
|
||||
cn_at_i: char* = self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, arg_node)
|
||||
pl_at_i: int = 0
|
||||
fe_at_i: GenTypes.FieldEntry* = self.Gen.ExprGenAttr._resolve_attr_field_entry(pool, trans, arg_node)
|
||||
if fe_at_i is not None and fe_at_i.Spec is not None: pl_at_i = fe_at_i.Spec.PtrLevel
|
||||
fi_at_i: str = None
|
||||
fi_at_i: char* = None
|
||||
if trans is not None: fi_at_i = trans._from_imports
|
||||
return self._ptr_layer_type_arg(pool, cn_at_i, pl_at_i, fi_at_i)
|
||||
return None
|
||||
|
||||
def _annotation_refers_type_param(self, node: ast.AST*, tp_name: str) -> int:
|
||||
def _annotation_refers_type_param(self, node: ast.AST*, tp_name: char*) -> int:
|
||||
"""Whether an annotation refers to type parameter tp_name (1=yes / 0=no)"""
|
||||
if node is None or tp_name is None: return 0
|
||||
k: int = node.kind()
|
||||
@@ -1022,7 +1022,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
return self._annotation_refers_type_param(bop_a.right, tp_name)
|
||||
return 0
|
||||
|
||||
def _get_ctor_init_params(self, class_name: str) -> list[ast.AST*]*:
|
||||
def _get_ctor_init_params(self, class_name: char*) -> list[ast.AST*]*:
|
||||
"""Return the generic template __init__ parameter list (including self); None if unavailable"""
|
||||
if class_name is None: return None
|
||||
template_cd: ast.ClassDef* = self.Gen.ClassGenGeneric._find_generic_template(class_name)
|
||||
@@ -1041,7 +1041,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
return fargs.args
|
||||
return None
|
||||
|
||||
def _find_ctor_type_param_param_index(self, class_name: str, tp_name: str) -> int:
|
||||
def _find_ctor_type_param_param_index(self, class_name: char*, tp_name: char*) -> int:
|
||||
"""Parameter index in the template __init__ annotated with tp_name (incl. self, 0-based); -1 if not found"""
|
||||
if class_name is None or tp_name is None: return -1
|
||||
plist: list[ast.AST*]* = self._get_ctor_init_params(class_name)
|
||||
@@ -1057,13 +1057,13 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if self._annotation_refers_type_param(ag.annotation, tp_name) != 0: return int(pi)
|
||||
return -1
|
||||
|
||||
def _find_ctor_type_param_arg_index(self, class_name: str, tp_name: str) -> int:
|
||||
def _find_ctor_type_param_arg_index(self, class_name: char*, tp_name: char*) -> int:
|
||||
"""Positional-arg index for the param annotated with tp_name in the template __init__; -1 if not found"""
|
||||
pi_arg: int = self._find_ctor_type_param_param_index(class_name, tp_name)
|
||||
if pi_arg < 0: return -1
|
||||
return pi_arg - 1
|
||||
|
||||
def _ctor_init_arg_slot_by_name(self, class_name: str, kw_name: str) -> int:
|
||||
def _ctor_init_arg_slot_by_name(self, class_name: char*, kw_name: char*) -> int:
|
||||
"""Map a keyword arg name to its non-self param slot; -1 if the template or name is missing"""
|
||||
if class_name is None or kw_name is None: return -1
|
||||
plist_sb: list[ast.AST*]* = self._get_ctor_init_params(class_name)
|
||||
@@ -1079,7 +1079,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if ag_sb.arg is not None and string.strcmp(ag_sb.arg, kw_name) == 0: return int(pi_sb) - 1
|
||||
return -1
|
||||
|
||||
def _find_ctor_type_param_kw_arg_index(self, class_name: str, tp_name: str, keywords: list[ast.AST*]*, kw_count: sizet, pos_count: int) -> int:
|
||||
def _find_ctor_type_param_kw_arg_index(self, class_name: char*, tp_name: char*, keywords: list[ast.AST*]*, kw_count: sizet, pos_count: int) -> int:
|
||||
"""Keyword-only construction: keyword-arg index for type param tp_name; -1 if not found"""
|
||||
if class_name is None or tp_name is None or keywords is None: return -1
|
||||
pi_kw: int = self._find_ctor_type_param_param_index(class_name, tp_name)
|
||||
@@ -1100,7 +1100,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if string.strcmp(kw_tp.arg, ag_kw.arg) == 0: return int(ki_kw)
|
||||
return -1
|
||||
|
||||
def _infer_ctor_type_args_from_ctx(self, pool: memhub.MemBuddy*, trans: HT.Translator*, class_name: str, tp_count: int, cl: ast.Call*) -> list[str]*:
|
||||
def _infer_ctor_type_args_from_ctx(self, pool: memhub.MemBuddy*, trans: HT.Translator*, class_name: char*, tp_count: int, cl: ast.Call*) -> list[str]*:
|
||||
"""Infer generic ctor type args from the assignment-target or return annotation context; None if N/A"""
|
||||
if pool is None or trans is None or class_name is None or cl is None: return None
|
||||
if tp_count <= 0: return None
|
||||
@@ -1130,7 +1130,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if len(type_args_ctx) != sizet(tp_count): return None
|
||||
return type_args_ctx
|
||||
|
||||
def _translate_generic_ctor_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, spec_name: str, cl: ast.Call*, trans: HT.Translator*, tmpl_name: str = None) -> mlirlite.Value*:
|
||||
def _translate_generic_ctor_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, spec_name: char*, cl: ast.Call*, trans: HT.Translator*, tmpl_name: char* = None) -> mlirlite.Value*:
|
||||
"""Translate a generic-class ctor call: __new__ + __before_init__ + __init__"""
|
||||
if pool is None or builder is None or mod is None or spec_name is None or cl is None: return None
|
||||
|
||||
@@ -1249,7 +1249,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if gi_has_init == 0:
|
||||
# 特化类的 HasInit 可能没被传播:再按非泛型路径同口径查"该方法是否真的存在"
|
||||
# (模块内声明 或 全局默认参数表),避免有 __init__ 的泛型类被漏掉。
|
||||
init_lk: str = pool.alloc(256)
|
||||
init_lk: char* = pool.alloc(256)
|
||||
if init_lk is not None:
|
||||
viperlib.snprintf(init_lk, 256, "%s.__init__", spec_name)
|
||||
if self.find_func_in_module(mod, init_lk) is not None: gi_has_init = 1
|
||||
@@ -1272,7 +1272,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
for fi_sf in range(int(struct_entry.FieldCount)):
|
||||
cand_sf: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(struct_entry, fi_sf)
|
||||
if cand_sf is None: continue
|
||||
cn_sf: str = self.Gen.StructGen.get_field_name_ptr(cand_sf)
|
||||
cn_sf: char* = self.Gen.StructGen.get_field_name_ptr(cand_sf)
|
||||
if cn_sf is not None and string.strcmp(cn_sf, "__vtable__") == 0: continue
|
||||
if tidx_sf == ai_sf:
|
||||
fe_sf = cand_sf
|
||||
|
||||
@@ -27,14 +27,14 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
|
||||
# _tc_h0_generic_func - generic function call: infer/specialize type args, then emit the call.
|
||||
# Must run before normal function/constructor dispatch; hit_box marks handled void calls.
|
||||
def _tc_h0_generic_func(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
def _tc_h0_generic_func(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: char*, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
if cl is None or trans is None: return None
|
||||
if self.Gen.ClassGenGeneric.GenericFuncKeys is None: return None
|
||||
if cl.func is None: return None
|
||||
# ---- Classify the generic call shape + template name / explicit type args ----
|
||||
tpl_name: str = None
|
||||
tpl_name: char* = None
|
||||
explicit_slice: ast.AST* = None
|
||||
tpl_mod_sha1: str = None
|
||||
tpl_mod_sha1: char* = None
|
||||
is_attr_call: int = 0
|
||||
fk: int = cl.func.kind()
|
||||
if fk == ast.ASTKind.Subscript:
|
||||
@@ -57,20 +57,20 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
tpl_name = at.attr
|
||||
if tpl_name is None: return None
|
||||
# ---- Resolve template key "{sha1}.{fname}": module-qualified > local > from_imports ----
|
||||
tpl_key: str = None
|
||||
tpl_key: char* = None
|
||||
if is_attr_call != 0:
|
||||
# Module-qualified call: only accept the key under that module's SHA1
|
||||
if tpl_mod_sha1 is not None:
|
||||
cand_q: str = self._generic_func_key(pool, tpl_mod_sha1, tpl_name)
|
||||
cand_q: char* = self._generic_func_key(pool, tpl_mod_sha1, tpl_name)
|
||||
if self.Gen.ClassGenGeneric._find_generic_func_template(cand_q) is not None: tpl_key = cand_q
|
||||
else:
|
||||
if trans.ModuleSha1 is not None:
|
||||
cand_l: str = self._generic_func_key(pool, trans.ModuleSha1, tpl_name)
|
||||
cand_l: char* = self._generic_func_key(pool, trans.ModuleSha1, tpl_name)
|
||||
if self.Gen.ClassGenGeneric._find_generic_func_template(cand_l) is not None: tpl_key = cand_l
|
||||
if tpl_key is None and trans._from_imports is not None:
|
||||
imp_sha: str = self._lookup_mod_sha1(pool, trans._from_imports, tpl_name, 0)
|
||||
imp_sha: char* = self._lookup_mod_sha1(pool, trans._from_imports, tpl_name, 0)
|
||||
if imp_sha is not None:
|
||||
cand_f: str = self._generic_func_key(pool, imp_sha, tpl_name)
|
||||
cand_f: char* = self._generic_func_key(pool, imp_sha, tpl_name)
|
||||
if self.Gen.ClassGenGeneric._find_generic_func_template(cand_f) is not None: tpl_key = cand_f
|
||||
if tpl_key is None: return None
|
||||
template_fd: ast.FunctionDef* = self.Gen.ClassGenGeneric._find_generic_func_template(tpl_key)
|
||||
@@ -94,8 +94,8 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if type_args is None: return None
|
||||
tpi: sizet
|
||||
for tpi in range(int(tp_count)):
|
||||
tp_name: str = tp_names.get(tpi)
|
||||
ta: str = None
|
||||
tp_name: char* = tp_names.get(tpi)
|
||||
ta: char* = None
|
||||
slot: int = self.Gen.ClassGenGeneric._find_generic_func_param_slot(template_fd, tp_name)
|
||||
if slot >= 0 and sizet(slot) < can: ta = self.Gen.ClassGenGeneric._infer_generic_func_type_arg(pool, cargs.get(sizet(slot)), tpl_name, trans)
|
||||
if ta is None and slot >= 0:
|
||||
@@ -110,18 +110,18 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
return None
|
||||
type_args.append(ta)
|
||||
# ---- Specialize ----
|
||||
spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_function(trans, tpl_key, type_args)
|
||||
spec_name: char* = self.Gen.ClassGenGeneric._specialize_generic_function(trans, tpl_key, type_args)
|
||||
if spec_name is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Generic function '{tpl_name}': specialization failed", "TypeError")
|
||||
return None
|
||||
# ---- Emit call ----
|
||||
return self._emit_generic_func_call(pool, builder, mod, trans, cl, spec_name, cargs, can, hit_box)
|
||||
|
||||
def _generic_func_key(self, pool: memhub.MemBuddy*, sha1: str, name: str) -> str:
|
||||
def _generic_func_key(self, pool: memhub.MemBuddy*, sha1: char*, name: char*) -> str:
|
||||
"""Build the generic function template key "{sha1}.{name}" in a new buffer."""
|
||||
if sha1 is None or name is None: return None
|
||||
klen: sizet = string.strlen(sha1) + string.strlen(name) + 2
|
||||
kbuf: str = pool.alloc(klen)
|
||||
kbuf: char* = pool.alloc(klen)
|
||||
if kbuf is None: return None
|
||||
viperlib.snprintf(kbuf, klen, "%s.%s", sha1, name)
|
||||
return kbuf
|
||||
@@ -147,7 +147,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if string.strcmp(kw.arg, ag.arg) == 0: return int(ki)
|
||||
return -1
|
||||
|
||||
def _emit_generic_func_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, trans: HT.Translator*, cl: ast.Call*, spec_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
def _emit_generic_func_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, trans: HT.Translator*, cl: ast.Call*, spec_name: char*, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
"""Emit the specialized-function call, coercing args to the specialized param types."""
|
||||
func: mlirlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, spec_name)
|
||||
if func is None:
|
||||
@@ -188,7 +188,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# reads its first field as a string and emits illegal IR. Use the looked-up symbol name.
|
||||
return mlirlite.build_call(builder, spec_name, head, int(can), ret_ty, 0)
|
||||
|
||||
def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: char*, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
"""Compile-time super()/ctraits detection; sets hit_box on interception, else returns None."""
|
||||
# super().method(args) -> static call to the parent method. Must intercept before attribute
|
||||
# dispatch, else Call(super) is treated as a plain function call and lookup hits self/vtable.
|
||||
@@ -220,7 +220,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
return mlirlite.const_int32(pool, 0)
|
||||
return None
|
||||
|
||||
def _tc_h2_c_special(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
def _tc_h2_c_special(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: char*, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
"""Special __asm__/__llvmir__ calls; marks hit_box for void calls, else returns None."""
|
||||
# Retired c.* pointer builtins: fail fast with the replacement syntax.
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
@@ -292,7 +292,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
return self.Gen.AsyncGen.translate_coro_gather(builder, pool, mod, cl, trans)
|
||||
return None
|
||||
|
||||
def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*:
|
||||
def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: char*, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*:
|
||||
"""stdarg sugar and str/int/bool built-in casts; returns None when unmatched."""
|
||||
# stdarg sugar (va_arg / arg / va_start / va_end): these are declared as pass bodies in
|
||||
# stdarg.vp and handled here at translation time by emitting LLVM va_arg / intrinsic calls.
|
||||
@@ -306,10 +306,10 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
elif string.strcmp(func_name, "va_end") == 0:
|
||||
return self.Gen.CallGenVa._translate_va_end_sugar(pool, builder, mod, cargs, can, funcs_ptr, func_count, trans)
|
||||
|
||||
# Builtin casts: str(x)/bytes(x) -> i8*, int(x) -> i32, equivalent to (str)(x)/(int32)(x).
|
||||
# Builtin casts: char*(x)/bytes(x) -> i8*, int(x) -> i32, equivalent to (str)(x)/(int32)(x).
|
||||
# In generic contexts T(x) first resolves T to a concrete type, then follows this path.
|
||||
if func_name is not None and can == 1:
|
||||
cast_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name)
|
||||
cast_fn_name: char* = self.Gen.TypeGenBase.resolve_generic_type_name(func_name)
|
||||
if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0:
|
||||
# str(x) / bytes(x) → i8* (bitcast)
|
||||
cast_arg: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
@@ -354,7 +354,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
return None
|
||||
return None
|
||||
|
||||
def _tc_h4_type_casts(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*:
|
||||
def _tc_h4_type_casts(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: char*, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*:
|
||||
"""Builtin / typedef type casts; returns None when unmatched."""
|
||||
# Module-qualified typedef cast (posix.mode_t(mode), win32.win32base.LPCWSTR(v), ...): the
|
||||
# callee is Attribute(<module path>, typedef); non-typedef names still go to the module call.
|
||||
@@ -362,7 +362,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
mt_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if mt_at.attr is not None:
|
||||
# Module path supports both `mod.T` and nested `pkg.mod.T`.
|
||||
mt_mod_path: str = None
|
||||
mt_mod_path: char* = None
|
||||
if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name:
|
||||
mt_mod_nm: ast.Name* = ast.Name*(mt_at.value)
|
||||
mt_mod_path = mt_mod_nm.id
|
||||
@@ -371,23 +371,23 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if mt_mod_path is not None:
|
||||
mod_td_ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.map_builtin_type(pool, func_name)
|
||||
if mod_td_ty is None:
|
||||
mod_td_str: str = self.Gen.TypeGenCType.lookup_ctypedef(func_name)
|
||||
mod_td_str: char* = self.Gen.TypeGenCType.lookup_ctypedef(func_name)
|
||||
if mod_td_str is None or self.Gen.TypeGenCType.is_ctypedef_found() == 0:
|
||||
# Library typedef closure may not be injected yet: scan the module source.
|
||||
mod_td_str = self.Gen.TypeGenResolve._lookup_library_typedef(pool, mt_mod_path, func_name)
|
||||
if mod_td_str is not None:
|
||||
mod_td_ast: ast.AST* = self.Gen.TypeGenResolve._parse_type_string(pool, mod_td_str, 0)
|
||||
if mod_td_ast is not None:
|
||||
mod_imp_td: str = None
|
||||
mod_fi_td: str = None
|
||||
mod_imp_td: char* = None
|
||||
mod_fi_td: char* = None
|
||||
if trans is not None:
|
||||
mod_imp_td = trans._imported_modules
|
||||
mod_fi_td = trans._from_imports
|
||||
mod_td_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, mod_td_ast, mod_imp_td, mod_fi_td, trans, 0)
|
||||
if mod_td_ty is None:
|
||||
# Final fallback: the shared typedef resolver also scans stdint/win32base.
|
||||
mod_imp_fb: str = None
|
||||
mod_fi_fb: str = None
|
||||
mod_imp_fb: char* = None
|
||||
mod_fi_fb: char* = None
|
||||
if trans is not None:
|
||||
mod_imp_fb = trans._imported_modules
|
||||
mod_fi_fb = trans._from_imports
|
||||
@@ -399,7 +399,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Bare typedef casts (BYTEPTR, HANDLE, CHARPTR, ...): all TypedefT names and builtin primitives
|
||||
# are castable. In generic contexts T(x) first resolves T, then goes through resolve_typedef_or_map.
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||||
bare_fn_name: str = self.Gen.TypeGenBase.resolve_generic_type_name(func_name)
|
||||
bare_fn_name: char* = self.Gen.TypeGenBase.resolve_generic_type_name(func_name)
|
||||
bare_ty: mlirlite.LLVMType* = None
|
||||
# Builtin names resolved from generic context (T->"double"/"float"): float must map to
|
||||
# f32, not f64.
|
||||
@@ -408,8 +408,8 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
else:
|
||||
# Prefer the TypedefT dynamic table (library typedef casts); on miss fall back to
|
||||
# map_builtin_type.
|
||||
bare_imp_c: str = None
|
||||
bare_fi_c: str = None
|
||||
bare_imp_c: char* = None
|
||||
bare_fi_c: char* = None
|
||||
if trans is not None:
|
||||
bare_imp_c = trans._imported_modules
|
||||
bare_fi_c = trans._from_imports
|
||||
@@ -419,8 +419,8 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0:
|
||||
gp_ast: ast.AST* = self.Gen.TypeGenResolve._parse_type_string(pool, bare_fn_name, 0)
|
||||
if gp_ast is not None:
|
||||
imp_gp: str = None
|
||||
fi_gp: str = None
|
||||
imp_gp: char* = None
|
||||
fi_gp: char* = None
|
||||
if trans is not None:
|
||||
imp_gp = trans._imported_modules
|
||||
fi_gp = trans._from_imports
|
||||
@@ -457,7 +457,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
|
||||
return None
|
||||
|
||||
def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*:
|
||||
def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: char*, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*:
|
||||
"""__sizeof__/len/isinstance built-ins; returns None when unmatched."""
|
||||
# Detect ClassName.__sizeof__() and return the struct size constant (i64); it is a builtin,
|
||||
# not a cross-module call. Supports e.g. Argument.__sizeof__() and module-qualified classes.
|
||||
@@ -465,7 +465,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
sz_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0:
|
||||
if sz_at.value is not None and can == 0:
|
||||
sz_cls_name: str = None
|
||||
sz_cls_name: char* = None
|
||||
sz_vk: int = sz_at.value.kind()
|
||||
if sz_vk == ast.ASTKind.Name:
|
||||
sz_cls_nm2: ast.Name* = ast.Name*(sz_at.value)
|
||||
@@ -480,7 +480,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
sz_inner_nm: ast.Name* = ast.Name*(sz_inner_at.value)
|
||||
if sz_inner_nm.id is not None:
|
||||
sz_full_len: sizet = string.strlen(sz_inner_nm.id) + 1 + string.strlen(sz_inner_at.attr) + 1
|
||||
sz_full_buf: str = pool.alloc(sz_full_len)
|
||||
sz_full_buf: char* = pool.alloc(sz_full_len)
|
||||
if sz_full_buf is not None:
|
||||
sz_full_buf[0] = '\0'
|
||||
string.strcat(sz_full_buf, sz_inner_nm.id)
|
||||
@@ -488,10 +488,10 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
string.strcat(sz_full_buf, sz_inner_at.attr)
|
||||
sz_cls_name = sz_full_buf
|
||||
elif sz_inner_at.value.kind() == ast.ASTKind.Attribute:
|
||||
sz_mod_path: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, sz_inner_at.value)
|
||||
sz_mod_path: char* = self.Gen.ExprGenAttr._attr_module_path_str(pool, sz_inner_at.value)
|
||||
if sz_mod_path is not None:
|
||||
sz_full_len2: sizet = string.strlen(sz_mod_path) + 1 + string.strlen(sz_inner_at.attr) + 1
|
||||
sz_full_buf2: str = pool.alloc(sz_full_len2)
|
||||
sz_full_buf2: char* = pool.alloc(sz_full_len2)
|
||||
if sz_full_buf2 is not None:
|
||||
sz_full_buf2[0] = '\0'
|
||||
string.strcat(sz_full_buf2, sz_mod_path)
|
||||
@@ -500,10 +500,10 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
sz_cls_name = sz_full_buf2
|
||||
# Resolve the struct type: type-name hit -> generic specialization (Stack[T]) -> receiver type (self/obj)
|
||||
sz_resolved_ty: mlirlite.LLVMType* = None
|
||||
sz_resolved_name: str = sz_cls_name
|
||||
sz_resolved_name: char* = sz_cls_name
|
||||
if sz_cls_name is not None:
|
||||
# Replace generic type parameter T: T.__sizeof__() -> int.__sizeof__()
|
||||
sz_orig: str = sz_cls_name
|
||||
sz_orig: char* = sz_cls_name
|
||||
sz_cls_name = self.Gen.TypeGenBase.resolve_generic_type_name(sz_cls_name)
|
||||
# Fallback when the TypeGenBase context is empty (template tp_names expired
|
||||
# across phases): replace T using trans's generic mapping.
|
||||
@@ -511,9 +511,9 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
gp_n: sizet = len(trans.GenericTypeParamNames)
|
||||
gp_i: sizet
|
||||
for gp_i in range(int(gp_n)):
|
||||
gpn: str = trans.GenericTypeParamNames.get(gp_i)
|
||||
gpn: char* = trans.GenericTypeParamNames.get(gp_i)
|
||||
if gpn is not None and string.strcmp(sz_orig, gpn) == 0:
|
||||
gta: str = trans.GenericTypeArgs.get(gp_i)
|
||||
gta: char* = trans.GenericTypeArgs.get(gp_i)
|
||||
if gta is not None: sz_cls_name = gta
|
||||
break
|
||||
sz_resolved_name = sz_cls_name
|
||||
@@ -528,10 +528,10 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if _sz_len_s > 0 and sz_cls_name[_sz_len_s - 1] == '*': return mlirlite.const_int64(pool, 8)
|
||||
# Save the full name (with module prefix) for exact module matching: stripping it
|
||||
# lets get_struct_type globally match a same-named class from another module.
|
||||
sz_full_name: str = sz_cls_name
|
||||
sz_full_name: char* = sz_cls_name
|
||||
# Strip the module prefix: the Viper parser yields Name(id="int") rather than
|
||||
# Attribute, so manually take the last class-name component.
|
||||
dot_pos: str = string.strrchr(sz_cls_name, '.')
|
||||
dot_pos: char* = string.strrchr(sz_cls_name, '.')
|
||||
if dot_pos is not None: sz_cls_name = dot_pos + 1
|
||||
# [Phase 3] Unified size convention: resolve library typedefs first, only then
|
||||
# use the hardcoded table. Pass trans's imports so from-import alias chains resolve.
|
||||
@@ -567,16 +567,16 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Module-qualified classes match the defining module exactly, preventing a
|
||||
# same-named class from another module from being matched globally.
|
||||
if sz_full_name is not None:
|
||||
szf_dot: str = string.strrchr(sz_full_name, '.')
|
||||
szf_dot: char* = string.strrchr(sz_full_name, '.')
|
||||
if szf_dot is not None:
|
||||
szf_mod_len: sizet = sizet(uint64(szf_dot) - uint64(sz_full_name))
|
||||
szf_mod: str = pool.alloc(szf_mod_len + 1)
|
||||
szf_mod: char* = pool.alloc(szf_mod_len + 1)
|
||||
if szf_mod is not None:
|
||||
string.strncpy(szf_mod, sz_full_name, szf_mod_len)
|
||||
szf_mod[szf_mod_len] = '\0'
|
||||
# Module-qualified builtin names are already handled by the builtin/size table.
|
||||
if szf_mod is not None:
|
||||
szf_sha1: str = self.Gen.StructGen._resolve_module_sha1(szf_mod, trans._from_imports if trans is not None else None)
|
||||
szf_sha1: char* = self.Gen.StructGen._resolve_module_sha1(szf_mod, trans._from_imports if trans is not None else None)
|
||||
if szf_sha1 is not None:
|
||||
szf_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(sz_cls_name, szf_sha1)
|
||||
if szf_entry is not None and szf_entry.Ty is not None: sz_resolved_ty = szf_entry.Ty
|
||||
@@ -595,9 +595,9 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
gai_sz: sizet = len(gen_args_sz)
|
||||
gai2_sz: sizet = 0
|
||||
for gai2_sz in range(int(gai_sz)):
|
||||
gres_sz: str = self.Gen.TypeGenBase.resolve_generic_type_name(gen_args_sz.get(gai2_sz))
|
||||
gres_sz: char* = self.Gen.TypeGenBase.resolve_generic_type_name(gen_args_sz.get(gai2_sz))
|
||||
gargs_resolved.append(gres_sz)
|
||||
spec_sz: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, gen_nm_sz.id, gargs_resolved)
|
||||
spec_sz: char* = self.Gen.ClassGenGeneric._specialize_generic_class(trans, gen_nm_sz.id, gargs_resolved)
|
||||
if spec_sz is not None:
|
||||
sz_resolved_name = spec_sz
|
||||
sz_resolved_ty = self.Gen.StructGen.get_struct_type(spec_sz)
|
||||
@@ -686,7 +686,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# strlen on the first field). list containers inline-read __count__; plain classes call {Class}.__len__.
|
||||
len_struct_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(len_val)
|
||||
if len_struct_ty is not None:
|
||||
len_cls_nm: str = self.Gen.StructGen.get_class_name_by_type(pool, len_struct_ty)
|
||||
len_cls_nm: char* = self.Gen.StructGen.get_class_name_by_type(pool, len_struct_ty)
|
||||
if len_cls_nm is None: self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() argument type inference failed (unknown struct class name)", "TypeError")
|
||||
# list builtin __len__: read __count__ (GEP offset 1, i64). Narrow len_arg_node
|
||||
# to ast.Call* explicitly, since passing a base pointer to a derived param is banned.
|
||||
@@ -696,13 +696,13 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
idx_one_lb: mlirlite.Value* = mlirlite.const_int64(pool, 1)
|
||||
cnt_ptr_lb: mlirlite.Value* = mlirlite.build_gep(builder, i64_ty_lb, len_val, idx_one_lb)
|
||||
if cnt_ptr_lb is not None: return mlirlite.build_load(builder, i64_ty_lb, cnt_ptr_lb)
|
||||
len_lookup: str = pool.alloc(128)
|
||||
len_lookup: char* = pool.alloc(128)
|
||||
if len_lookup is not None:
|
||||
viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm)
|
||||
len_fn2: mlirlite.Function* = self.find_func_in_module(mod, len_lookup)
|
||||
if len_fn2 is not None:
|
||||
len_ret_ty2: mlirlite.LLVMType* = mlirlite.function_get_ret_ty(len_fn2)
|
||||
len_fn_name2: str = mlirlite.function_get_name(len_fn2)
|
||||
len_fn_name2: char* = mlirlite.function_get_name(len_fn2)
|
||||
if len_ret_ty2 is not None and len_fn_name2 is not None:
|
||||
# Align the self parameter type (bitcast to the method's first param)
|
||||
len_self_arg2: mlirlite.Value* = len_val
|
||||
@@ -714,12 +714,12 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
return mlirlite.build_call(builder, len_fn_name2, len_self_arg2, 1, len_ret_ty2, 0)
|
||||
# len_fn2 miss (cross-module method): build the exact name {sha1}.{cls}.__len__
|
||||
# from the struct's module sha1, resolve the return type from text.ll/vpi, then call.
|
||||
len_cls_sha1_x: str = self.Gen.StructGen.get_struct_sha1(len_cls_nm)
|
||||
len_cls_sha1_x: char* = self.Gen.StructGen.get_struct_sha1(len_cls_nm)
|
||||
if len_cls_sha1_x is not None:
|
||||
# Buffer must fit "{sha1}.{cls}.__len__": 2 dots + "__len__"(7) + NUL = 10;
|
||||
# +8 truncates the last two chars and breaks the link.
|
||||
len_ml_x: sizet = string.strlen(len_cls_sha1_x) + string.strlen(len_cls_nm) + 10
|
||||
len_mangled_x: str = pool.alloc(len_ml_x)
|
||||
len_mangled_x: char* = pool.alloc(len_ml_x)
|
||||
if len_mangled_x is not None:
|
||||
viperlib.snprintf(len_mangled_x, len_ml_x, "%s.%s.__len__", len_cls_sha1_x, len_cls_nm)
|
||||
len_ret_x: mlirlite.LLVMType* = self._lookup_method_ret_ty_via_vpi(pool, len_cls_sha1_x, len_cls_nm, "__len__")
|
||||
@@ -734,7 +734,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# fail-fast: the class has no __len__ (compile-time error, matching TPC
|
||||
# HandlesExprBuiltin._FailFastLenUnsupported wording).
|
||||
self.Gen.TypeGenErr.fatal_error(len_arg_node, f"len() argument type '{len_cls_nm}' has no __len__ method. len() only supports fixed-size arrays/array pointers (t.ArrayT[T, N]), i8* (str/bytes), or structs with __len__; non-i8 bare pointers/scalar pointers have no length semantics: use str/bytes for strings, record the length yourself when the element count is needed, or use rawptr[Element] and maintain the element count explicitly", "TypeError")
|
||||
# Non-struct: str (Ptr(Int8)) uses strlen; other types fail fast
|
||||
# Non-struct: char* (Ptr(Int8)) uses strlen; other types fail fast
|
||||
len_arg_ty: mlirlite.LLVMType* = mlirlite.value_get_ty(len_val)
|
||||
len_is_str: int = 0
|
||||
if len_arg_ty is not None and self.Gen.ExprGenBase.is_ptr_type(len_arg_ty) != 0:
|
||||
@@ -778,7 +778,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
|
||||
return None
|
||||
|
||||
def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: char*, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*:
|
||||
"""Static class/method/receiver/self.field/list built-ins; sets hit_box, else returns None."""
|
||||
# REnum.kind() compiles to a __tag read (offset 0, type from the field declaration): bitcast obj
|
||||
# to __tag* + load. Four criteria detect REnum, incl. pointee __tag and X.field annotations.
|
||||
@@ -789,7 +789,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if rk_obj is not None and rk_obj.Ty is not None:
|
||||
rk_ty: mlirlite.LLVMType* = rk_obj.Ty
|
||||
rk_load: int = 0
|
||||
rk_cls: str = None
|
||||
rk_cls: char* = None
|
||||
rk_pointee: mlirlite.LLVMType* = None
|
||||
# rk_is_rn: whether already determined to be a REnum, decoupled from rk_cls.
|
||||
rk_is_rn: int = 0
|
||||
@@ -820,17 +820,17 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
rk_nm: ast.Name* = ast.Name*(rk_at.value)
|
||||
if rk_nm.id is not None:
|
||||
rk_ve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, rk_nm.id)
|
||||
rk_annot_raw: str = self.Gen.VarGen.var_annot_class_name(rk_ve)
|
||||
rk_annot_raw: char* = self.Gen.VarGen.var_annot_class_name(rk_ve)
|
||||
if rk_annot_raw is not None:
|
||||
# Truncate the union/generic suffix (" | rawptr" / "[...]")
|
||||
rk_ae: sizet = 0
|
||||
while rk_annot_raw[rk_ae] != '\0' and rk_annot_raw[rk_ae] != ' ' and rk_annot_raw[rk_ae] != '|' and rk_annot_raw[rk_ae] != '[': rk_ae += 1
|
||||
rk_ab: str = pool.alloc(rk_ae + 1)
|
||||
rk_ab: char* = pool.alloc(rk_ae + 1)
|
||||
if rk_ab is not None:
|
||||
string.strncpy(rk_ab, rk_annot_raw, rk_ae)
|
||||
rk_ab[rk_ae] = '\0'
|
||||
# Strip the module prefix ("mlirlite.LLVMType" -> "LLVMType")
|
||||
rk_ad: str = string.strrchr(rk_ab, '.')
|
||||
rk_ad: char* = string.strrchr(rk_ab, '.')
|
||||
if rk_ad is not None and rk_ad[1] != '\0': rk_cls = rk_ad + 1
|
||||
else: rk_cls = rk_ab
|
||||
# Same criteria as above (table or struct with __tag), not just the variant table
|
||||
@@ -850,17 +850,17 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
rk_bnm: ast.Name* = ast.Name*(rk_bat.value)
|
||||
if rk_bnm.id is not None:
|
||||
rk_bve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, rk_bnm.id)
|
||||
rk_bannot: str = self.Gen.VarGen.var_annot_class_name(rk_bve)
|
||||
rk_bannot: char* = self.Gen.VarGen.var_annot_class_name(rk_bve)
|
||||
if rk_bannot is not None:
|
||||
rk_blen: sizet = 0
|
||||
while rk_bannot[rk_blen] != '\0' and rk_bannot[rk_blen] != ' ' and rk_bannot[rk_blen] != '|' and rk_bannot[rk_blen] != '[': rk_blen += 1
|
||||
rk_bbuf: str = pool.alloc(rk_blen + 1)
|
||||
rk_bbuf: char* = pool.alloc(rk_blen + 1)
|
||||
if rk_bbuf is not None:
|
||||
string.strncpy(rk_bbuf, rk_bannot, rk_blen)
|
||||
rk_bbuf[rk_blen] = '\0'
|
||||
# Strip the module prefix ("mlirlite.Value" -> "Value")
|
||||
rk_bdot: str = string.strrchr(rk_bbuf, '.')
|
||||
rk_bcls: str = rk_bbuf
|
||||
rk_bdot: char* = string.strrchr(rk_bbuf, '.')
|
||||
rk_bcls: char* = rk_bbuf
|
||||
if rk_bdot is not None and rk_bdot[1] != '\0': rk_bcls = rk_bdot + 1
|
||||
rk_bst: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type(rk_bcls)
|
||||
if rk_bst is not None:
|
||||
@@ -871,7 +871,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
rk_fpt = rk_fpt.Pointee
|
||||
if rk_fpt is not None and self.Gen.ExprGenBase.is_ptr_type(rk_fpt) != 0: rk_fpt = rk_fpt.Pointee
|
||||
if rk_fpt is not None:
|
||||
rk_fcls: str = self.Gen.StructGen.get_class_name_by_type(pool, rk_fpt)
|
||||
rk_fcls: char* = self.Gen.StructGen.get_class_name_by_type(pool, rk_fpt)
|
||||
if rk_fcls is not None:
|
||||
if self.Gen.ClassGenEnum._is_renum_class_name(rk_fcls) != 0 or self.Gen.ClassGenEnum._is_renum_by_entry(rk_fcls) != 0:
|
||||
rk_is_rn = 1
|
||||
@@ -954,7 +954,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# The struct value is inline in the slot: the slot address is the object address (self)
|
||||
rp_val = self.Gen.VarGen.repl_try_addr(trans, rp_nm.id, cl)
|
||||
else: rp_val = self.Gen.VarGen.repl_try_read(trans, rp_nm.id, cl)
|
||||
rp_cls: str = None
|
||||
rp_cls: char* = None
|
||||
if rp_val is not None and rp_val.Ty is not None:
|
||||
rp_sty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(rp_val)
|
||||
if rp_sty is not None: rp_cls = self.Gen.StructGen.get_class_name_by_type(pool, rp_sty)
|
||||
@@ -983,7 +983,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
recv_ty_c = recv_ty_c.Pointee
|
||||
# Heap objects (@t.Object) are double pointers: deref once more to get the struct
|
||||
if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0: recv_ty_c = recv_ty_c.Pointee
|
||||
recv_cls_c: str = self.Gen.StructGen.get_class_name_by_type(pool, recv_ty_c)
|
||||
recv_cls_c: char* = self.Gen.StructGen.get_class_name_by_type(pool, recv_ty_c)
|
||||
if recv_cls_c is not None:
|
||||
if self.Gen.CallGenProp._is_list_builtin_receiver(pool, recv_val_c, recv_cls_c, method_at.attr, cl) == 0:
|
||||
obj_ptr_c: mlirlite.Value* = recv_val_c
|
||||
@@ -1014,7 +1014,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if nl_slot is not None: nl_deref = nl_slot
|
||||
nl_struct: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(nl_deref)
|
||||
if nl_struct is not None:
|
||||
nl_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, nl_struct)
|
||||
nl_cls: char* = self.Gen.StructGen.get_class_name_by_type(pool, nl_struct)
|
||||
if nl_cls is not None:
|
||||
if self.Gen.CallGenProp._is_list_builtin_receiver(pool, nl_deref, nl_cls, func_name, cl) == 0:
|
||||
if hit_box is not None: hit_box[0] = 1
|
||||
@@ -1028,15 +1028,15 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Identify list generic container annotations early (shared by the class branches below): rawptr[list[rawptr[AST]]] is Ptr(Ptr(Struct('list[...]'))), and the list specialty struct is not registered as a normal class, so unwrap one rawptr and flag is_list_annot_builtin for the inlined list branch.
|
||||
var_entry: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, method_obj_nm.id)
|
||||
is_list_annot_builtin: int = 0
|
||||
la_buf: str = self.Gen.VarGen.var_annot_class_name(var_entry)
|
||||
la_buf: char* = self.Gen.VarGen.var_annot_class_name(var_entry)
|
||||
if la_buf is not None:
|
||||
la_tail: str = la_buf
|
||||
la_tail: char* = la_buf
|
||||
if string.strncmp(la_buf, "rawptr[", 7) == 0: la_tail = la_buf + 7
|
||||
if string.strncmp(la_tail, "list", 4) == 0:
|
||||
if self.Gen.CallGenProp._is_list_builtin_receiver(pool, obj_var, la_tail, func_name, cl) != 0: is_list_annot_builtin = 1
|
||||
match obj_var.Ty:
|
||||
case mlirlite.LLVMType.Ptr(obj_struct_ty):
|
||||
class_nm: str = self.Gen.StructGen.get_class_name_by_type(pool, obj_struct_ty)
|
||||
class_nm: char* = self.Gen.StructGen.get_class_name_by_type(pool, obj_struct_ty)
|
||||
if class_nm is not None:
|
||||
# list builtin container methods (append/get/set/pop/clear/__iter__/...) are
|
||||
# inlined by the list builtin branch below; skip _translate_method_call for them.
|
||||
@@ -1047,7 +1047,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Ptr(Struct) before lookup.
|
||||
match obj_struct_ty:
|
||||
case mlirlite.LLVMType.Ptr(inner_struct_ty):
|
||||
inner_nm: str = self.Gen.StructGen.get_class_name_by_type(pool, inner_struct_ty)
|
||||
inner_nm: char* = self.Gen.StructGen.get_class_name_by_type(pool, inner_struct_ty)
|
||||
if inner_nm is not None:
|
||||
# Skip list builtin methods here too (same as the Ptr(Struct) branch);
|
||||
# inner_nm may also be misread as the inner element class.
|
||||
@@ -1063,12 +1063,12 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if fd_name_res is not None: return fd_name_res
|
||||
# AnnotClassName fallback: for unions simplified to Ptr(i8), look up the struct by the
|
||||
# original annotation's class name. Skip when is_list_annot_builtin is set.
|
||||
annot_val: str = self.Gen.VarGen.var_annot_class_name(var_entry)
|
||||
annot_val: char* = self.Gen.VarGen.var_annot_class_name(var_entry)
|
||||
if annot_val is not None and is_list_annot_builtin == 0:
|
||||
# Parse the module-qualified name "memhub.MemBuddy" -> mod_nm="memhub", cls_nm="MemBuddy"
|
||||
dot_ptr: str = string.strrchr(annot_val, '.')
|
||||
cls_nm2: str = annot_val
|
||||
mod_nm2: str = None
|
||||
dot_ptr: char* = string.strrchr(annot_val, '.')
|
||||
cls_nm2: char* = annot_val
|
||||
mod_nm2: char* = None
|
||||
if dot_ptr is not None:
|
||||
cls_nm2 = dot_ptr + 1
|
||||
total_len_av: sizet = string.strlen(annot_val)
|
||||
@@ -1099,12 +1099,12 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if fd_res is not None: return fd_res
|
||||
# Struct unregistered (cross-module dependency not translated): look up
|
||||
# the module SHA1 to build the method call name.
|
||||
sha1_fc: str = None
|
||||
sha1_fc: char* = None
|
||||
if mod_nm2 is not None: sha1_fc = self._lookup_module_sha1(mod_nm2)
|
||||
if sha1_fc is not None:
|
||||
# Build the "{sha1}.{cls_nm2}.{func_name}" call name
|
||||
mlen3: sizet = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3
|
||||
mangled3: str = pool.alloc(mlen3)
|
||||
mangled3: char* = pool.alloc(mlen3)
|
||||
if mangled3 is not None:
|
||||
viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name)
|
||||
# load obj_ptr (self)
|
||||
@@ -1161,7 +1161,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
expr_root: ast.AST* = expr_method_at.value
|
||||
while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute: expr_root = ast.Attribute*(expr_root).value
|
||||
if expr_root is not None and expr_root.kind() == ast.ASTKind.Name:
|
||||
expr_root_nm: str = ast.Name*(expr_root).id
|
||||
expr_root_nm: char* = ast.Name*(expr_root).id
|
||||
if expr_root_nm is not None:
|
||||
if trans._imported_modules is not None:
|
||||
if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, expr_root_nm) != 0: is_mod_path_expr = 1
|
||||
@@ -1169,7 +1169,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Translate the receiver expression (the result should be Ptr(Struct))
|
||||
expr_obj: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans)
|
||||
if expr_obj is not None and expr_obj.Ty is not None:
|
||||
expr_cls_nm: str = None
|
||||
expr_cls_nm: char* = None
|
||||
# Recursively unwrap Ptr to handle the Ptr(Ptr(Struct)) of X* unions (e.g. Vec3**);
|
||||
# otherwise the method call is treated as a bare @dot and links undefined.
|
||||
expr_struct_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(expr_obj)
|
||||
@@ -1212,7 +1212,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Translate self.__pool__ to get the field value (an already-loaded object pointer)
|
||||
field_obj: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans)
|
||||
if field_obj is not None and field_obj.Ty is not None:
|
||||
field_cls_nm: str = None
|
||||
field_cls_nm: char* = None
|
||||
# Path 1: get the class name from the field value's LLVM type
|
||||
match field_obj.Ty:
|
||||
case mlirlite.LLVMType.Ptr(field_struct_ty):
|
||||
@@ -1228,9 +1228,9 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
case mlirlite.LLVMType.Ptr(field_owner_struct_ty):
|
||||
field_info: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(field_owner_struct_ty, inner_attr.attr)
|
||||
if field_info is not None:
|
||||
field_annot: str = self.Gen.StructGen.get_field_annot_class_name(field_info)
|
||||
field_annot: char* = self.Gen.StructGen.get_field_annot_class_name(field_info)
|
||||
if field_annot is not None:
|
||||
dot_p: str = string.strrchr(field_annot, 46)
|
||||
dot_p: char* = string.strrchr(field_annot, 46)
|
||||
if dot_p is not None: field_cls_nm = dot_p + 1
|
||||
else: field_cls_nm = field_annot
|
||||
if field_cls_nm is not None:
|
||||
@@ -1253,7 +1253,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
lm_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if lm_at is not None and lm_at.attr is not None and lm_at.value is not None:
|
||||
lm_name: str = lm_at.attr
|
||||
lm_name: char* = lm_at.attr
|
||||
# Check whether this is a list method name
|
||||
lm_is_list: int = 0
|
||||
if string.strcmp(lm_name, "get") == 0: lm_is_list = 1
|
||||
@@ -1278,7 +1278,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Confirm the object really is a list (the branch matches by method name only, and
|
||||
# get/set are not list-specific); skip otherwise to avoid wrong GEP offsets.
|
||||
lm_conf_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||||
lm_conf_nm: str = None
|
||||
lm_conf_nm: char* = None
|
||||
if lm_conf_ty is not None: lm_conf_nm = mlirlite.get_struct_name(lm_conf_ty)
|
||||
# [S4] Compare the container base name exactly: the LLVM name carries a module sha1
|
||||
# prefix; SpecTypeNameBaseIs strips/truncates before comparing, avoiding substring false hits.
|
||||
@@ -1292,7 +1292,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Element type T is resolved from the list specialization name (list[int]->i32,
|
||||
# list[str]->i8*); using a fixed i8* would corrupt adjacent elements in set/pop.
|
||||
lm_esty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||||
lm_ename: str = None
|
||||
lm_ename: char* = None
|
||||
if lm_esty is not None: lm_ename = mlirlite.get_struct_name(lm_esty)
|
||||
lm_elem_ty: mlirlite.LLVMType* = None
|
||||
if lm_ename is not None: lm_elem_ty = self.Gen.ExprGenName._list_elem_type_from_name(pool, lm_ename)
|
||||
@@ -1382,7 +1382,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# memory reallocation handled in the _list implementation.
|
||||
elif string.strcmp(lm_name, "append") == 0:
|
||||
if can >= 1:
|
||||
ap_sha1: str = self._lookup_module_sha1("_list")
|
||||
ap_sha1: char* = self._lookup_module_sha1("_list")
|
||||
if ap_sha1 is None:
|
||||
# Dependency module not compiled (_list not in the chain): fail fast, never
|
||||
# silently skip append (elements would never be added).
|
||||
@@ -1390,22 +1390,22 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if ap_sha1 is not None:
|
||||
# The append symbol is {sha1}.list[AST*].append (specialized name), not
|
||||
# {sha1}.list.append; derive the specialized name from lm_obj's type.
|
||||
ap_spec_nm: str = None
|
||||
ap_spec_nm: char* = None
|
||||
ap_struct_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||||
if ap_struct_ty is not None: ap_spec_nm = self.Gen.StructGen.get_class_name_by_type(pool, ap_struct_ty)
|
||||
if ap_spec_nm is None: ap_spec_nm = "list"
|
||||
# Trigger generic specialization translation (idempotent): the append define is
|
||||
# emitted when the specialty class is translated, otherwise the symbol is missing.
|
||||
if trans is not None and ap_spec_nm is not None:
|
||||
lbkt_ap: str = string.strchr(ap_spec_nm, '[')
|
||||
lbkt_ap: char* = string.strchr(ap_spec_nm, '[')
|
||||
if lbkt_ap is not None:
|
||||
rbkt_ap: str = string.strrchr(ap_spec_nm, ']')
|
||||
rbkt_ap: char* = string.strrchr(ap_spec_nm, ']')
|
||||
if rbkt_ap is not None and rbkt_ap > lbkt_ap:
|
||||
base_len_ap: sizet = sizet(uint64(lbkt_ap) - uint64(ap_spec_nm))
|
||||
arg_len_ap: sizet = sizet(uint64(rbkt_ap) - uint64(lbkt_ap) - 1)
|
||||
if base_len_ap > 0 and arg_len_ap > 0:
|
||||
base_buf_ap: str = pool.alloc(base_len_ap + 1)
|
||||
arg_buf_ap: str = pool.alloc(arg_len_ap + 1)
|
||||
base_buf_ap: char* = pool.alloc(base_len_ap + 1)
|
||||
arg_buf_ap: char* = pool.alloc(arg_len_ap + 1)
|
||||
if base_buf_ap is not None and arg_buf_ap is not None:
|
||||
string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap)
|
||||
base_buf_ap[base_len_ap] = '\0'
|
||||
@@ -1414,14 +1414,14 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
args_ap: list[str]* = list[str](pool, 8)
|
||||
if args_ap is not None:
|
||||
# Comma-separated multiple type args (list[X] / dict[K, V])
|
||||
cur_ap: str = arg_buf_ap
|
||||
cur_ap: char* = arg_buf_ap
|
||||
while cur_ap is not None:
|
||||
comma_ap: str = string.strchr(cur_ap, ',')
|
||||
comma_ap: char* = string.strchr(cur_ap, ',')
|
||||
if comma_ap is None:
|
||||
args_ap.append(cur_ap)
|
||||
break
|
||||
seg_len_ap: sizet = sizet(uint64(comma_ap) - uint64(cur_ap))
|
||||
seg_buf_ap: str = pool.alloc(seg_len_ap + 1)
|
||||
seg_buf_ap: char* = pool.alloc(seg_len_ap + 1)
|
||||
if seg_buf_ap is not None:
|
||||
string.strncpy(seg_buf_ap, cur_ap, seg_len_ap)
|
||||
seg_buf_ap[seg_len_ap] = '\0'
|
||||
@@ -1431,7 +1431,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# Call name "{sha1}.{spec}.append": length is spec + 25 (16+1+7+1), so the old +8
|
||||
# truncated the trailing 'd' and produced an undefined symbol.
|
||||
ap_mlen: sizet = string.strlen(ap_sha1) + string.strlen(ap_spec_nm) + 26
|
||||
ap_mangled: str = pool.alloc(ap_mlen)
|
||||
ap_mangled: char* = pool.alloc(ap_mlen)
|
||||
if ap_mangled is not None:
|
||||
viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", ap_sha1, ap_spec_nm)
|
||||
ap_item_node: ast.AST* = cargs.get(0)
|
||||
|
||||
@@ -14,7 +14,7 @@ from . import CallGenBase
|
||||
# CallGenFd - split from CallGenMixin (stage B): FakeDuck / requires field injection / provider stack
|
||||
novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
"""FakeDuck / requires field injection / provider stack"""
|
||||
def _translate_fakeduck_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cls_name: str, method_name: str, cl: ast.Call*, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
def _translate_fakeduck_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cls_name: char*, method_name: char*, cl: ast.Call*, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
"""FakeDuck: resolve a str variable's method call to extension class _Type/_str, return the call result or None"""
|
||||
if pool is None or builder is None or cl is None or trans is None: return None
|
||||
if method_name is None: return None
|
||||
@@ -27,11 +27,11 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
if string.strcmp(fd_at.attr, method_name) != 0: return None
|
||||
# Candidate extension classes: _Type first (a.type_id()), then _str (a.upper() etc.)
|
||||
fd_func: mlirlite.Function* = None
|
||||
fd_cls: str = None
|
||||
fd_key: str = pool.alloc(160)
|
||||
fd_cls: char* = None
|
||||
fd_key: char* = pool.alloc(160)
|
||||
if fd_key is not None:
|
||||
for fd_ci in range(2):
|
||||
fd_cn: str = "_Type"
|
||||
fd_cn: char* = "_Type"
|
||||
if fd_ci == 1: fd_cn = "_str"
|
||||
viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name)
|
||||
fd_func = self.find_func_in_module(mod, fd_key)
|
||||
@@ -53,7 +53,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
fd_onm: ast.Name* = ast.Name*(fd_at.value)
|
||||
if fd_onm.id is not None:
|
||||
# Pool-persistent buffer (an f-string stack buffer would expire after return)
|
||||
fd_mn: str = pool.alloc(256)
|
||||
fd_mn: char* = pool.alloc(256)
|
||||
if fd_mn is not None: viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id)
|
||||
fd_meta: mlirlite.Value* = self.Gen.VarGen.lookup_current(trans.SymTab, fd_mn)
|
||||
if fd_meta is not None and fd_has_fields != 0: fd_self = fd_meta
|
||||
@@ -99,7 +99,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
if fd_arg.kind() == ast.ASTKind.Constant:
|
||||
fd_ac: ast.Constant* = ast.Constant*(fd_arg)
|
||||
if fd_ac.const_kind == ast.CONST_CHAR:
|
||||
ch_buf: str = pool.alloc(2)
|
||||
ch_buf: char* = pool.alloc(2)
|
||||
if ch_buf is not None:
|
||||
ch_buf[0] = char(fd_ac.int_val)
|
||||
ch_buf[1] = '\0'
|
||||
@@ -111,11 +111,11 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
# Return type and call name (from the function definition hit by find_func_in_module)
|
||||
fd_ret_ty: mlirlite.LLVMType* = mlirlite.function_get_ret_ty(fd_func)
|
||||
if fd_ret_ty is None: fd_ret_ty = mlirlite.Int32(pool)
|
||||
fd_fname: str = mlirlite.function_get_name(fd_func)
|
||||
fd_fname: char* = mlirlite.function_get_name(fd_func)
|
||||
if fd_fname is None: return None
|
||||
# Refine return type: cross-module declare may simplify a list[T] specialization return type to Ptr(i8), degrading the caller's alloca type -> parts[0] takes the char-index path instead of list inline __getitem__ (printf %s crash). Authority is the defining module's vpi (fallback text.ll); extract the module sha1 only when the name is "{16hex}.{func}" (via GenApi.sha1_prefix_len)
|
||||
if GenApi.sha1_prefix_len(fd_fname) != 0:
|
||||
fd_sha1: str = pool.alloc(17)
|
||||
fd_sha1: char* = pool.alloc(17)
|
||||
if fd_sha1 is not None:
|
||||
string.strncpy(fd_sha1, fd_fname, 16)
|
||||
fd_sha1[16] = '\0'
|
||||
@@ -131,7 +131,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
# For each class __requires__ field (registered by fd1), call _find_provider(field) at runtime; if non-NULL bitcast and store it (conditional inject); skip when _find_provider is unregistered.
|
||||
|
||||
# ============================================================
|
||||
def _inject_requires_fields(self, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, meta_ptr: mlirlite.Value*, class_name: str) -> int:
|
||||
def _inject_requires_fields(self, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, meta_ptr: mlirlite.Value*, class_name: char*) -> int:
|
||||
"""Inject requires fields from the with context, return the injected field count"""
|
||||
if trans is None or pool is None or builder is None or mod is None: return 0
|
||||
if meta_ptr is None or class_name is None: return 0
|
||||
@@ -139,7 +139,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
# (matches TPC L4048-4050); otherwise non-with projects would emit undefined {sha1}._find_provider calls.
|
||||
fd_fn_probe: mlirlite.Function* = self.find_func_in_module(mod, "_find_provider")
|
||||
if fd_fn_probe is None: return 0
|
||||
fd_fname: str = mlirlite.function_get_name(fd_fn_probe)
|
||||
fd_fname: char* = mlirlite.function_get_name(fd_fn_probe)
|
||||
if fd_fname is None: return 0
|
||||
cnt: int = self.Gen.ClassGenBase.class_meta_count(GenTypes.CLASS_META_REQUIRES, class_name)
|
||||
if cnt <= 0: return 0
|
||||
@@ -153,7 +153,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
if cur_func is None: return 0
|
||||
injected: int = 0
|
||||
for ji in range(int(cnt)):
|
||||
fname: str = self.Gen.ClassGenBase.class_meta_field_at(GenTypes.CLASS_META_REQUIRES, class_name, ji)
|
||||
fname: char* = self.Gen.ClassGenBase.class_meta_field_at(GenTypes.CLASS_META_REQUIRES, class_name, ji)
|
||||
if fname is None: continue
|
||||
fe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(sty, fname)
|
||||
if fe is None or fe.Ty is None: continue
|
||||
@@ -173,7 +173,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
# conflict -> llc "Terminator found in the middle of a basic block").
|
||||
vtc2: int = trans._label_counter
|
||||
trans._label_counter = vtc2 + 1
|
||||
fd_bb_buf2: str = pool.alloc(64)
|
||||
fd_bb_buf2: char* = pool.alloc(64)
|
||||
if fd_bb_buf2 is None: continue
|
||||
viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2)
|
||||
fd_skip_bb: mlirlite.BasicBlock* = mlirlite.create_block(pool, cur_func, fd_bb_buf2)
|
||||
@@ -196,7 +196,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
# Matches TPC HandlesWith.py L138-174: push _push_provider(field, ctx_i8) on entry and equal _pop_provider() on exit.
|
||||
|
||||
# ============================================================
|
||||
def _emit_provider_push(self, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cls_name: str, ctx_val: mlirlite.Value*) -> int:
|
||||
def _emit_provider_push(self, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cls_name: char*, ctx_val: mlirlite.Value*) -> int:
|
||||
"""Emit a _push_provider(field, ctx_i8) call per provided field, return the field count"""
|
||||
if trans is None or pool is None or builder is None or mod is None: return 0
|
||||
if cls_name is None or ctx_val is None: return 0
|
||||
@@ -206,7 +206,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
# skip when this module does not import _withcontent, to avoid undefined symbol).
|
||||
fd_pfn_probe: mlirlite.Function* = self.find_func_in_module(mod, "_push_provider")
|
||||
if fd_pfn_probe is None: return 0
|
||||
fd_pfn: str = mlirlite.function_get_name(fd_pfn_probe)
|
||||
fd_pfn: char* = mlirlite.function_get_name(fd_pfn_probe)
|
||||
if fd_pfn is None: return 0
|
||||
i8_ty_p: mlirlite.LLVMType* = mlirlite.Int8(pool)
|
||||
if i8_ty_p is None: return 0
|
||||
@@ -218,7 +218,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
fd_ctx_i8: mlirlite.Value* = mlirlite.build_bitcast(builder, ctx_val, i8_ptr_ty_p)
|
||||
if fd_ctx_i8 is None: return 0
|
||||
for pi in range(int(fd_pc)):
|
||||
fname: str = self.Gen.ClassGenBase.class_meta_field_at(GenTypes.CLASS_META_PROVIDES, cls_name, pi)
|
||||
fname: char* = self.Gen.ClassGenBase.class_meta_field_at(GenTypes.CLASS_META_PROVIDES, cls_name, pi)
|
||||
if fname is None: continue
|
||||
fd_fstr: mlirlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fname, trans)
|
||||
if fd_fstr is None: continue
|
||||
@@ -227,7 +227,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
self._ensure_method_declare(pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2)
|
||||
mlirlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0)
|
||||
return fd_pc
|
||||
def _emit_provider_pop(self, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cls_name: str) -> int:
|
||||
def _emit_provider_pop(self, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cls_name: char*) -> int:
|
||||
"""Emit a _pop_provider() call per provided field, return the field count"""
|
||||
if trans is None or pool is None or builder is None or mod is None: return 0
|
||||
if cls_name is None: return 0
|
||||
@@ -237,7 +237,7 @@ novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
# skip when this module does not import _withcontent, to avoid undefined symbol).
|
||||
fd_pon_probe: mlirlite.Function* = self.find_func_in_module(mod, "_pop_provider")
|
||||
if fd_pon_probe is None: return 0
|
||||
fd_pon: str = mlirlite.function_get_name(fd_pon_probe)
|
||||
fd_pon: char* = mlirlite.function_get_name(fd_pon_probe)
|
||||
if fd_pon is None: return 0
|
||||
ret_i32_q: mlirlite.LLVMType* = mlirlite.Int32(pool)
|
||||
if ret_i32_q is None: return 0
|
||||
|
||||
@@ -17,7 +17,7 @@ from . import CallGenBase
|
||||
novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
"""C-lib declarations / return-type inference / kwargs call helpers (extends Base)"""
|
||||
|
||||
def _ensure_c_lib_declare(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, name: str) -> mlirlite.Function*:
|
||||
def _ensure_c_lib_declare(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, name: char*) -> mlirlite.Function*:
|
||||
"""Create a declare for a known C-lib function"""
|
||||
if pool is None or mod is None or name is None: return None
|
||||
|
||||
@@ -94,7 +94,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
mlirlite.add_param(pool, fn, i64_ty, "n")
|
||||
return fn
|
||||
|
||||
def _promote_clib_call_args(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, call_name: str, head: mlirlite.Value*, count: int) -> mlirlite.Value*:
|
||||
def _promote_clib_call_args(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, call_name: char*, head: mlirlite.Value*, count: int) -> mlirlite.Value*:
|
||||
"""Promote bare-name C-lib call arguments to their standard signature widths"""
|
||||
if pool is None or builder is None or call_name is None or head is None: return head
|
||||
# bare names only (no '.' -> no sha1 prefix); prefixed ones use vpi definition-side parsing
|
||||
@@ -148,16 +148,16 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
|
||||
# _coerce_args_to_def_params: coerce cross-module call args to vpi definition-side param
|
||||
# types so call/declare/define widths match; bare C-lib names use the C-lib path instead.
|
||||
def _coerce_args_to_def_params(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, call_name: str, head: mlirlite.Value*, count: int, cargs: list[ast.AST*]* = None, self_off: int = 0, trans: HT.Translator* = None) -> mlirlite.Value*:
|
||||
def _coerce_args_to_def_params(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, call_name: char*, head: mlirlite.Value*, count: int, cargs: list[ast.AST*]* = None, self_off: int = 0, trans: HT.Translator* = None) -> mlirlite.Value*:
|
||||
"""Coerce cross-module call args to vpi definition-side param types; returns the rebuilt chain"""
|
||||
if pool is None or builder is None or call_name is None or head is None: return head
|
||||
if self._is_sha1_mangled_call(call_name) == 0: return head
|
||||
# split {sha1}.{rest}: if rest has '.', it is {cls}.{method}, else {func}
|
||||
rest: str = call_name + 17
|
||||
cls_nm: str = None
|
||||
meth_nm: str = rest
|
||||
rest: char* = call_name + 17
|
||||
cls_nm: char* = None
|
||||
meth_nm: char* = rest
|
||||
# take the last '.': the method has none, and the first '.' would truncate qualified type args
|
||||
dot_r: str = string.strrchr(rest, 46)
|
||||
dot_r: char* = string.strrchr(rest, 46)
|
||||
if dot_r is not None:
|
||||
cls_len: sizet = uint64(dot_r) - uint64(rest)
|
||||
if cls_len <= 0: return head
|
||||
@@ -178,7 +178,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
sha1_buf[16] = '\0'
|
||||
# ensure-load + direct cache lookup (not _vpi_method_param_annot, which misses module funcs)
|
||||
if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0: VpiReader._ensure_vpi_param_annot_loaded(sha1_buf, self.Gen.CallGenBase.TempDir)
|
||||
prm_annots: str = VpiReader._lookup_vpi_param_annots(sha1_buf, cls_nm, meth_nm)
|
||||
prm_annots: char* = VpiReader._lookup_vpi_param_annots(sha1_buf, cls_nm, meth_nm)
|
||||
# generic-specialized class: annotations live on the template class, so fall back to template lookup
|
||||
tpl_src: int = 0
|
||||
if prm_annots is None:
|
||||
@@ -206,7 +206,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
# Value-reference params (&T / &temp T): auto-address the argument (cross-module callee).
|
||||
# The mode comes from the definition-side vpi annotation segment (shared resolver); if the
|
||||
# arg is not a pointer it is addressed (ref: lvalue) or copied into a temp slot (temp).
|
||||
vpi_cur_sha: str = None
|
||||
vpi_cur_sha: char* = None
|
||||
if trans is not None: vpi_cur_sha = trans.ModuleSha1
|
||||
mode_cm: int = self.Gen.CallGenBase._vpi_auto_addr_mode(call_name, vpi_cur_sha, idx)
|
||||
if mode_cm != 0 and trans is not None and trans.Module is not None:
|
||||
@@ -291,14 +291,14 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
pass
|
||||
return val
|
||||
|
||||
def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy*, func_name: str, node: ast.AST*, fatal_if_unknown: int) -> mlirlite.LLVMType*:
|
||||
def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy*, func_name: char*, node: ast.AST*, fatal_if_unknown: int) -> mlirlite.LLVMType*:
|
||||
"""Infer the return type of an external includes function; a whitelist miss may fail fast"""
|
||||
if pool is None or func_name is None: return mlirlite.Int32(pool)
|
||||
|
||||
# extract the bare function name by stripping the SHA1 prefix
|
||||
# (16 hex digits + '.'), e.g. "240a9a4157959a9f.parse" -> "parse".
|
||||
bare_name: str = func_name
|
||||
dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.')
|
||||
bare_name: char* = func_name
|
||||
dot_pos: char* = string.strrchr(func_name, 46) # 46 = ord('.')
|
||||
if dot_pos is not None:
|
||||
# the part after '.' is the bare function name
|
||||
bare_name = dot_pos + 1
|
||||
@@ -396,7 +396,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
# Default i32 placeholder: fatal_if_unknown=1 fails fast; =0 (Phase A mid-pass) stays silent.
|
||||
if fatal_if_unknown != 0: self.Gen.TypeGenErr.fatal_error(node, f"external function return type is unregistered and cannot be inferred conclusively (defaulting to i32 would truncate pointers/i64; provide a stub declaration or add it to the whitelist): {func_name}", "TypeError")
|
||||
return mlirlite.Int32(pool)
|
||||
def _get_external_func_param_ty(self, pool: memhub.MemBuddy*, func_name: str, param_idx: int) -> mlirlite.LLVMType*:
|
||||
def _get_external_func_param_ty(self, pool: memhub.MemBuddy*, func_name: char*, param_idx: int) -> mlirlite.LLVMType*:
|
||||
"""Return the expected type of an external function's param_idx-th parameter, or None (fallback only)"""
|
||||
if pool is None or func_name is None: return None
|
||||
|
||||
@@ -409,7 +409,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
# list iteration is unsupported; use range + get instead
|
||||
api_count: sizet = len(win32_apis)
|
||||
for ai in range(int(api_count)):
|
||||
api_name: str = win32_apis.get(ai)
|
||||
api_name: char* = win32_apis.get(ai)
|
||||
if string.strcmp(api_name, func_name) == 0: return i64_ty
|
||||
|
||||
# Allocators: size params are declared i64 (size_t); without promotion on bare-name fallback call/define widths mismatch; calloc/realloc size is idx 1
|
||||
@@ -421,7 +421,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
if param_idx == 1: return i64_ty
|
||||
|
||||
return None
|
||||
def _is_sha1_mangled_call(self, call_name: str) -> int:
|
||||
def _is_sha1_mangled_call(self, call_name: char*) -> int:
|
||||
"""Return whether call_name is a cross-module Viper function ("{16 hex}.func")"""
|
||||
if call_name is None: return 0
|
||||
if GenApi.sha1_prefix_len(call_name) != 0: return 1
|
||||
@@ -498,7 +498,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
# _translate_call_with_kwargs: keyword-arg call; builds args in found_func.Params order (positional first, else match by param name)
|
||||
|
||||
# ============================================================
|
||||
def _translate_call_with_kwargs(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, func_name: str, found_func: mlirlite.Function*, cargs: list[ast.AST*]*, can: sizet, keywords: list[ast.AST*]*, kw_count: sizet, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
def _translate_call_with_kwargs(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, func_name: char*, found_func: mlirlite.Function*, cargs: list[ast.AST*]*, can: sizet, keywords: list[ast.AST*]*, kw_count: sizet, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
"""Translate a call with keyword arguments, building args in parameter order"""
|
||||
head: mlirlite.Value* = None
|
||||
tail: mlirlite.Value* = None
|
||||
@@ -510,11 +510,11 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
|
||||
# Default-arg lookup for omitted params (same source as CallGenMixin non-kwargs path):
|
||||
# module SHA1 is the "{sha1}.func" prefix or current module; the name+SHA1-keyed snapshot survives resets.
|
||||
kw_callee_sha: str = None
|
||||
kw_found_name: str = mlirlite.function_get_name(found_func)
|
||||
kw_callee_sha: char* = None
|
||||
kw_found_name: char* = mlirlite.function_get_name(found_func)
|
||||
if kw_found_name is not None:
|
||||
if GenApi.sha1_prefix_len(kw_found_name) != 0:
|
||||
kw_sha_buf: str = pool.alloc(17)
|
||||
kw_sha_buf: char* = pool.alloc(17)
|
||||
if kw_sha_buf is not None:
|
||||
string.strncpy(kw_sha_buf, kw_found_name, 16)
|
||||
kw_sha_buf[16] = '\0'
|
||||
@@ -544,7 +544,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
arg_val = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, param_ty)
|
||||
else:
|
||||
# Find the matching keyword argument
|
||||
param_name: str = mlirlite.param_get_name(cur_param)
|
||||
param_name: char* = mlirlite.param_get_name(cur_param)
|
||||
if param_name is not None:
|
||||
for ki in range(int(kw_count)):
|
||||
kw: ast.Keyword* = ast.Keyword*(keywords.get(ki))
|
||||
@@ -582,8 +582,8 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
cur_param = mlirlite.param_get_next(cur_param)
|
||||
|
||||
# declare and define both use found_func.Name: normal funcs carry the SHA1 prefix, t.ExternT/t.State/t.ExportT use bare names (bare names desync call/define symbols)
|
||||
call_name: str = func_name
|
||||
found_name: str = mlirlite.function_get_name(found_func)
|
||||
call_name: char* = func_name
|
||||
found_name: char* = mlirlite.function_get_name(found_func)
|
||||
if found_name is not None: call_name = found_name
|
||||
|
||||
# Return type (via accessor)
|
||||
|
||||
@@ -44,14 +44,14 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if self.Gen.CallGenBase.StaticCount <= 0: return 0
|
||||
sc_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if sc_at.value is None or sc_at.attr is None: return 0
|
||||
sc_mod: str = None
|
||||
sc_mod: char* = None
|
||||
if sc_at.value.kind() == ast.ASTKind.Name:
|
||||
sc_nm: ast.Name* = ast.Name*(sc_at.value)
|
||||
sc_mod = sc_nm.id
|
||||
elif sc_at.value.kind() == ast.ASTKind.Attribute: sc_mod = self.Gen.ExprGenAttr._attr_module_path_str(pool, sc_at.value)
|
||||
if sc_mod is None: return 0
|
||||
if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, sc_mod) == 0: return 0
|
||||
sc_sha1: str = self.Gen.StructGen._resolve_module_sha1(sc_mod, trans._from_imports)
|
||||
sc_sha1: char* = self.Gen.StructGen._resolve_module_sha1(sc_mod, trans._from_imports)
|
||||
if sc_sha1 is None: return 0
|
||||
if string.strncmp(sc_sha1, trans.ModuleSha1, 16) == 0: return 0
|
||||
if self.Gen.CallGenBase.IsStaticSymbol(sc_sha1, sc_at.attr) == 0: return 0
|
||||
@@ -130,7 +130,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if param_idx < can:
|
||||
if cargs is not None: arg_node_kw = cargs.get(param_idx)
|
||||
else:
|
||||
pname_kw: str = mlirlite.param_get_name(cur_param)
|
||||
pname_kw: char* = mlirlite.param_get_name(cur_param)
|
||||
if pname_kw is not None and keywords is not None:
|
||||
ki_kw: sizet
|
||||
for ki_kw in range(int(kw_count)):
|
||||
@@ -149,7 +149,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
|
||||
# _defaults_entry_from_vpi - 全局表里没有该函数的缺省值时,直接按定义模块 .vpi 签名临时造一条
|
||||
# 快照条目(kinds/ints/strs 由文本解析得到,字符串已深拷贝进 PermPool),仅本次调用使用。
|
||||
def _defaults_entry_from_vpi(self, pool: memhub.MemBuddy*, sha1: str, name: str) -> GenTypes.FuncDefaultsEntry*:
|
||||
def _defaults_entry_from_vpi(self, pool: memhub.MemBuddy*, sha1: char*, name: char*) -> GenTypes.FuncDefaultsEntry*:
|
||||
"""按 .vpi 签名临时构造缺省值条目;无缺省值或不可重建返回 None"""
|
||||
cap: int = 128
|
||||
# 快照数组放 PermPool:条目可能在后续 pool reset 之后才被消费,放 pool 会悬空。
|
||||
@@ -179,15 +179,15 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 早期补参用的是 dfx_callee_sha,链式接收者(`self.Gen.X.m(...)`)解析不出发起模块时它会
|
||||
# 退化成调用方 SHA1,表查不到;此时 call_name 已带定义模块 SHA1 前缀,是权威键,再补一次。
|
||||
# 返回补齐后的实参个数。
|
||||
def _fill_defaults_late(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, builder: mlirlite.IRBuilder*, trans: HT.Translator*, cl: ast.Call*, call_name: str, head: mlirlite.Value*, can: sizet) -> sizet:
|
||||
def _fill_defaults_late(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, builder: mlirlite.IRBuilder*, trans: HT.Translator*, cl: ast.Call*, call_name: char*, head: mlirlite.Value*, can: sizet) -> sizet:
|
||||
"""按 call_name 里的定义模块 SHA1 前缀补缺省参数;返回新的实参个数"""
|
||||
if head is None or can == 0 or call_name is None: return can
|
||||
if self.Gen.CallGenLib._is_sha1_mangled_call(call_name) == 0: return can
|
||||
sh_buf: str = pool.alloc(17)
|
||||
sh_buf: char* = pool.alloc(17)
|
||||
if sh_buf is None: return can
|
||||
string.strncpy(sh_buf, call_name, 16)
|
||||
sh_buf[16] = '\0'
|
||||
cname: str = call_name + 17
|
||||
cname: char* = call_name + 17
|
||||
if cname[0] == '\0': return can
|
||||
# 只做 SHA1 隔离的查找:表按 (名字, 定义模块 SHA1) 定位;表里没有就直接读该模块的 .vpi。
|
||||
# 绝不按裸名跨模块搜(`run` 这类名字在多个模块里都有,会拿错签名去补参/校验)。
|
||||
@@ -263,7 +263,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
self._CheckStaticCallCrossModule(pool, trans, cl)
|
||||
if cl is None: return None
|
||||
|
||||
func_name: str = self.Gen.ExprGenBase.get_func_name(cl.func)
|
||||
func_name: char* = self.Gen.ExprGenBase.get_func_name(cl.func)
|
||||
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
can: sizet = 0
|
||||
@@ -291,19 +291,19 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 走下面的跨模块回退时置 0 —— 跨模块的掩码是合并值,不能再按"字段位"裁剪(会变成漏报)。
|
||||
loc_mask: int = 1
|
||||
# 跨模块回退解析出的被调者模块 sha1(最终裁决要用它去查对方 .vpi 的指令契约)
|
||||
mod_sha_ec: str = None
|
||||
mod_sha_ec: char* = None
|
||||
if esc_mask == 0:
|
||||
loc_mask = 0
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_ec: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
mod_p_ec: str = None
|
||||
mod_p_ec: char* = None
|
||||
if at_ec.value is not None and at_ec.value.kind() == ast.ASTKind.Name:
|
||||
mn_ec: ast.Name* = ast.Name*(at_ec.value)
|
||||
if mn_ec.id is not None: mod_p_ec = mn_ec.id
|
||||
elif at_ec.value is not None and at_ec.value.kind() == ast.ASTKind.Attribute:
|
||||
mod_p_ec = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_ec.value)
|
||||
if mod_p_ec is not None:
|
||||
fi_ec: str = None
|
||||
fi_ec: char* = None
|
||||
if trans is not None: fi_ec = trans._from_imports
|
||||
mod_sha_ec = self.Gen.StructGen._resolve_module_sha1(mod_p_ec, fi_ec)
|
||||
if mod_sha_ec is None and trans is not None and trans._from_imports is not None:
|
||||
@@ -353,17 +353,17 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if cargs is not None and func_name is not None:
|
||||
wf_mask = GenApi.get_param_willfree(func_name)
|
||||
if wf_mask == 0:
|
||||
mod_sha_wf: str = None
|
||||
mod_sha_wf: char* = None
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_wf: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
mod_p_wf: str = None
|
||||
mod_p_wf: char* = None
|
||||
if at_wf.value is not None and at_wf.value.kind() == ast.ASTKind.Name:
|
||||
mn_wf: ast.Name* = ast.Name*(at_wf.value)
|
||||
if mn_wf.id is not None: mod_p_wf = mn_wf.id
|
||||
elif at_wf.value is not None and at_wf.value.kind() == ast.ASTKind.Attribute:
|
||||
mod_p_wf = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_wf.value)
|
||||
if mod_p_wf is not None:
|
||||
fi_wf: str = None
|
||||
fi_wf: char* = None
|
||||
if trans is not None: fi_wf = trans._from_imports
|
||||
mod_sha_wf = self.Gen.StructGen._resolve_module_sha1(mod_p_wf, fi_wf)
|
||||
if mod_sha_wf is None and trans is not None and trans._from_imports is not None:
|
||||
@@ -402,7 +402,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
sub_node: ast.Subscript* = ast.Subscript*(cl.func)
|
||||
if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name:
|
||||
gen_nm_node: ast.Name* = ast.Name*(sub_node.value)
|
||||
gen_class_name: str = gen_nm_node.id
|
||||
gen_class_name: char* = gen_nm_node.id
|
||||
# Check whether this is a generic class template.
|
||||
template_cd: ast.ClassDef* = self.Gen.ClassGenGeneric._find_generic_template(gen_class_name)
|
||||
if template_cd is not None:
|
||||
@@ -410,7 +410,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
gen_type_args: list[str]* = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_node.slice, trans._from_imports)
|
||||
if gen_type_args is not None and len(gen_type_args) > 0:
|
||||
# Specialize the generic class and return the specialized name.
|
||||
spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, gen_class_name, gen_type_args)
|
||||
spec_name: char* = self.Gen.ClassGenGeneric._specialize_generic_class(trans, gen_class_name, gen_type_args)
|
||||
if spec_name is not None:
|
||||
# Generic ctor call: list[str](pool, 8) -> __new__ + __before_init__ + __init__.
|
||||
# Do not use spec_name as func_name (star-import fallback would pick a wrong SHA1).
|
||||
@@ -429,7 +429,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if sub_cast_arg is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, sub_cast_arg, sub_cast_ty, cl.args.get(0), trans)
|
||||
# Generic class template not found: the defining module may not be imported.
|
||||
gt_err: str = pool.alloc(256)
|
||||
gt_err: char* = pool.alloc(256)
|
||||
if gt_err is not None:
|
||||
viperlib.snprintf(gt_err, 256, "Generic class '%s': template not found; the defining module may not be imported", gen_class_name)
|
||||
self.Gen.TypeGenErr.fatal_error(gen_nm_node, gt_err)
|
||||
@@ -488,14 +488,14 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
mod_qual_done: int = 0
|
||||
if trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_qc0: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
mod_path0: str = None
|
||||
mod_path0: char* = None
|
||||
if at_qc0.value is not None and at_qc0.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm0: ast.Name* = ast.Name*(at_qc0.value)
|
||||
if mod_nm0.id is not None: mod_path0 = mod_nm0.id
|
||||
elif at_qc0.value is not None and at_qc0.value.kind() == ast.ASTKind.Attribute: mod_path0 = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc0.value)
|
||||
if mod_path0 is not None:
|
||||
if self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, mod_path0) != 0:
|
||||
mod_sha1_0: str = self._lookup_module_sha1(mod_path0)
|
||||
mod_sha1_0: char* = self._lookup_module_sha1(mod_path0)
|
||||
if mod_sha1_0 is not None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, mod_sha1_0)
|
||||
mod_qual_done = 1
|
||||
@@ -515,7 +515,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if imp_ok != 0:
|
||||
# Module-qualified construction: resolve by project module SHA1, not trans.ModuleSha1
|
||||
# (the current file); otherwise the bare-name fallback picks the wrong same-name class.
|
||||
mod_sha1_qc2: str = None
|
||||
mod_sha1_qc2: char* = None
|
||||
if mod_nm_qc.id is not None: mod_sha1_qc2 = self._lookup_module_sha1(mod_nm_qc.id)
|
||||
if mod_sha1_qc2 is not None: gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, mod_sha1_qc2)
|
||||
if gen_ctor_entry is None: gen_ctor_entry = self.Gen.StructGen.find_struct(func_name)
|
||||
@@ -523,11 +523,11 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
elif at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Attribute:
|
||||
# Multi-level module path construction: win32.fileio.File(...); build the path via
|
||||
# attr_module_path_str, check the full import, then find the struct by that module's SHA1.
|
||||
mod_path_qc: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc.value)
|
||||
mod_path_qc: char* = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc.value)
|
||||
if mod_path_qc is not None:
|
||||
imp_ok_qc: int = self.Gen.ImportsGen.is_module_imported(trans._imported_modules, mod_path_qc)
|
||||
if imp_ok_qc != 0:
|
||||
mod_sha1_qc: str = self._lookup_module_sha1(mod_path_qc)
|
||||
mod_sha1_qc: char* = self._lookup_module_sha1(mod_path_qc)
|
||||
if mod_sha1_qc is not None: gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, mod_sha1_qc)
|
||||
if gen_ctor_entry is None: gen_ctor_entry = self.Gen.StructGen.find_struct(func_name)
|
||||
if gen_ctor_entry is not None: struct_ty = gen_ctor_entry.Ty
|
||||
@@ -535,14 +535,14 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# original name, so resolve alias -> original before find_struct to avoid a link-time undefined reference.
|
||||
if gen_ctor_entry is None and trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||||
if trans._from_imports is not None:
|
||||
ctor_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0)
|
||||
ctor_sha1: char* = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0)
|
||||
if ctor_sha1 is not None:
|
||||
ctor_orig: str = self.Gen.ImportsGen.lookup_from_import_original(trans._from_imports, func_name)
|
||||
ctor_orig: char* = self.Gen.ImportsGen.lookup_from_import_original(trans._from_imports, func_name)
|
||||
if ctor_orig is not None:
|
||||
# Copy into a separate NUL-terminated buffer (the from_imports buffer is not terminated).
|
||||
co_len: sizet = 0
|
||||
while ctor_orig[co_len] != ' ' and ctor_orig[co_len] != '\0': co_len += 1
|
||||
co_buf: str = pool.alloc(co_len + 1)
|
||||
co_buf: char* = pool.alloc(co_len + 1)
|
||||
if co_buf is not None:
|
||||
for co_i in range(int(co_len)): co_buf[co_i] = ctor_orig[co_i]
|
||||
co_buf[co_len] = '\0'
|
||||
@@ -614,7 +614,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
ais_bare: sizet = sizet(aip_bare)
|
||||
# [D25 fail-fast] Never default to "int": with no hint and too few args it would
|
||||
# wrongly specialize to list[int]/Box[int] (4-byte elements, pointer truncation/crash).
|
||||
ta_bare: str = None
|
||||
ta_bare: char* = None
|
||||
if ais_bare < can: ta_bare = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(ais_bare), func_name, trans)
|
||||
if ta_bare is None:
|
||||
# [C2] Keyword-only arg (Box(v=42)): match the keyword by __init__ param name
|
||||
@@ -629,7 +629,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if ta_bare is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Cannot infer type argument {tpi_bare + 1} of generic class '{func_name}' from the arguments, " f"silent default to int is forbidden (it produces wrong specializations such as list[int] -> elements treated as 4 bytes/i32 -> pointer truncation crash); " f"annotate the argument type or annotate explicitly, e.g. {func_name}[Type](...)", "TypeError")
|
||||
inferred_args_bare.append(ta_bare)
|
||||
spec_name_bare: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, func_name, inferred_args_bare)
|
||||
spec_name_bare: char* = self.Gen.ClassGenGeneric._specialize_generic_class(trans, func_name, inferred_args_bare)
|
||||
if spec_name_bare is not None: return self.Gen.CallGenCtor._translate_generic_ctor_call(pool, builder, mod, spec_name_bare, cl, trans, func_name)
|
||||
|
||||
# REnum variant construction: ClassName.VariantName(args...), e.g. LLVMType.Int(1). Must run
|
||||
@@ -639,7 +639,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Name:
|
||||
rc_cls_node: ast.Name* = ast.Name*(rc_at.value)
|
||||
if rc_cls_node.id is not None:
|
||||
rc_cls_name: str = rc_cls_node.id
|
||||
rc_cls_name: char* = rc_cls_node.id
|
||||
# Check whether ClassName is a registered REnum; also use _is_renum_by_entry (a __tag
|
||||
# makes it an REnum) so a missing variant table does not silently fall through to a misleading error.
|
||||
if self.Gen.ClassGenEnum._is_renum_class_name(rc_cls_name) != 0 or self.Gen.ClassGenEnum._is_renum_by_entry(rc_cls_name) != 0:
|
||||
@@ -652,21 +652,21 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
elif rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Attribute:
|
||||
# Module-qualified REnum variant: mod.Class.Variant(args...), e.g. mlirlite.LLVMType.Struct(...).
|
||||
# Only require the leftmost module imported and the class name in the global REnum table.
|
||||
rc_mq_path: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, rc_at.value)
|
||||
rc_mq_path: char* = self.Gen.ExprGenAttr._attr_module_path_str(pool, rc_at.value)
|
||||
if rc_mq_path is not None:
|
||||
rc_mq_dot: str = string.strrchr(rc_mq_path, 46) # 46 = ord('.')
|
||||
rc_mq_dot: char* = string.strrchr(rc_mq_path, 46) # 46 = ord('.')
|
||||
if rc_mq_dot is not None and rc_mq_dot[1] != '\0':
|
||||
# Module path = everything before the last segment (multi-level supported); use
|
||||
# strlen integer differences, not pointer subtraction (which emits illegal IR).
|
||||
rc_mq_len: sizet = string.strlen(rc_mq_path) - string.strlen(rc_mq_dot + 1) - 1
|
||||
rc_mq_mod: str = pool.alloc(rc_mq_len + 1)
|
||||
rc_mq_mod: char* = pool.alloc(rc_mq_len + 1)
|
||||
if rc_mq_mod is not None:
|
||||
string.memcpy(rc_mq_mod, rc_mq_path, rc_mq_len)
|
||||
rc_mq_mod[rc_mq_len] = '\0'
|
||||
rc_mq_imp: int = 1
|
||||
if trans is not None and trans._imported_modules is not None: rc_mq_imp = self.Gen.ImportsGen.is_module_imported(trans._imported_modules, rc_mq_mod)
|
||||
if rc_mq_imp != 0:
|
||||
rc_mq_cls: str = rc_mq_dot + 1
|
||||
rc_mq_cls: char* = rc_mq_dot + 1
|
||||
# Check whether the class name is a registered REnum class.
|
||||
if self.Gen.ClassGenEnum._is_renum_class_name(rc_mq_cls) != 0:
|
||||
rc_mq_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(rc_mq_cls, func_name)
|
||||
@@ -677,9 +677,9 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||||
if func_name is not None and trans is not None:
|
||||
if self.Gen.AsyncGen.is_async_func(trans, func_name) != 0:
|
||||
can_buf: str = pool.alloc(64)
|
||||
can_buf: char* = pool.alloc(64)
|
||||
if can_buf is not None: viperlib.snprintf(can_buf, 64, "create_%s", func_name)
|
||||
create_an: str = self.Gen.FuncGenBase._mangle_func_name(trans, can_buf, 0)
|
||||
create_an: char* = self.Gen.FuncGenBase._mangle_func_name(trans, can_buf, 0)
|
||||
create_fn_an: mlirlite.Function* = self.find_func_in_module(mod, create_an)
|
||||
if create_fn_an is not None:
|
||||
frame_ty_an: mlirlite.LLVMType* = self.Gen.AsyncGen._lookup_coro_frame(trans, func_name)
|
||||
@@ -719,7 +719,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||||
# Bare-name call: allow exact + suffix matching. Custom decorator wrapper rewrite: original
|
||||
# name -> __decor_wrap_{name} (wrapper is generated at function-translation end and is reachable).
|
||||
decor_wrap_nm: str = self.Gen.ClassGenBase.lookup_decor_wrapper(func_name)
|
||||
decor_wrap_nm: char* = self.Gen.ClassGenBase.lookup_decor_wrapper(func_name)
|
||||
if decor_wrap_nm is not None: found_func = self.find_func_in_module(mod, decor_wrap_nm)
|
||||
else:
|
||||
# Bare-name call to a function defined in this module: hit the module function table first (authoritative for module-level names), then fall back to the module list scan.
|
||||
@@ -727,7 +727,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if actual_funcs is not None:
|
||||
# Prefer same-module functions: the _funcs table is polluted by dependency stubs,
|
||||
# so pass trans.ModuleSha1 to match the "{ModuleSha1}.{name}" entry first (AstTest root cause).
|
||||
tbl_owner_sha1: str = None
|
||||
tbl_owner_sha1: char* = None
|
||||
if trans is not None: tbl_owner_sha1 = trans.ModuleSha1
|
||||
mod_fn_tb = self.Gen.CallGenLeafKit.find_func_in_table(actual_funcs, actual_func_count, func_name, tbl_owner_sha1)
|
||||
if mod_fn_tb is not None:
|
||||
@@ -735,7 +735,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 重载:本模块同名 >=2 时按实参静态类型决议(返回值不参与)。
|
||||
# 单候选维持原行为零开销;候选 >=2 且有实参无法定型 -> resolve 内 fail-fast。
|
||||
if actual_funcs is not None:
|
||||
ovl_owner: str = None
|
||||
ovl_owner: char* = None
|
||||
if trans is not None: ovl_owner = trans.ModuleSha1
|
||||
ovl_cnt: int = self.Gen.CallGenLeafKit.count_owned_overloads(actual_funcs, actual_func_count, func_name, ovl_owner)
|
||||
if ovl_cnt >= 2:
|
||||
@@ -745,13 +745,13 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
# No table entry: fall back to scanning FuncHead, also passing owner_sha1 so an
|
||||
# inactive same-name forward declaration does not get mis-bound to an earlier stub.
|
||||
ff_owner_sha1: str = None
|
||||
ff_owner_sha1: char* = None
|
||||
if trans is not None: ff_owner_sha1 = trans.ModuleSha1
|
||||
found_func = self.find_func_in_module(mod, func_name, ff_owner_sha1)
|
||||
# Reject suffix matches that hit a class method (SHA1.Class.method): a bare-name call sharing a
|
||||
# name with a module function would bind to the method and recurse infinitely (stack overflow).
|
||||
if found_func is not None:
|
||||
bn_name: str = mlirlite.function_get_name(found_func)
|
||||
bn_name: char* = mlirlite.function_get_name(found_func)
|
||||
if bn_name is not None:
|
||||
bn_dots: int = 0
|
||||
bni2: sizet = 0
|
||||
@@ -760,7 +760,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
bni2 += 1
|
||||
if bn_dots >= 2:
|
||||
# Extract segment 2 (SHA1.Class.method -> Class; SHA1.submod.func -> submod).
|
||||
bn_seg2: str = pool.alloc(64)
|
||||
bn_seg2: char* = pool.alloc(64)
|
||||
if bn_seg2 is not None:
|
||||
bn_seg2[0] = '\0'
|
||||
bsi2: sizet = 0
|
||||
@@ -782,10 +782,10 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
# 跨模块重载:先从接收者路径解析目标模块 SHA1,再在候选集里决议。
|
||||
# vpi 注入的重载符号是 {sha1}.name_v{hash}、函数表项名带后缀,所以用 prefix 模式。
|
||||
xm_sha1_ovl: str = None
|
||||
xm_sha1_ovl: char* = None
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute and trans is not None and trans._imported_modules is not None:
|
||||
xm_at_ovl: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
xm_path_ovl: str = None
|
||||
xm_path_ovl: char* = None
|
||||
if xm_at_ovl is not None and xm_at_ovl.value is not None:
|
||||
if xm_at_ovl.value.kind() == ast.ASTKind.Name:
|
||||
xm_nm_ovl: ast.Name* = ast.Name*(xm_at_ovl.value)
|
||||
@@ -815,20 +815,20 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if xm_at is not None and xm_at.value is not None and trans is not None and trans._imported_modules is not None:
|
||||
# Module path: one-level Name (syslibtest_impl.run) or nested Attribute (os._win32.exists).
|
||||
# The nested case must be validated too, else it suffix-matches this module's own define (recursion).
|
||||
xm_mod_path: str = None
|
||||
xm_mod_path: char* = None
|
||||
if xm_at.value.kind() == ast.ASTKind.Name:
|
||||
xm_nm: ast.Name* = ast.Name*(xm_at.value)
|
||||
if xm_nm.id is not None: xm_mod_path = xm_nm.id
|
||||
elif xm_at.value.kind() == ast.ASTKind.Attribute: xm_mod_path = self.Gen.ExprGenAttr._attr_module_path_str(pool, xm_at.value)
|
||||
if xm_mod_path is not None:
|
||||
if self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, xm_mod_path) != 0:
|
||||
mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path)
|
||||
mod_sha1_chk: char* = self._lookup_module_sha1(xm_mod_path)
|
||||
if mod_sha1_chk is None and trans._from_imports is not None:
|
||||
# import X as Y (e.g. import fat32_diskio as diskio): resolve the alias before
|
||||
# lookup, else this check is skipped and the suffix match hits a same-name local function.
|
||||
mod_sha1_chk = self.Gen.StructGen._resolve_module_sha1(xm_mod_path, trans._from_imports)
|
||||
if mod_sha1_chk is not None:
|
||||
ff_nm2: str = mlirlite.function_get_name(found_func)
|
||||
ff_nm2: char* = mlirlite.function_get_name(found_func)
|
||||
if ff_nm2 is not None:
|
||||
if string.strncmp(ff_nm2, mod_sha1_chk, 16) != 0:
|
||||
# ExportT / t.State 型跨模块函数**定义与声明都用裸名**(stdlib.free、
|
||||
@@ -848,7 +848,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if cx_ok == 0:
|
||||
if self.Gen.CallGenBase._is_reexport_owner(pool, mod_sha1_chk, func_name, ff_nm2) != 0: cx_ok = 1
|
||||
if cx_ok == 0: found_func = None
|
||||
ff_name: str = mlirlite.function_get_name(found_func)
|
||||
ff_name: char* = mlirlite.function_get_name(found_func)
|
||||
if ff_name is not None:
|
||||
ff_dots: int = 0
|
||||
ffi2: sizet = 0
|
||||
@@ -857,7 +857,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
ffi2 += 1
|
||||
if ff_dots >= 2:
|
||||
# Extract segment 2 (SHA1.Class.method -> Class; SHA1.submod.func -> submod).
|
||||
seg2: str = pool.alloc(64)
|
||||
seg2: char* = pool.alloc(64)
|
||||
if seg2 is not None:
|
||||
seg2[0] = '\0'
|
||||
si: sizet = 0
|
||||
@@ -891,9 +891,9 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name and string.strcmp(func_name, "abs") == 0 and can == 1:
|
||||
abs_arg: ast.AST* = cargs.get(0)
|
||||
if abs_arg is not None:
|
||||
abs_cls: str = self.Gen.CallGenProp._resolve_obj_class_name(pool, trans, abs_arg)
|
||||
abs_cls: char* = self.Gen.CallGenProp._resolve_obj_class_name(pool, trans, abs_arg)
|
||||
if abs_cls is not None:
|
||||
abs_sc: str = self.Gen.ExprGenOps._resolve_dunder_by_class(pool, mod, abs_cls, "__abs__", trans)
|
||||
abs_sc: char* = self.Gen.ExprGenOps._resolve_dunder_by_class(pool, mod, abs_cls, "__abs__", trans)
|
||||
if abs_sc is not None:
|
||||
abs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, abs_arg, None, 0, trans)
|
||||
if abs_val is not None: return self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, abs_sc, "__abs__", abs_val, None, 0, trans)
|
||||
@@ -903,7 +903,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# builtins auto-link: when no C library matches, link ord/chr etc. from the builtins module by
|
||||
# creating a {builtins_sha1}.{name} declare with the agreed signature (ord(i8)->i32, chr(i32)->i8).
|
||||
if found_func is None:
|
||||
bi_sha1: str = self._lookup_module_sha1("builtins")
|
||||
bi_sha1: char* = self._lookup_module_sha1("builtins")
|
||||
if bi_sha1 is not None:
|
||||
bi_ret: mlirlite.LLVMType* = None
|
||||
bi_p1: mlirlite.LLVMType* = None
|
||||
@@ -925,10 +925,10 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
bi_ret = mlirlite.Int32(pool)
|
||||
bi_p1 = mlirlite.Int32(pool)
|
||||
if bi_ret is not None:
|
||||
bi_sym: str = func_name
|
||||
bi_sym: char* = func_name
|
||||
if self.Gen.CallGenBase.is_cexport_func(bi_sha1, func_name) == 0:
|
||||
bi_sym_len: sizet = string.strlen(bi_sha1) + string.strlen(func_name) + 2
|
||||
bi_sym_buf: str = pool.alloc(bi_sym_len)
|
||||
bi_sym_buf: char* = pool.alloc(bi_sym_len)
|
||||
if bi_sym_buf is not None:
|
||||
viperlib.snprintf(bi_sym_buf, bi_sym_len, "%s.%s", bi_sha1, func_name)
|
||||
bi_sym = bi_sym_buf
|
||||
@@ -950,9 +950,9 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
vpi_ret_ty: mlirlite.LLVMType* = None
|
||||
# Source module SHA1 for cross-module return-type resolution (assigned only in the Attribute
|
||||
# branch). Must be initialized to None, else a bare call reads stack garbage and crashes.
|
||||
mod_ret_sha1: str = None
|
||||
mod_ret_sha1: char* = None
|
||||
# Module path (assigned only for Attribute); declared outside the if so the bare-name fallback can read it safely.
|
||||
mod_path_ret: str = None
|
||||
mod_path_ret: char* = None
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_ret: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
# Resolve the callee module path: both one-level (stdlib.free) and multi-level
|
||||
@@ -964,17 +964,17 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if mod_path_ret is not None:
|
||||
# import X as Y (e.g. import lib.core.Gen.GenApi as GenApi): an exact module-name lookup
|
||||
# cannot resolve the alias and would wrongly fail-fast; use _resolve_module_sha1 (alias restore + exact/suffix).
|
||||
fi_from_rt: str = None
|
||||
fi_from_rt: char* = None
|
||||
if trans is not None: fi_from_rt = trans._from_imports
|
||||
mod_ret_sha1 = self.Gen.StructGen._resolve_module_sha1(mod_path_ret, fi_from_rt)
|
||||
if mod_ret_sha1 is not None:
|
||||
# Lazy in-function import: VpiReader imports HandlesExprCall, so a top-level import would cycle.
|
||||
VpiReader._ensure_vpi_ret_annot_loaded(mod_ret_sha1, self.Gen.CallGenBase.TempDir)
|
||||
ret_annot_fc: str = VpiReader._lookup_vpi_ret_annot(mod_ret_sha1, None, func_name)
|
||||
ret_annot_fc: char* = VpiReader._lookup_vpi_ret_annot(mod_ret_sha1, None, func_name)
|
||||
if ret_annot_fc is None:
|
||||
# Package vpi miss (the function is defined in a submodule, e.g. fltk.Fl_Input_value in
|
||||
# fltk._cfl_input): use re-export to locate the defining module, then query its vpi.
|
||||
rr_src: str = self.Gen.ImportsGen.lookup_reexport_call(mod_ret_sha1, func_name)
|
||||
rr_src: char* = self.Gen.ImportsGen.lookup_reexport_call(mod_ret_sha1, func_name)
|
||||
if rr_src is None: rr_src = self._lookup_reexport_from_vpi(pool, mod_ret_sha1, func_name)
|
||||
if rr_src is not None:
|
||||
rr_total: sizet = string.strlen(rr_src)
|
||||
@@ -985,11 +985,11 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
rr_start: sizet = rr_i
|
||||
while rr_i < rr_total and rr_src[rr_i] != ' ': rr_i += 1
|
||||
rr_len: sizet = rr_i - rr_start
|
||||
rr_buf: str = pool.alloc(rr_len + 1)
|
||||
rr_buf: char* = pool.alloc(rr_len + 1)
|
||||
if rr_buf is not None:
|
||||
string.strncpy(rr_buf, rr_src + rr_start, rr_len)
|
||||
rr_buf[rr_len] = '\0'
|
||||
rr_sha1: str = self._lookup_module_sha1(rr_buf)
|
||||
rr_sha1: char* = self._lookup_module_sha1(rr_buf)
|
||||
# Re-export sources may be registered under a qualified
|
||||
# module name; fall back to suffix lookup on exact miss.
|
||||
if rr_sha1 is None: rr_sha1 = self._lookup_module_sha1_suffix(rr_buf)
|
||||
@@ -1013,21 +1013,21 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 结果被丢弃(独立调用语句)时不 fail-fast:占位 i32 无害,没必要中断编译。
|
||||
if trans is not None and trans._declare_only == 0 and trans._discard_result == 0:
|
||||
vpi_rc_d: int = 0
|
||||
vpi_annot_d: str = None
|
||||
vpi_annot_d: char* = None
|
||||
if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0:
|
||||
vpi_rc_d = VpiReader._ensure_vpi_ret_annot_loaded(mod_ret_sha1, self.Gen.CallGenBase.TempDir)
|
||||
vpi_annot_d = VpiReader._lookup_vpi_ret_annot(mod_ret_sha1, None, func_name)
|
||||
annot_s_d: str = "-"
|
||||
annot_s_d: char* = "-"
|
||||
if vpi_annot_d is not None: annot_s_d = vpi_annot_d
|
||||
# sha1 来源拆解:exact / suffix 各自返回什么,用来区分"存表里就是错的"
|
||||
# 与"后缀匹配撞到了别的模块"(两者修法完全不同)。
|
||||
ex_s_d: str = "-"
|
||||
ex_s_d: char* = "-"
|
||||
if mod_path_ret is not None:
|
||||
_ex_d: str = self.Gen.CallGenBase._lookup_module_sha1(mod_path_ret)
|
||||
_ex_d: char* = self.Gen.CallGenBase._lookup_module_sha1(mod_path_ret)
|
||||
if _ex_d is not None: ex_s_d = _ex_d
|
||||
sf_s_d: str = "-"
|
||||
sf_s_d: char* = "-"
|
||||
if mod_path_ret is not None:
|
||||
_sf_d: str = self.Gen.CallGenBase._lookup_module_sha1_suffix(mod_path_ret)
|
||||
_sf_d: char* = self.Gen.CallGenBase._lookup_module_sha1_suffix(mod_path_ret)
|
||||
if _sf_d is not None: sf_s_d = _sf_d
|
||||
# 走 VPC Diag(源码行 + 调用栈),而不是单行 VLogger.error:
|
||||
# 单行输出丢掉了位置与调用链,无法定位到底是谁在什么上下文里调用了它。
|
||||
@@ -1073,9 +1073,9 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
c_struct: mlirlite.LLVMType* = None
|
||||
if c_obj is not None: c_struct = self.Gen.StructGen.get_struct_type_from_value(c_obj)
|
||||
if c_struct is not None:
|
||||
c_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, c_struct)
|
||||
c_cls: char* = self.Gen.StructGen.get_class_name_by_type(pool, c_struct)
|
||||
if c_cls is not None:
|
||||
c_call_cls: str = self.Gen.ExprGenOps._resolve_dunder_by_class(pool, mod, c_cls, "__call__", trans)
|
||||
c_call_cls: char* = self.Gen.ExprGenOps._resolve_dunder_by_class(pool, mod, c_cls, "__call__", trans)
|
||||
if c_call_cls is not None: return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, c_call_cls, "__call__", c_obj, cl, trans)
|
||||
# Closure variable (nested function hoisted and registered): extract fn_ptr/env_ptr and call indirectly.
|
||||
if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0:
|
||||
@@ -1086,7 +1086,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# holds {fn_ptr, env_ptr} and must pass env, else a direct call jumps into closure data and crashes.
|
||||
ve_fp: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, func_name)
|
||||
is_cptr_annot_fp: int = 0
|
||||
fp_annot: str = self.Gen.VarGen.var_annot_class_name(ve_fp)
|
||||
fp_annot: char* = self.Gen.VarGen.var_annot_class_name(ve_fp)
|
||||
if fp_annot is not None:
|
||||
# [S4] PtrT marker = annotation base name exactly "PtrT": t.Callable[[A],R] also resolves to
|
||||
# Ptr(i8) (same Spec), so only the annotation name can carry the marker; substring matching would misfire.
|
||||
@@ -1152,7 +1152,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
fpi += 1
|
||||
if fp is not None: fpty = mlirlite.param_get_ty(fp)
|
||||
# Value-reference params (&T / &temp T): auto-address the argument (same-module callee).
|
||||
ao_name: str = None
|
||||
ao_name: char* = None
|
||||
if found_func is not None: ao_name = mlirlite.function_get_name(found_func)
|
||||
arg_val: mlirlite.Value* = self.Gen.CallGenBase.translate_call_arg(builder, pool, mod, trans, ao_name, int(ai), arg, fpty, "param")
|
||||
if arg_val is not None:
|
||||
@@ -1178,15 +1178,15 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
ext_param_ty: mlirlite.LLVMType* = None
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_pt: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
mpath_pt: str = None
|
||||
mpath_pt: char* = None
|
||||
if at_pt.value is not None and at_pt.value.kind() == ast.ASTKind.Name:
|
||||
nm_pt: ast.Name* = ast.Name*(at_pt.value)
|
||||
mpath_pt = nm_pt.id
|
||||
elif at_pt.value is not None and at_pt.value.kind() == ast.ASTKind.Attribute: mpath_pt = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_pt.value)
|
||||
if mpath_pt is not None:
|
||||
fi_pt: str = None
|
||||
fi_pt: char* = None
|
||||
if trans is not None: fi_pt = trans._from_imports
|
||||
sha_pt: str = self.Gen.StructGen._resolve_module_sha1(mpath_pt, fi_pt)
|
||||
sha_pt: char* = self.Gen.StructGen._resolve_module_sha1(mpath_pt, fi_pt)
|
||||
if sha_pt is not None:
|
||||
if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0: VpiReader._ensure_vpi_param_annot_loaded(sha_pt, self.Gen.CallGenBase.TempDir)
|
||||
ext_param_ty = VpiReader._resolve_vpi_param_annot_seg(pool, sha_pt, None, func_name, ai, mlirlite.Int32(pool), mlirlite.Ptr(pool, mlirlite.Int8(pool)))
|
||||
@@ -1266,10 +1266,10 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
df_param_count: int = 0
|
||||
# Compute the callee module SHA1 as a qualifier key (module.func -> that module; bare -> current),
|
||||
# so usb.uhci.init(1 arg) does not wrongly match mm.init (5 params) and add extra arguments.
|
||||
dfx_callee_sha: str = None
|
||||
dfx_callee_sha: char* = None
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
dfx_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
dfx_mod_path: str = None
|
||||
dfx_mod_path: char* = None
|
||||
if dfx_at.value is not None and dfx_at.value.kind() == ast.ASTKind.Name:
|
||||
dfx_mn: ast.Name* = ast.Name*(dfx_at.value)
|
||||
if dfx_mn.id is not None: dfx_mod_path = dfx_mn.id
|
||||
@@ -1281,7 +1281,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# and returns None for `import X.Y as Z` (Z is not a module name). Without the alias restore the
|
||||
# qualifier degrades to the current module SHA1, so find_func_defaults misses the defining module
|
||||
# and the defaults are never filled (rhttps.get(url, verify) emits 2 operands for a 3-param callee).
|
||||
dfx_fi: str = None
|
||||
dfx_fi: char* = None
|
||||
if trans is not None: dfx_fi = trans._from_imports
|
||||
dfx_callee_sha = self.Gen.StructGen._resolve_module_sha1(dfx_mod_path, dfx_fi)
|
||||
if dfx_callee_sha is None and self.Gen.TypeGenBase is not None: dfx_callee_sha = self.Gen.TypeGenBase.CurrentModuleSha1
|
||||
@@ -1299,10 +1299,10 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# Package re-export fallback (e.g. json.write defined in includes/json/__writer.vp): the defaults
|
||||
# table is keyed by the defining module SHA1, so re-resolve the re-export and query again (else defaults are skipped).
|
||||
if gd_entry is None and dfx_callee_sha is not None:
|
||||
rr_src_dx: str = self.Gen.ImportsGen.lookup_reexport_call(dfx_callee_sha, func_name)
|
||||
rr_src_dx: char* = self.Gen.ImportsGen.lookup_reexport_call(dfx_callee_sha, func_name)
|
||||
if rr_src_dx is None: rr_src_dx = self._lookup_reexport_from_vpi(pool, dfx_callee_sha, func_name)
|
||||
if rr_src_dx is not None:
|
||||
rr_sha_dx: str = self._lookup_module_sha1(rr_src_dx)
|
||||
rr_sha_dx: char* = self._lookup_module_sha1(rr_src_dx)
|
||||
if rr_sha_dx is not None: gd_entry = self.Gen.CallGenLeafKit.find_func_defaults(func_name, rr_sha_dx)
|
||||
# 键失配兜底:链式接收者(`self.Gen.ExprGenMixin.translate_value(...)`)解析不出发起模块,
|
||||
# dfx_callee_sha 退化成调用方自己的 SHA1,限定查表落空 —— 由后面的 _fill_defaults_late
|
||||
@@ -1319,7 +1319,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
dfx_cnt: int = 0
|
||||
dfx_p: mlirlite.Param* = mlirlite.function_get_param_head(found_func)
|
||||
while dfx_p is not None:
|
||||
dfx_nm: str = mlirlite.param_get_name(dfx_p)
|
||||
dfx_nm: char* = mlirlite.param_get_name(dfx_p)
|
||||
if dfx_nm is None or (string.strcmp(dfx_nm, "%__eh_msg_out__") != 0 and string.strcmp(dfx_nm, "%__eh_code_out__") != 0):
|
||||
dfx_cnt += 1
|
||||
dfx_p = mlirlite.param_get_next(dfx_p)
|
||||
@@ -1359,7 +1359,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
fc_cnt: int = 0
|
||||
fc_p: mlirlite.Param* = mlirlite.function_get_param_head(found_func)
|
||||
while fc_p is not None:
|
||||
fp_nm_z: str = mlirlite.param_get_name(fc_p)
|
||||
fp_nm_z: char* = mlirlite.param_get_name(fc_p)
|
||||
if fp_nm_z is None or (string.strcmp(fp_nm_z, "%__eh_msg_out__") != 0 and string.strcmp(fp_nm_z, "%__eh_code_out__") != 0):
|
||||
fc_cnt += 1
|
||||
fc_p = mlirlite.param_get_next(fc_p)
|
||||
@@ -1384,12 +1384,12 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
|
||||
# Use the actual function name from the module (may carry a SHA1 prefix); ExternT/State/ExportT
|
||||
# functions use the bare name. Both declare and define must use found_func.Name (mismatched names cause undefined references).
|
||||
call_name: str = func_name
|
||||
call_name: char* = func_name
|
||||
# Original function name (recorded for aliased imports, e.g. from X import parse as json_parse -> "parse"),
|
||||
# used to re-infer the return type after alias handling so _infer_external_func_ret_ty can match.
|
||||
orig_func_name: str = None
|
||||
orig_func_name: char* = None
|
||||
if found_func is not None:
|
||||
found_name: str = mlirlite.function_get_name(found_func)
|
||||
found_name: char* = mlirlite.function_get_name(found_func)
|
||||
if found_name is not None:
|
||||
call_name = found_name
|
||||
# ExportT bare-name fallback: a cross-module stub declare may carry a SHA1 prefix while the
|
||||
@@ -1397,7 +1397,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if found_func.IsDeclared != 0:
|
||||
# Use the single source of truth GenApi.sha1_prefix_len (converged in C10).
|
||||
if GenApi.sha1_prefix_len(found_name) != 0:
|
||||
cx_sha1_buf: str = pool.alloc(17)
|
||||
cx_sha1_buf: char* = pool.alloc(17)
|
||||
if cx_sha1_buf is not None:
|
||||
string.memcpy(cx_sha1_buf, found_name, 16)
|
||||
cx_sha1_buf[16] = '\0'
|
||||
@@ -1409,13 +1409,13 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if xmod_at.value is not None and (xmod_at.value.kind() == ast.ASTKind.Name or xmod_at.value.kind() == ast.ASTKind.Attribute):
|
||||
# Module path: one-level Name (string.strchr) or nested Attribute (os._win32.exists). The nested
|
||||
# case must be resolved too, else it suffix-matches this module's own define (infinite recursion).
|
||||
xmod_path: str = None
|
||||
xmod_path: char* = None
|
||||
if xmod_at.value.kind() == ast.ASTKind.Name:
|
||||
xmod_nm: ast.Name* = ast.Name*(xmod_at.value)
|
||||
if xmod_nm.id is not None: xmod_path = xmod_nm.id
|
||||
else: xmod_path = self.Gen.ExprGenAttr._attr_module_path_str(pool, xmod_at.value)
|
||||
if xmod_path is not None:
|
||||
mod_sha1: str = self._lookup_module_sha1(xmod_path)
|
||||
mod_sha1: char* = self._lookup_module_sha1(xmod_path)
|
||||
if mod_sha1 is not None:
|
||||
# fast-fail: a module-qualified call requires the module to be imported by this file;
|
||||
# the global SHA1 store contains all scanned includes, so an unimported module would silently resolve.
|
||||
@@ -1423,13 +1423,13 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if trans is not None and trans._imported_modules is not None:
|
||||
is_xmod_imported = self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, xmod_path)
|
||||
if is_xmod_imported == 0:
|
||||
err_ni: str = pool.alloc(256)
|
||||
err_ni: char* = pool.alloc(256)
|
||||
if err_ni is not None:
|
||||
viperlib.snprintf(err_ni, 256, "Cross-module call '%s.%s': module '%s' not imported (import %s first)", xmod_path, func_name, xmod_path, xmod_path)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_ni)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, "Cross-module call: module not imported")
|
||||
# Check whether it is a re-export function (e.g. ast._lexer_init actually defined in ast.lexer).
|
||||
reexport_src: str = self.Gen.ImportsGen.lookup_reexport_call(mod_sha1, func_name)
|
||||
reexport_src: char* = self.Gen.ImportsGen.lookup_reexport_call(mod_sha1, func_name)
|
||||
if reexport_src is None:
|
||||
# Re-export table miss (includes modules with existing stub/text are not fully translated,
|
||||
# so the table may be empty): resolve the module's .vpi from-import to locate the defining module.
|
||||
@@ -1446,11 +1446,11 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
cs_start: sizet = cs_i
|
||||
while cs_i < cs_total and reexport_src[cs_i] != ' ': cs_i += 1
|
||||
cs_seg: sizet = cs_i - cs_start
|
||||
cs_buf: str = pool.alloc(cs_seg + 1)
|
||||
cs_buf: char* = pool.alloc(cs_seg + 1)
|
||||
if cs_buf is not None:
|
||||
string.strncpy(cs_buf, reexport_src + cs_start, cs_seg)
|
||||
cs_buf[cs_seg] = '\0'
|
||||
cand_sha1: str = self._lookup_module_sha1(cs_buf)
|
||||
cand_sha1: char* = self._lookup_module_sha1(cs_buf)
|
||||
if cand_sha1 is None: cand_sha1 = self._lookup_module_sha1_suffix(cs_buf)
|
||||
if cand_sha1 is not None:
|
||||
if self.Gen.CallGenBase.is_cexport_func(cand_sha1, func_name) != 0 or self._is_state_func_from_vpi(pool, cand_sha1, func_name) != 0:
|
||||
@@ -1473,7 +1473,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if VpiReader._lookup_vpi_ret_annot(mod_sha1, None, func_name) is not None: orig_has_def = 1
|
||||
if orig_has_def == 0:
|
||||
# Original module does not define it: fall back to the first candidate (e.g. ast._lexer_init in ast.lexer).
|
||||
reexport_sha1: str = self._lookup_module_sha1(reexport_src)
|
||||
reexport_sha1: char* = self._lookup_module_sha1(reexport_src)
|
||||
if reexport_sha1 is None: reexport_sha1 = self._lookup_module_sha1_suffix(reexport_src)
|
||||
if reexport_sha1 is not None: mod_sha1 = reexport_sha1
|
||||
# ExportT functions define with the bare name (@strlen), so the cross-module call must use the bare name too.
|
||||
@@ -1486,7 +1486,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
call_name = func_name
|
||||
else:
|
||||
mangled_len: sizet = string.strlen(mod_sha1) + string.strlen(func_name) + 2
|
||||
mangled: str = pool.alloc(mangled_len)
|
||||
mangled: char* = pool.alloc(mangled_len)
|
||||
if mangled is not None:
|
||||
viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name)
|
||||
call_name = mangled
|
||||
@@ -1501,7 +1501,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if is_imported_mod != 0:
|
||||
# Aliased import (import X as Y): Y is in _imported_modules but the exact SHA1 lookup fails
|
||||
# (mod_arr holds file names); try from_imports (alias -> full name -> suffix SHA1) with allow_star_fallback=0.
|
||||
alias_sha1: str = None
|
||||
alias_sha1: char* = None
|
||||
if trans is not None and trans._from_imports is not None: alias_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0)
|
||||
if alias_sha1 is not None:
|
||||
if self.Gen.CallGenBase.is_cexport_func(alias_sha1, func_name) != 0: call_name = func_name
|
||||
@@ -1510,13 +1510,13 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
call_name = func_name
|
||||
else:
|
||||
AliasMangledLen: sizet = string.strlen(alias_sha1) + string.strlen(func_name) + 2
|
||||
alias_mangled: str = pool.alloc(AliasMangledLen)
|
||||
alias_mangled: char* = pool.alloc(AliasMangledLen)
|
||||
if alias_mangled is not None:
|
||||
viperlib.snprintf(alias_mangled, AliasMangledLen, "%s.%s", alias_sha1, func_name)
|
||||
call_name = alias_mangled
|
||||
else:
|
||||
# Imported module but SHA1 unregistered: the module was not compiled, so error out immediately.
|
||||
err_msg_imp: str = pool.alloc(256)
|
||||
err_msg_imp: char* = pool.alloc(256)
|
||||
if err_msg_imp is not None:
|
||||
viperlib.snprintf(err_msg_imp, 256, "Module '%s' is imported but its SHA1 is not registered (the module was not compiled)", xmod_path)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg_imp)
|
||||
@@ -1524,14 +1524,14 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
# Check whether it is a from-import name (e.g. from .__types import LLVMType): LLVMType is a
|
||||
# class, not a module, but Ptr is a module-level function of __types; disable star-import fallback.
|
||||
from_sha1: str = None
|
||||
from_sha1: char* = None
|
||||
if trans is not None and trans._from_imports is not None: from_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0)
|
||||
if from_sha1 is not None:
|
||||
# ExportT functions define with the bare name, so the cross-module call must use the bare name.
|
||||
if self.Gen.CallGenBase.is_cexport_func(from_sha1, func_name) != 0: call_name = func_name
|
||||
else:
|
||||
fmangled_len: sizet = string.strlen(from_sha1) + string.strlen(func_name) + 2
|
||||
fmangled: str = pool.alloc(fmangled_len)
|
||||
fmangled: char* = pool.alloc(fmangled_len)
|
||||
if fmangled is not None:
|
||||
viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name)
|
||||
call_name = fmangled
|
||||
@@ -1547,12 +1547,12 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if base_defined == 0 and GenApi.is_nonlocal_name(trans, xmod_path) != 0: base_defined = 1
|
||||
if base_defined == 0 and self.Gen.StructGen.find_struct(xmod_path) is not None: base_defined = 1
|
||||
if base_defined == 0:
|
||||
err_msg_ne: str = pool.alloc(256)
|
||||
err_msg_ne: char* = pool.alloc(256)
|
||||
if err_msg_ne is not None:
|
||||
viperlib.snprintf(err_msg_ne, 256, "name '%s' is not defined (used as a module in '%s.%s'; missing an import?)", xmod_path, xmod_path, func_name)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg_ne, "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, f"name '{xmod_path}' is not defined", "NameError")
|
||||
err_msg2: str = pool.alloc(256)
|
||||
err_msg2: char* = pool.alloc(256)
|
||||
if err_msg2 is not None:
|
||||
viperlib.snprintf(err_msg2, 256, "Cross-module call '%s.%s': module SHA1 not found", xmod_path, func_name)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg2)
|
||||
@@ -1561,18 +1561,18 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# Bare-name call (not Attribute): check from_imports. Star-import fallback is disabled for calls
|
||||
# (star import is for types/constants); a missed function then fails fast at compile time instead of linking wrong.
|
||||
if trans is not None and trans._from_imports is not None:
|
||||
bare_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0)
|
||||
bare_sha1: char* = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0)
|
||||
if bare_sha1 is not None:
|
||||
# Alias handling: from X import Y as Z -> calling Z must mangle with Y (e.g. from json.__parser
|
||||
# import parse as json_parse -> SHA1.parse, not SHA1.json_parse).
|
||||
bare_orig: str = self.Gen.ImportsGen.lookup_from_import_original(trans._from_imports, func_name)
|
||||
bare_func_name: str = func_name
|
||||
bare_orig: char* = self.Gen.ImportsGen.lookup_from_import_original(trans._from_imports, func_name)
|
||||
bare_func_name: char* = func_name
|
||||
if bare_orig is not None:
|
||||
# bare_orig points into the from_imports buffer and is not NUL-terminated, so copy it
|
||||
# into a separate buffer (truncating at space or NUL).
|
||||
bo_len: sizet = 0
|
||||
while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0': bo_len += 1
|
||||
bo_buf: str = pool.alloc(bo_len + 1)
|
||||
bo_buf: char* = pool.alloc(bo_len + 1)
|
||||
if bo_buf is not None:
|
||||
for bo_i in range(int(bo_len)): bo_buf[bo_i] = bare_orig[bo_i]
|
||||
bo_buf[bo_len] = '\0'
|
||||
@@ -1582,28 +1582,28 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
orig_func_name = bare_func_name
|
||||
# Re-export resolution: a from-imported bare function may actually be defined in a submodule
|
||||
# (e.g. dump defined in ast.base, ast/__init__ only re-exports), so redirect to the defining module SHA1.
|
||||
reexport_src2: str = self.Gen.ImportsGen.lookup_reexport_call(bare_sha1, bare_func_name)
|
||||
reexport_src2: char* = self.Gen.ImportsGen.lookup_reexport_call(bare_sha1, bare_func_name)
|
||||
if reexport_src2 is None:
|
||||
# Re-export table miss: resolve the module's .vpi from-import on demand.
|
||||
reexport_src2 = self._lookup_reexport_from_vpi(pool, bare_sha1, bare_func_name)
|
||||
if reexport_src2 is not None:
|
||||
reexport_sha1_2: str = self._lookup_module_sha1(reexport_src2)
|
||||
reexport_sha1_2: char* = self._lookup_module_sha1(reexport_src2)
|
||||
if reexport_sha1_2 is not None: bare_sha1 = reexport_sha1_2
|
||||
if self.Gen.CallGenBase.is_cexport_func(bare_sha1, bare_func_name) != 0: call_name = bare_func_name
|
||||
else:
|
||||
bare_mangled_len: sizet = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2
|
||||
bare_mangled: str = pool.alloc(bare_mangled_len)
|
||||
bare_mangled: char* = pool.alloc(bare_mangled_len)
|
||||
if bare_mangled is not None:
|
||||
viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name)
|
||||
call_name = bare_mangled
|
||||
else:
|
||||
err_msg3: str = pool.alloc(256)
|
||||
err_msg3: char* = pool.alloc(256)
|
||||
if err_msg3 is not None:
|
||||
viperlib.snprintf(err_msg3, 256, "Bare-name call '%s' is undefined and not imported", func_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_msg3)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Bare-name call undefined and not imported")
|
||||
else:
|
||||
err_msg4: str = pool.alloc(256)
|
||||
err_msg4: char* = pool.alloc(256)
|
||||
if err_msg4 is not None:
|
||||
viperlib.snprintf(err_msg4, 256, "Bare-name call '%s' is undefined and not imported", func_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_msg4)
|
||||
@@ -1622,12 +1622,12 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# returning functions and the default i32 truncates them; the authority is text.ll define, then the vpi annotation.
|
||||
if self.Gen.CallGenLib._is_sha1_mangled_call(call_name) != 0:
|
||||
if trans is None or trans._declare_only == 0:
|
||||
cf_dot: str = string.strchr(call_name, '.')
|
||||
cf_last: str = string.strrchr(call_name, '.')
|
||||
cf_dot: char* = string.strchr(call_name, '.')
|
||||
cf_last: char* = string.strrchr(call_name, '.')
|
||||
if cf_dot is not None and cf_last is not None:
|
||||
cf_sha1: str = stdlib.malloc(17)
|
||||
cf_sha1: char* = stdlib.malloc(17)
|
||||
cf_bare_len: sizet = string.strlen(call_name) - (sizet(uint64(cf_last) - uint64(call_name))) - 1
|
||||
cf_bare: str = stdlib.malloc(cf_bare_len + 1)
|
||||
cf_bare: char* = stdlib.malloc(cf_bare_len + 1)
|
||||
if cf_sha1 is not None and cf_bare is not None:
|
||||
string.strncpy(cf_sha1, call_name, 16)
|
||||
cf_sha1[16] = '\0'
|
||||
@@ -1645,8 +1645,8 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# text.ll both key methods by class, so the class segment must be passed
|
||||
# through. Only when it names a registered class: `{sha}.submod.func` has
|
||||
# the same shape but its symbol is the bare module function.
|
||||
cf_cls: str = None
|
||||
cf_mid: str = cf_dot + 1
|
||||
cf_cls: char* = None
|
||||
cf_mid: char* = cf_dot + 1
|
||||
if uint64(cf_last) > uint64(cf_mid):
|
||||
cf_mid_len: sizet = sizet(uint64(cf_last) - uint64(cf_mid))
|
||||
cf_cls_buf: bytes = stdlib.malloc(cf_mid_len + 1)
|
||||
@@ -1686,11 +1686,11 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 而 _ensure_method_declare 又会按 can 建短 declare —— 旧逻辑会把这个错误一路藏到
|
||||
# mlir-opt 的 "incorrect number of operands"。含关键字实参或可变参数时跳过。
|
||||
if self.Gen.CallGenLib._is_sha1_mangled_call(call_name) != 0 and (cl.keywords is None or len(cl.keywords) == 0):
|
||||
ar_sha: str = pool.alloc(17)
|
||||
ar_sha: char* = pool.alloc(17)
|
||||
if ar_sha is not None:
|
||||
string.strncpy(ar_sha, call_name, 16)
|
||||
ar_sha[16] = '\0'
|
||||
ar_name: str = call_name + 17
|
||||
ar_name: char* = call_name + 17
|
||||
ar_n: int = VpiReader.LookupParamCountByName(pool, ar_sha, ar_name)
|
||||
if ar_n >= 0 and int(can) != ar_n:
|
||||
# ar_n comes from a scan of the .vpi *text*. What this call actually binds to
|
||||
|
||||
Reference in new issue
Block a user