From ebd339e79a09b033ed1e9c581be08ae460e5f867 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 1 Oct 2026 22:36:58 +0800 Subject: [PATCH] =?UTF-8?q?docs(wiki):=20=E8=A1=A5=20T*(x)=20=E5=BC=BA?= =?UTF-8?q?=E8=BD=AC=E6=AD=A7=E4=B9=89=E7=BA=A6=E6=9D=9F=E3=80=81isinstanc?= =?UTF-8?q?e=20=E4=B8=8E=20FakeDuck=20=E7=AB=A0=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 02-type-system.md | 19 ++++++++++++ 06-oop.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 11-builtins.md | 4 +++ 3 files changed, 96 insertions(+) diff --git a/02-type-system.md b/02-type-system.md index 09d3ebf..bb7e288 100644 --- a/02-type-system.md +++ b/02-type-system.md @@ -686,6 +686,25 @@ q: void* = x # void* ↔ 任意 T* 双向隐式可转, 对于比较、四则运算,可以不使用强制类型转换而依靠隐式类型转换;但严谨数学计算推荐显式强转,避免判断出错。此外,若将一个不同类型的右值赋值到左值,则会隐式将右值转换为左值的类型。 +### `T*(x)` 指针强转 + +C 风格强转可直接写 `T*(x)`——等价 `(T*)(x)`、`(T*)x`、`(T | t.CPtr)(x)`(四者产出**同一 AST、同一 IR 路径**): + +```python +node: Node* = Node*(child) +p: int* = int*(raw) +data: uint8* = uint8*(s) +``` + +**歧义与约束**(`a * (b)` 是合法乘法,所以判定必须是纯语法的): + +1. `T` 必须是**类型原子**(Name / Attribute / Subscript); +2. `T` 与 `*` 串、`*` 串与 `(` 之间**必须紧贴**(无空白 / 无换行)。 + +⇒ `T*(x)` 中的 `T` 必须是**类型名**(class 原型、typedef、`uint8` 等类型原子);`T` 若解析不出类型,会在类型解析阶段 fail-fast。而 `a * (b)`、`n * (m - 1)`、`(i + 1) * (j)`(有空白,或前驱不是类型原子)仍按**乘法**解析。 + +生成的 IR 与其它强转同路径:指针↔指针 `bitcast`、整数→指针 `inttoptr`、指针→整数 `ptrtoint`、整数↔整数 `zext/sext/trunc`。 + ## 宏定义常量 使用 `t.CDefine` 定义编译时常量(新写法用软关键字 `define X = v` / `define X: T = v`)。`t.CDefine` 不是数据类型,而是编译时元指令——标记为 `t.CDefine` 的常量在 LLVM IR 中不生成任何全局变量,而是在引用处直接内联展开。详见 [01-overview.md 中 t.CDefine 深度解析](01-overview.md#tcdefine-深度解析)。 diff --git a/06-oop.md b/06-oop.md index c4f3c54..6e6ee6b 100644 --- a/06-oop.md +++ b/06-oop.md @@ -669,6 +669,79 @@ del obj # 期望:调用 obj.__del__() 或 obj.__delete__()(尚未实 del arr[idx] # 调用 arr.__delitem__(idx) ``` +## `isinstance` + +`isinstance(obj, Cls)` 不是关键字,而是编译器在调用点按函数名识别的内建(返回 `i1`)。 + +```python +if isinstance(obj, Base): + ... + +if isinstance(obj, (A, B)): # 元组:任一命中即为真 + ... +``` + +语义: + +- **`virtual` 类(带 vtable)**:运行时读对象头部 vtable 指针,与「目标类**及其全部已知子类**的 vtable 地址集合」逐一比较,相等即真 ⇒ 正确覆盖多态子类(这也是运行期唯一能拿到实际类的途径); +- **`novirtual` 类 / 未知类(无 vtable)**:回退**编译期静态 MRO 判定**(据 obj 的静态类型)——可能保守判假。 + +第二参数支持:裸类名 / 跨模块 `mod.Cls`(只取短名)/ 元组 `(A, B)`。**不支持** REnum 变体、`t.CEnum` 等。 + +限制:已知子类集合上限 64、元组上限 15;Viper 侧类型推断失败即 fail-fast(`TypeError: isinstance() 参数类型推断失败`)。 + +> 注意:胖节点 AST 的节点分派用的是**虚方法 `kind()`**(返回 `ASTKind`),不是 `isinstance`;文档中提到的 `vtype` 字段目前**不存在**(属迁移规划)。 + +## FakeDuck(伪鸭子类型) + +FakeDuck 让**内建类型 `str`**(LLVM 层就是 `i8*`)也能像对象一样调用方法、读写字段——通过**扩展类**实现,**不是**关键字 / 装饰器 / 基类。 + +### 启用方式(命名约定 + import) + +- 扩展类必须命名为 `_str`(字符串扩展方法)或 `_Type`(通用基类),定义在被 `import` 的模块中; +- 使用者 `import _fakeduck`(提供 `_str` / `_Type`);`with` 自动注入还需 `import _withcontent`。 + +内置扩展类见 [includes/_fakeduck.vp](../includes/_fakeduck.vp):`_Type.type_id()`;`_str` 提供 `upper` / `lower` / `capitalize` / `swapcase` / `title` / `casefold` / `isupper` / `islower` / `isalpha` / `isdigit` / `isalnum` / `isspace` / `isascii` / `istitle` / `split` 等。 + +### 扩展方法调用 + +```python +import _fakeduck + +a: str = "Hello" +tid: int = a.type_id() # 解析到扩展类 _Type.type_id +u: str = a.upper() # 解析到扩展类 _str.upper +``` + +分派是**回退**:先走普通结构体方法,全部落空后才尝试 FakeDuck;接收者注解是 `list[...]` 时**跳过**。方法名在 `_Type` / `_str` 中查找。 + +### 影子字段与 with 自动注入 + +编译期为每个**裸 `str`** 变量额外开一个影子结构体 `<变量名>__meta__`,用来存 per-instance 字段(`__data__`、`__mbuddy__`): + +```python +a.__mbuddy__ = bd # 语法糖,等价 a.set_mbuddy(bd) +d: str = a.__data__ # 读影子字段 +``` + +`with` 上下文可**自动注入**字段:提供方类用类体注解 `__provides__ = ['字段名']` 声明,消费方扩展类用 `__requires__ = ['字段名']` 声明: + +```python +with memhub.MemBuddy(arena, 65536) as bd: + s: str = "WithTest" # __mbuddy__ 自动注入,无需手动赋值 + u2: str = s.upper() +``` + +另有 `__require_must__`:表示该字段必须由某个外层 `with` 提供,否则编译期 fail-fast。 + +### 限制 + +- 影子结构体**只对裸 `str` 注解创建**(`bytes` / `char*` 不创建);`_bytes` 扩展类**未实现**。 +- `len()` / 下标 `[]` / `for` 迭代等**不走 FakeDuck**,而是 `list[T]` 的 dunder / 内建分派。 +- `with` 注入依赖运行时 provider 栈([includes/_withcontent.vp](../includes/_withcontent.vp)),未 import `_withcontent` 时跳过注入。 + +真实用例:[Test/FakeDuckTest](../Test/FakeDuckTest)。 + ## Dunder 方法完整参考 ### 已实现自动调度的 Dunder 方法 diff --git a/11-builtins.md b/11-builtins.md index 4f06a73..ae47807 100644 --- a/11-builtins.md +++ b/11-builtins.md @@ -69,6 +69,10 @@ for i in range(0, 10, 2): pass # for (int i = 0; i < 10; i += 2) 函数指针类型构造子:`callable` / `Callable` / `t.Callable` / `c.Callable` 在类型域等价,统一为 `i8*`(带签名形态额外登记返回类型)。详见 [02-type-system.md 的数组指针与函数指针](02-type-system.md#数组指针与函数指针)。 +### isinstance + +`isinstance(obj, Cls)` / `isinstance(obj, (A, B))`:编译器内建(返回 `i1`)——对带 vtable 的对象做**运行时子类判定**,无 vtable 时回退编译期静态判定。详见 [06-oop.md 的 isinstance 章节](06-oop.md#isinstance)。 + ## 运算符 ### 算术运算符