Files
Viper_Wiki/10-imports.md
T
2026-10-13 15:36:42 +08:00

263 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 10 - 模块与导入系统
Viper 的模块系统基于 Python 的 `import` 语法,但编译时通过 TransPyC 的符号表和类型系统实现跨模块的类型解析。
> 注:`extern`/`export`/`define` 关键字属语言语法([includes/ast](../includes/ast) parser 中的软关键字;`define` 为宏函数),而非 `t` 模块的类型注解。
## 导入语法
### 标准导入
```python
import t, c # Viper 内置类型和操作模块
import asm # 汇编辅助模块
import string # 字符串操作模块
```
### 模块导入
```python
import bootinfo
import intr
import platform.pch as pch
import drivers.serial.uart.serial as serial
```
### from 导入
```python
from stdint import * # 导入所有 stdint 类型别名
from drivers.video.vesafb.vga import _VGAScreenDriver
```
### 相对导入
```python
from . import submodule
from .. import parent_module
```
## 特殊模块
### `t` 模块
类型定义模块,提供所有 C 类型对应的 Viper 类型。每个 Viper 文件通常都需要导入:
```python
import t
```
### `c` 模块
C 语言操作模块,提供指针操作、内联汇编、预处理指令等:
```python
import c
```
### `asm` 模块
汇编辅助模块,提供常用汇编指令的封装:
```python
import asm
asm.sti() # __asm__ __volatile__("sti");
asm.hlt() # __asm__ __volatile__("hlt");
asm.cli() # __asm__ __volatile__("cli");
asm.nop() # __asm__ __volatile__("nop");
asm.BSSClean() # 清零 BSS 段
```
### `string` 模块
字符串/内存操作模块,对应 C 标准库的 `string.h`:
> 确认:string 模块确实使用 Viper `__asm__` 内联汇编进行加速(`memset`/`memcpy`/`memmove` 等,见 [includes/string.vp](../includes/string.vp))。因使用 x86_64 专有汇编,某些函数在其它架构可能需要手动重新编写。
```python
import string
string.memset(&buf, 0, 64) # memset(&buf, 0, 64);
string.memcpy(dst, src, size) # memcpy(dst, src, size);
string.memmove(dst, src, size) # memmove(dst, src, size);
string.memcmp(a, b, size) # memcmp(a, b, size);
string.strcmp(a, b) # strcmp(a, b);
string.strcpy(dst, src) # strcpy(dst, src);
```
### `stdint` 模块
提供 C `stdint.h` 中的类型别名:
```python
from stdint import *
# 提供以下类型别名:
# UINT8PTR, UINT16PTR, UINT32PTR, UINT64PTR
# INT8PTR, INT16PTR, INT32PTR, INT64PTR
# 等等
```
### `viperlib` 模块
ViperOS 标准库,提供常用 C 库函数:
```python
import viperlib
viperlib.snprintf(&buf, 64, "value=%d", 42) # snprintf(&buf, 64, "value=%d", 42);
```
### `ast` 模块(自研解析器)
[includes/ast](../includes/ast) 是**完全自研的 Python 解析器**(词法器 + 语法器 + AST 构造,现行 9 个文件约 8K 行;"约 4176 LOC"为 2026-06 历史口径),覆盖 CPython 几乎全部语法。这是向 `ViperC` 完全自举的关键组件——自举后编译器不再依赖 Python 运行时解析源文件。
```python
from ast import parse, parse_expression
root: AST* = parse(src, pool) # 解析整个源文件
expr: AST* = parse_expression(src, pool) # 解析单个表达式
```
AST 采用**胖节点**设计:70+ 变体共用一个 struct,用 `vtype`(`ASTVType` 枚举)区分类型,通用字段直接属性访问。详见 [13-bootstrapping.md](13-bootstrapping.md) 和 [Test/AstTest](../Test/AstTest)。
### `llvmlite` 模块(自研 IR 生成库)
[includes/llvmlite](../includes/llvmlite) 是**完全自研的 LLVM IR 文本生成库**(现行约 5.9K 行;"约 1500 LOC"为 2026-06 历史口径),封装类型/值/模块/函数/基本块/构造器的创建与打印。同样是自举的关键组件。
```python
from llvmlite import LLVMTypeCore, LLVMModuleCore
type_core: LLVMTypeCore = LLVMTypeCore(pool)
i32: LLVMType* = type_core.Int32()
ptr_ty: LLVMType* = type_core.Ptr(i32)
mod_core: LLVMModuleCore = LLVMModuleCore(pool)
mod: Module* = mod_core.NewModule("main")
func: Function* = mod_core.CreateFunction(mod, "main", ret_ty)
```
类型系统用 `t.REnum`(`LLVMType`,少变体适合 match),指令 opcode 用 `t.CEnum`(`IROp`),对象分配用普通类 + `mpool`。详见 [includes/llvmlite/README.md](../includes/llvmlite/README.md) 的选型论证。
### `linkedlist` 模块(novirtual + PEP 695 泛型示范)
[includes/linkedlist](../includes/linkedlist.vp) 提供链表实现,是 `novirtual` 非多态继承和 PEP 695 递归泛型继承的典范用例:
```python
from linkedlist import LinkedNode, GSList
novirtual class Node(LinkedNode): # 非多态继承,零 vtable 开销
value: int
lst: GSList[Node]* = &GSList[Node]()
node: Node* = &Node()
node.value = 42
lst.append(node) # 类型安全:append 只接受 Node
```
包含 `LinkedNode`/`SListNode`(双向/单向节点)和 `GSList[T]`(泛型链表,支持递归泛型继承 `class GNode(GSListNode[GNode])`)。详见 [05-classes.md 的泛型类章节](05-classes.md#泛型类pep-695-语法) 和 [06-oop.md 的 novirtual 章节](06-oop.md#novirtual-非多态继承)。
### `w32` 模块(Win32 FFI 绑定)
[includes/w32](../includes/w32) 提供 Win32 API 绑定,全部用 `extern def` 软关键字声明(解析器内部改写为 `t.State` 标记):
```python
from w32.win32file import CreateFileA, ReadFile, WriteFile
from w32.win32console import WriteConsole
from w32.win32memory import HeapAlloc, HeapFree
from w32.win32process import CreateProcess
from w32.win32sync import CreateMutex, WaitForSingleObject
handle: HANDLE = CreateFileA("test.txt", GENERIC_READ, FILE_SHARE_READ,
None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, None)
```
子模块:`win32base`(基础类型/常量)、`win32file`(文件 IO)、`win32console`(控制台)、`win32memory`(内存)、`win32process`(进程/线程)、`win32sync`(同步对象)、`fileio`(高层文件操作封装)。详见 [08-c-operations.md 的 FFI 章节](08-c-operations.md#ffi-外部函数声明)。
### `coro`/`stdio`/`stdlib`/`memhub`/`testcheck` 等内置模块
特殊模块清单末尾补充:
- `coro`:协程运行时,提供 `coro_run`/`coro_sleep`/`coro_destroy`/`coro_exception`/`coro_exception_msg`/`coro_gather`
- `stdio` / `stdlib`:C 标准库风格的 IO 与通用库函数
- `memhub`:内存管理中枢
- `testcheck`:测试辅助(断言/检查用例);使用 `assert` 时自动导入(见 [07-control-flow.md 的 assert 语句](07-control-flow.md#assert-语句))
## 模块解析流程
### 编译时模块加载
Viper 的 `import` 是编译时操作,不涉及运行时模块加载。完整的模块解析流程与两阶段编译紧密耦合:
1. **阶段一**:从入口文件出发,通过 `import` 语句递归发现所有可达的源文件
2. **阶段一**:对每个源文件生成 `<SHA1>.vpi` 签名存根和 `<SHA1>.stub.ll` LLVM IR 声明
3. **阶段二**:加载所有 `.vpi` 和 `.stub.ll`,构建共享符号表
4. **阶段二**:翻译源文件时,通过符号表解析跨模块的类型和函数引用
5. **阶段二**:将被引用模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部
> 注:阶段一主要产出 `.vpi`;`.stub.ll`/`.text.ll` 由阶段二 Phase A 写盘。`.vpi`/`.stub` 按需加载而非全量;共享符号表为内存 `StubMergerStore`;`_sha1_map.txt` 仅人类可读(映射本体在内存 `Sha1Store`)。
### 类型存根文件(.vpi)
`.vpi` 文件是模块的声明接口,由 `PythonToStubConverter` 在阶段一生成。VPC 自举路径使用自研 `StubGen`/`Converter.vp`(从 AST 直接生成,不依赖 CPython 的 `PythonToStubConverter`)。存根文件的内容规则:
| 元素 | 存根表示 |
|------|---------|
| `t.CDefine` 常量 | 保留完整定义(含赋值) |
| `t.CDefine` 函数 | 保留完整函数体 |
| 普通函数 | 仅保留签名:`def foo(...) -> T: pass` |
| 全局变量 | TPC 一代 `PythonToStubConverter` 会添加 `t.CExtern`;VPC 自研 `StubGen`/`Converter.vp` 不再添加(跨模块 external declare 由 `VpiReader` 依 vpi 全局自动注入) |
| 类定义 | 保留成员类型注解和方法签名 |
### SHA1 命名空间与导入
每个模块的函数和结构体在 LLVM IR 中自动加上 SHA1 前缀,消除跨模块符号冲突。SHA1 取文件内容 `sha1` 摘要的**前 8 字节**(16 个十六进制字符)。豁免(保留裸名)的符号:`t.CExport` / `t.CExtern` / `t.State` 标记的函数、以及 `main`。详见 [README.MD 中 SHA1 命名空间机制](README.MD#sha1-命名空间机制)。
### 跨模块约束
- **`static` 不得跨模块**:`static` 符号(函数 / 全局变量)仅限定义模块内可见,`mod.x` 取值、`mod.f()` 调用、`from mod import x` 三种形态都会编译期 `NameError` fail-fast。
- **`extern` 全局**:`extern NAME: T` 生成裸名 `@NAME = external global T`,跨模块引用侧由 vpi 注入同名 external 声明。
- **`extern` 重名的解析顺序(临时规则,待修正)**:当多个模块声明了同名 `extern` 符号时,调用点按**依赖 / 导入顺序取「最近」的那个**实体。顺序不同可能解析到不同实现 ⇒ 当前请**避免多模块重复声明同名 `extern`**;该行为是临时约定,**日后会修正**为可显式区分来源的机制。
- **循环 import 防护**:翻译阶段禁止把模块自己的 vpi 反向注入(循环 import 会在同模块制造同名 declare);本文件自己声明的 `extern` 裸名优先于依赖 vpi 注入的同名声明。
- **跨模块调用的 declare 形参以定义侧为准**:调用点按 vpi 定义侧形参注解对实参 coerce,保证 call / declare / define 三者类型一致。
### 符号表
所有模块的类型信息统一存储在 `SymbolTable` 中,包含:
- 结构体/联合体/枚举定义
- 函数签名
- 全局变量
- typedef 别名
- `t.CDefine` 常量
### 跨模块类型引用
```python
# 在 fat32_types.vp 中定义
class fat32_fileinfo:
fname: [13]char
attr: uint8
file_size: uint32
# 在其他模块中引用
import fat32_types
info: fat32_types.fat32_fileinfo
```
跨模块引用的结构体在 LLVM IR 中使用 SHA1 前缀的类型名:
```llvm
%"<SHA1_of_fat32_types>.fat32_fileinfo" = type { [13 x i8], i8, i32 }
```
## 项目 includes 配置
在 `project.json` 中配置模块搜索路径:
```json
{
"includes": ["../.."],
"source_dir": "./Kernel"
}
```
编译器会在 `includes` 指定的目录中搜索导入的模块。