refactor(viperc): 退役 t/c 模块标记,内建类型改由编译器直接识别
This commit is contained in:
1 parent
3242560d02
commit
42b094a575
25 files changed
+409
-632
No files matched your search
@@ -440,8 +440,6 @@ def _PhaseADumpNode(temp_dir: str, td_len: sizet, sha1: str, depth: int, prefix:
|
||||
nm[tl] = 0
|
||||
is_last: int = 0
|
||||
if idx + 1 >= token_count: is_last = 1
|
||||
builtin: int = 0
|
||||
if string.strcmp(nm, "t") == 0 or string.strcmp(nm, "c") == 0: builtin = 1
|
||||
dep_sha1: str = _PhaseAResolveDepSha1(nm)
|
||||
txt_ok: int = 0
|
||||
if dep_sha1 is not None: txt_ok = _PhaseATextLLExists(temp_dir, td_len, dep_sha1)
|
||||
@@ -449,10 +447,7 @@ def _PhaseADumpNode(temp_dir: str, td_len: sizet, sha1: str, depth: int, prefix:
|
||||
# stack pointer for a literal -> printf %s crashes and the graph output is swallowed)
|
||||
br_1: str = "|-- "
|
||||
br_2: str = "`-- "
|
||||
if builtin != 0:
|
||||
if is_last != 0: stdio.printf("%s%s%s (builtin)\n", prefix, br_2, nm)
|
||||
else: stdio.printf("%s%s%s (builtin)\n", prefix, br_1, nm)
|
||||
elif dep_sha1 is None:
|
||||
if dep_sha1 is None:
|
||||
if is_last != 0: stdio.printf("%s%s%s (unresolved)\n", prefix, br_2, nm)
|
||||
else: stdio.printf("%s%s%s (unresolved)\n", prefix, br_1, nm)
|
||||
elif txt_ok != 0:
|
||||
@@ -463,7 +458,7 @@ def _PhaseADumpNode(temp_dir: str, td_len: sizet, sha1: str, depth: int, prefix:
|
||||
else: stdio.printf("%s%s%s [MISS] text.ll=%s\n", prefix, br_1, nm, dep_sha1)
|
||||
# Drill down: MISS follows the whole chain (to PA_GRAPH_DEPTH_MAX); OK probes 1 level only
|
||||
can_expand: int = 0
|
||||
if dep_sha1 is not None and builtin == 0:
|
||||
if dep_sha1 is not None:
|
||||
if txt_ok == 0:
|
||||
if depth + 1 < PA_GRAPH_DEPTH_MAX: can_expand = 1
|
||||
else:
|
||||
|
||||
@@ -776,27 +776,8 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*, rel_path: str, buf
|
||||
tree_children: list[ast.AST*]* = tree.children
|
||||
n: sizet = len(tree_children)
|
||||
|
||||
# Pass 1: detect import t/c
|
||||
has_import_t: int = 0
|
||||
has_import_c: int = 0
|
||||
for i in range(int(n)):
|
||||
stmt: ast.AST* = tree_children.get(i)
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.Import:
|
||||
imp: ast.Import* = ast.Import*(stmt)
|
||||
if imp.names is not None:
|
||||
imp_names: list[ast.AST*]* = imp.names
|
||||
an: sizet = len(imp_names)
|
||||
for ai in range(int(an)):
|
||||
al: ast.Alias* = ast.Alias*(imp_names.get(ai))
|
||||
if al is not None and al.name is not None:
|
||||
if string.strcmp(al.name, "t") == 0: has_import_t = 1
|
||||
elif string.strcmp(al.name, "c") == 0: has_import_c = 1
|
||||
|
||||
# Add missing import t/c
|
||||
if has_import_t == 0 and has_import_c == 0: pos = _PyiEmit(buf, buf_size, pos, "import t, c\n\n")
|
||||
elif has_import_t == 0: pos = _PyiEmit(buf, buf_size, pos, "import t\n\n")
|
||||
elif has_import_c == 0: pos = _PyiEmit(buf, buf_size, pos, "import c\n\n")
|
||||
else: pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
# t / c are retired compiler-internal modules: the stub never injects their imports.
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
|
||||
# Pass 2: emit declarations
|
||||
for i in range(int(n)):
|
||||
@@ -886,12 +867,9 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*, rel_path: str, buf
|
||||
# If there is a value (e.g. a CDefine constant) emit = value.
|
||||
# CTypedef is special: its value is a type expression, rendered by _PyiTypeStr.
|
||||
is_ctypedef_ann: int = 0
|
||||
if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Attribute:
|
||||
ctd_at: ast.Attribute* = ast.Attribute*(aa.annotation)
|
||||
if ctd_at.attr is not None and string.strcmp(ctd_at.attr, "CTypedef") == 0:
|
||||
if ctd_at.value is not None and ctd_at.value.kind() == ast.ASTKind.Name:
|
||||
ctd_mod: ast.Name* = ast.Name*(ctd_at.value)
|
||||
if ctd_mod.id is not None and string.strcmp(ctd_mod.id, "t") == 0: is_ctypedef_ann = 1
|
||||
if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Name:
|
||||
ctd_nm: ast.Name* = ast.Name*(aa.annotation)
|
||||
if ctd_nm.id is not None and string.strcmp(ctd_nm.id, "CTypedef") == 0: is_ctypedef_ann = 1
|
||||
if is_ctypedef_ann != 0 and aa.value is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, aa.value)
|
||||
|
||||
@@ -1645,10 +1645,10 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy*, seg: str) -> mlirlite.L
|
||||
stdlib.free(inner_buf_rp)
|
||||
if inner_ty_rp is not None: return mlirlite.Ptr(pool, inner_ty_rp)
|
||||
return None
|
||||
# t.CPtr[T] / c.CPtr[T] subscript pointers (nesting allowed, e.g. t.CPtr[t.CPtr]
|
||||
# -> Ptr(Ptr(i8))); same as TypeGenResolve's Subscript(CPtr) branch: Ptr(resolve(T)).
|
||||
# CPtr[T] subscript pointers (nesting allowed, e.g. CPtr[CPtr] -> Ptr(Ptr(i8)));
|
||||
# same as TypeGenResolve's Subscript(CPtr) branch: Ptr(resolve(T)).
|
||||
cptr_sub_pfx: sizet = 0
|
||||
if string.strncmp(seg, "t.CPtr[", 7) == 0 or string.strncmp(seg, "c.CPtr[", 7) == 0: cptr_sub_pfx = 7
|
||||
if string.strncmp(seg, "CPtr[", 6) == 0: cptr_sub_pfx = 6
|
||||
if cptr_sub_pfx > 0:
|
||||
seg_len_cp: sizet = string.strlen(seg)
|
||||
if seg_len_cp > cptr_sub_pfx + 1 and seg[seg_len_cp - 1] == ']':
|
||||
@@ -1661,15 +1661,12 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy*, seg: str) -> mlirlite.L
|
||||
stdlib.free(inner_buf_cp)
|
||||
if inner_ty_cp is not None: return mlirlite.Ptr(pool, inner_ty_cp)
|
||||
return None
|
||||
# t.XXX / c.XXX built-in type mapping
|
||||
if string.strncmp(seg, "t.", 2) == 0 or string.strncmp(seg, "c.", 2) == 0:
|
||||
attr_nm: str = seg + 2
|
||||
# t.CExport is an export marker, not a real type; FuncGenDef maps it to Void,
|
||||
# Bare builtin type names (int8 / uint64 / sizet / CPtr / CExport ...)
|
||||
if string.strchr(seg, '.') is None:
|
||||
# CExport is an export marker, not a real type; FuncGenDef maps it to Void,
|
||||
# so normalize it here too or cross-module return types fail fast.
|
||||
if string.strcmp(attr_nm, "CExport") == 0: return mlirlite.Void(pool)
|
||||
# [stage 2] unified: CTypedef dynamic table first (library typedefs analyzed normally),
|
||||
# on miss fall back to map_t_type (t/c library internal special-casing).
|
||||
mapped_ty: mlirlite.LLVMType* = GenApi.resolve_typedef_or_map(pool, attr_nm, None, None)
|
||||
if string.strcmp(seg, "CExport") == 0: return mlirlite.Void(pool)
|
||||
mapped_ty: mlirlite.LLVMType* = GenApi.resolve_typedef_or_map(pool, seg, None, None)
|
||||
if mapped_ty is not None: return mapped_ty
|
||||
return None
|
||||
# module-qualified class name "memhub.MemBuddy" -> use last segment to look up struct
|
||||
@@ -1689,7 +1686,7 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy*, seg: str) -> mlirlite.L
|
||||
# bare enum name -> EnumTable fallback (as above: enums are not in StructTable)
|
||||
bare_enum_ty: mlirlite.LLVMType* = GenApi.get_enum_base_type(seg)
|
||||
if bare_enum_ty is not None: return bare_enum_ty
|
||||
# bare typedef name (e.g. VOIDPTR): CTypedef dynamic table first, on miss fall back to map_t_type
|
||||
# bare typedef name (e.g. VOIDPTR): CTypedef dynamic table first, on miss fall back to map_builtin_type
|
||||
mapped_bare: mlirlite.LLVMType* = GenApi.resolve_typedef_or_map(pool, seg, None, None)
|
||||
if mapped_bare is not None: return mapped_bare
|
||||
return None
|
||||
@@ -1793,7 +1790,7 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*, ret_annot: str, i32_ty: m
|
||||
seg_buf[seg_len2] = '\0'
|
||||
# CPtr subscript segments must be recognized first: the definition side treats
|
||||
# `X*[T]` as "CPtr side contributes N pointer levels, the other side the base".
|
||||
if string.strncmp(seg_buf, "t.CPtr[", 7) == 0 or string.strncmp(seg_buf, "c.CPtr[", 7) == 0:
|
||||
if string.strncmp(seg_buf, "CPtr[", 6) == 0:
|
||||
seg_ty_cs: mlirlite.LLVMType* = _resolve_single_vpi_type_str(pool, seg_buf)
|
||||
if seg_ty_cs is not None:
|
||||
# Count outer Ptr nesting (same as the definition side). Do not update the
|
||||
@@ -1813,10 +1810,10 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*, ret_annot: str, i32_ty: m
|
||||
if lvl_cs > cptr_sub_lvl:
|
||||
cptr_sub_lvl = lvl_cs
|
||||
cptr_sub_ty = seg_ty_cs
|
||||
elif string.strcmp(seg_buf, "t.CPtr") == 0 or string.strcmp(seg_buf, "CPtr") == 0: has_cptr = 1
|
||||
elif string.strcmp(seg_buf, "t.CRef") == 0 or string.strcmp(seg_buf, "CRef") == 0: has_cref = 1
|
||||
elif string.strcmp(seg_buf, "t.CTempRef") == 0 or string.strcmp(seg_buf, "CTempRef") == 0: has_cref = 1
|
||||
elif string.strcmp(seg_buf, "void") == 0 or string.strcmp(seg_buf, "CVoid") == 0 or string.strcmp(seg_buf, "void") == 0:
|
||||
elif string.strcmp(seg_buf, "CPtr") == 0: has_cptr = 1
|
||||
elif string.strcmp(seg_buf, "CRef") == 0: has_cref = 1
|
||||
elif string.strcmp(seg_buf, "CTempRef") == 0: has_cref = 1
|
||||
elif string.strcmp(seg_buf, "void") == 0 or string.strcmp(seg_buf, "CVoid") == 0:
|
||||
# Bare void is an alias of t.CVoid and must be handled the same, else the
|
||||
# else branch sets first_td and produces the illegal Ptr(Void) (void* = i8*).
|
||||
has_cvoid = 1
|
||||
@@ -2614,9 +2611,9 @@ def _vpi_class_has_packed(decorator_list: list[ast.AST*]*) -> int:
|
||||
if deco is None: continue
|
||||
if deco.kind() == ast.ASTKind.Call:
|
||||
cl: ast.Call* = ast.Call*(deco)
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: continue
|
||||
at0: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if at0.attr is None or string.strcmp(at0.attr, "Attribute") != 0: continue
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Name: continue
|
||||
at0: ast.Name* = ast.Name*(cl.func)
|
||||
if at0.id is None or string.strcmp(at0.id, "Attribute") != 0: continue
|
||||
if cl.args is None: continue
|
||||
an: sizet = len(cl.args)
|
||||
for ai in range(int(an)):
|
||||
@@ -3527,12 +3524,7 @@ def _repl_stub_deco_flags(deco_list: list[ast.AST*]*) -> int:
|
||||
if deco is None: continue
|
||||
nm: str = None
|
||||
k: int = deco.kind()
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(deco)
|
||||
if at.attr is not None and at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
vn: ast.Name* = ast.Name*(at.value)
|
||||
if vn.id is not None and string.strcmp(vn.id, "t") == 0: nm = at.attr
|
||||
elif k == ast.ASTKind.Name:
|
||||
if k == ast.ASTKind.Name:
|
||||
nn: ast.Name* = ast.Name*(deco)
|
||||
nm = nn.id
|
||||
if nm is None: continue
|
||||
|
||||
@@ -23,14 +23,14 @@ novirtual class AssignGenMixin:
|
||||
|
||||
RecoverFound: int
|
||||
|
||||
# Check whether an annotation is t.CDefine (module-level function)
|
||||
# Check whether an annotation is the CDefine marker (module-level function)
|
||||
def is_cdefine_annotation(self, annot: ast.AST*) -> int:
|
||||
"""Return 1 if the annotation is t.CDefine, else 0."""
|
||||
"""Return 1 if the annotation is the CDefine marker, else 0."""
|
||||
if annot is None: return 0
|
||||
k: int = annot.kind()
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(annot)
|
||||
if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0: return 1
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(annot)
|
||||
if nm.id is not None and string.strcmp(nm.id, "CDefine") == 0: return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(annot)
|
||||
@@ -325,13 +325,9 @@ novirtual class AssignGenMixin:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[VPC] shift count out of range: the count {v} is >= the left operand width {lhs_bits} bits; " f"the result would be 0 or undefined (not a value the compiler may guess). " f"Fix: use a count < {lhs_bits}, or widen the left operand.", "ValueError")
|
||||
|
||||
def _is_cdefine_marker_node(self, node: ast.AST*) -> int:
|
||||
"""Return 1 if the node is a t.CDefine marker node."""
|
||||
"""Return 1 if the node is the CDefine marker node."""
|
||||
if node is None: return 0
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0: return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None and string.strcmp(nm.id, "CDefine") == 0: return 1
|
||||
@@ -363,7 +359,7 @@ novirtual class AssignGenMixin:
|
||||
def _int_bits_of_type_name(self, pool: memhub.MemBuddy*, nm: str, depth: int) -> int:
|
||||
"""类型名 → 整数位宽(0=未知/非整数)。depth 防 typedef 环。
|
||||
|
||||
覆盖:内建名(int/bool/int8../uint64/sizet)、`t.CXxx`(map_t_type)、
|
||||
覆盖:内建名(int/bool/int8../uint64/sizet)、`t.CXxx`(map_builtin_type)、
|
||||
以及**用户 typedef**(如 stdint 的 `WORD: t.CTypedef = uint16` —— 经 lookup_ctypedef
|
||||
取其底层类型文本再递归定宽)。此前用户 typedef 一律返回 0,导致
|
||||
`define X: WORD = ...` 的声明宽度不参与校验/物化。
|
||||
@@ -380,7 +376,7 @@ novirtual class AssignGenMixin:
|
||||
if string.strcmp(nm, "int32") == 0 or string.strcmp(nm, "uint32") == 0: return 32
|
||||
if string.strcmp(nm, "int64") == 0 or string.strcmp(nm, "uint64") == 0: return 64
|
||||
if string.strcmp(nm, "sizet") == 0 or string.strcmp(nm, "size_t") == 0: return 64
|
||||
ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.map_t_type(pool, nm)
|
||||
ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.map_builtin_type(pool, nm)
|
||||
if ty is not None:
|
||||
match ty:
|
||||
case mlirlite.LLVMType.Int(bits):
|
||||
@@ -432,7 +428,7 @@ novirtual class AssignGenMixin:
|
||||
def _float_kind_of_type_name(self, pool: memhub.MemBuddy*, nm: str, depth: int) -> int:
|
||||
"""类型名 → 1 表示它是 32 位 float(f32),0 表示 double 或非浮点/未知。depth 防 typedef 环。
|
||||
|
||||
覆盖:内建名 float、`t.CFloat` / `t.CFloat32T`(map_t_type)、用户/include typedef(递归展开)。
|
||||
覆盖:内建名 float、`t.CFloat` / `t.CFloat32T`(map_builtin_type)、用户/include typedef(递归展开)。
|
||||
"""
|
||||
if nm is None or depth > 10: return 0
|
||||
# 去掉模块/类限定前缀:`t.CFloat` → `CFloat`;`stdint.float32` → `float32`
|
||||
@@ -441,7 +437,7 @@ novirtual class AssignGenMixin:
|
||||
return self._float_kind_of_type_name(pool, dot + 1, depth + 1)
|
||||
if string.strcmp(nm, "float") == 0: return 1
|
||||
if string.strcmp(nm, "float32") == 0: return 1
|
||||
ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.map_t_type(pool, nm)
|
||||
ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.map_builtin_type(pool, nm)
|
||||
if ty is not None:
|
||||
match ty:
|
||||
case mlirlite.LLVMType.Float(bits):
|
||||
@@ -1502,34 +1498,22 @@ novirtual class AssignGenMixin:
|
||||
return 0
|
||||
|
||||
def _is_addrlike_call(self, node: ast.AST*) -> int:
|
||||
"""Return 1 if the rhs is an explicit pointer expression (c.Addr/c.Deref/c.Cast/c.Ptr call, or new-syntax `&x` / `*p`)."""
|
||||
"""Return 1 if the rhs is an explicit pointer expression (`&x` / `*p`).
|
||||
"""
|
||||
if node is None: return 0
|
||||
# New syntax (R3/R4): `&x` and `*p` parse as UnaryOp(AddrOf) / UnaryOp(Deref) and replace the
|
||||
# c.Addr / c.Deref call forms. A pointer-valued RHS must not take the module-global
|
||||
# "object with static storage -> copy the object" branch, so both forms count as addrlike.
|
||||
# `&x` and `*p` parse as UnaryOp(AddrOf) / UnaryOp(Deref). A pointer-valued RHS must not
|
||||
# take the module-global "object with static storage -> copy the object" branch.
|
||||
if node.kind() == ast.ASTKind.UnaryOp:
|
||||
uo_al: ast.UnaryOp* = ast.UnaryOp*(node)
|
||||
if uo_al.op == ast.OpKind.AddrOf: return 1
|
||||
if uo_al.op == ast.OpKind.Deref: return 1
|
||||
return 0
|
||||
if node.kind() != ast.ASTKind.Call: return 0
|
||||
cl: ast.Call* = ast.Call*(node)
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: return 0
|
||||
at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if at.value is None or at.value.kind() != ast.ASTKind.Name: return 0
|
||||
vn: ast.Name* = ast.Name*(at.value)
|
||||
if vn.id is None or string.strcmp(vn.id, "c") != 0: return 0
|
||||
if at.attr is None: return 0
|
||||
if string.strcmp(at.attr, "Addr") == 0: return 1
|
||||
if string.strcmp(at.attr, "Deref") == 0: return 1
|
||||
if string.strcmp(at.attr, "Cast") == 0: return 1
|
||||
if string.strcmp(at.attr, "Ptr") == 0: return 1
|
||||
return 0
|
||||
|
||||
def _is_addr_of_expr(self, node: ast.AST*) -> int:
|
||||
"""Return 1 only for an explicit address-of expression (`&x` / `c.Addr(x)`).
|
||||
"""Return 1 only for an explicit address-of expression (`&x`).
|
||||
|
||||
Distinct from _is_addrlike_call, which also counts deref/cast forms: assigning a *deref*
|
||||
Distinct from _is_addrlike_call, which also counts deref forms: assigning a *deref*
|
||||
result (`*p`) to a value-typed variable is a legitimate value copy, so only `&x` indicates
|
||||
a missing `*` in the annotation.
|
||||
"""
|
||||
@@ -1538,14 +1522,6 @@ novirtual class AssignGenMixin:
|
||||
uo_ao: ast.UnaryOp* = ast.UnaryOp*(node)
|
||||
if uo_ao.op == ast.OpKind.AddrOf: return 1
|
||||
return 0
|
||||
if node.kind() != ast.ASTKind.Call: return 0
|
||||
cl_ao: ast.Call* = ast.Call*(node)
|
||||
if cl_ao.func is None or cl_ao.func.kind() != ast.ASTKind.Attribute: return 0
|
||||
at_ao: ast.Attribute* = ast.Attribute*(cl_ao.func)
|
||||
if at_ao.value is None or at_ao.value.kind() != ast.ASTKind.Name: return 0
|
||||
vn_ao: ast.Name* = ast.Name*(at_ao.value)
|
||||
if vn_ao.id is None or string.strcmp(vn_ao.id, "c") != 0: return 0
|
||||
if at_ao.attr is not None and string.strcmp(at_ao.attr, "Addr") == 0: return 1
|
||||
return 0
|
||||
|
||||
def _DerefPunBits(self, pool: memhub.MemBuddy*, ty: mlirlite.LLVMType*) -> int:
|
||||
@@ -1577,20 +1553,65 @@ novirtual class AssignGenMixin:
|
||||
if string.strcmp(ty_nm, "CUInt64T") == 0: return 1
|
||||
if string.strcmp(ty_nm, "CInt64T") == 0: return 1
|
||||
if string.strcmp(ty_nm, "CSizeT") == 0: return 1
|
||||
# builtin 64-bit short names
|
||||
if string.strcmp(ty_nm, "sizet") == 0: return 1
|
||||
if string.strcmp(ty_nm, "size_t") == 0: return 1
|
||||
if string.strcmp(ty_nm, "int64") == 0: return 1
|
||||
if string.strcmp(ty_nm, "uint64") == 0: return 1
|
||||
if string.strcmp(ty_nm, "intfast64") == 0: return 1
|
||||
if string.strcmp(ty_nm, "uintfast64") == 0: return 1
|
||||
if string.strcmp(ty_nm, "intleast64") == 0: return 1
|
||||
if string.strcmp(ty_nm, "uintleast64") == 0: return 1
|
||||
if string.strcmp(ty_nm, "longlong") == 0: return 1
|
||||
if string.strcmp(ty_nm, "ulonglong") == 0: return 1
|
||||
if string.strcmp(ty_nm, "ptrdifft") == 0: return 1
|
||||
return 0
|
||||
|
||||
def _is_scalar_ty_name(self, ty_name: str) -> int:
|
||||
"""Return 1 if the type name is a known pure scalar (whitelist)."""
|
||||
if ty_name is None: return 0
|
||||
# Strip the t./c. namespace prefix so int and bare aliases are judged the same
|
||||
if ty_name[0] == 't' and ty_name[1] == '.': ty_name += 2
|
||||
elif ty_name[0] == 'c' and ty_name[1] == '.': ty_name += 2
|
||||
if string.strchr(ty_name, '|') is not None: return 0
|
||||
if string.strchr(ty_name, '*') is not None: return 0
|
||||
if string.strcmp(ty_name, "str") == 0: return 0
|
||||
if string.strcmp(ty_name, "bytes") == 0: return 0
|
||||
if string.strcmp(ty_name, "CPtr") == 0: return 0
|
||||
if string.strstr(ty_name, "Ptr") is not None: return 0
|
||||
# builtin short type names
|
||||
if string.strcmp(ty_name, "sizet") == 0: return 1
|
||||
if string.strcmp(ty_name, "size_t") == 0: return 1
|
||||
if string.strcmp(ty_name, "int8") == 0: return 1
|
||||
if string.strcmp(ty_name, "int16") == 0: return 1
|
||||
if string.strcmp(ty_name, "int32") == 0: return 1
|
||||
if string.strcmp(ty_name, "int64") == 0: return 1
|
||||
if string.strcmp(ty_name, "uint8") == 0: return 1
|
||||
if string.strcmp(ty_name, "uint16") == 0: return 1
|
||||
if string.strcmp(ty_name, "uint32") == 0: return 1
|
||||
if string.strcmp(ty_name, "uint64") == 0: return 1
|
||||
if string.strcmp(ty_name, "intfast8") == 0: return 1
|
||||
if string.strcmp(ty_name, "intfast16") == 0: return 1
|
||||
if string.strcmp(ty_name, "intfast32") == 0: return 1
|
||||
if string.strcmp(ty_name, "intfast64") == 0: return 1
|
||||
if string.strcmp(ty_name, "uintfast8") == 0: return 1
|
||||
if string.strcmp(ty_name, "uintfast16") == 0: return 1
|
||||
if string.strcmp(ty_name, "uintfast32") == 0: return 1
|
||||
if string.strcmp(ty_name, "uintfast64") == 0: return 1
|
||||
if string.strcmp(ty_name, "intleast8") == 0: return 1
|
||||
if string.strcmp(ty_name, "intleast16") == 0: return 1
|
||||
if string.strcmp(ty_name, "intleast32") == 0: return 1
|
||||
if string.strcmp(ty_name, "intleast64") == 0: return 1
|
||||
if string.strcmp(ty_name, "uintleast8") == 0: return 1
|
||||
if string.strcmp(ty_name, "uintleast16") == 0: return 1
|
||||
if string.strcmp(ty_name, "uintleast32") == 0: return 1
|
||||
if string.strcmp(ty_name, "uintleast64") == 0: return 1
|
||||
if string.strcmp(ty_name, "uchar") == 0: return 1
|
||||
if string.strcmp(ty_name, "short") == 0: return 1
|
||||
if string.strcmp(ty_name, "ushort") == 0: return 1
|
||||
if string.strcmp(ty_name, "uint") == 0: return 1
|
||||
if string.strcmp(ty_name, "long") == 0: return 1
|
||||
if string.strcmp(ty_name, "ulong") == 0: return 1
|
||||
if string.strcmp(ty_name, "longlong") == 0: return 1
|
||||
if string.strcmp(ty_name, "ulonglong") == 0: return 1
|
||||
if string.strcmp(ty_name, "ptrdifft") == 0: return 1
|
||||
# Whitelist: known pure scalars (base names + stdint uppercase aliases)
|
||||
if string.strcmp(ty_name, "int") == 0: return 1
|
||||
if string.strcmp(ty_name, "char") == 0: return 1
|
||||
@@ -1913,7 +1934,7 @@ novirtual class AssignGenMixin:
|
||||
def const_assign_msg(self, kind: str, name: str, src_name: str) -> str:
|
||||
"""Build the const-assignment error message used by const_assign_fail."""
|
||||
decl: str = "(annotation contains t.CConst; the source name at the declaration was not recorded)"
|
||||
if src_name is not None: decl = f"t.CConst | {src_name}"
|
||||
if src_name is not None: decl = f"CConst | {src_name}"
|
||||
return GenApi.escape_fstring_copy(f"cannot assign to const variable '{name}' ({kind}); " f"declaration type (including const): {decl}" f"; fix: remove the const descriptor / t.CConst from the declaration, or assign once at the declaration " f"and afterwards use only non-const copies/temporaries; a const object forbids assignment, " f"augmented assignment and element assignment within its scope, and this never degrades to a warning")
|
||||
|
||||
def const_assign_fail(self, node: ast.AST*, kind: str, name: str, src_name: str) -> int:
|
||||
@@ -2242,18 +2263,12 @@ novirtual class AssignGenMixin:
|
||||
if annot is None or annot.kind() != ast.ASTKind.Subscript: return 0
|
||||
sub: ast.Subscript* = ast.Subscript*(annot)
|
||||
if sub.value is None or sub.slice is None: return 0
|
||||
if sub.value.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(sub.value)
|
||||
if at.attr is None or string.strcmp(at.attr, "CArray") != 0: return 0
|
||||
if at.value is None or at.value.kind() != ast.ASTKind.Name: return 0
|
||||
mv: ast.Name* = ast.Name*(at.value)
|
||||
if mv.id is None or string.strcmp(mv.id, "t") != 0: return 0
|
||||
elif sub.value.kind() == ast.ASTKind.Name:
|
||||
# Bare CArray / builtin rawarray / builtin array are all equivalent to t.CArray
|
||||
if sub.value.kind() == ast.ASTKind.Name:
|
||||
# Bare CArray / builtin rawarray / builtin array are all equivalent.
|
||||
bn: ast.Name* = ast.Name*(sub.value)
|
||||
if bn.id is None or (string.strcmp(bn.id, "CArray") != 0 and string.strcmp(bn.id, "rawarray") != 0 and string.strcmp(bn.id, "array") != 0): return 0
|
||||
else: return 0
|
||||
# Single-param form: slice is not a Tuple (e.g. t.CArray[u64])
|
||||
# Single-param form: slice is not a Tuple (e.g. CArray[u64])
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple: return 1
|
||||
# Two-param form with count=None is equivalent to single-param
|
||||
tup: ast.Tuple* = ast.Tuple*(sub.slice)
|
||||
|
||||
@@ -669,21 +669,11 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
return buf
|
||||
return ""
|
||||
|
||||
# Attribute: t.ASM_DESCR.XXX or t.XXX
|
||||
# Attribute: ASM_DESCR.XXX
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
# t.ASM_DESCR.XXX
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Attribute:
|
||||
inner: ast.Attribute* = ast.Attribute*(at.value)
|
||||
if inner.value is not None and inner.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm: ast.Name* = ast.Name*(inner.value)
|
||||
if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0:
|
||||
if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0: return self._resolve_register(at.attr)
|
||||
# t.XXX shorthand form
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm2: ast.Name* = ast.Name*(at.value)
|
||||
if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0: return self._resolve_register(at.attr)
|
||||
# Bare ASM_DESCR.XXX: equivalent form without the t. prefix
|
||||
if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "ASM_DESCR") == 0: return self._resolve_register(at.attr)
|
||||
return ""
|
||||
|
||||
@@ -724,12 +714,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if string.strcmp(nm.id, "irinp") == 0: return "LInp"
|
||||
if string.strcmp(nm.id, "irout") == 0: return "LOut"
|
||||
return None
|
||||
if node.func.kind() != ast.ASTKind.Attribute: return None
|
||||
at: ast.Attribute* = ast.Attribute*(node.func)
|
||||
if at.value is None or at.value.kind() != ast.ASTKind.Name: return None
|
||||
mod_nm: ast.Name* = ast.Name*(at.value)
|
||||
if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0: return None
|
||||
return at.attr
|
||||
return None
|
||||
|
||||
|
||||
def _asm_name_is_mangled(self, name: str) -> int:
|
||||
|
||||
@@ -248,54 +248,28 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# irinp/irout standalone calls return 0 (meaningful only inside __llvmir__ f-strings)
|
||||
return mlirlite.ConstInt(pool, mlirlite.Int32(pool), 0, "0")
|
||||
|
||||
# Detect c.Deref / c.DerefAs / c.Addr special calls (inline IR, no call emitted)
|
||||
# and coro.* coroutine interception (inline translation, VPC-M1).
|
||||
# Detect coro.* coroutine interception (inline translation, VPC-M1).
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_node: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm: ast.Name* = ast.Name*(at_node.value)
|
||||
is_coro_mod: int = 0
|
||||
if mod_nm.id is not None and string.strcmp(mod_nm.id, "coro") == 0: is_coro_mod = 1
|
||||
if mod_nm.id is not None and (string.strcmp(mod_nm.id, "c") == 0 or is_coro_mod != 0):
|
||||
if string.strcmp(func_name, "Deref") == 0: return self.Gen.CallGenCBuiltin.translate_c_deref(pool, builder, mod, cl, trans)
|
||||
elif string.strcmp(func_name, "DerefAs") == 0: return self.Gen.CallGenCBuiltin.translate_c_derefas(pool, builder, mod, cl, trans)
|
||||
elif string.strcmp(func_name, "Addr") == 0: return self.Gen.CallGenCBuiltin.translate_c_addr(pool, builder, mod, cl, trans)
|
||||
elif string.strcmp(func_name, "Set") == 0:
|
||||
# c.Set(a, b) = a = b (assignment, not pointer deref). Treating it as a plain
|
||||
# call would emit @Set and fail to link (undefined reference to `Set').
|
||||
return self.Gen.CallGenCBuiltin.translate_c_set(pool, builder, mod, cl, trans)
|
||||
elif string.strcmp(func_name, "Load") == 0: return self.Gen.CallGenCBuiltin.translate_c_load(pool, builder, mod, cl, trans)
|
||||
elif string.strcmp(func_name, "Asm") == 0:
|
||||
# translate_c_asm returns None for void: set the hit flag so translate_call
|
||||
# does not fall through to the external function path.
|
||||
if hit_box is not None: hit_box[0] = 1
|
||||
return self.Gen.CallGenCBuiltin.translate_c_asm(pool, builder, mod, cl, trans)
|
||||
elif string.strcmp(func_name, "LLVMIR") == 0:
|
||||
# c.LLVMIR always returns void (None): set the hit flag
|
||||
if hit_box is not None: hit_box[0] = 1
|
||||
return self.Gen.CallGenCBuiltin.translate_c_llvmir(pool, builder, mod, cl, trans)
|
||||
elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0:
|
||||
# c.LInp/c.LOut standalone calls return 0 (only meaningful in c.LLVMIR f-strings)
|
||||
return mlirlite.ConstInt(pool, mlirlite.Int32(pool), 0, "0")
|
||||
elif string.strcmp(func_name, "CIf") == 0 or string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0 or string.strcmp(func_name, "CElif") == 0 or string.strcmp(func_name, "CElse") == 0 or string.strcmp(func_name, "CEndif") == 0:
|
||||
# The c.CIf-family spellings were removed: report the replacement.
|
||||
# (There is no runtime fallback: compile-time conditions use cif/celif/celse.)
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "c.CIf/c.CIfdef/c.CIfndef/c.CElif/c.CElse/c.CEndif were removed; use the cif/celif/celse statements and the defined(NAME) predicate instead (e.g. `cif defined(NAME):` ... `celse:` ...)", "NameError")
|
||||
return None
|
||||
elif is_coro_mod != 0 and string.strcmp(func_name, "coro_run") == 0:
|
||||
if is_coro_mod != 0:
|
||||
if string.strcmp(func_name, "coro_run") == 0:
|
||||
# coro.coro_run(frame): inline translation (resume loop until done, returns the ret slot).
|
||||
# Note: translate_coro_* take (builder, pool, mod, cl, trans), unlike the c.* branches.
|
||||
# Note: translate_coro_* take (builder, pool, mod, cl, trans).
|
||||
return self.Gen.AsyncGen.translate_coro_run(builder, pool, mod, cl, trans)
|
||||
elif is_coro_mod != 0 and string.strcmp(func_name, "coro_destroy") == 0:
|
||||
elif string.strcmp(func_name, "coro_destroy") == 0:
|
||||
# coro.coro_destroy(frame): return the frame to the pool (M7 free-list)
|
||||
return self.Gen.AsyncGen.translate_coro_destroy(builder, pool, mod, cl, trans)
|
||||
elif is_coro_mod != 0 and string.strcmp(func_name, "coro_exception") == 0:
|
||||
elif string.strcmp(func_name, "coro_exception") == 0:
|
||||
# coro.coro_exception(frame): return the frame exc slot (M4)
|
||||
return self.Gen.AsyncGen.translate_coro_exception(builder, pool, mod, cl, trans)
|
||||
elif is_coro_mod != 0 and string.strcmp(func_name, "coro_exception_msg") == 0:
|
||||
elif string.strcmp(func_name, "coro_exception_msg") == 0:
|
||||
# coro.coro_exception_msg(frame): return the frame msg slot (M7)
|
||||
return self.Gen.AsyncGen.translate_coro_exception_msg(builder, pool, mod, cl, trans)
|
||||
elif is_coro_mod != 0 and string.strcmp(func_name, "coro_gather") == 0:
|
||||
elif string.strcmp(func_name, "coro_gather") == 0:
|
||||
# coro.coro_gather(frames...): advance all coroutines concurrently (M4)
|
||||
return self.Gen.AsyncGen.translate_coro_gather(builder, pool, mod, cl, trans)
|
||||
return None
|
||||
@@ -362,112 +336,15 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
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*:
|
||||
"""t.XXX / typedef type casts; returns None when unmatched."""
|
||||
# Detect t.XXX type casts (uint64(ptr), rawptr(val), int(val), ...): when func is t.XXX and
|
||||
# XXX is a known type, treat it as a cast; once confirmed, never fall through to cross-module calls.
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
tc_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name:
|
||||
tc_mod_nm: ast.Name* = ast.Name*(tc_at.value)
|
||||
if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0:
|
||||
# t.CType(value, TypeName, rawptr) casts value to TypeName*; TypeName is a type
|
||||
# name (not a value), so it must be handled explicitly or it falls through to a FATAL.
|
||||
if string.strcmp(func_name, "CType") == 0 and can >= 2:
|
||||
cty_node: ast.AST* = cargs.get(1)
|
||||
ctype_target: mlirlite.LLVMType* = None
|
||||
if cty_node is not None:
|
||||
cti_imp: str = None
|
||||
cti_fi: str = None
|
||||
if trans is not None:
|
||||
cti_imp = trans._imported_modules
|
||||
cti_fi = trans._from_imports
|
||||
ctype_target = self.Gen.TypeGenResolve.resolve_annotation_type(pool, cty_node, cti_imp, cti_fi, trans, 0)
|
||||
if ctype_target is not None:
|
||||
if can == 3:
|
||||
cty_arg3: ast.AST* = cargs.get(2)
|
||||
cty_is_cptr: int = 0
|
||||
if cty_arg3 is not None:
|
||||
# Form 1: rawptr (Attribute)
|
||||
if cty_arg3.kind() == ast.ASTKind.Attribute:
|
||||
cty_at3: ast.Attribute* = ast.Attribute*(cty_arg3)
|
||||
if cty_at3.attr is not None and string.strcmp(cty_at3.attr, "CPtr") == 0:
|
||||
if cty_at3.value is not None and cty_at3.value.kind() == ast.ASTKind.Name:
|
||||
cty_nm3: ast.Name* = ast.Name*(cty_at3.value)
|
||||
if cty_nm3.id is not None and string.strcmp(cty_nm3.id, "t") == 0: cty_is_cptr = 1
|
||||
# Form 2: bare CPtr
|
||||
elif cty_arg3.kind() == ast.ASTKind.Name:
|
||||
cty_bn3: ast.Name* = ast.Name*(cty_arg3)
|
||||
if cty_bn3.id is not None and string.strcmp(cty_bn3.id, "CPtr") == 0: cty_is_cptr = 1
|
||||
if cty_is_cptr != 0:
|
||||
# CVoid* -> i8* (void* is represented as i8* in LLVM)
|
||||
match ctype_target:
|
||||
case mlirlite.LLVMType.Void():
|
||||
ctype_target = mlirlite.Int8(pool)
|
||||
case _:
|
||||
pass
|
||||
ctype_target = mlirlite.Ptr(pool, ctype_target)
|
||||
cty_arg0: ast.AST* = cargs.get(0)
|
||||
if cty_arg0 is not None:
|
||||
cty_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cty_arg0, funcs_ptr, func_count, trans)
|
||||
if cty_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cty_val, ctype_target, cty_arg0, trans)
|
||||
# t.CType confirmed: even if type resolution fails, do not fall through to a cross-module FATAL
|
||||
return None
|
||||
# CConst is a const marker: CConst(val, rawptr) -> Ptr(i8) (const void*). Without
|
||||
# this it emits an undefined @CConst; single-arg CConst(x) returns the value unchanged.
|
||||
if string.strcmp(func_name, "CConst") == 0:
|
||||
if can >= 2:
|
||||
cconst_ptr_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
cconst_arg: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
if cconst_arg is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cconst_arg, cconst_ptr_ty, cargs.get(0), trans)
|
||||
elif can == 1: return self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
return None
|
||||
target_ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.map_t_type(pool, func_name)
|
||||
if target_ty is not None:
|
||||
tc_effective_can: sizet = can
|
||||
# Two-arg form: int(val, rawptr) -> Ptr(target_ty). void* is illegal in LLVM,
|
||||
# so CVoid* must be represented as i8*.
|
||||
if can == 2:
|
||||
tc_arg2_node: ast.AST* = cargs.get(1)
|
||||
tc_arg2_is_cptr: int = 0
|
||||
if tc_arg2_node is not None:
|
||||
# Form 1: rawptr (Attribute form)
|
||||
if tc_arg2_node.kind() == ast.ASTKind.Attribute:
|
||||
tc_arg2_at: ast.Attribute* = ast.Attribute*(tc_arg2_node)
|
||||
if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0:
|
||||
if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name:
|
||||
tc_arg2_nm: ast.Name* = ast.Name*(tc_arg2_at.value)
|
||||
if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: tc_arg2_is_cptr = 1
|
||||
# Form 2: bare CPtr (usable after `from t import CPtr`, e.g. t.CXXX(x, CPtr))
|
||||
elif tc_arg2_node.kind() == ast.ASTKind.Name:
|
||||
tc_arg2_bn: ast.Name* = ast.Name*(tc_arg2_node)
|
||||
if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0: tc_arg2_is_cptr = 1
|
||||
if tc_arg2_is_cptr != 0:
|
||||
# CVoid* -> i8* (void* is represented as i8* in LLVM)
|
||||
match target_ty:
|
||||
case mlirlite.LLVMType.Void():
|
||||
target_ty = mlirlite.Int8(pool)
|
||||
case _:
|
||||
pass
|
||||
target_ty = mlirlite.Ptr(pool, target_ty)
|
||||
tc_effective_can = 1
|
||||
if tc_effective_can == 1:
|
||||
tc_arg_node: ast.AST* = cargs.get(0)
|
||||
if tc_arg_node is not None:
|
||||
# Pass target_ty as the 8th arg: otherwise constants pick their width from
|
||||
# the i32 range and uint64(-1) materializes as i32 -1 then zext (N1).
|
||||
tc_arg_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, tc_arg_node, None, 0, trans, target_ty)
|
||||
if tc_arg_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, tc_arg_val, target_ty, tc_arg_node, trans)
|
||||
# t.XXX cast confirmed but arg shape unsupported: return None, do not fall through to FATAL
|
||||
return None
|
||||
|
||||
"""Builtin / typedef type casts; returns None when unmatched."""
|
||||
# Module-qualified typedef cast (posix.mode_t(mode), win32.win32base.HANDLE(v), ...): func is
|
||||
# Attribute(Name(module), typedef); non-typedef names still go to the module function call.
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
mt_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
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)
|
||||
if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 and string.strcmp(mt_mod_nm.id, "c") != 0:
|
||||
mod_td_ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.map_t_type(pool, func_name)
|
||||
if mt_mod_nm.id 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)
|
||||
if mod_td_str is not None and self.Gen.TypeGenCType.is_ctypedef_found() != 0:
|
||||
@@ -483,26 +360,26 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
mt_arg_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans, mod_td_ty)
|
||||
if mt_arg_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, mt_arg_val, mod_td_ty, cargs.get(0), trans)
|
||||
|
||||
# Bare typedef casts (BYTEPTR, HANDLE, CHARPTR, ...): all CTypedef names and t/c primitives
|
||||
# Bare typedef casts (BYTEPTR, HANDLE, CHARPTR, ...): all CTypedef 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_ty: mlirlite.LLVMType* = None
|
||||
# Builtin names resolved from generic context (T->"double"/"float"): map_t_type only knows
|
||||
# t.CDouble, and float must map to t.CFloat (f32), not f64.
|
||||
# Builtin names resolved from generic context (T->"double"/"float"): float must map to
|
||||
# f32, not f64.
|
||||
if string.strcmp(bare_fn_name, "double") == 0: bare_ty = mlirlite.Double(pool)
|
||||
elif string.strcmp(bare_fn_name, "float") == 0: bare_ty = mlirlite.Float(pool)
|
||||
else:
|
||||
# Prefer the CTypedef dynamic table (library typedef casts); on miss fall back to
|
||||
# map_t_type, which (after phase-2 convergence) no longer contains stdint aliases.
|
||||
# map_builtin_type.
|
||||
bare_imp_c: str = None
|
||||
bare_fi_c: str = None
|
||||
if trans is not None:
|
||||
bare_imp_c = trans._imported_modules
|
||||
bare_fi_c = trans._from_imports
|
||||
bare_ty = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, bare_fn_name, bare_imp_c, bare_fi_c)
|
||||
# Names substituted from generic context (T->"int") are unknown to map_t_type, so fall
|
||||
# back to resolve_annotation_type (supports t.CXxx / struct class names / aliases).
|
||||
# Names substituted from generic context (T->"int") are unknown to map_builtin_type, so fall
|
||||
# back to resolve_annotation_type (supports builtin names / struct class names / aliases).
|
||||
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:
|
||||
@@ -518,17 +395,10 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
bare_arg2_node: ast.AST* = cargs.get(1)
|
||||
bare_arg2_is_cptr: int = 0
|
||||
if bare_arg2_node is not None:
|
||||
# Form 1: rawptr (Attribute form)
|
||||
if bare_arg2_node.kind() == ast.ASTKind.Attribute:
|
||||
bare_arg2_at: ast.Attribute* = ast.Attribute*(bare_arg2_node)
|
||||
if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0:
|
||||
if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name:
|
||||
bare_arg2_nm: ast.Name* = ast.Name*(bare_arg2_at.value)
|
||||
if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0: bare_arg2_is_cptr = 1
|
||||
# Form 2: bare CPtr (usable after `from t import CPtr`)
|
||||
elif bare_arg2_node.kind() == ast.ASTKind.Name:
|
||||
# Builtin pointer marker: CPtr / rawptr
|
||||
if bare_arg2_node.kind() == ast.ASTKind.Name:
|
||||
bare_arg2_bn: ast.Name* = ast.Name*(bare_arg2_node)
|
||||
if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0: bare_arg2_is_cptr = 1
|
||||
if bare_arg2_bn.id is not None and (string.strcmp(bare_arg2_bn.id, "CPtr") == 0 or string.strcmp(bare_arg2_bn.id, "rawptr") == 0): bare_arg2_is_cptr = 1
|
||||
if bare_arg2_is_cptr != 0:
|
||||
# CVoid* -> i8* (void* is represented as i8* in LLVM)
|
||||
match bare_ty:
|
||||
@@ -668,8 +538,8 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if szf_mod is not None:
|
||||
string.strncpy(szf_mod, sz_full_name, szf_mod_len)
|
||||
szf_mod[szf_mod_len] = '\0'
|
||||
# Exempt t/c builtins (int etc. are already handled by the builtin/size table)
|
||||
if string.strcmp(szf_mod, "t") != 0 and string.strcmp(szf_mod, "c") != 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)
|
||||
if szf_sha1 is not None:
|
||||
szf_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(sz_cls_name, szf_sha1)
|
||||
@@ -1247,8 +1117,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if expr_root is not None and expr_root.kind() == ast.ASTKind.Name:
|
||||
expr_root_nm: str = ast.Name*(expr_root).id
|
||||
if expr_root_nm is not None:
|
||||
if string.strcmp(expr_root_nm, "t") == 0 or string.strcmp(expr_root_nm, "c") == 0: is_mod_path_expr = 1
|
||||
elif trans._imported_modules 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
|
||||
if evk != ast.ASTKind.Name and is_mod_path_expr == 0:
|
||||
# Translate the receiver expression (the result should be Ptr(Struct))
|
||||
|
||||
@@ -1291,8 +1291,8 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name)
|
||||
call_name = mangled
|
||||
else:
|
||||
# t and c are internal libraries exempt from SHA1 lookup: use bare-name calls.
|
||||
if string.strcmp(xmod_path, "t") == 0 or string.strcmp(xmod_path, "c") == 0: call_name = func_name
|
||||
# Only real modules reach this path; a missing module segment falls back to a bare name.
|
||||
if xmod_path is None: call_name = func_name
|
||||
else:
|
||||
# Check whether it is an imported module name (e.g. BuildPipeline.run_pipeline): if imported
|
||||
# but its SHA1 is unregistered the module was not compiled, so error out instead of a misleading from_imports lookup.
|
||||
|
||||
@@ -147,11 +147,7 @@ novirtual class ClassGenBase:
|
||||
while alias_orig[og_len_ce] != ' ' and alias_orig[og_len_ce] != '\0': og_len_ce += 1
|
||||
if og_len_ce == 5 and string.strncmp(alias_orig, "CEnum", 5) == 0: return 1
|
||||
return 0
|
||||
# Attribute(t.CEnum) form.
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(base_node)
|
||||
if at.attr is not None and string.strcmp(at.attr, "CEnum") == 0: return 1
|
||||
return 0
|
||||
# Attribute form was retired together with the t module prefix.
|
||||
return 0
|
||||
def _is_enum_class(self, cd: ast.ClassDef*, trans: HT.Translator* = None) -> int:
|
||||
"""Return 1 if the ClassDef is a CEnum (subclasses t.CEnum or uses @t.CEnum)."""
|
||||
@@ -185,11 +181,7 @@ novirtual class ClassGenBase:
|
||||
while alias_orig[og_len_cu] != ' ' and alias_orig[og_len_cu] != '\0': og_len_cu += 1
|
||||
if og_len_cu == 6 and string.strncmp(alias_orig, "CUnion", 6) == 0: return 1
|
||||
return 0
|
||||
# Attribute(t.CUnion) form.
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(base_node)
|
||||
if at.attr is not None and string.strcmp(at.attr, "CUnion") == 0: return 1
|
||||
return 0
|
||||
# Attribute form was retired together with the t module prefix.
|
||||
return 0
|
||||
def _is_union_class(self, cd: ast.ClassDef*, trans: HT.Translator* = None) -> int:
|
||||
"""Return 1 if the ClassDef is a CUnion (subclasses t.CUnion or uses @t.CUnion)."""
|
||||
@@ -223,11 +215,7 @@ novirtual class ClassGenBase:
|
||||
while alias_orig[og_len_cr] != ' ' and alias_orig[og_len_cr] != '\0': og_len_cr += 1
|
||||
if og_len_cr == 5 and string.strncmp(alias_orig, "REnum", 5) == 0: return 1
|
||||
return 0
|
||||
# Attribute(t.REnum) form.
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(base_node)
|
||||
if at.attr is not None and string.strcmp(at.attr, "REnum") == 0: return 1
|
||||
return 0
|
||||
# Attribute form was retired together with the t module prefix.
|
||||
return 0
|
||||
def _is_renum_class(self, cd: ast.ClassDef*, trans: HT.Translator* = None) -> int:
|
||||
"""Return 1 if the ClassDef is a REnum (subclasses t.REnum or uses @t.REnum)."""
|
||||
@@ -245,7 +233,7 @@ novirtual class ClassGenBase:
|
||||
if self._is_crenum_base(base_node, trans) == 1: return 1
|
||||
return 0
|
||||
def _has_decorator(self, decorator_list: list[ast.AST*]*, deco_name: str) -> int:
|
||||
"""Return 1 if decorator_list contains the given decorator name."""
|
||||
"""Return 1 if decorator_list contains the given bare builtin decorator name."""
|
||||
if decorator_list is None: return 0
|
||||
dn: sizet = len(decorator_list)
|
||||
if dn == 0: return 0
|
||||
@@ -253,16 +241,7 @@ novirtual class ClassGenBase:
|
||||
deco: ast.AST* = decorator_list.get(di)
|
||||
if deco is None: continue
|
||||
k: int = deco.kind()
|
||||
# @t.NoVTable form (Attribute).
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(deco)
|
||||
if at.attr is not None and string.strcmp(at.attr, deco_name) == 0:
|
||||
# Check that value is Name('t').
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
vn: ast.Name* = ast.Name*(at.value)
|
||||
if vn.id is not None and string.strcmp(vn.id, "t") == 0: return 1
|
||||
return 0
|
||||
# @NoVTable form (Name; from t import NoVTable).
|
||||
# @NoVTable / @CVTable / @TLS / @CStatic form (bare builtin Name).
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(deco)
|
||||
if nm.id is not None and string.strcmp(nm.id, deco_name) == 0: return 1
|
||||
@@ -290,10 +269,10 @@ novirtual class ClassGenBase:
|
||||
k: int = deco.kind()
|
||||
if k == ast.ASTKind.Call:
|
||||
cl: ast.Call* = ast.Call*(deco)
|
||||
# @c.Attribute(t.attr.xxx) form: func is Attribute(c, "Attribute").
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: continue
|
||||
at0: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if at0.attr is None or string.strcmp(at0.attr, "Attribute") != 0: continue
|
||||
# @Attribute(attr.xxx) form: func is the bare builtin Name("Attribute").
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Name: continue
|
||||
at0: ast.Name* = ast.Name*(cl.func)
|
||||
if at0.id is None or string.strcmp(at0.id, "Attribute") != 0: continue
|
||||
if cl.args is None: continue
|
||||
an: sizet = len(cl.args)
|
||||
for ai in range(int(an)):
|
||||
@@ -319,7 +298,7 @@ novirtual class ClassGenBase:
|
||||
return int(cn.int_val)
|
||||
return 0
|
||||
def _class_aligned_value(self, decorator_list: list[ast.AST*]*) -> int:
|
||||
"""Return the alignment bytes from @c.Attribute(t.attr.aligned(N)); 0 when absent."""
|
||||
"""Return the alignment bytes from @Attribute(attr.aligned(N)); 0 when absent."""
|
||||
if decorator_list is None: return 0
|
||||
dn: sizet = len(decorator_list)
|
||||
if dn == 0: return 0
|
||||
@@ -328,9 +307,9 @@ novirtual class ClassGenBase:
|
||||
if deco is None: continue
|
||||
if deco.kind() == ast.ASTKind.Call:
|
||||
cl: ast.Call* = ast.Call*(deco)
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: continue
|
||||
at0: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if at0.attr is None or string.strcmp(at0.attr, "Attribute") != 0: continue
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Name: continue
|
||||
at0: ast.Name* = ast.Name*(cl.func)
|
||||
if at0.id is None or string.strcmp(at0.id, "Attribute") != 0: continue
|
||||
if cl.args is None: continue
|
||||
an: sizet = len(cl.args)
|
||||
for ai in range(int(an)):
|
||||
@@ -366,9 +345,6 @@ novirtual class ClassGenBase:
|
||||
vn: ast.Name* = ast.Name*(at.value)
|
||||
is_prop_name: int = 0
|
||||
if vn.id is not None and string.strcmp(vn.id, "property") == 0: is_prop_name = 1
|
||||
# @t.TLS one-time init marker (mirrors TPC HandlesFunctions):
|
||||
# value must be Name('t'); bare @TLS is handled by the Name branch.
|
||||
if vn.id is not None and string.strcmp(vn.id, "t") == 0 and string.strcmp(at.attr, "TLS") == 0: meta |= META_TLS
|
||||
# Recognize @property.setter and @x.setter/getter/deleter.
|
||||
if is_prop_name != 0 or string.strcmp(at.attr, "setter") == 0 or string.strcmp(at.attr, "getter") == 0 or string.strcmp(at.attr, "deleter") == 0:
|
||||
if string.strcmp(at.attr, "setter") == 0: meta |= GenTypes.META_PROP_SETTER
|
||||
|
||||
@@ -42,7 +42,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# [enum bool rule] `t.CBool` and bare `bool` both materialize as 8 bits in enum member annotations,
|
||||
# else the same member would split into i1 / i8; the global `t.CBool` stays i1 (only enums differ).
|
||||
if string.strcmp(at.attr, "CBool") == 0: return mlirlite.Int8(pool)
|
||||
# Other t.CXxx types: unified (CTypedef dynamic table first, fall back to map_t_type)
|
||||
# Other t.CXxx types: unified (CTypedef dynamic table first, fall back to map_builtin_type)
|
||||
ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, at.attr, imported_modules, from_imports)
|
||||
if ty is not None: return ty
|
||||
# [S4 fail-fast] annotated but unresolvable -> no silent i32 fallback
|
||||
@@ -266,7 +266,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
tgt: ast.Name* = ast.Name*(aa.target)
|
||||
if tgt.id is None: continue
|
||||
|
||||
# [enum spec fail-fast] Members may not be pointer types: t.CPtr / CRef /
|
||||
# [enum spec fail-fast] Members may not be pointer types: rawptr / CRef /
|
||||
# CTempRef / CAutoPtr / rawptr[...] / str / bytes and unions carrying a pointer. Checked before type resolution.
|
||||
if self._enum_member_annotation_is_ptr(aa.annotation) == 1:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"enum member '{tgt.id}' cannot be a pointer type (enum values only support integer member types)", "TypeError")
|
||||
@@ -601,6 +601,18 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# analysis; the hardcoded size table below is only a fallback for t/c core primitives.
|
||||
dyn_sz: int = self.Gen.TypeGenResolve.get_type_size_bytes(pool, type_name, None, None)
|
||||
if dyn_sz > 0: return dyn_sz
|
||||
# Builtin short names
|
||||
if string.strcmp(type_name, "sizet") == 0 or string.strcmp(type_name, "size_t") == 0: return 8
|
||||
if string.strcmp(type_name, "int8") == 0 or string.strcmp(type_name, "uint8") == 0: return 1
|
||||
if string.strcmp(type_name, "uchar") == 0: return 1
|
||||
if string.strcmp(type_name, "int16") == 0 or string.strcmp(type_name, "uint16") == 0: return 2
|
||||
if string.strcmp(type_name, "short") == 0 or string.strcmp(type_name, "ushort") == 0: return 2
|
||||
if string.strcmp(type_name, "int32") == 0 or string.strcmp(type_name, "uint32") == 0: return 4
|
||||
if string.strcmp(type_name, "int") == 0 or string.strcmp(type_name, "uint") == 0: return 4
|
||||
if string.strcmp(type_name, "long") == 0 or string.strcmp(type_name, "ulong") == 0: return 4
|
||||
if string.strcmp(type_name, "int64") == 0 or string.strcmp(type_name, "uint64") == 0: return 8
|
||||
if string.strcmp(type_name, "longlong") == 0 or string.strcmp(type_name, "ulonglong") == 0: return 8
|
||||
if string.strcmp(type_name, "ptrdifft") == 0: return 8
|
||||
# Builtin types
|
||||
if string.strcmp(type_name, "int") == 0: return 4
|
||||
if string.strcmp(type_name, "CInt") == 0: return 4
|
||||
@@ -793,7 +805,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
|
||||
# Register into HandlesStruct.
|
||||
# A forward-declared placeholder for THIS class may have been created *during the variant walk*
|
||||
# above: a variant field like `Pointee: LLVMType*` is `BinOp(LLVMType | t.CPtr)` (parser's
|
||||
# above: a variant field like `Pointee: LLVMType*` is `BinOp(LLVMType | rawptr)` (parser's
|
||||
# _make_ptr_type expands the C-style suffix into a union, NOT into `rawptr[...]`), so resolving it
|
||||
# resolves the class name and calls ensure_forward_class. register_struct de-duplicates by Ty
|
||||
# pointer, so it would add a SECOND same-named entry and get_struct_type/find_struct (first match
|
||||
|
||||
@@ -318,10 +318,10 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if sign == TSpec.TS_SIGN_SIGNED: return "int64"
|
||||
return None
|
||||
# ---- Floats: exact bit width (no signedness concept, unambiguous) ----
|
||||
if string.strcmp(buf, "half") == 0: return "t.CFloat16T"
|
||||
if string.strcmp(buf, "half") == 0: return "float16"
|
||||
if string.strcmp(buf, "float") == 0: return "float"
|
||||
if string.strcmp(buf, "double") == 0: return "double"
|
||||
if string.strcmp(buf, "fp128") == 0: return "t.CFloat128T"
|
||||
if string.strcmp(buf, "fp128") == 0: return "float128"
|
||||
return None
|
||||
|
||||
def infer_scalar_type_arg_from_llvm_ty(self, pool: memhub.MemBuddy*, ty: mlirlite.LLVMType*, sign: int) -> str:
|
||||
|
||||
@@ -694,7 +694,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
arg_m: ast.Arg* = ast.Arg*(alist.get(ai_m))
|
||||
mm: int = 0
|
||||
if arg_m is not None and arg_m.annotation is not None:
|
||||
if self.Gen.TypeGenResolve._is_t_attr(arg_m.annotation, "CVoid", imported_modules) == 0:
|
||||
if self.Gen.TypeGenResolve._is_builtin_marker(arg_m.annotation, "CVoid", imported_modules) == 0:
|
||||
mm = self.Gen.TypeGenResolve.ref_param_mode(arg_m.annotation, imported_modules)
|
||||
if mm == 1: mode_buf[mode_cnt] = char(49)
|
||||
elif mm == 2: mode_buf[mode_cnt] = char(50)
|
||||
|
||||
@@ -65,6 +65,42 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
def _is_t_type_object_name(self, name: str) -> int:
|
||||
"""Check whether name is a t.py type-object name (CPtr/CInt/CDouble, ...)."""
|
||||
if name is None: return 0
|
||||
# builtin short type names (int8/uint64/sizet/...)
|
||||
if string.strcmp(name, "sizet") == 0: return 1
|
||||
if string.strcmp(name, "size_t") == 0: return 1
|
||||
if string.strcmp(name, "int8") == 0: return 1
|
||||
if string.strcmp(name, "int16") == 0: return 1
|
||||
if string.strcmp(name, "int32") == 0: return 1
|
||||
if string.strcmp(name, "int64") == 0: return 1
|
||||
if string.strcmp(name, "uint8") == 0: return 1
|
||||
if string.strcmp(name, "uint16") == 0: return 1
|
||||
if string.strcmp(name, "uint32") == 0: return 1
|
||||
if string.strcmp(name, "uint64") == 0: return 1
|
||||
if string.strcmp(name, "intfast8") == 0: return 1
|
||||
if string.strcmp(name, "intfast16") == 0: return 1
|
||||
if string.strcmp(name, "intfast32") == 0: return 1
|
||||
if string.strcmp(name, "intfast64") == 0: return 1
|
||||
if string.strcmp(name, "uintfast8") == 0: return 1
|
||||
if string.strcmp(name, "uintfast16") == 0: return 1
|
||||
if string.strcmp(name, "uintfast32") == 0: return 1
|
||||
if string.strcmp(name, "uintfast64") == 0: return 1
|
||||
if string.strcmp(name, "intleast8") == 0: return 1
|
||||
if string.strcmp(name, "intleast16") == 0: return 1
|
||||
if string.strcmp(name, "intleast32") == 0: return 1
|
||||
if string.strcmp(name, "intleast64") == 0: return 1
|
||||
if string.strcmp(name, "uintleast8") == 0: return 1
|
||||
if string.strcmp(name, "uintleast16") == 0: return 1
|
||||
if string.strcmp(name, "uintleast32") == 0: return 1
|
||||
if string.strcmp(name, "uintleast64") == 0: return 1
|
||||
if string.strcmp(name, "uchar") == 0: return 1
|
||||
if string.strcmp(name, "short") == 0: return 1
|
||||
if string.strcmp(name, "ushort") == 0: return 1
|
||||
if string.strcmp(name, "uint") == 0: return 1
|
||||
if string.strcmp(name, "long") == 0: return 1
|
||||
if string.strcmp(name, "ulong") == 0: return 1
|
||||
if string.strcmp(name, "longlong") == 0: return 1
|
||||
if string.strcmp(name, "ulonglong") == 0: return 1
|
||||
if string.strcmp(name, "ptrdifft") == 0: return 1
|
||||
# type object names in t.py (PascalCase, initial uppercase)
|
||||
if string.strcmp(name, "CPtr") == 0: return 1
|
||||
if string.strcmp(name, "CInt") == 0: return 1
|
||||
@@ -217,33 +253,13 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if use_ty is None: use_ty = mlirlite.Int8(pool)
|
||||
# ensure cross-module struct types in use_ty have an opaque declaration
|
||||
mlirlite.module_ensure_opaque_for_type(mod, pool, use_ty)
|
||||
# special case: type objects in t.py (CPtr/CInt/CDouble etc.). t.py is not compiled but
|
||||
# these objects are referenced at runtime, so emit a linkonce_odr definition with null init.
|
||||
is_t_type_obj: int = 0
|
||||
if string.strcmp(mod_path_w, "t") == 0: is_t_type_obj = self._is_t_type_object_name(at.attr)
|
||||
# a class name is not a module-level global: registered classes/structs/REnums are always
|
||||
# handled by the class/REnum paths, never manufactured into an external global here.
|
||||
if is_t_type_obj == 0 and self.Gen.StructGen.find_struct(at.attr) is not None: return None
|
||||
# fallback declaration name: t type objects (t.py uncompiled, no sha1) keep the bare
|
||||
# linkonce_odr name; other module attributes carry the target module's SHA1 prefix.
|
||||
gv_name_ba: str = at.attr
|
||||
if is_t_type_obj == 0: gv_name_ba = self.Gen.FuncGenBase._mangle_name_with_sha1(self._lookup_module_sha1(mod_path_w), at.attr)
|
||||
if self.Gen.StructGen.find_struct(at.attr) is not None: return None
|
||||
# fallback declaration name: other module attributes carry the target module's SHA1 prefix.
|
||||
gv_name_ba: str = self.Gen.FuncGenBase._mangle_name_with_sha1(self._lookup_module_sha1(mod_path_w), at.attr)
|
||||
ext_gv: mlirlite.GlobalVariable* = mlirlite.new_global_variable(pool, gv_name_ba, use_ty)
|
||||
if ext_gv is not None:
|
||||
if is_t_type_obj != 0:
|
||||
# t.CPtr etc.: create a definition with a null initializer (linkonce_odr)
|
||||
ext_gv.Linkage = "linkonce_odr"
|
||||
# initializer text for i8* null
|
||||
null_init: bytes = pool.alloc(8)
|
||||
if null_init is not None:
|
||||
null_init[0] = 'n'
|
||||
null_init[1] = 'u'
|
||||
null_init[2] = 'l'
|
||||
null_init[3] = 'l'
|
||||
null_init[4] = '\0'
|
||||
ext_gv.Initializer = null_init
|
||||
else: ext_gv.Initializer = None
|
||||
else:
|
||||
# regular module attribute: external declaration (definition provided elsewhere)
|
||||
ext_gv.Linkage = "external"
|
||||
ext_gv.Initializer = None
|
||||
@@ -256,32 +272,19 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
# module attribute (sys._mbuddy → global), then struct field (GEP + load). Name bases skip the struct load.
|
||||
|
||||
|
||||
# _get_cderef_attr_base - base pointer of a c.Deref(ptr).attr access (like *p.a → p->a): return the ptr
|
||||
# itself, not the loaded struct value; None for non-c.Deref forms (_deref_if_ptr_ptr resolves the level).
|
||||
# _get_cderef_attr_base - base pointer of a `(*ptr).attr` access (like p->a): return the ptr
|
||||
# itself, not the loaded struct value; None for non-deref forms (_deref_if_ptr_ptr resolves the level).
|
||||
def _get_cderef_attr_base(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, at_value: ast.AST*, trans: HT.Translator* = None) -> mlirlite.Value*:
|
||||
"""Return the ptr itself for a dereferenced attribute base (`c.Deref(ptr).attr` / `(*ptr).attr`), else None (no load)."""
|
||||
"""Return the ptr itself for a dereferenced attribute base (`(*ptr).attr`), else None (no load)."""
|
||||
if at_value is None: return None
|
||||
# New syntax form: `(*ptr).attr` is AST UnaryOp(OpKind.Deref) — identical semantics to the legacy
|
||||
# `c.Deref(ptr).attr`. Without this branch the attribute write path sees a *loaded struct value*
|
||||
# as the base and fails with "base=非指针类型,无法做属性写入"; the read path silently does an
|
||||
# extra struct load. Both must GEP the pointer itself (R4 migration of `c.Deref` -> `*`).
|
||||
# `(*ptr).attr` is AST UnaryOp(OpKind.Deref). Without this branch the attribute write path
|
||||
# sees a *loaded struct value* as the base; both paths must GEP the pointer itself.
|
||||
if at_value.kind() == ast.ASTKind.UnaryOp:
|
||||
uo_cd: ast.UnaryOp* = ast.UnaryOp*(at_value)
|
||||
if uo_cd.op != ast.OpKind.Deref or uo_cd.operand is None: return None
|
||||
inner_uo: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, uo_cd.operand, None, 0, trans)
|
||||
if inner_uo is not None and self.is_ptr_type(inner_uo.Ty) != 0: return inner_uo
|
||||
return None
|
||||
if at_value.kind() != ast.ASTKind.Call: return None
|
||||
cl_cd: ast.Call* = ast.Call*(at_value)
|
||||
if cl_cd.func is None or cl_cd.func.kind() != ast.ASTKind.Attribute: return None
|
||||
f_cd: ast.Attribute* = ast.Attribute*(cl_cd.func)
|
||||
if f_cd.attr is None or string.strcmp(f_cd.attr, "Deref") != 0: return None
|
||||
if f_cd.value is None or f_cd.value.kind() != ast.ASTKind.Name: return None
|
||||
nm_cd: ast.Name* = ast.Name*(f_cd.value)
|
||||
if nm_cd.id is None or string.strcmp(nm_cd.id, "c") != 0: return None
|
||||
if cl_cd.args is None or len(cl_cd.args) < 1: return None
|
||||
inner_cd: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cl_cd.args.get(0), None, 0, trans)
|
||||
if inner_cd is not None and self.is_ptr_type(inner_cd.Ty) != 0: return inner_cd
|
||||
return None
|
||||
def translate_attribute(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, trans: HT.Translator* = None) -> mlirlite.Value*:
|
||||
"""Translate an attribute access and return the loaded field value."""
|
||||
@@ -482,7 +485,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
return None # it is a submodule, hand it to the nested attribute path
|
||||
# special case: t.ASM_DESCR is the inline-asm constraint namespace, not a CDefine; its
|
||||
# .XXX is handled by _asm_resolve_constraint, so return None for the nested path to handle.
|
||||
if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0: return None
|
||||
if string.strcmp(nm_ma.id, "ASM_DESCR") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0: return None
|
||||
# ALL_CAPS module attribute that is not a CDefine: load it as a cross-module global when the
|
||||
# module defines a same-named global (e.g. PA_DEPS_MAX_STR); else fail-fast (undefined value).
|
||||
if self.Gen.ExprGenCdef._is_cdefine_name_pattern(at.attr) != 0:
|
||||
|
||||
@@ -328,12 +328,11 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if match_ok == 0: continue
|
||||
if pyi_buf[line_start + name_len] != ':': continue
|
||||
|
||||
# check the line contains "t.CDefine"
|
||||
# scan the line for "t.CDefine"
|
||||
# check the line contains the CDefine marker
|
||||
has_cdefine: int = 0
|
||||
ci: sizet = line_start + name_len + 1
|
||||
while ci + 8 <= line_start + line_len:
|
||||
if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and pyi_buf[ci + 4] == 'e' and pyi_buf[ci + 5] == 'f' and pyi_buf[ci + 6] == 'i' and pyi_buf[ci + 7] == 'n' and pyi_buf[ci + 8] == 'e'):
|
||||
while ci + 7 <= line_start + line_len:
|
||||
if (pyi_buf[ci] == 'C' and pyi_buf[ci + 1] == 'D' and pyi_buf[ci + 2] == 'e' and pyi_buf[ci + 3] == 'f' and pyi_buf[ci + 4] == 'i' and pyi_buf[ci + 5] == 'n' and pyi_buf[ci + 6] == 'e'):
|
||||
has_cdefine = 1
|
||||
break
|
||||
ci += 1
|
||||
|
||||
@@ -201,13 +201,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Call:
|
||||
cl: ast.Call* = ast.Call*(node)
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm: ast.Name* = ast.Name*(at.value)
|
||||
if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0 and at.attr is not None:
|
||||
if self._type_name_unsigned(at.attr) != 0: return 1
|
||||
return 0
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: return 0
|
||||
# Plain function call: widen by the callee's **declared return type**. Without this,
|
||||
# `uint64(f())` with `def f() -> uint32` emitted `sext i32 -> i64` (verified in the
|
||||
# generated IR), so a u32 with bit 31 set grew 0xFFFFFFFF in the high half — a real
|
||||
@@ -359,13 +353,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Call:
|
||||
cl: ast.Call* = ast.Call*(node)
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm: ast.Name* = ast.Name*(at.value)
|
||||
if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0 and at.attr is not None:
|
||||
if self._spec_sign_from_annot(at.attr) == TSpec.TS_SIGN_SIGNED: return 1
|
||||
return 0
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None:
|
||||
|
||||
@@ -42,23 +42,12 @@ novirtual class FuncGenBase(CallGenBase.CallGenBase):
|
||||
call_node: ast.Call* = ast.Call*(deco)
|
||||
if call_node.func is None: continue
|
||||
cfk: int = call_node.func.kind()
|
||||
if cfk != ast.ASTKind.Attribute: continue
|
||||
|
||||
# Detect c.Attribute
|
||||
func_attr: ast.Attribute* = ast.Attribute*(call_node.func)
|
||||
if func_attr.attr is None: continue
|
||||
if string.strcmp(func_attr.attr, "Attribute") != 0: continue
|
||||
if func_attr.value is None: continue
|
||||
fvk: int = func_attr.value.kind()
|
||||
if fvk != ast.ASTKind.Name: continue
|
||||
c_name: ast.Name* = ast.Name*(func_attr.value)
|
||||
if c_name.id is None: continue
|
||||
if string.strcmp(c_name.id, "c") != 0: continue
|
||||
# 不要求 `import c`:`@__attribute__(...)` 会被 ast/parser.vp(_DesugarMagicAttribute)
|
||||
# 脱糖成 `@c.Attribute(...)`,这里的 `c.` 前缀是编译器自己产生的(用户写的是
|
||||
# `@__attribute__`,并非 `@c.Attribute`)。若在此要求 `import c`,用户明明没引入 c
|
||||
# 就会把整条装饰器静默丢弃(`stackrealign`/`always_inline` 等函数属性全失效)。
|
||||
# extract_func_section 本就没有这个守卫,二者保持一致。
|
||||
# Detect the builtin Attribute(...) wrapper emitted by @__attribute__(...).
|
||||
if cfk != ast.ASTKind.Name: continue
|
||||
func_nm: ast.Name* = ast.Name*(call_node.func)
|
||||
if func_nm.id is None: continue
|
||||
if string.strcmp(func_nm.id, "Attribute") != 0: continue
|
||||
|
||||
# Iterate args and extract attrs
|
||||
if call_node.args is None: continue
|
||||
@@ -80,7 +69,7 @@ novirtual class FuncGenBase(CallGenBase.CallGenBase):
|
||||
if found_any == 0: return None
|
||||
return attrs_buf
|
||||
def extract_func_section(self, pool: memhub.MemBuddy*, decorator_list: list[ast.AST*]*, imported_modules: str) -> str:
|
||||
"""Extract @c.Attribute(t.attr.section(...)) as the attr-group text."""
|
||||
"""Extract @Attribute(attr.section(...)) as the attr-group text."""
|
||||
if pool is None or decorator_list is None: return None
|
||||
dn: sizet = len(decorator_list)
|
||||
if dn == 0: return None
|
||||
@@ -88,9 +77,9 @@ novirtual class FuncGenBase(CallGenBase.CallGenBase):
|
||||
deco: ast.AST* = decorator_list.get(di)
|
||||
if deco is None or deco.kind() != ast.ASTKind.Call: continue
|
||||
call_node: ast.Call* = ast.Call*(deco)
|
||||
if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute: continue
|
||||
func_attr: ast.Attribute* = ast.Attribute*(call_node.func)
|
||||
if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0: continue
|
||||
if call_node.func is None or call_node.func.kind() != ast.ASTKind.Name: continue
|
||||
func_nm: ast.Name* = ast.Name*(call_node.func)
|
||||
if func_nm.id is None or string.strcmp(func_nm.id, "Attribute") != 0: continue
|
||||
if call_node.args is None: continue
|
||||
args_list: list[ast.AST*]* = call_node.args
|
||||
an: sizet = len(args_list)
|
||||
@@ -272,11 +261,11 @@ novirtual class FuncGenBase(CallGenBase.CallGenBase):
|
||||
for ai in range(int(an)):
|
||||
arg: ast.Arg* = ast.Arg*(alist.get(ai))
|
||||
if arg is not None and arg.arg is not None:
|
||||
# t.CVoid means no args: skip
|
||||
# CVoid / void means no args: skip
|
||||
if arg.annotation is not None:
|
||||
if arg.annotation.kind() == ast.ASTKind.Attribute:
|
||||
at_cf: ast.Attribute* = ast.Attribute*(arg.annotation)
|
||||
if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0: continue
|
||||
if arg.annotation.kind() == ast.ASTKind.Name:
|
||||
at_cn: ast.Name* = ast.Name*(arg.annotation)
|
||||
if at_cn.id is not None and (string.strcmp(at_cn.id, "CVoid") == 0 or string.strcmp(at_cn.id, "void") == 0): continue
|
||||
param_ty: mlirlite.LLVMType* = i32_ty
|
||||
if arg.annotation is not None:
|
||||
resolved: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, None, None, None, 0)
|
||||
|
||||
@@ -38,7 +38,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
arg: ast.Arg* = ast.Arg*(alist.get(i))
|
||||
if arg is None or arg.arg is None: continue
|
||||
# CVoid params are not emitted into the signature, so they must not occupy a mode slot.
|
||||
if arg.annotation is not None and self.Gen.TypeGenResolve._is_t_attr(arg.annotation, "CVoid", imp) != 0: continue
|
||||
if arg.annotation is not None and self.Gen.TypeGenResolve._is_builtin_marker(arg.annotation, "CVoid", imp) != 0: continue
|
||||
m: int = 0
|
||||
if arg.annotation is not None: m = self.Gen.TypeGenResolve.ref_param_mode(arg.annotation, imp)
|
||||
if m == 1: buf[cnt] = char(49)
|
||||
@@ -110,14 +110,11 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
# Value-reference markers are parameter-only: `-> &T` fails fast (never a silent Ptr(T) return).
|
||||
self.Gen.TypeGenResolve.reject_ref_marker_position(fd.returns, imported_modules, "a function return type")
|
||||
ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, fd.returns, imported_modules, from_imports, trans, 0)
|
||||
# A lone t.CExport return annotation is an export modifier with no real type -> Void
|
||||
# A lone CExport return annotation is an export modifier with no real type -> Void
|
||||
# (CExport fell back to i32, forcing the tail check to return i32: mm.vp free root cause).
|
||||
if fd.returns.kind() == ast.ASTKind.Attribute:
|
||||
ce_at: ast.Attribute* = ast.Attribute*(fd.returns)
|
||||
if ce_at.attr is not None and string.strcmp(ce_at.attr, "CExport") == 0:
|
||||
if ce_at.value is not None and ce_at.value.kind() == ast.ASTKind.Name:
|
||||
ce_nm: ast.Name* = ast.Name*(ce_at.value)
|
||||
if ce_nm.id is not None and string.strcmp(ce_nm.id, "t") == 0: ret_ty = mlirlite.Void(pool)
|
||||
if fd.returns.kind() == ast.ASTKind.Name:
|
||||
ce_at: ast.Name* = ast.Name*(fd.returns)
|
||||
if ce_at.id is not None and string.strcmp(ce_at.id, "CExport") == 0: ret_ty = mlirlite.Void(pool)
|
||||
if ret_ty is None and fd.returns is not None:
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0) != 0: ret_ty = mlirlite.Void(pool)
|
||||
# @c.CReturn decorator removed: encountering it is a compile-time error (use -> tuple[...] for multiple returns)
|
||||
@@ -206,7 +203,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if arg is None or arg.arg is None: continue
|
||||
# CVoid means empty param: skip
|
||||
if arg.annotation is not None:
|
||||
if self.Gen.TypeGenResolve._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if self.Gen.TypeGenResolve._is_builtin_marker(arg.annotation, "CVoid", imported_modules) != 0: continue
|
||||
param_ty: mlirlite.LLVMType* = i32_ty
|
||||
if arg.annotation is not None:
|
||||
resolved: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, imported_modules, from_imports, trans, 0)
|
||||
@@ -280,14 +277,11 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
# Value-reference markers are parameter-only: `-> &T` fails fast (never a silent Ptr(T) return).
|
||||
self.Gen.TypeGenResolve.reject_ref_marker_position(fd.returns, imported_modules, "a function return type")
|
||||
ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, fd.returns, imported_modules, from_imports, trans, 0)
|
||||
# A lone t.CExport return annotation is an export modifier with no real type -> Void
|
||||
# A lone CExport return annotation is an export modifier with no real type -> Void
|
||||
# (CExport fell back to i32, forcing return i32: mm.vp free root cause). Mixed types keep the resolved result.
|
||||
if fd.returns.kind() == ast.ASTKind.Attribute:
|
||||
ce_at2: ast.Attribute* = ast.Attribute*(fd.returns)
|
||||
if ce_at2.attr is not None and string.strcmp(ce_at2.attr, "CExport") == 0:
|
||||
if ce_at2.value is not None and ce_at2.value.kind() == ast.ASTKind.Name:
|
||||
ce_nm2: ast.Name* = ast.Name*(ce_at2.value)
|
||||
if ce_nm2.id is not None and string.strcmp(ce_nm2.id, "t") == 0: ret_ty = mlirlite.Void(pool)
|
||||
if fd.returns.kind() == ast.ASTKind.Name:
|
||||
ce_at2: ast.Name* = ast.Name*(fd.returns)
|
||||
if ce_at2.id is not None and string.strcmp(ce_at2.id, "CExport") == 0: ret_ty = mlirlite.Void(pool)
|
||||
|
||||
# If the return annotation is purely a decorator marker (e.g. t.State, no real type), use void.
|
||||
# Must be checked before infer_return_type, which would return at least i32.
|
||||
@@ -412,7 +406,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
arg_e: ast.Arg* = ast.Arg*(alist_e.get(ai_e))
|
||||
if arg_e is not None and arg_e.arg is not None:
|
||||
# CVoid means empty param: skip, do not add to the function signature
|
||||
if arg_e.annotation is not None and self.Gen.TypeGenResolve._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if arg_e.annotation is not None and self.Gen.TypeGenResolve._is_builtin_marker(arg_e.annotation, "CVoid", imported_modules) != 0: continue
|
||||
param_ty_e: mlirlite.LLVMType* = i32_ty
|
||||
if arg_e.annotation is not None:
|
||||
resolved_e: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg_e.annotation, imported_modules, from_imports, trans, 0)
|
||||
@@ -479,7 +473,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
rearg: ast.Arg* = ast.Arg*(reuse_list.get(reuse_i))
|
||||
if rearg is None or rearg.arg is None: continue
|
||||
# CVoid means empty param: not part of the signature (mirrors the add_param loops above)
|
||||
if rearg.annotation is not None and self.Gen.TypeGenResolve._is_t_attr(rearg.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if rearg.annotation is not None and self.Gen.TypeGenResolve._is_builtin_marker(rearg.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if reused_p is None:
|
||||
# 复用声明形参少于定义:签名与函数体必然错配,禁止静默,fail-fast
|
||||
self.Gen.TypeGenErr.fatal_error(rearg, f"reused declaration for '{fd.name}' has fewer parameters than the definition", "TypeError")
|
||||
@@ -537,7 +531,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
arg: ast.Arg* = ast.Arg*(alist.get(ai))
|
||||
if arg is not None and arg.arg is not None:
|
||||
# CVoid means empty param: skip, do not add to the function signature
|
||||
if arg.annotation is not None and self.Gen.TypeGenResolve._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if arg.annotation is not None and self.Gen.TypeGenResolve._is_builtin_marker(arg.annotation, "CVoid", imported_modules) != 0: continue
|
||||
param_ty: mlirlite.LLVMType* = i32_ty
|
||||
if arg.annotation is not None:
|
||||
resolved: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, imported_modules, from_imports, trans, 0)
|
||||
@@ -678,7 +672,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if arg2 is not None and arg2.arg is not None:
|
||||
# CVoid means empty param: skip, do not create an alloca
|
||||
if arg2.annotation is not None:
|
||||
if self.Gen.TypeGenResolve._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if self.Gen.TypeGenResolve._is_builtin_marker(arg2.annotation, "CVoid", imported_modules) != 0: continue
|
||||
param_ty2: mlirlite.LLVMType* = i32_ty
|
||||
if arg2.annotation is not None:
|
||||
resolved2: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg2.annotation, imported_modules, from_imports, trans, 0)
|
||||
|
||||
@@ -94,7 +94,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
arg_n: ast.Arg* = ast.Arg*(alist_n.get(ai_n))
|
||||
if arg_n is None or arg_n.arg is None: continue
|
||||
if arg_n.annotation is not None:
|
||||
if self.Gen.TypeGenResolve._is_t_attr(arg_n.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if self.Gen.TypeGenResolve._is_builtin_marker(arg_n.annotation, "CVoid", imported_modules) != 0: continue
|
||||
pty_n: mlirlite.LLVMType* = i32_ty
|
||||
if arg_n.annotation is not None:
|
||||
resolved_n: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg_n.annotation, imported_modules, from_imports, trans, 0)
|
||||
@@ -147,7 +147,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
arg_p: ast.Arg* = ast.Arg*(alist_p.get(api))
|
||||
if arg_p is None or arg_p.arg is None: continue
|
||||
if arg_p.annotation is not None:
|
||||
if self.Gen.TypeGenResolve._is_t_attr(arg_p.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if self.Gen.TypeGenResolve._is_builtin_marker(arg_p.annotation, "CVoid", imported_modules) != 0: continue
|
||||
if idx_p >= param_count: break
|
||||
pty2_n: mlirlite.LLVMType* = i32_ty
|
||||
if param_tys is not None:
|
||||
|
||||
@@ -86,16 +86,16 @@ def fatal_error(node: ast.AST*, msg: str, err_type: str = "SyntaxError") -> None
|
||||
if gg is not None: gg.TypeGenErr.fatal_error(node, msg, err_type)
|
||||
|
||||
|
||||
# ---------------- map_t_type (delegates to TypeGenResolve.map_t_type) ----------------
|
||||
def map_t_type(pool: memhub.MemBuddy*, type_name: str) -> mlirlite.LLVMType*:
|
||||
"""Delegate to gen.map_t_type"""
|
||||
if _g_gen is not None: _g_gen.TypeGenResolve.map_t_type(pool, type_name)
|
||||
# ---------------- map_builtin_type (delegates to TypeGenResolve.map_builtin_type) ----------------
|
||||
def map_builtin_type(pool: memhub.MemBuddy*, type_name: str) -> mlirlite.LLVMType*:
|
||||
"""Delegate to gen.map_builtin_type"""
|
||||
if _g_gen is not None: _g_gen.TypeGenResolve.map_builtin_type(pool, type_name)
|
||||
return None
|
||||
|
||||
|
||||
# ---------------- resolve_typedef_or_map (delegates to TypeGenResolve.resolve_typedef_or_map) ----------------
|
||||
def resolve_typedef_or_map(pool: memhub.MemBuddy*, name: str, imported_modules: str, from_imports: str, trans: HT.Translator* = None) -> mlirlite.LLVMType*:
|
||||
"""Delegate to gen.resolve_typedef_or_map: CTypedef table first, then map_t_type."""
|
||||
"""Delegate to gen.resolve_typedef_or_map: CTypedef table first, then map_builtin_type."""
|
||||
if _g_gen is not None: return _g_gen.TypeGenResolve.resolve_typedef_or_map(pool, name, imported_modules, from_imports, trans)
|
||||
return None
|
||||
|
||||
|
||||
@@ -546,9 +546,12 @@ novirtual class ImportsGenMixin:
|
||||
def _check_import_sha1(self, node: ast.AST*, mod_name: str) -> int:
|
||||
"""Fail-fast when an imported module's SHA1 is not registered."""
|
||||
if mod_name is None: return 1
|
||||
# t/c are internal libraries exempt from includes scanning; so are ctraits (a .vpi
|
||||
# compile-time macro lib) and viperbuild (a compiler builtin macro lib).
|
||||
if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0 or string.strcmp(mod_name, "ctraits") == 0: return 1
|
||||
# t / c were retired: their types are builtin and their C helpers now have language syntax.
|
||||
if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0:
|
||||
self._report_import_error(node, "`import t` / `import c` is retired; builtin types and C helpers no longer live in modules")
|
||||
return 0
|
||||
# ctraits (a .vpi compile-time macro lib) and viperbuild (a compiler builtin macro lib) stay exempt.
|
||||
if string.strcmp(mod_name, "ctraits") == 0: return 1
|
||||
if string.strcmp(mod_name, "viperbuild") == 0: return 1
|
||||
mod_sha1: str = StubMergerStore.LookupSha1ByModName(mod_name)
|
||||
if mod_sha1 is None:
|
||||
|
||||
@@ -53,18 +53,11 @@ novirtual class StmtGenCifMixin:
|
||||
return 0
|
||||
|
||||
def _is_cif_call(self, node: ast.AST*) -> int:
|
||||
"""Check whether test is a cif marker call (c.@CIf family, or a bare @CIf-family name)."""
|
||||
"""Check whether test is a cif marker call (bare @CIf-family name)."""
|
||||
if node is None or node.kind() != ast.ASTKind.Call: return 0
|
||||
cl: ast.Call* = ast.Call*(node)
|
||||
if cl.func is None: return 0
|
||||
fk: int = cl.func.kind()
|
||||
if fk == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if at.attr is None: return 0
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
vn: ast.Name* = ast.Name*(at.value)
|
||||
if vn.id is not None and string.strcmp(vn.id, "c") == 0: return self._is_cif_attr(at.attr)
|
||||
return 0
|
||||
if fk == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(cl.func)
|
||||
if nm.id is not None and self._is_cif_attr(nm.id) != 0: return 1
|
||||
|
||||
@@ -2652,7 +2652,7 @@ novirtual class StructGenMixin:
|
||||
if mod_buf_f is not None:
|
||||
string.strncpy(mod_buf_f, name, mod_len_f)
|
||||
mod_buf_f[mod_len_f] = '\0'
|
||||
if string.strcmp(mod_buf_f, "t") != 0 and string.strcmp(mod_buf_f, "c") != 0:
|
||||
if mod_buf_f is not None:
|
||||
# A 16-hex module segment is a SHA1 literal (e.g. "{9aab}.Scene3D", TypeGenResolve L1397-1402's sha1-prefix form): skip the store module-name lookup (store keys are module names, not sha1) and match name+sha1 exactly.
|
||||
# Otherwise _resolve_module_sha1("9aab") returns None and a bare-name fallback returns the first-registered wrong cross-module Scene3D entry (VKernel gfx / App gfx both define Scene3D -> wrong ownership -> ret_sha1=0ae -> Phase A _deps_pending deadlock). [C10 convergence] The module segment is exactly 16 lowercase hex = SHA1 literal: go through GenApi.is_sha1_hex16 (single source of truth).
|
||||
mod_hex_ok: int = GenApi.is_sha1_hex16(mod_buf_f)
|
||||
@@ -2905,7 +2905,7 @@ novirtual class StructGenMixin:
|
||||
if mod_buf_q is not None:
|
||||
string.strncpy(mod_buf_q, class_name, mod_len_q)
|
||||
mod_buf_q[mod_len_q] = '\0'
|
||||
if string.strcmp(mod_buf_q, "t") != 0 and string.strcmp(mod_buf_q, "c") != 0:
|
||||
if mod_buf_q is not None:
|
||||
# A 16-hex module segment ("{16hex}.Class", the normalized generic type-arg form) is the module SHA1; a registered class proves that module compiled, so match name+sha1 exactly without _resolve_module_sha1 (store keys are module names, so querying the sha1 is always None and would fail-fast wrongly).
|
||||
# [C10 convergence] The module segment is exactly 16 lowercase hex = SHA1 literal: go through GenApi.is_sha1_hex16; generic subscript dots are already skipped by _last_dot_outside_brackets, so only top-level a.b forms remain here.
|
||||
mod_hex_ok_q: int = GenApi.is_sha1_hex16(mod_buf_q)
|
||||
|
||||
@@ -351,29 +351,17 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
vn: sizet = len(self.CTypedefVisiting)
|
||||
if vn > 0: self.CTypedefVisiting.pop()
|
||||
def _is_ctypedef_annotation(self, annotation: ast.AST*) -> int:
|
||||
"""Return 1 if the annotation is t.CTypedef, otherwise 0."""
|
||||
"""Return 1 if the annotation is the CTypedef marker, otherwise 0."""
|
||||
if annotation is None: return 0
|
||||
k_v: int = annotation.kind()
|
||||
if k_v != ast.ASTKind.Attribute: return 0
|
||||
at: ast.Attribute* = ast.Attribute*(annotation)
|
||||
# Use ast module accessors for field access: a direct at.attr read may emit a
|
||||
# wrong GEP from the stub type and crash strcmp.
|
||||
at_attr_v: str = ast.attribute_get_attr(at)
|
||||
if at_attr_v is None: return 0
|
||||
if annotation.kind() != ast.ASTKind.Name: return 0
|
||||
nm: ast.Name* = ast.Name*(annotation)
|
||||
nm_id_v: str = ast.name_get_id(nm)
|
||||
if nm_id_v is None: return 0
|
||||
# Length-bounded compare instead of strcmp: the token may lack a NUL and strcmp
|
||||
# reads past the page; check byte 9 is a terminator/separator.
|
||||
if string.strncmp(at_attr_v, "CTypedef", 8) != 0: return 0
|
||||
sep_ch_d: char = at_attr_v[8]
|
||||
# reads past the page; check byte 8 is a terminator/separator.
|
||||
if string.strncmp(nm_id_v, "CTypedef", 8) != 0: return 0
|
||||
sep_ch_d: char = nm_id_v[8]
|
||||
if sep_ch_d != '\0' and sep_ch_d != ' ' and sep_ch_d != '\n' and sep_ch_d != '\r' and sep_ch_d != '\t' and sep_ch_d != '|': return 0
|
||||
at_val_v: ast.AST* = ast.attribute_get_value(at)
|
||||
if at_val_v is None or at_val_v.kind() != ast.ASTKind.Name: return 0
|
||||
mod_nm: ast.Name* = ast.Name*(at_val_v)
|
||||
mod_id_v: str = ast.name_get_id(mod_nm)
|
||||
if mod_id_v is None: return 0
|
||||
# same length-bounded compare ("t" may lack a NUL)
|
||||
if string.strncmp(mod_id_v, "t", 1) != 0: return 0
|
||||
sep_ch_m: char = mod_id_v[1]
|
||||
if sep_ch_m != '\0' and sep_ch_m != ' ' and sep_ch_m != '\n' and sep_ch_m != '\r' and sep_ch_m != '\t' and sep_ch_m != '|': return 0
|
||||
return 1
|
||||
def ScanCTypedefDeclarations(self, pool: memhub.MemBuddy*, tree: ast.AST*) -> int:
|
||||
"""Scan top-level AST nodes and register all NAME: t.CTypedef = Type declarations."""
|
||||
|
||||
@@ -140,14 +140,13 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
|
||||
k: int = node.kind()
|
||||
|
||||
# Attribute node: t.CExtern, t.State, t.CExport, t.CInline
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is not None:
|
||||
if string.strcmp(at.attr, marker_name) == 0: return 1
|
||||
# Name node: builtin markers CExtern / State / CExport / CInline / CStatic / CConst / CVolatile
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None and string.strcmp(nm.id, marker_name) == 0: return 1
|
||||
return 0
|
||||
|
||||
# BinOp node: int | t.CExtern (recurse into both children)
|
||||
# BinOp node: int | CExtern (recurse into both children)
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(node)
|
||||
if self.has_decorator_marker(bop.left, marker_name, depth + 1) != 0: return 1
|
||||
@@ -298,7 +297,7 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
if arg is None or arg.arg is None: continue
|
||||
param_ty: mlirlite.LLVMType* = i32_ty
|
||||
if arg.annotation is not None:
|
||||
# Unified: prefer the CTypedef dynamic table, fall back to map_t_type
|
||||
# Unified: prefer the CTypedef dynamic table, fall back to map_builtin_type
|
||||
# (stage 2 removed hardcoded aliases; BYTE etc. now rely on library typedefs)
|
||||
if arg.annotation.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(arg.annotation)
|
||||
|
||||
@@ -266,6 +266,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# TypeGenCDef.lookup_cdefine_constant), since -1 is a valid constant.
|
||||
self.Gen.TypeGenCDef.lookup_cdefine_constant(name)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0: return 1
|
||||
if self.map_builtin_type(pool, name) is not None: return 1
|
||||
if string.strcmp(name, "int") == 0: return 1
|
||||
if string.strcmp(name, "char") == 0: return 1
|
||||
if string.strcmp(name, "bool") == 0: return 1
|
||||
@@ -278,25 +279,20 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if name[0] >= 'A' and name[0] <= 'Z': return 1
|
||||
return 0
|
||||
|
||||
# _is_ptr_marker_text - whether text is a bare pointer marker (t.CPtr / c.CPtr / CPtr);
|
||||
# only the CPtr family counts, consistent with _is_cptr_marker.
|
||||
# _is_ptr_marker_text - whether text is the builtin pointer marker (CPtr).
|
||||
def _is_ptr_marker_text(self, txt: str) -> int:
|
||||
"""Whether txt is a bare pointer marker (one pointer layer): 1=yes / 0=no."""
|
||||
if txt is None: return 0
|
||||
if string.strcmp(txt, "CPtr") == 0: return 1
|
||||
if string.strcmp(txt, "t.CPtr") == 0: return 1
|
||||
if string.strcmp(txt, "c.CPtr") == 0: return 1
|
||||
return 0
|
||||
|
||||
# _is_ptr_subscript_container_text - whether text is a pointer subscript container name
|
||||
# (rawptr / t.rawptr / c.rawptr / CPtr); subscript forms then fold to `T*`.
|
||||
# (rawptr / CPtr); subscript forms then fold to `T*`.
|
||||
def _is_ptr_subscript_container_text(self, txt: str) -> int:
|
||||
"""Whether txt names a pointer subscript container (rawptr/CPtr): 1=yes / 0=no."""
|
||||
if txt is None: return 0
|
||||
if self._is_ptr_marker_text(txt) != 0: return 1
|
||||
if string.strcmp(txt, "rawptr") == 0: return 1
|
||||
if string.strcmp(txt, "t.rawptr") == 0: return 1
|
||||
if string.strcmp(txt, "c.rawptr") == 0: return 1
|
||||
return 0
|
||||
|
||||
# _ptr_star_text - append one pointer layer to a type-name text (base + "*");
|
||||
@@ -517,20 +513,6 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
sha1c = self._class_true_def_sha1(pool, type_name, sha1c)
|
||||
res_c: str = self._concat_sha1_class(pool, sha1c, type_name)
|
||||
if res_c is not None: return res_c
|
||||
# ---- 5.2 bare name from builtin t/c -> normalize to "t.X" / "c.X"; t/c have no
|
||||
# module SHA1, so a bare import would otherwise split from `t.X`.
|
||||
if from_imports is not None:
|
||||
_bi_mod: str = self.Gen.ImportsGen.lookup_from_import(from_imports, type_name, 0)
|
||||
if _bi_mod is not None:
|
||||
if (string.strcmp(_bi_mod, "t") == 0 or string.strcmp(_bi_mod, "c") == 0) and self.map_t_type(pool, type_name) is not None:
|
||||
_bi_len: sizet = string.strlen(_bi_mod) + 1 + string.strlen(type_name) + 1
|
||||
_bi_buf: str = pool.alloc(_bi_len)
|
||||
if _bi_buf is not None:
|
||||
_bi_buf[0] = '\0'
|
||||
string.strcat(_bi_buf, _bi_mod)
|
||||
string.strcat(_bi_buf, ".")
|
||||
string.strcat(_bi_buf, type_name)
|
||||
return _bi_buf
|
||||
# ---- 5.5 bare name that is a registered class: prefix with its defining module
|
||||
# SHA1; rule 5 only checks from_imports and would split specialization names.
|
||||
if string.strchr(type_name, '[') is None and string.strchr(type_name, '.') is None:
|
||||
@@ -791,7 +773,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
"""Get the file currently being compiled (used for error attribution)."""
|
||||
return self.CurrentFile
|
||||
def resolve_typedef_or_map(self, pool: memhub.MemBuddy*, name: str, imported_modules: str, from_imports: str, trans: HT.Translator* = None) -> mlirlite.LLVMType*:
|
||||
"""Resolve a name as a CTypedef first, falling back to map_t_type."""
|
||||
"""Resolve a name as a CTypedef first, falling back to map_builtin_type."""
|
||||
if name is None: return None
|
||||
if self.Gen.TypeGenCType.CTypedefResolveDepth < TypeGenMixin.MAX_CTYPEDEF_DEPTH:
|
||||
ts_rt: str = self.Gen.TypeGenCType.lookup_ctypedef(name)
|
||||
@@ -804,7 +786,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenCType.CTypedefResolveDepth -= 1
|
||||
self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
if ity_rt is not None: return ity_rt
|
||||
# [builtins last match] After the typedef table and map_t_type both miss, check
|
||||
# [builtins last match] After the typedef table and map_builtin_type both miss, check
|
||||
# includes/builtins.vp (e.g. rawptr: t.CTypedef = t.CPtr) and parse recursively.
|
||||
btd_r: str = self._lookup_builtins_typedef(pool, name)
|
||||
if btd_r is not None:
|
||||
@@ -827,7 +809,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
lib_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, lib_node, imported_modules, from_imports, trans, 1)
|
||||
self.Gen.TypeGenCType.CTypedefResolveDepth -= 1
|
||||
if lib_ty is not None: return lib_ty
|
||||
# Bare Python/C builtin aliases: map_t_type only knows the t.CXxx spelling, so
|
||||
# Bare Python/C builtin aliases: map_builtin_type only knows the t.CXxx spelling, so
|
||||
# resolve them here to match resolve_annotation_type's bare-name branch. Without
|
||||
# this the two-arg form int(x, t.CPtr) misses _tc_h4 and fails fast as "int".
|
||||
if string.strcmp(name, "str") == 0: return mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
@@ -838,7 +820,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if string.strcmp(name, "float") == 0: return mlirlite.Float(pool)
|
||||
if string.strcmp(name, "double") == 0: return mlirlite.Double(pool)
|
||||
if string.strcmp(name, "void") == 0: return mlirlite.Void(pool)
|
||||
return self.map_t_type(pool, name)
|
||||
return self.map_builtin_type(pool, name)
|
||||
def get_type_size_bytes(self, pool: memhub.MemBuddy*, name: str, imported_modules: str, from_imports: str) -> int:
|
||||
"""Return the type size in bytes via resolve_typedef_or_map, or 0 on failure."""
|
||||
if name is None: return 0
|
||||
@@ -962,7 +944,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
while name_l > 0 and buf[line_start + name_l - 1] == ' ': name_l -= 1
|
||||
if name_l == 0 or name_l >= 128: return 0
|
||||
rest: str = buf + line_start + j + 1
|
||||
if string.strstr(rest, "t.CTypedef") is None: return 0
|
||||
if string.strstr(rest, "CTypedef") is None: return 0
|
||||
eq: str = string.strstr(rest, "=")
|
||||
if eq is None: return 0
|
||||
vs = sizet(uint64(eq) - uint64(buf)) - line_start + 1
|
||||
@@ -979,18 +961,18 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
out_buf[name_l] = '\0'
|
||||
# Normalize a C-style typedef RHS (`const T` / `T*`) into the canonical `|` union text,
|
||||
# mirroring TPC's TypeAnnotationResolver._NormalizeTypedefRhsText: leading const/volatile
|
||||
# become `t.CConst |` / `t.CVolatile |`, trailing `*` runs become ` | t.CPtr`. Text without
|
||||
# become `CConst |` / `CVolatile |`, trailing `*` runs become ` | CPtr`. Text without
|
||||
# these forms is copied verbatim (byte-identical to the pre-normalization behavior).
|
||||
pos: sizet = name_l + 1
|
||||
k: sizet = vs
|
||||
while True:
|
||||
if k + 6 <= ve and string.strncmp(buf + line_start + k, "const", 5) == 0 and (buf[line_start + k + 5] == ' ' or buf[line_start + k + 5] == '\t'):
|
||||
string.memcpy(out_buf + pos, "t.CConst | ", 11)
|
||||
pos += 11
|
||||
string.memcpy(out_buf + pos, "CConst | ", 9)
|
||||
pos += 9
|
||||
k += 6
|
||||
elif k + 9 <= ve and string.strncmp(buf + line_start + k, "volatile", 8) == 0 and (buf[line_start + k + 8] == ' ' or buf[line_start + k + 8] == '\t'):
|
||||
string.memcpy(out_buf + pos, "t.CVolatile | ", 14)
|
||||
pos += 14
|
||||
string.memcpy(out_buf + pos, "CVolatile | ", 12)
|
||||
pos += 12
|
||||
k += 9
|
||||
else:
|
||||
break
|
||||
@@ -1004,16 +986,16 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
vlen2: sizet = ve2 - k
|
||||
if vlen2 > 190: vlen2 = 190
|
||||
# Output capacity guard (register_ctypedef_from_source allocates 512 bytes for NAME\0VALUE\0).
|
||||
if pos + vlen2 + ptrs * 11 > 500:
|
||||
if pos + ptrs * 11 >= 500: ptrs = 0
|
||||
if pos + ptrs * 11 >= 500: vlen2 = 0
|
||||
else: vlen2 = 500 - pos - ptrs * 11
|
||||
if pos + vlen2 + ptrs * 7 > 500:
|
||||
if pos + ptrs * 7 >= 500: ptrs = 0
|
||||
if pos + ptrs * 7 >= 500: vlen2 = 0
|
||||
else: vlen2 = 500 - pos - ptrs * 7
|
||||
for ci2 in range(int(vlen2)):
|
||||
out_buf[pos + ci2] = buf[line_start + k + ci2]
|
||||
pos += vlen2
|
||||
for pi in range(int(ptrs)):
|
||||
string.memcpy(out_buf + pos, " | t.CPtr", 9)
|
||||
pos += 9
|
||||
string.memcpy(out_buf + pos, " | CPtr", 7)
|
||||
pos += 7
|
||||
out_buf[pos] = '\0'
|
||||
return 1
|
||||
def _lookup_builtins_typedef(self, pool: memhub.MemBuddy*, name: str) -> str:
|
||||
@@ -1024,10 +1006,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefName = self.Gen.TypeGenCType.store_builtins_diag(0, name)
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefResult = None
|
||||
# rawptr is built into the compiler (a reserved word on both TPC/VPC) and takes
|
||||
# priority over any external declaration; always return t.CPtr.
|
||||
# priority over any external declaration; always return CPtr.
|
||||
if string.strcmp(name, "rawptr") == 0:
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefResult = "t.CPtr"
|
||||
return "t.CPtr"
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefResult = "CPtr"
|
||||
return "CPtr"
|
||||
ts_b: str = self.Gen.TypeGenCType.lookup_ctypedef(name)
|
||||
if ts_b is not None and self.Gen.TypeGenCType.CTypedefFound != 0:
|
||||
# The table value may still be a module-qualified ref (size_t -> stdint.size_t); expand it
|
||||
@@ -1371,10 +1353,38 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if entry is None or entry.Ty is None: return None
|
||||
return mlirlite.Ptr(pool, entry.Ty)
|
||||
|
||||
def map_t_type(self, pool: memhub.MemBuddy*, type_name: str) -> mlirlite.LLVMType*:
|
||||
"""Map a t.CXxx / c.CXxx type name to its LLVMType. Note: str = i8* = bytes."""
|
||||
def map_builtin_type(self, pool: memhub.MemBuddy*, type_name: str) -> mlirlite.LLVMType*:
|
||||
"""Map a builtin type name to its LLVMType. Note: str = i8* = bytes."""
|
||||
if type_name is None: return None
|
||||
|
||||
# Builtin short names (no import / typedef required)
|
||||
if string.strcmp(type_name, "sizet") == 0 or string.strcmp(type_name, "size_t") == 0: return mlirlite.Int64(pool)
|
||||
elif string.strcmp(type_name, "int8") == 0 or string.strcmp(type_name, "intfast8") == 0 or string.strcmp(type_name, "intleast8") == 0: return mlirlite.Int8(pool)
|
||||
elif string.strcmp(type_name, "int16") == 0 or string.strcmp(type_name, "intfast16") == 0 or string.strcmp(type_name, "intleast16") == 0: return mlirlite.Int16(pool)
|
||||
elif string.strcmp(type_name, "int32") == 0 or string.strcmp(type_name, "intfast32") == 0 or string.strcmp(type_name, "intleast32") == 0: return mlirlite.Int32(pool)
|
||||
elif string.strcmp(type_name, "int64") == 0 or string.strcmp(type_name, "intfast64") == 0 or string.strcmp(type_name, "intleast64") == 0: return mlirlite.Int64(pool)
|
||||
elif string.strcmp(type_name, "uint8") == 0 or string.strcmp(type_name, "uintfast8") == 0 or string.strcmp(type_name, "uintleast8") == 0: return mlirlite.Int8(pool)
|
||||
elif string.strcmp(type_name, "uint16") == 0 or string.strcmp(type_name, "uintfast16") == 0 or string.strcmp(type_name, "uintleast16") == 0: return mlirlite.Int16(pool)
|
||||
elif string.strcmp(type_name, "uint32") == 0 or string.strcmp(type_name, "uintfast32") == 0 or string.strcmp(type_name, "uintleast32") == 0: return mlirlite.Int32(pool)
|
||||
elif string.strcmp(type_name, "uint64") == 0 or string.strcmp(type_name, "uintfast64") == 0 or string.strcmp(type_name, "uintleast64") == 0: return mlirlite.Int64(pool)
|
||||
elif string.strcmp(type_name, "uchar") == 0: return mlirlite.Int8(pool)
|
||||
elif string.strcmp(type_name, "ushort") == 0: return mlirlite.Int16(pool)
|
||||
elif string.strcmp(type_name, "uint") == 0: return mlirlite.Int32(pool)
|
||||
elif string.strcmp(type_name, "short") == 0: return mlirlite.Int16(pool)
|
||||
elif string.strcmp(type_name, "long") == 0: return mlirlite.Int32(pool)
|
||||
elif string.strcmp(type_name, "ulong") == 0: return mlirlite.Int32(pool)
|
||||
elif string.strcmp(type_name, "longlong") == 0: return mlirlite.Int64(pool)
|
||||
elif string.strcmp(type_name, "ulonglong") == 0: return mlirlite.Int64(pool)
|
||||
elif string.strcmp(type_name, "ptrdifft") == 0: return mlirlite.Int64(pool)
|
||||
elif string.strcmp(type_name, "intptr") == 0 or string.strcmp(type_name, "uintptr") == 0: return mlirlite.Int64(pool)
|
||||
# Exact-width float / char short names (stdint aliases use these directly)
|
||||
elif string.strcmp(type_name, "float8") == 0 or string.strcmp(type_name, "float16") == 0: return mlirlite.Half(pool)
|
||||
elif string.strcmp(type_name, "float32") == 0: return mlirlite.Float(pool)
|
||||
elif string.strcmp(type_name, "float64") == 0: return mlirlite.Double(pool)
|
||||
elif string.strcmp(type_name, "float128") == 0: return mlirlite.FP128(pool)
|
||||
elif string.strcmp(type_name, "char8") == 0: return mlirlite.Int8(pool)
|
||||
elif string.strcmp(type_name, "char16") == 0 or string.strcmp(type_name, "wchar") == 0: return mlirlite.Int16(pool)
|
||||
elif string.strcmp(type_name, "char32") == 0: return mlirlite.Int32(pool)
|
||||
# Basic integer types
|
||||
if string.strcmp(type_name, "CInt") == 0: return mlirlite.Int32(pool)
|
||||
elif string.strcmp(type_name, "CChar") == 0: return mlirlite.Int8(pool)
|
||||
@@ -1402,6 +1412,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
elif string.strcmp(type_name, "CFloat32T") == 0: return mlirlite.Float(pool)
|
||||
elif string.strcmp(type_name, "CFloat64T") == 0: return mlirlite.Double(pool)
|
||||
elif string.strcmp(type_name, "CFloat128T") == 0: return mlirlite.FP128(pool)
|
||||
# Exact-width char types (C11 char8_t/char16_t/char32_t, Windows wchar_t = 16-bit)
|
||||
elif string.strcmp(type_name, "CChar8T") == 0: return mlirlite.Int8(pool)
|
||||
elif string.strcmp(type_name, "CChar16T") == 0 or string.strcmp(type_name, "CWCharT") == 0: return mlirlite.Int16(pool)
|
||||
elif string.strcmp(type_name, "CChar32T") == 0: return mlirlite.Int32(pool)
|
||||
# Pointer / void: t.CPtr = i8*, str = i8* = str = bytes
|
||||
elif string.strcmp(type_name, "CPtr") == 0: return mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
# Unsigned function pointer: bare t.Callable -> i8* (same LLVM repr as the full
|
||||
@@ -1448,46 +1462,30 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
elif string.strcmp(type_name, "float") == 0: return mlirlite.Float(pool)
|
||||
elif string.strcmp(type_name, "double") == 0: return mlirlite.Double(pool)
|
||||
return None
|
||||
def _is_t_attr(self, node: ast.AST*, attr_name: str, imported_modules: str) -> int:
|
||||
"""Whether a node is `t.attr_name` or a bare `attr_name` imported from t."""
|
||||
def _is_builtin_marker(self, node: ast.AST*, attr_name: str, imported_modules: str) -> int:
|
||||
"""Whether a node is the bare builtin marker name (e.g. CPtr / CRef)."""
|
||||
if node is None or attr_name is None: return 0
|
||||
if node.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is None: return 0
|
||||
if string.strcmp(at.attr, attr_name) != 0: return 0
|
||||
if at.value is None or at.value.kind() != ast.ASTKind.Name: return 0
|
||||
val_nm: ast.Name* = ast.Name*(at.value)
|
||||
if val_nm.id is None: return 0
|
||||
if string.strcmp(val_nm.id, "t") == 0:
|
||||
# t is a builtin library (SHA1-exempt) and may be absent from _imported_modules;
|
||||
# an explicit t.CPtr / t.CVoid unambiguously means module t.
|
||||
return 1
|
||||
return 0
|
||||
# Bare form: from t import attr_name -> Name(id == attr_name)
|
||||
if node.kind() == ast.ASTKind.Name:
|
||||
if node.kind() != ast.ASTKind.Name: return 0
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is None: return 0
|
||||
if string.strcmp(nm.id, attr_name) != 0: return 0
|
||||
# A bare name requires module t to be imported (from t import X registers it)
|
||||
if self.Gen.ImportsGen.is_module_imported(imported_modules, "t") == 0: return 0
|
||||
return 1
|
||||
return 0
|
||||
def _is_cptr_marker(self, node: ast.AST*, imported_modules: str) -> int:
|
||||
"""Whether a node is a CPtr pointer marker: 1=yes / 0=no."""
|
||||
if self._is_t_attr(node, "CPtr", imported_modules) != 0: return 1
|
||||
if self._is_builtin_marker(node, "CPtr", imported_modules) != 0: return 1
|
||||
if node is not None and node.kind() == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None and string.strcmp(nm.id, "CPtr") == 0: return 1
|
||||
return 0
|
||||
def _is_ref_marker(self, node: ast.AST*, imported_modules: str) -> int:
|
||||
"""Whether a node is a CRef/CTempRef value-reference marker: 1=yes / 0=no."""
|
||||
if self._is_t_attr(node, "CRef", imported_modules) != 0: return 1
|
||||
if self._is_t_attr(node, "CTempRef", imported_modules) != 0: return 1
|
||||
if self._is_builtin_marker(node, "CRef", imported_modules) != 0: return 1
|
||||
if self._is_builtin_marker(node, "CTempRef", imported_modules) != 0: return 1
|
||||
return 0
|
||||
def _is_byteorder_marker(self, node: ast.AST*, imported_modules: str) -> int:
|
||||
"""Whether a node is a byte-order marker: 0=none / 1=BigEndian / 2=LittleEndian."""
|
||||
if self._is_t_attr(node, "BigEndian", imported_modules) != 0: return 1
|
||||
if self._is_t_attr(node, "LittleEndian", imported_modules) != 0: return 2
|
||||
if self._is_builtin_marker(node, "BigEndian", imported_modules) != 0: return 1
|
||||
if self._is_builtin_marker(node, "LittleEndian", imported_modules) != 0: return 2
|
||||
return 0
|
||||
def target_is_big_endian(self) -> int:
|
||||
"""Whether the compilation target is big-endian (1) or little-endian (0).
|
||||
@@ -1511,12 +1509,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
"""Syntactic value-reference marker test (no import context): 0=none / 1=CRef / 2=CTempRef."""
|
||||
if node is None: return 0
|
||||
nm: str = None
|
||||
if node.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
at_vn: ast.Name* = ast.Name*(at.value)
|
||||
if at_vn.id is not None and string.strcmp(at_vn.id, "t") == 0: nm = at.attr
|
||||
elif node.kind() == ast.ASTKind.Name:
|
||||
if node.kind() == ast.ASTKind.Name:
|
||||
nm = (ast.Name*(node)).id
|
||||
if nm is None: return 0
|
||||
if string.strcmp(nm, "CRef") == 0: return 1
|
||||
@@ -1527,10 +1520,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if node is None or node.kind() != ast.ASTKind.BinOp: return 0
|
||||
bo: ast.BinOp* = ast.BinOp*(node)
|
||||
if bo.op != ast.OpKind.BitOr: return 0
|
||||
if self._is_t_attr(bo.left, "CTempRef", imported_modules) != 0: return 2
|
||||
if self._is_t_attr(bo.right, "CTempRef", imported_modules) != 0: return 2
|
||||
if self._is_t_attr(bo.left, "CRef", imported_modules) != 0: return 1
|
||||
if self._is_t_attr(bo.right, "CRef", imported_modules) != 0: return 1
|
||||
if self._is_builtin_marker(bo.left, "CTempRef", imported_modules) != 0: return 2
|
||||
if self._is_builtin_marker(bo.right, "CTempRef", imported_modules) != 0: return 2
|
||||
if self._is_builtin_marker(bo.left, "CRef", imported_modules) != 0: return 1
|
||||
if self._is_builtin_marker(bo.right, "CRef", imported_modules) != 0: return 1
|
||||
return 0
|
||||
def reject_ref_marker_position(self, node: ast.AST*, imported_modules: str, where: str) -> int:
|
||||
"""Fail fast when a value-reference marker (&T / &temp T) is used outside a parameter position."""
|
||||
@@ -1538,18 +1531,15 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"value-reference parameter annotation '&T' / '&temp T' is only allowed in function parameter position, not for {where}", "TypeError")
|
||||
return 1
|
||||
def _is_cptr_subscript(self, node: ast.AST*) -> int:
|
||||
"""Whether a node is a t.CPtr[T] subscript pointer type (e.g. t.CPtr[t.CPtr])."""
|
||||
"""Whether a node is a CPtr[T] subscript pointer type (e.g. CPtr[CPtr])."""
|
||||
if node is None or node.kind() != ast.ASTKind.Subscript: return 0
|
||||
sub: ast.Subscript* = ast.Subscript*(node)
|
||||
if sub.value is None or sub.value.kind() != ast.ASTKind.Attribute: return 0
|
||||
at: ast.Attribute* = ast.Attribute*(sub.value)
|
||||
if at.attr is None or string.strcmp(at.attr, "CPtr") != 0: return 0
|
||||
if at.value is None or at.value.kind() != ast.ASTKind.Name: return 0
|
||||
nm: ast.Name* = ast.Name*(at.value)
|
||||
if nm.id is None or string.strcmp(nm.id, "t") != 0: return 0
|
||||
if sub.value is None or sub.value.kind() != ast.ASTKind.Name: return 0
|
||||
nm: ast.Name* = ast.Name*(sub.value)
|
||||
if nm.id is None or string.strcmp(nm.id, "CPtr") != 0: return 0
|
||||
return 1
|
||||
def _is_tattr_marker(self, node: ast.AST*) -> int:
|
||||
"""Whether a node is a `t.attr.<name>` marker (including the call form)."""
|
||||
def _is_cattr_marker(self, node: ast.AST*) -> int:
|
||||
"""Whether a node is an `attr.<name>` builtin marker (including the call form)."""
|
||||
if node is None: return 0
|
||||
inner: ast.AST* = node
|
||||
if inner.kind() == ast.ASTKind.Call:
|
||||
@@ -1559,22 +1549,17 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if inner.kind() != ast.ASTKind.Attribute: return 0
|
||||
at: ast.Attribute* = ast.Attribute*(inner)
|
||||
if at.attr is None or at.value is None: return 0
|
||||
if at.value.kind() != ast.ASTKind.Attribute: return 0
|
||||
root: ast.Attribute* = ast.Attribute*(at.value)
|
||||
if root.attr is None or root.value is None: return 0
|
||||
if root.value.kind() != ast.ASTKind.Name: return 0
|
||||
rn: ast.Name* = ast.Name*(root.value)
|
||||
if rn.id is None or string.strcmp(rn.id, "t") != 0: return 0
|
||||
if string.strcmp(root.attr, "attr") != 0: return 0
|
||||
if at.value.kind() != ast.ASTKind.Name: return 0
|
||||
rn: ast.Name* = ast.Name*(at.value)
|
||||
if rn.id is None or string.strcmp(rn.id, "attr") != 0: return 0
|
||||
return 1
|
||||
def _is_cvoid_marker(self, node: ast.AST*, imported_modules: str) -> int:
|
||||
"""Whether a node is a CVoid pointer marker: 1=yes / 0=no."""
|
||||
if self._is_t_attr(node, "CVoid", imported_modules) != 0: return 1
|
||||
if self._is_builtin_marker(node, "CVoid", imported_modules) != 0: return 1
|
||||
if node is not None and node.kind() == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
# Bare CVoid (from t import CVoid) is synonymous with the builtin alias void
|
||||
if nm.id is not None:
|
||||
if string.strcmp(nm.id, "CVoid") == 0 or string.strcmp(nm.id, "void") == 0: return 1
|
||||
# Bare CVoid is synonymous with the builtin alias void
|
||||
if nm.id is not None and string.strcmp(nm.id, "void") == 0: return 1
|
||||
return 0
|
||||
def annotation_to_str(self, annot: ast.AST*) -> str:
|
||||
"""Render a type-annotation AST to a readable string; None means not extractable."""
|
||||
@@ -1713,7 +1698,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# can record it; consumers degrade gracefully for non-struct names.
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
val_nm2: ast.Name* = ast.Name*(at.value)
|
||||
if val_nm2.id is not None and string.strcmp(val_nm2.id, "t") == 0: return at.attr
|
||||
if val_nm2.id is not None and string.strcmp(val_nm2.id, "attr") == 0: return at.attr
|
||||
# Restore import aliases: val_nm2.id may be an alias like Y for
|
||||
# "import X as Y"; storing the real qualified name enables cross-module lookup.
|
||||
real_mod2: str = val_nm2.id
|
||||
@@ -2069,11 +2054,11 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
elif string.strcmp(nm.id, "None") == 0: return mlirlite.Void(pool)
|
||||
elif string.strcmp(nm.id, "int") == 0: return mlirlite.Int32(pool)
|
||||
elif string.strcmp(nm.id, "char") == 0:
|
||||
# char = i8 (consistent with CChar/char in map_t_type)
|
||||
# char = i8 (consistent with CChar/char in map_builtin_type)
|
||||
return mlirlite.Int8(pool)
|
||||
elif string.strcmp(nm.id, "bytes") == 0: return mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
elif string.strcmp(nm.id, "bool") == 0:
|
||||
# bool = t.CBool = i1 (consistent with CBool in map_t_type)
|
||||
# bool = t.CBool = i1 (consistent with CBool in map_builtin_type)
|
||||
return mlirlite.Int1(pool)
|
||||
# Bare float types: float = t.CFloat = f32, double = t.CDouble = f64
|
||||
elif string.strcmp(nm.id, "float") == 0: return mlirlite.Float(pool)
|
||||
@@ -2133,9 +2118,9 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
if inner_ty is not None: return inner_ty
|
||||
else: self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
# Fallback: map_t_type hardcoded typedefs (VOIDPTR/HANDLE/ULONG etc.) resolve even
|
||||
# Fallback: map_builtin_type hardcoded typedefs (VOIDPTR/HANDLE/ULONG etc.) resolve even
|
||||
# when from-import lookup fails; struct names return None and are deferred by declare_only.
|
||||
mapped_ty_fallback: mlirlite.LLVMType* = self.map_t_type(pool, nm.id)
|
||||
mapped_ty_fallback: mlirlite.LLVMType* = self.map_builtin_type(pool, nm.id)
|
||||
if mapped_ty_fallback is not None: return mapped_ty_fallback
|
||||
# [stage 1a] from-import alias reverse lookup: a bare alias XXX is in no table, so
|
||||
# reverse it to the original name and recurse (supports typedef alias chains).
|
||||
@@ -2190,15 +2175,11 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is None: return None
|
||||
# Check whether value is Name('t') or Name('c')
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
val_name: ast.Name* = ast.Name*(at.value)
|
||||
if val_name.id is not None:
|
||||
# t/c are builtin libraries (SHA1-exempt); an explicit t.XXX unambiguously
|
||||
# means the builtin module and does not rely on imported_modules.
|
||||
is_builtin_attr: int = 0
|
||||
if string.strcmp(val_name.id, "t") == 0 or string.strcmp(val_name.id, "c") == 0: is_builtin_attr = 1
|
||||
if is_builtin_attr == 0:
|
||||
# `attr.<name>` is a builtin attribute marker, never a type.
|
||||
if string.strcmp(val_name.id, "attr") == 0: return None
|
||||
# SHA1 prefix ("{16hex}.Class"): the module segment is a SHA1 (already
|
||||
# compiled), so skip the imported_modules check via GenApi.is_sha1_hex16.
|
||||
sha1_attr: int = GenApi.is_sha1_hex16(val_name.id)
|
||||
@@ -2221,7 +2202,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if nested_ty_q is not None: return nested_ty_q
|
||||
return None
|
||||
# [stage 1b] Prefer the library typedef dynamic table (single source of
|
||||
# truth); on miss fall back to map_t_type (t/c internal special cases).
|
||||
# truth); on miss fall back to map_builtin_type (t/c internal special cases).
|
||||
if self.Gen.TypeGenCType.CTypedefResolveDepth < TypeGenMixin.MAX_CTYPEDEF_DEPTH:
|
||||
ctypedef_attr: str = self.Gen.TypeGenCType.lookup_ctypedef(at.attr)
|
||||
if ctypedef_attr is not None and self.Gen.TypeGenCType.CTypedefFound != 0:
|
||||
@@ -2234,7 +2215,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
if inner_ty_attr is not None: return inner_ty_attr
|
||||
# First try the builtin type mapping (int etc.)
|
||||
mapped_ty: mlirlite.LLVMType* = self.map_t_type(pool, at.attr)
|
||||
mapped_ty: mlirlite.LLVMType* = self.map_builtin_type(pool, at.attr)
|
||||
if mapped_ty is not None: return mapped_ty
|
||||
# Module-qualified class type: Module.ClassName (namespace isolation).
|
||||
# The SHA1-prefixed form should use the full name to hit the defining struct.
|
||||
@@ -2244,14 +2225,14 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
mod_sha1_rv: str = None
|
||||
# val_name.id is the module segment: it is a SHA1 alias only if it is exactly
|
||||
# 16 lowercase hex (via GenApi.is_sha1_hex16, the single source of truth).
|
||||
if is_builtin_attr == 0 and GenApi.is_sha1_hex16(val_name.id) != 0:
|
||||
if GenApi.is_sha1_hex16(val_name.id) != 0:
|
||||
mod_sha1_rv = val_name.id
|
||||
full_q: str = self._concat_sha1_class(pool, val_name.id, at.attr)
|
||||
if full_q is not None: full_attr_ty = self.Gen.StructGen.get_struct_type(full_q)
|
||||
if full_attr_ty is not None: return full_attr_ty
|
||||
# Cross-module qualified name (Module.Class): resolve by module ownership, not
|
||||
# bare-name fallback; module name -> sha1 then hit "{sha1}.{Class}" exactly.
|
||||
if is_builtin_attr == 0:
|
||||
if val_name.id is not None:
|
||||
# Module name -> sha1 (exact/suffix/alias restoration via
|
||||
# StructGenMixin._resolve_module_sha1).
|
||||
mod_sha1_v: str = self.Gen.StructGen._resolve_module_sha1(val_name.id, from_imports)
|
||||
@@ -2325,7 +2306,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# Nested module-qualified enum class (three-level name): look up the enum base type
|
||||
if self.Gen.StmtGenDecl.is_enum_class(at.attr) == 1: return self.Gen.StmtGenDecl.get_enum_base_type(at.attr)
|
||||
# Nested module-qualified typedef (win32.win32base.HANDLE = VOIDPTR): same
|
||||
# lookup_ctypedef + recursion + map_t_type fallback as the Name branch.
|
||||
# lookup_ctypedef + recursion + map_builtin_type fallback as the Name branch.
|
||||
if self.Gen.TypeGenCType.CTypedefResolveDepth < TypeGenMixin.MAX_CTYPEDEF_DEPTH:
|
||||
nested_td_str: str = self.Gen.TypeGenCType.lookup_ctypedef(at.attr)
|
||||
if nested_td_str is not None and self.Gen.TypeGenCType.CTypedefFound != 0:
|
||||
@@ -2338,7 +2319,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
if nested_ty is not None: return nested_ty
|
||||
else: self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
mapped_ty_na: mlirlite.LLVMType* = self.map_t_type(pool, at.attr)
|
||||
mapped_ty_na: mlirlite.LLVMType* = self.map_builtin_type(pool, at.attr)
|
||||
if mapped_ty_na is not None: return mapped_ty_na
|
||||
# Nested module-qualified typedef fallback (win32.win32base.HANDLE = VOIDPTR):
|
||||
# build the full module path from the nested Attribute, then scan the library source.
|
||||
@@ -2382,24 +2363,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# (left marker -> other is right; right marker -> other is left).
|
||||
other_node: ast.AST* = bop.left
|
||||
if left_is_cptr != 0 or left_is_ref != 0: other_node = bop.right
|
||||
# Detect whether the other side is t.CVoid (void* = i8*), strictly validating
|
||||
# the full form (Attribute with value Name("t"), or bare CVoid with t imported).
|
||||
other_is_cvoid: int = 0
|
||||
if other_node is not None:
|
||||
if other_node.kind() == ast.ASTKind.Attribute:
|
||||
oat2: ast.Attribute* = ast.Attribute*(other_node)
|
||||
if oat2.attr is not None and string.strcmp(oat2.attr, "CVoid") == 0:
|
||||
if oat2.value is not None and oat2.value.kind() == ast.ASTKind.Name:
|
||||
ov2: ast.Name* = ast.Name*(oat2.value)
|
||||
if ov2.id is not None and string.strcmp(ov2.id, "t") == 0: other_is_cvoid = 1
|
||||
elif other_node.kind() == ast.ASTKind.Name:
|
||||
onm2: ast.Name* = ast.Name*(other_node)
|
||||
if onm2.id is not None:
|
||||
if string.strcmp(onm2.id, "CVoid") == 0:
|
||||
if self.Gen.ImportsGen.is_module_imported(imported_modules, "t") != 0: other_is_cvoid = 1
|
||||
elif string.strcmp(onm2.id, "void") == 0:
|
||||
# Builtin alias void: synonymous with t.CVoid, no import t needed
|
||||
other_is_cvoid = 1
|
||||
# Detect whether the other side is CVoid / void (void* = i8*).
|
||||
other_is_cvoid: int = self._is_cvoid_marker(other_node, imported_modules)
|
||||
if other_is_cvoid != 0: return mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
other_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, other_node, imported_modules, from_imports, trans, depth + 1)
|
||||
# If the result is void, merging with CPtr gives void* = i8*; must guard None
|
||||
@@ -2508,10 +2473,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
|
||||
# No CPtr marker: return the first non-attribute-marker side. Attribute markers
|
||||
# (t.attr.<name>) are not types and are prepended left, so skip them.
|
||||
if self._is_tattr_marker(bop.left) == 0:
|
||||
if self._is_cattr_marker(bop.left) == 0:
|
||||
left_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, bop.left, imported_modules, from_imports, trans, depth + 1)
|
||||
if left_ty is not None: return left_ty
|
||||
if self._is_tattr_marker(bop.right) == 0:
|
||||
if self._is_cattr_marker(bop.right) == 0:
|
||||
right_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, bop.right, imported_modules, from_imports, trans, depth + 1)
|
||||
if right_ty is not None: return right_ty
|
||||
return None
|
||||
@@ -2575,9 +2540,9 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
count_n: int = self.Gen.TypeGenCType._eval_const_int_expr(count_node_n, pool, from_imports, imported_modules)
|
||||
if self.Gen.TypeGenCType.ConstEvalOk == 0 or count_n <= 0: return None
|
||||
return mlirlite.Array(pool, elem_ty_n, count_n)
|
||||
# rawptr[T] builtin bare pointer: equivalent to t.CPtr[T] -> Ptr(T), always
|
||||
# appending exactly 1 layer. The old "absorb a layer" compensation is removed.
|
||||
if string.strcmp(gen_nm.id, "rawptr") == 0:
|
||||
# rawptr[T] / CPtr[T] builtin bare pointer: equivalent to `T*` -> Ptr(T),
|
||||
# always appending exactly 1 layer. The old "absorb a layer" compensation is removed.
|
||||
if string.strcmp(gen_nm.id, "rawptr") == 0 or string.strcmp(gen_nm.id, "CPtr") == 0:
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||
rp_elem: mlirlite.LLVMType* = self.resolve_annotation_type(pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
if rp_elem is None: return None
|
||||
@@ -2607,30 +2572,26 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
fb_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, fb_node, imported_modules, from_imports, trans, depth + 1)
|
||||
if fb_ty is not None: return fb_ty
|
||||
return None
|
||||
# Check whether value is an Attribute (t.CArray / t.Callable / module-qualified generic like numpy.ndarray[T])
|
||||
if sub.value.kind() != ast.ASTKind.Attribute: self.Gen.TypeGenErr.fatal_type_error(node, "Unsupported Subscript type annotation (only t.CArray / t.Callable are supported)")
|
||||
# Check whether value is an Attribute (module-qualified generic like numpy.ndarray[T])
|
||||
if sub.value.kind() != ast.ASTKind.Attribute: self.Gen.TypeGenErr.fatal_type_error(node, "Unsupported Subscript type annotation (only CArray / Callable are supported)")
|
||||
arr_at: ast.Attribute* = ast.Attribute*(sub.value)
|
||||
if arr_at.attr is None: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript Attribute missing attr")
|
||||
# Module-qualified generic class: numpy.ndarray[t.CDouble] -> use the bare class name
|
||||
# ndarray for specialization (before the t.CArray / t.Callable checks).
|
||||
# Module-qualified generic class: numpy.ndarray[CDouble] -> use the bare class name
|
||||
# ndarray for specialization.
|
||||
if trans is not None:
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(arr_at.attr) is not None:
|
||||
return self._resolve_generic_subscript_ty(pool, sub, arr_at.attr, trans, imported_modules, from_imports, depth + 1)
|
||||
if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray / t.Callable must be qualified by the module name")
|
||||
if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name: self.Gen.TypeGenErr.fatal_type_error(node, "CArray / Callable must be qualified by the module name")
|
||||
arr_val_name: ast.Name* = ast.Name*(arr_at.value)
|
||||
if arr_val_name.id is None: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript module name is None")
|
||||
# Function pointer type: t.Callable[[A, B], Ret] -> i8* (function values are bitcast to
|
||||
# Function pointer type: Callable[[A, B], Ret] -> i8* (function values are bitcast to
|
||||
# i8* for storage and the signature is rebuilt at calls, matching VPC convention).
|
||||
if string.strcmp(arr_at.attr, "Callable") == 0:
|
||||
# t/c are builtin namespaces (not compiled, not in imported_modules); no import check needed
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.Callable module not imported")
|
||||
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
# Pointer type: t.CPtr[T] -> Ptr(T); always appends exactly 1 layer, no exceptions
|
||||
# (`t.CPtr[T]` == `T*`). The old "absorb a layer" compensation is removed.
|
||||
# Pointer type: CPtr[T] -> Ptr(T); always appends exactly 1 layer, no exceptions.
|
||||
if string.strcmp(arr_at.attr, "CPtr") == 0:
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CPtr module not imported")
|
||||
if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "CPtr module not imported")
|
||||
inner_cptr_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
if inner_cptr_ty is None:
|
||||
# Element type not ready (class not yet registered): prefer a forward declaration
|
||||
@@ -2639,9 +2600,9 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if _fwd_cptr_ty is not None: return _fwd_cptr_ty
|
||||
return None
|
||||
return mlirlite.Ptr(pool, inner_cptr_ty)
|
||||
if string.strcmp(arr_at.attr, "CArray") != 0: self.Gen.TypeGenErr.fatal_type_error(node, "Unsupported Subscript type annotation (only t.CArray / t.Callable are supported)")
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray module not imported")
|
||||
if string.strcmp(arr_at.attr, "CArray") != 0: self.Gen.TypeGenErr.fatal_type_error(node, "Unsupported Subscript type annotation (only CArray / Callable are supported)")
|
||||
if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "CArray module not imported")
|
||||
# Single-arg form: t.CArray[elem_ty] -> Ptr(elem_ty), equivalent to
|
||||
# t.CArray[elem_ty, None] (statically inferred length array).
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||
|
||||
@@ -86,6 +86,44 @@ def SpecSignFromTypeNameSpan(text: str, start: sizet, end: sizet) -> int:
|
||||
if _spec_name_eq(text, start, end, "CSizeT") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUIntPtrT") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CBool") != 0: return TS_SIGN_UNSIGNED
|
||||
# --- builtin short names ---
|
||||
if _spec_name_eq(text, start, end, "sizet") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "size_t") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uint8") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uint16") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uint32") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uint64") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintfast8") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintfast16") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintfast32") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintfast64") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintleast8") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintleast16") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintleast32") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintleast64") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uchar") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "ushort") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uint") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "ulong") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "ulonglong") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "uintptr") != 0: return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "int8") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "int16") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "int32") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "int64") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intfast8") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intfast16") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intfast32") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intfast64") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intleast8") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intleast16") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intleast32") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intleast64") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "short") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "long") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "longlong") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "ptrdifft") != 0: return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "intptr") != 0: return TS_SIGN_SIGNED
|
||||
# --- builtin lowercase scalars ---
|
||||
if _spec_name_eq(text, start, end, "bool") != 0: return TS_SIGN_UNSIGNED
|
||||
# --- t/c core signed primitives ---
|
||||
|
||||
Reference in new issue
Block a user