- 12-project.md 改建为 12-compilation-system.md:介绍编译系统总览、工程配置 project.vpj 与 viperbuild 元编程;同步 README 与第 17 章的引用 - README.MD:新增「C-LIKE 语法(逐步支持)」小节——自研语法器 includes/ast 将逐步 支持 C-LIKE 写法,双端写法与语义长期维护,但实际工程仍推荐 ABC-LIKE;流水线章节 去掉「Python 单文件模式 / project.json」旧措辞,改述工程根来源并补 --src 与 viperbuild - 02-type-system.md:long / unsigned long 位宽改为平台相关(Windows LLP64=32、 LP64=64)并补注权威实现;修正 stdint.LONGLONG / ULONGLONG 展开;统一整型 None 判空写法 - 05-classes.md:补 t.Anonymous 废弃告警;07-control-flow.md:for-else 改为已实现措辞 - 15/16/17/18 章重编号为 14/15/16/17,填补 14-oo-refactor 删除后的编号空洞, 同步各章标题与全仓引用
199 lines
3.8 KiB
Markdown
199 lines
3.8 KiB
Markdown
# 09 - 异常处理
|
|
|
|
> 本章待修订(机制与实现存在偏差,见各节标注)
|
|
>
|
|
> 说明:本章讲的是**语言层 `try/except`**(错误码 + 错误消息出参)。运行期崩溃 / 按键时打印的**调用栈回溯**是另一套机制,见 [16-traceback.md](16-traceback.md)。
|
|
|
|
Viper 支持 Python 风格的 `try/except/finally` 异常处理,采用基于错误码 + 错误消息出参的传播机制(不使用 C++ 风格的零开销异常)。
|
|
|
|
## 异常处理机制
|
|
|
|
编译器自动为可能抛出异常的函数追加 `__eh_code_out__(i32*)` 与 `__eh_msg_out__(i8**)` 出参;调用点传入接收缓冲,调用后检查 `msg != NULL`,按 `code` 匹配 `except`。
|
|
|
|
## try / except
|
|
|
|
```python
|
|
try:
|
|
result = risky_operation()
|
|
except ValueError:
|
|
serial.puts("ValueError occurred\n")
|
|
except OSError:
|
|
serial.puts("OSError occurred\n")
|
|
except Exception:
|
|
serial.puts("Unknown error\n")
|
|
```
|
|
|
|
### 内置异常类型
|
|
|
|
Viper 预定义了以下异常类型及其错误码:
|
|
|
|
| 异常类型 | 错误码 |
|
|
|---------|--------|
|
|
| `ValueError` | 1 |
|
|
| `TypeError` | 2 |
|
|
| `RuntimeError` | 3 |
|
|
| `ZeroDivisionError` | 4 |
|
|
| `IndexError` | 5 |
|
|
| `KeyError` | 6 |
|
|
| `IOError` | 7 |
|
|
| `OSError` | 8 |
|
|
| `AssertionError` | 9 |
|
|
| `Exception` | 99 |
|
|
|
|
### 自定义异常
|
|
|
|
```python
|
|
class DiskFullError(Exception):
|
|
pass
|
|
|
|
class ReadOnlyError(DiskFullError):
|
|
pass
|
|
```
|
|
|
|
自定义异常会自动分配递增的错误码(从 100 开始),并支持继承匹配。
|
|
|
|
### 多异常捕获
|
|
|
|
> 语法暂不支持(期望)。
|
|
|
|
```python
|
|
try:
|
|
result = operation()
|
|
except (ValueError, TypeError):
|
|
serial.puts("Value or Type error\n")
|
|
```
|
|
|
|
### 获取异常信息
|
|
|
|
```python
|
|
try:
|
|
result = operation()
|
|
except Exception as e:
|
|
serial.puts("Error occurred\n")
|
|
```
|
|
|
|
## try / finally
|
|
|
|
> 普通函数中尚未实现(仅协程子集支持纯 try/finally)——期望/后续修正
|
|
|
|
```python
|
|
try:
|
|
result = operation()
|
|
finally:
|
|
cleanup()
|
|
```
|
|
|
|
`finally` 块无论是否发生异常都会执行。
|
|
|
|
## try / except / finally
|
|
|
|
> 普通函数中尚未实现(仅协程子集支持纯 try/finally)——期望/后续修正
|
|
|
|
```python
|
|
try:
|
|
result = operation()
|
|
except ValueError:
|
|
handle_value_error()
|
|
finally:
|
|
cleanup()
|
|
```
|
|
|
|
## raise 语句
|
|
|
|
### 抛出异常
|
|
|
|
```python
|
|
raise ValueError("invalid value")
|
|
```
|
|
|
|
### 抛出自定义异常
|
|
|
|
```python
|
|
raise MyCustomError("something went wrong")
|
|
```
|
|
|
|
### 重新抛出异常
|
|
|
|
> 当前裸 raise 不重新抛出(返回默认值),期望实现重抛当前异常。
|
|
|
|
```python
|
|
raise
|
|
```
|
|
|
|
### StopIteration
|
|
|
|
`StopIteration` 有特殊处理,用于迭代器协议:
|
|
|
|
```python
|
|
raise StopIteration
|
|
```
|
|
|
|
## 异常处理的编译实现
|
|
|
|
### 函数签名变换
|
|
|
|
可能抛出异常的函数会自动添加错误输出参数:
|
|
|
|
```python
|
|
def risky_operation() -> int:
|
|
if error:
|
|
raise ValueError("bad value")
|
|
return 0
|
|
```
|
|
|
|
编译后等价于:
|
|
|
|
```c
|
|
int risky_operation(char** __eh_msg_out__, int* __eh_code_out__) {
|
|
if (error) {
|
|
*__eh_code_out__ = 1; // ValueError code
|
|
*__eh_msg_out__ = "bad value";
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### 调用点变换
|
|
|
|
```python
|
|
try:
|
|
result = risky_operation()
|
|
except ValueError:
|
|
handle_error()
|
|
```
|
|
|
|
编译后等价于:
|
|
|
|
```c
|
|
char* __eh_msg = NULL;
|
|
int __eh_code = 0;
|
|
int result = risky_operation(&__eh_msg, &__eh_code);
|
|
if (__eh_msg != NULL) {
|
|
if (__eh_code == 1) { // ValueError
|
|
handle_error();
|
|
}
|
|
}
|
|
```
|
|
|
|
## 异常继承匹配
|
|
|
|
异常匹配支持继承体系。捕获父类异常时,子类异常也会被匹配:
|
|
|
|
```python
|
|
class FileSystemError(Exception):
|
|
pass
|
|
|
|
class FileNotFoundError(FileSystemError):
|
|
pass
|
|
|
|
class PermissionError(FileSystemError):
|
|
pass
|
|
|
|
try:
|
|
operation()
|
|
except FileSystemError:
|
|
# 也会捕获 FileNotFoundError 和 PermissionError
|
|
handle_fs_error()
|
|
```
|