From b1090abe702d071b3cc1dd88d319bc113236acea Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 11 Sep 2026 20:02:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(tpv):=20=E6=96=B0=E5=A2=9E=20TypeSpec=20?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E7=B1=BB=E5=9E=8B=E6=8F=8F=E8=BF=B0=E7=AC=A6?= =?UTF-8?q?=EF=BC=88S1=EF=BC=8C=E6=9C=AA=E6=8E=A5=E7=BA=BF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类型信息目前散落在 AnnotClassName/IsPtrElement/TypeStr 等字符串与布尔里, 导致「无符号/指针层级/数组维度/函数签名」到处重复解析且结论不一致 (Debugger/_Type.md 二次盘点 A/C 类)。 新增 App/lib/core/Gen/Type/TypeSpec.vp 作为统一描述符: - TypeSpec:Kind/Bits/IsSigned/PtrLevel/Elem/ArrayCount/BaseName/Ret/Params/ ParamCount/IsVarArg/Storage,以及元素语义三元组 ElemBits/IsElemPtr/ DerefBase(替代单一 IsPtrElement 布尔——同一 Ptr(i8) 下存在两种相反语义) - TypeSpecArena 驻留表(对象持有,非全局表)+ InternSpec 去重(键=规范文本) - SpecToText/TextToSpec 规范文本编解码(驻留键/日志/vpi 通道) - 构造器 NewTypeSpec/NewTypeStruct/NewTypePtr/NewTypeArray/NewTypeFunc - 访问器 SpecIsPtr/SpecPointedTo/SpecIsUnsigned/SpecBitWidth - SpecSelfCheck 自检(不参与编译流程) - 实例与数组一律 PermPool 分配(跨 mark 持久,跨模块可直接传指针) GenTypes 仅加 import 使该模块参与编译(否则新文件不会被编译、无法验证); 未改动任何既有调用点,产物 IR 应与上一版一致。 --- App/lib/core/Gen/GenTypes.vp | 4 + App/lib/core/Gen/Type/TypeSpec.vp | 769 ++++++++++++++++++++++++++++++ 2 files changed, 773 insertions(+) create mode 100644 App/lib/core/Gen/Type/TypeSpec.vp diff --git a/App/lib/core/Gen/GenTypes.vp b/App/lib/core/Gen/GenTypes.vp index a6b4f74..e236906 100644 --- a/App/lib/core/Gen/GenTypes.vp +++ b/App/lib/core/Gen/GenTypes.vp @@ -3,6 +3,10 @@ from stdint import * import ast import llvmlite import memhub +# TypeSpec:统一类型描述符(Debugger/_Type.md 第 6 节设计)。 +# S1 阶段仅 import 使该模块参与编译(尚未在任何条目上使用其字段); +# S2 起在 VarEntry/FieldEntry/FuncEntry 上加 Spec 字段并双写。 +import lib.core.Gen.Type.TypeSpec as TypeSpec # ============================================================ diff --git a/App/lib/core/Gen/Type/TypeSpec.vp b/App/lib/core/Gen/Type/TypeSpec.vp new file mode 100644 index 0000000..8dc4be1 --- /dev/null +++ b/App/lib/core/Gen/Type/TypeSpec.vp @@ -0,0 +1,769 @@ +import t, c +from stdint import * +import llvmlite +import memhub +import string +import viperlib +import lib.core.CompilerFactory as CompilerFactory + + +# ============================================================ +# TypeSpec - 统一类型描述符(对齐 TPC lib/core/TypeSpec.py,去 Python 化) +# +# 背景(见 Debugger/_Type.md 第 6 节设计): +# TPV 现有类型信息散落在「字符串 + 零散布尔」里 —— VarEntry.AnnotClassName / +# FieldEntry.AnnotClassName(注解类名串当影子类型系统)、VarEntry.IsPtrElement +# (单一布尔,只覆盖一种 8 字节步长情形)、FuncEntry.TypeStr(函数类型存文本), +# 而 llvmlite.LLVMType 只保留解析结果、已抹平指针层级/数组维度/原始注解。 +# 结果是「是否无符号/指针几层/数组几维/函数签名」到处重复解析字符串 +# (同一值被末段类名/完整限定名/精确名/mangled 前缀/截断串五种语义解释)。 +# +# 本文件是 S1 阶段产物:**只提供结构与构造/序列化,不改动任何既有调用点**。 +# S2 起才在各解析处「双写」本结构;S3 逐块切读;S4 删旧字符串路径。 +# +# 生命周期(设计 D1):实例与内部数组一律 `CompilerFactory.factory.PermPool` +# 分配(契约见 CompilerFactory.vp:跨 mark 持久、从不 reset),故跨文件/跨模块 +# 可直接传指针,无需序列化。代价是 PermPool 只增不减 ⇒ 由 InternSpec 驻留去重。 +# +# 不用全局表:驻留表挂在 TypeSpecArena 实例上,由调用方(S2 起为 Generator) +# 持有并传入,避免模块级可变态。 +# ============================================================ + + +# ============================================================ +# Kind - 基础类型种类 +# ============================================================ +TS_UNKNOWN: t.CDefine = 0 +TS_INT: t.CDefine = 1 +TS_UINT: t.CDefine = 2 +TS_FLOAT: t.CDefine = 3 +TS_BOOL: t.CDefine = 4 +TS_PTR: t.CDefine = 5 +TS_ARRAY: t.CDefine = 6 +TS_STRUCT: t.CDefine = 7 +TS_VOID: t.CDefine = 8 +TS_FUNC: t.CDefine = 9 +TS_UNION: t.CDefine = 10 +TS_ENUM: t.CDefine = 11 + +# ============================================================ +# IsSigned - 符号性(单一真源,替代 _annot_str_unsigned 的子串扫描) +# ============================================================ +TS_SIGN_UNKNOWN: t.CDefine = -1 +TS_SIGN_UNSIGNED: t.CDefine = 0 +TS_SIGN_SIGNED: t.CDefine = 1 + +# 驻留表默认容量与单条类型文本上限(超限 fail-fast,绝不静默丢弃/截断) +# 容量 × 文本上限即驻留表键缓冲的 PermPool 占用(8192 × 256 = 2MB) +SPEC_INTERN_MAX: t.CDefine = 8192 +SPEC_TEXT_MAX: t.CDefine = 256 + + +# ============================================================ +# TypeSpec - 类型描述符 +# +# 元素语义三字段说明(ElemBits/IsElemPtr/DerefBase): +# 它们替代旧的 VarEntry.IsPtrElement 单一布尔。原因(_Type.md D7-4): +# `str | t.CPtr`、`bytes | t.CPtr`、泛型 `T | t.CPtr`、`64 位标量 | t.CPtr` +# 退化后的 LLVM 类型**都是单层 Ptr(i8)**,即 PtrLevel=1 同时对应两种相反语义, +# 仅靠指针层级无法区分;区分靠的是注解内容 ⇒ 需要「元素宽度 + 元素是否指针 + +# 基址是否需二次解引用」三元组。 +# ============================================================ +@t.NoVTable +class TypeSpec: + """统一类型描述符(字段语义见上)""" + Kind: int # TS_* 之一 + Bits: int # 位宽;非整型/浮点为 0 + IsSigned: int # TS_SIGN_* (-1 未知 / 0 无符号 / 1 有符号) + PtrLevel: int # 指针层级(0=非指针) + Elem: TypeSpec | t.CPtr # Ptr/Array 的指向或元素(None=无) + ArrayCount: int # Array 的元素个数(0=未知/动态) + BaseName: str # 结构体/枚举/类名(带模块 sha1;PermPool 深拷贝) + Ret: TypeSpec | t.CPtr # Func:返回类型 + Params: sizet | t.CPtr # Func:参数数组(连续 TypeSpec* 指针,ParamCount 个) + ParamCount: int # Func:参数个数 + IsVarArg: int # Func:1=变参(...) + Storage: int # 限定宏位标志(0=无) + ElemBits: int # 元素槽位宽(元素语义三元组 1/3) + IsElemPtr: int # 元素是否为指针(1=是)(2/3) + DerefBase: int # 基址是否需二次解引用(1=是)(3/3) + Ty: llvmlite.LLVMType | t.CPtr # 解析结果缓存(可空) + + +# ============================================================ +# TypeSpecArena - 驻留表(对象持有,非全局表) +# +# Keys :cap * SPEC_TEXT_MAX 的连续文本缓冲,第 i 条键位于 Keys + i*SPEC_TEXT_MAX +# Specs :cap 个 TypeSpec 指针 +# Count :已驻留条数;Cap:容量 +# ============================================================ +@t.NoVTable +class TypeSpecArena: + """TypeSpec 驻留表(按规范文本键去重,同型只存一份)""" + Keys: bytes + Specs: sizet | t.CPtr + Count: int + Cap: int + + +# ============================================================ +# _spec_key_at - 取第 i 个键的 str 指针(键缓冲内偏移 i * SPEC_TEXT_MAX) +# ============================================================ +def _spec_key_at(keys: bytes, index: int) -> str: + """返回第 index 条键的 str 指针(指向 keys 缓冲内部,不可 free)""" + if keys is None or index < 0: + return None + addr: uint64 = uint64(keys) + uint64(index * SPEC_TEXT_MAX) + return (str | t.CPtr)(t.CVoid(addr, t.CPtr)) + + +# ============================================================ +# SpecArenaInit - 初始化驻留表(幂等;cap<=0 时用 SPEC_INTERN_MAX) +# 返回 0=成功 / 1=失败(分配失败 fail-fast 由调用方处理,此处返回错误码) +# ============================================================ +def SpecArenaInit(arena: TypeSpecArena | t.CPtr, cap: int) -> int: + """初始化驻留表;已初始化则直接返回 0""" + if arena is None: + return 1 + if arena.Keys is not None: + return 0 + use_cap: int = cap + if use_cap <= 0: + use_cap = SPEC_INTERN_MAX + pp: memhub.MemBuddy | t.CPtr = CompilerFactory.factory.PermPool + keys: bytes = pp.alloc(use_cap * SPEC_TEXT_MAX) + if keys is None: + return 1 + specs: sizet | t.CPtr = pp.alloc(use_cap * 8) + if specs is None: + return 1 + string.memset(keys, 0, use_cap * SPEC_TEXT_MAX) + string.memset(specs, 0, use_cap * 8) + arena.Keys = keys + arena.Specs = specs + arena.Count = 0 + arena.Cap = use_cap + return 0 + + +# ============================================================ +# _spec_alloc - 从 PermPool 分配一个清零的 TypeSpec(不驻留,内部用) +# ============================================================ +def _spec_alloc() -> TypeSpec | t.CPtr: + """分配并清零一个 TypeSpec(PermPool)""" + pp: memhub.MemBuddy | t.CPtr = CompilerFactory.factory.PermPool + size: sizet = TypeSpec.__sizeof__() + sp: TypeSpec | t.CPtr = (TypeSpec | t.CPtr)(t.CVoid(pp.alloc(size), t.CPtr)) + if sp is None: + return None + string.memset(sp, 0, size) + sp.Kind = TS_UNKNOWN + sp.Bits = 0 + sp.IsSigned = TS_SIGN_UNKNOWN + sp.PtrLevel = 0 + sp.IsVarArg = 0 + sp.Storage = 0 + return sp + + +# ============================================================ +# _spec_make - 构造一个基础 TypeSpec(不驻留) +# ============================================================ +def _spec_make(kind: int, bits: int, is_signed: int) -> TypeSpec | t.CPtr: + """构造基础 TypeSpec(PermPool,不驻留)""" + sp: TypeSpec | t.CPtr = _spec_alloc() + if sp is None: + return None + sp.Kind = kind + sp.Bits = bits + sp.IsSigned = is_signed + return sp + + +# ============================================================ +# _spec_set_struct_name - 深拷贝类名到 PermPool(跨文件存活) +# ============================================================ +def _spec_set_struct_name(sp: TypeSpec | t.CPtr, name: str) -> int: + """把类名深拷贝到 PermPool 并写入 BaseName,返回 0=成功 / 1=失败""" + if sp is None or name is None: + return 1 + n: sizet = string.strlen(name) + if n <= 0: + return 1 + buf: str = CompilerFactory.factory.PermPool.alloc(n + 1) + if buf is None: + return 1 + string.strcpy(buf, name) + sp.BaseName = buf + return 0 + + +# ============================================================ +# NewTypeSpec - 构造基础类型(驻留) +# ============================================================ +def NewTypeSpec(arena: TypeSpecArena | t.CPtr, kind: int, + bits: int, is_signed: int) -> TypeSpec | t.CPtr: + """构造基础 TypeSpec 并驻留,失败返回 None""" + sp: TypeSpec | t.CPtr = _spec_make(kind, bits, is_signed) + if sp is None: + return None + return InternSpec(arena, sp) + + +# ============================================================ +# NewTypeStruct - 构造结构体/枚举/类类型(驻留) +# ============================================================ +def NewTypeStruct(arena: TypeSpecArena | t.CPtr, kind: int, + base_name: str) -> TypeSpec | t.CPtr: + """构造 struct/union/enum 类型(BaseName 深拷贝 + 驻留),失败返回 None""" + sp: TypeSpec | t.CPtr = _spec_make(kind, 0, TS_SIGN_UNKNOWN) + if sp is None: + return None + if _spec_set_struct_name(sp, base_name) != 0: + return None + return InternSpec(arena, sp) + + +# ============================================================ +# NewTypePtr - 构造指针类型(PtrLevel = 元素 PtrLevel + 1,驻留) +# ============================================================ +def NewTypePtr(arena: TypeSpecArena | t.CPtr, + elem: TypeSpec | t.CPtr) -> TypeSpec | t.CPtr: + """构造指针类型:指向 elem(PtrLevel 逐层递增),失败返回 None""" + if elem is None: + return None + sp: TypeSpec | t.CPtr = _spec_make(TS_PTR, 0, TS_SIGN_UNKNOWN) + if sp is None: + return None + sp.Elem = elem + sp.PtrLevel = elem.PtrLevel + 1 + sp.ElemBits = elem.Bits + sp.IsElemPtr = 0 + if elem.Kind == TS_PTR: + sp.IsElemPtr = 1 + return InternSpec(arena, sp) + + +# ============================================================ +# NewTypeArray - 构造数组类型(ArrayCount 个 elem,驻留) +# ============================================================ +def NewTypeArray(arena: TypeSpecArena | t.CPtr, elem: TypeSpec | t.CPtr, + count: int) -> TypeSpec | t.CPtr: + """构造数组类型:elem[count](count<=0 表示长度未知/动态),失败返回 None""" + if elem is None or count < 0: + return None + sp: TypeSpec | t.CPtr = _spec_make(TS_ARRAY, 0, TS_SIGN_UNKNOWN) + if sp is None: + return None + sp.Elem = elem + sp.ArrayCount = count + sp.ElemBits = elem.Bits + sp.IsElemPtr = 0 + if elem.Kind == TS_PTR: + sp.IsElemPtr = 1 + return InternSpec(arena, sp) + + +# ============================================================ +# NewTypeFunc - 构造函数签名类型(ret + 参数数组 + 变参,驻留) +# params:TypeSpec* 连续数组(由调用方预先构造并保证存活);count 个 +# ============================================================ +def NewTypeFunc(arena: TypeSpecArena | t.CPtr, ret: TypeSpec | t.CPtr, + params: sizet | t.CPtr, count: int, + is_vararg: int) -> TypeSpec | t.CPtr: + """构造函数签名类型,失败返回 None""" + if ret is None or count < 0: + return None + if count > 0 and params is None: + return None + sp: TypeSpec | t.CPtr = _spec_make(TS_FUNC, 0, TS_SIGN_UNKNOWN) + if sp is None: + return None + sp.Ret = ret + sp.Params = params + sp.ParamCount = count + sp.IsVarArg = is_vararg + return InternSpec(arena, sp) + + +# ============================================================ +# SpecBaseText - 基础类型(非 Ptr/Array/Func)的规范文本 +# 返回 0=已写入 / 1=不适用/失败 +# ============================================================ +def SpecBaseText(sp: TypeSpec | t.CPtr, buf: str, buf_size: sizet) -> int: + """把基础类型写成规范文本;Ptr/Array/Func 不适用时返回 1""" + if sp is None or buf is None or buf_size == 0: + return 1 + if sp.Kind == TS_INT: + viperlib.snprintf(buf, buf_size, "i%d", sp.Bits) + return 0 + if sp.Kind == TS_UINT: + viperlib.snprintf(buf, buf_size, "u%d", sp.Bits) + return 0 + if sp.Kind == TS_FLOAT: + viperlib.snprintf(buf, buf_size, "f%d", sp.Bits) + return 0 + if sp.Kind == TS_BOOL: + viperlib.snprintf(buf, buf_size, "bool") + return 0 + if sp.Kind == TS_STRUCT: + viperlib.snprintf(buf, buf_size, "st:%s", sp.BaseName) + return 0 + if sp.Kind == TS_UNION: + viperlib.snprintf(buf, buf_size, "un:%s", sp.BaseName) + return 0 + if sp.Kind == TS_ENUM: + viperlib.snprintf(buf, buf_size, "en:%s", sp.BaseName) + return 0 + if sp.Kind == TS_VOID: + viperlib.snprintf(buf, buf_size, "void") + return 0 + return 1 + + +# ============================================================ +# SpecToText - 规范文本编码(驻留键 / 日志 / vpi·stub 通道) +# +# 格式草案: +# i32 / u64 / f64 / bool / void +# st:{sha1}.Class 结构体(BaseName 原样);un: / en: 同构,分别表示联合/枚举 +# p:INNER 指针(每层一个 "p:" 前缀,层数即 PtrLevel) +# arr[N]:INNER 数组(N=0 表示长度未知) +# fn(INNER,INNER,...)->RET 函数签名(变参追加 "...") +# 递归深度上限 32(防环);超限或缓冲不足返回 1(fail-fast 由调用方决定) +# ============================================================ +def SpecToText(sp: TypeSpec | t.CPtr, buf: str, buf_size: sizet) -> int: + """把 TypeSpec 编码为规范文本,返回 0=成功 / 1=失败""" + return _spec_to_text(sp, buf, buf_size, 0) + + +def _spec_to_text(sp: TypeSpec | t.CPtr, buf: str, buf_size: sizet, + depth: int) -> int: + """SpecToText 的递归实现(depth 上限 32)""" + if sp is None or buf is None or buf_size == 0 or depth > 32: + return 1 + buf[0] = '\0' + if sp.Kind == TS_PTR: + # p: + 内层 + inner_buf: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if inner_buf is None: + return 1 + if _spec_to_text(sp.Elem, inner_buf, SPEC_TEXT_MAX, depth + 1) != 0: + return 1 + viperlib.snprintf(buf, buf_size, "p:%s", inner_buf) + return 0 + if sp.Kind == TS_ARRAY: + # arr[N]: + 内层 + inner_buf_a: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if inner_buf_a is None: + return 1 + if _spec_to_text(sp.Elem, inner_buf_a, SPEC_TEXT_MAX, depth + 1) != 0: + return 1 + viperlib.snprintf(buf, buf_size, "arr[%d]:%s", sp.ArrayCount, inner_buf_a) + return 0 + if sp.Kind == TS_FUNC: + # fn(p1,p2,...)->ret + pos: sizet = 0 + pos = _spec_text_append(buf, buf_size, pos, "fn(") + i: int = 0 + while i < sp.ParamCount: + if i > 0: + pos = _spec_text_append(buf, buf_size, pos, ",") + param: TypeSpec | t.CPtr = _spec_param_at(sp, i) + if param is None: + return 1 + param_buf: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if param_buf is None: + return 1 + if _spec_to_text(param, param_buf, SPEC_TEXT_MAX, depth + 1) != 0: + return 1 + pos = _spec_text_append(buf, buf_size, pos, param_buf) + i += 1 + if sp.IsVarArg == 1: + if sp.ParamCount > 0: + pos = _spec_text_append(buf, buf_size, pos, ",...") + else: + pos = _spec_text_append(buf, buf_size, pos, "...") + pos = _spec_text_append(buf, buf_size, pos, ")->") + ret_buf: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if ret_buf is None: + return 1 + if _spec_to_text(sp.Ret, ret_buf, SPEC_TEXT_MAX, depth + 1) != 0: + return 1 + pos = _spec_text_append(buf, buf_size, pos, ret_buf) + return 0 + # 基础类型 + return SpecBaseText(sp, buf, buf_size) + + +# ============================================================ +# _spec_text_append - 有界尾部追加(返回新的写入位置;溢出时不再写入) +# ============================================================ +def _spec_text_append(buf: str, buf_size: sizet, pos: sizet, text: str) -> sizet: + """把 text 追加到 buf 的 pos 处(有界),返回新位置""" + if buf is None or text is None: + return pos + tlen: sizet = string.strlen(text) + i: sizet = 0 + while i < tlen: + if pos + 1 >= buf_size: + return pos + buf[pos] = text[i] + pos += 1 + i += 1 + buf[pos] = '\0' + return pos + + +# ============================================================ +# _spec_param_at - 取函数签名第 i 个参数 TypeSpec 指针 +# ============================================================ +def _spec_param_at(sp: TypeSpec | t.CPtr, index: int) -> TypeSpec | t.CPtr: + """返回 Func 类型第 index 个参数的 TypeSpec 指针,越界返回 None""" + if sp is None or sp.Params is None or index < 0 or index >= sp.ParamCount: + return None + addr: uint64 = uint64(sp.Params) + uint64(index * 8) + slot: sizet | t.CPtr = (sizet | t.CPtr)(t.CVoid(addr, t.CPtr)) + if slot is None: + return None + return (TypeSpec | t.CPtr)(t.CVoid(uint64(slot[0]), t.CPtr)) + + +# ============================================================ +# TextToSpec - 规范文本解码(SpecToText 的逆;不驻留,由调用方决定是否驻留) +# 解析失败返回 None(fail-fast 由调用方决定) +# ============================================================ +def TextToSpec(text: str) -> TypeSpec | t.CPtr: + """把规范文本解码为 TypeSpec(PermPool,不驻留),失败返回 None""" + if text is None: + return None + return _text_to_spec(text, 0) + + +def _text_to_spec(text: str, depth: int) -> TypeSpec | t.CPtr: + """TextToSpec 的递归实现(depth 上限 32)""" + if text is None or depth > 32: + return None + # 指针:p:INNER + if string.strncmp(text, "p:", 2) == 0: + inner: TypeSpec | t.CPtr = _text_to_spec(text + 2, depth + 1) + if inner is None: + return None + sp_p: TypeSpec | t.CPtr = _spec_make(TS_PTR, 0, TS_SIGN_UNKNOWN) + if sp_p is None: + return None + sp_p.Elem = inner + sp_p.PtrLevel = inner.PtrLevel + 1 + sp_p.ElemBits = inner.Bits + if inner.Kind == TS_PTR: + sp_p.IsElemPtr = 1 + return sp_p + # 数组:arr[N]:INNER + if string.strncmp(text, "arr[", 4) == 0: + rb: str = string.strchr(text, ']') + if rb is None: + return None + count: int = string.atoi(text + 4) + if count < 0: + return None + colon: str = string.strchr(rb, ':') + if colon is None: + return None + inner_a: TypeSpec | t.CPtr = _text_to_spec(colon + 1, depth + 1) + if inner_a is None: + return None + sp_a: TypeSpec | t.CPtr = _spec_make(TS_ARRAY, 0, TS_SIGN_UNKNOWN) + if sp_a is None: + return None + sp_a.Elem = inner_a + sp_a.ArrayCount = count + sp_a.ElemBits = inner_a.Bits + if inner_a.Kind == TS_PTR: + sp_a.IsElemPtr = 1 + return sp_a + # 函数:fn(...)->RET + if string.strncmp(text, "fn(", 3) == 0: + return _text_to_func(text, depth) + # 结构体/联合/枚举:st:NAME / un:NAME / en:NAME + if string.strncmp(text, "st:", 3) == 0: + return _spec_make_struct(TS_STRUCT, text + 3) + if string.strncmp(text, "un:", 3) == 0: + return _spec_make_struct(TS_UNION, text + 3) + if string.strncmp(text, "en:", 3) == 0: + return _spec_make_struct(TS_ENUM, text + 3) + if string.strcmp(text, "bool") == 0: + return _spec_make(TS_BOOL, 1, TS_SIGN_UNSIGNED) + if string.strcmp(text, "void") == 0: + return _spec_make(TS_VOID, 0, TS_SIGN_UNKNOWN) + # i32 / u64 / f64 + if text[0] == 'u' or text[0] == 'i' or text[0] == 'f': + bits: int = stdlib.atoi(text + 1) + if bits <= 0: + return None + if text[0] == 'u': + return _spec_make(TS_UINT, bits, TS_SIGN_UNSIGNED) + if text[0] == 'i': + return _spec_make(TS_INT, bits, TS_SIGN_SIGNED) + return _spec_make(TS_FLOAT, bits, TS_SIGN_SIGNED) + return None + + +# ============================================================ +# _spec_make_struct - 构造 struct(深拷贝名字) +# ============================================================ +def _spec_make_struct(kind: int, name: str) -> TypeSpec | t.CPtr: + """构造 struct/union/enum 类型(不驻留),失败返回 None""" + if name is None or name[0] == '\0': + return None + sp: TypeSpec | t.CPtr = _spec_make(kind, 0, TS_SIGN_UNKNOWN) + if sp is None: + return None + if _spec_set_struct_name(sp, name) != 0: + return None + return sp + + +# ============================================================ +# _text_to_func - 解析 "fn(p1,p2,...)->RET" +# ============================================================ +def _text_to_func(text: str, depth: int) -> TypeSpec | t.CPtr: + """解析函数签名文本,失败返回 None""" + lp: str = string.strchr(text, '(') + if lp is None: + return None + arrow: str = string.strstr(text, ")->") + if arrow is None: + return None + # 参数段范围(lp+1 .. arrow-1) + params_buf: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if params_buf is None: + return None + params_buf[0] = '\0' + nlen: sizet = t.CSizeT(t.CUInt64T(arrow) - t.CUInt64T(lp)) - 1 + if nlen > 0: + string.strncpy(params_buf, lp + 1, nlen) + params_buf[nlen] = '\0' + is_vararg: int = 0 + if string.strstr(params_buf, "...") is not None: + is_vararg = 1 + # 逐段解析参数(按顶层 ',' 分割;变参段 "..." 跳过) + param_specs: sizet | t.CPtr = CompilerFactory.factory.PermPool.alloc(8 * 64) + if param_specs is None: + return None + pcount: int = 0 + if nlen > 0: + cur: str = params_buf + while cur is not None: + comma: str = string.strchr(cur, ',') + seg: str = cur + if comma is not None: + seg_make: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if seg_make is None: + return None + seg_len: sizet = t.CSizeT(t.CUInt64T(comma) - t.CUInt64T(cur)) + string.strncpy(seg_make, cur, seg_len) + seg_make[seg_len] = '\0' + seg = seg_make + cur = comma + 1 + else: + cur = None + if string.strcmp(seg, "...") == 0: + continue + if pcount >= 64: + return None + psp: TypeSpec | t.CPtr = _text_to_spec(seg, depth + 1) + if psp is None: + return None + slot_p: sizet | t.CPtr = (sizet | t.CPtr)( + t.CVoid(uint64(param_specs) + uint64(pcount * 8), t.CPtr)) + if slot_p is None: + return None + slot_p[0] = sizet(psp) + pcount += 1 + ret: TypeSpec | t.CPtr = _text_to_spec(arrow + 3, depth + 1) + if ret is None: + return None + sp_f: TypeSpec | t.CPtr = _spec_make(TS_FUNC, 0, TS_SIGN_UNKNOWN) + if sp_f is None: + return None + sp_f.Ret = ret + sp_f.Params = param_specs + sp_f.ParamCount = pcount + sp_f.IsVarArg = is_vararg + return sp_f + + +# ============================================================ +# InternSpec - 规范化驻留:同键只保留一份,返回驻留后的实例 +# 键 = SpecToText;超容量 fail-fast(绝不静默丢弃/复用错误实例) +# ============================================================ +def InternSpec(arena: TypeSpecArena | t.CPtr, + sp: TypeSpec | t.CPtr) -> TypeSpec | t.CPtr: + """按规范文本键驻留 TypeSpec;失败返回 None""" + if arena is None or sp is None: + return sp + if SpecArenaInit(arena, 0) != 0: + return None + key_buf: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if key_buf is None: + return None + if SpecToText(sp, key_buf, SPEC_TEXT_MAX) != 0: + return None + # 线性查找已有键(规模与类型种数同阶,量级不大;命中即复用) + i: int = 0 + while i < arena.Count: + exist_key: str = _spec_key_at(arena.Keys, i) + if exist_key is not None and string.strcmp(exist_key, key_buf) == 0: + slot_e: sizet | t.CPtr = (sizet | t.CPtr)( + t.CVoid(uint64(arena.Specs) + uint64(i * 8), t.CPtr)) + if slot_e is None: + return None + return (TypeSpec | t.CPtr)(t.CVoid(uint64(slot_e[0]), t.CPtr)) + i += 1 + # 未命中:追加(容量检查 → fail-fast) + if arena.Count >= arena.Cap: + return None + dst_key: str = _spec_key_at(arena.Keys, arena.Count) + if dst_key is None: + return None + string.strcpy(dst_key, key_buf) + slot_n: sizet | t.CPtr = (sizet | t.CPtr)( + t.CVoid(uint64(arena.Specs) + uint64(arena.Count * 8), t.CPtr)) + if slot_n is None: + return None + slot_n[0] = sizet(sp) + arena.Count += 1 + return sp + + +# ============================================================ +# 只读访问器(供 S3 起替换旧的字符串判定) +# ============================================================ +def SpecIsPtr(sp: TypeSpec | t.CPtr) -> int: + """是否指针类型(PtrLevel>0)""" + if sp is None: + return 0 + if sp.PtrLevel > 0: + return 1 + return 0 + + +def SpecPointedTo(sp: TypeSpec | t.CPtr) -> TypeSpec | t.CPtr: + """指针的指向类型(非指针返回 None)""" + if sp is None or sp.Kind != TS_PTR: + return None + return sp.Elem + + +def SpecIsUnsigned(sp: TypeSpec | t.CPtr) -> int: + """是否无符号整数(单一真源;未知返回 0)""" + if sp is None: + return 0 + if sp.IsSigned == TS_SIGN_UNSIGNED: + return 1 + return 0 + + +def SpecBitWidth(sp: TypeSpec | t.CPtr) -> int: + """位宽(非整形/浮点返回 0)""" + if sp is None: + return 0 + return sp.Bits + + +# ============================================================ +# SpecSelfCheck - S1 自检(不参与编译流程,供手动调用/后续单测) +# +# 构造若干类型 → 编码 → 解码 → 再编码,比较两次文本是否一致(往返一致)。 +# 返回 0=全部通过;否则返回失败用例编号(从 1 起) +# ============================================================ +def SpecSelfCheck() -> int: + """TypeSpec 编解码自检,返回 0=通过 / 失败用例号""" + arena: TypeSpecArena | t.CPtr = (TypeSpecArena | t.CPtr)( + t.CVoid(CompilerFactory.factory.PermPool.alloc(TypeSpecArena.__sizeof__()), t.CPtr)) + if arena is None: + return 1 + string.memset(arena, 0, TypeSpecArena.__sizeof__()) + if SpecArenaInit(arena, 64) != 0: + return 1 + + # 1) u64 + s_u64: TypeSpec | t.CPtr = NewTypeSpec(arena, TS_UINT, 64, TS_SIGN_UNSIGNED) + if s_u64 is None: + return 1 + if _check_roundtrip(s_u64, "u64") != 0: + return 1 + + # 2) i32 + s_i32: TypeSpec | t.CPtr = NewTypeSpec(arena, TS_INT, 32, TS_SIGN_SIGNED) + if s_i32 is None: + return 2 + if _check_roundtrip(s_i32, "i32") != 0: + return 2 + + # 3) u64* + s_p: TypeSpec | t.CPtr = NewTypePtr(arena, s_u64) + if s_p is None: + return 3 + if _check_roundtrip(s_p, "p:u64") != 0: + return 3 + + # 4) i8[4] + s_arr: TypeSpec | t.CPtr = NewTypeArray(arena, s_i32, 4) + if s_arr is None: + return 4 + if _check_roundtrip(s_arr, "arr[4]:i32") != 0: + return 4 + + # 5) fn(i32,u64)->i32(变参) + params: sizet | t.CPtr = CompilerFactory.factory.PermPool.alloc(8 * 2) + if params is None: + return 5 + slot0: sizet | t.CPtr = (sizet | t.CPtr)(t.CVoid(uint64(params), t.CPtr)) + if slot0 is None: + return 5 + slot0[0] = sizet(s_i32) + slot1: sizet | t.CPtr = (sizet | t.CPtr)(t.CVoid(uint64(params) + 8, t.CPtr)) + if slot1 is None: + return 5 + slot1[0] = sizet(s_u64) + s_fn: TypeSpec | t.CPtr = NewTypeFunc(arena, s_i32, params, 2, 1) + if s_fn is None: + return 5 + if _check_roundtrip(s_fn, "fn(i32,u64,...)->i32") != 0: + return 5 + + # 6) 驻留去重:同一文本第二次应返回同一实例 + s_u64_again: TypeSpec | t.CPtr = NewTypeSpec(arena, TS_UINT, 64, TS_SIGN_UNSIGNED) + if s_u64_again is None: + return 6 + if t.CUInt64T(s_u64_again) != t.CUInt64T(s_u64): + return 6 + return 0 + + +# ============================================================ +# _check_roundtrip - 自检辅助:编码应等于 expect,且解码再编码应一致 +# ============================================================ +def _check_roundtrip(sp: TypeSpec | t.CPtr, expect: str) -> int: + """编码比对 + 解码往返一致;返回 0=通过 / 1=失败""" + if sp is None or expect is None: + return 1 + buf1: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if buf1 is None: + return 1 + if SpecToText(sp, buf1, SPEC_TEXT_MAX) != 0: + return 1 + if string.strcmp(buf1, expect) != 0: + return 1 + back: TypeSpec | t.CPtr = TextToSpec(buf1) + if back is None: + return 1 + buf2: str = CompilerFactory.factory.PermPool.alloc(SPEC_TEXT_MAX) + if buf2 is None: + return 1 + if SpecToText(back, buf2, SPEC_TEXT_MAX) != 0: + return 1 + if string.strcmp(buf2, expect) != 0: + return 1 + return 0