Files
Viper_Wiki/07-control-flow.md
TermiNexus d7a4012b20 docs(lang): 修正 cif/defined() 条件编译、值引用注解与 assert 语义口径
07-control-flow / 08-c-operations / 10-imports / README:cif-celif-celse 成套语法与 defined() 谓词改写条件编译章节;值引用注解 &T / &temp T 取代 t.CNeedPtr;assert 自动导入 testcheck 并改译 testcheck.check(cond, None, msg)。MergeWiki.py 仅微调合并快照横幅措辞。
2026-10-07 19:02:43 +08:00

7.2 KiB
Raw Permalink Blame History

07 - 控制流

Viper 支持 Python 风格的控制流语句,编译为 LLVM IR 的基本块和分支指令。

条件语句

if / elif / else

if x > 0:
    y = 1
elif x == 0:
    y = 0
else:
    y = -1

等价 C 代码:

if (x > 0) {
    y = 1;
} else if (x == 0) {
    y = 0;
} else {
    y = -1;
}

条件表达式

is_dir: int = 1 if (info.attr & AM_DIR) else 0

等价 C 代码:

int is_dir = (info.attr & AM_DIR) ? 1 : 0;

None 检查

if BootInfo is not None:
    paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize)
else:
    paging.init(0, 0)

等价 C 代码:

if (BootInfo != NULL) {
    paging_init(BootInfo->MemmapAddr, BootInfo->MemmapSize);
} else {
    paging_init(0, 0);
}

循环语句

while 循环

i: int = 0
while i < 10:
    buf[i] = 0
    i += 1

等价 C 代码:

int i = 0;
while (i < 10) {
    buf[i] = 0;
    i += 1;
}

while-else

while 支持 else 子句,与 if-else 一样是语言的一部分:

while i < count:
    if found:
        break
else:
    serial.puts("not found\n")

else 块在循环正常结束(非 break 退出)时执行;break 会跳过 else。

无限循环

while True:
    sched.Scheduler._yield()

等价 C 代码:

while (1) {
    scheduler_yield();
}

for 循环(range)(关于 for 循环的更多用法,参见 06-oop.md 中 迭代器协议)

for i in range(10):
    buf[i] = 0

for i in range(5, 10):
    buf[i] = 0

for i in range(0, 100, 2):
    buf[i] = 0

等价 C 代码:

for (int i = 0; i < 10; i++) {
    buf[i] = 0;
}

for (int i = 5; i < 10; i++) {
    buf[i] = 0;
}

for (int i = 0; i < 100; i += 2) {
    buf[i] = 0;
}

for 循环(迭代器)

如果类实现了 __iter__ 和 __next__ 方法,可以使用 for ... in 迭代:

container: Iter = Iter()
for item in container:
    process(item)

for-else

for 支持 else 子句,与 while-else 一样是语言的一部分:

for i in range(count):
    if items[i] == target:
        break
else:
    serial.puts("not found\n")

else 块在循环正常结束(迭代耗尽,非 break 退出)时执行;break 会跳过 else。

break 和 continue

while True:
    if done:
        break
    if skip:
        continue
    process()

match 语句

Viper 支持 Python 3.10+ 的 match 语句,编译为 C 的 switch 语句:

match self.ctype:
    case UI_LABEL:
        self.RenderLabel(sh)
    case UI_BUTTON:
        self.RenderButton(sh)
    case UI_PANEL:
        self.RenderPanel(sh)
    case _:
        pass

等价 C 代码:

switch (self->ctype) {
    case UI_LABEL:
        self_RenderLabel(self, sh);
        break;
    case UI_BUTTON:
        self_RenderButton(self, sh);
        break;
    case UI_PANEL:
        self_RenderPanel(self, sh);
        break;
    default:
        break;
}

match 值匹配

match code:
    case 0:
        serial.puts("OK\n")
    case 1:
        serial.puts("Error\n")
    case _:
        serial.puts("Unknown\n")

match 或模式

期望实现——当前实现只取第一个值做 switch case,其余值会落入默认分支

match value:
    case 1 | 2 | 3:
        serial.puts("small\n")
    case _:
        serial.puts("other\n")

match 内的 break

match 编译为 switch,因此 case 体内的 break 语义是跳出本 match(不是跳出外层循环)——即使在循环里的 match,case 内的 break 也只结束这个 match:

for i in range(n):
    match i:
        case 1:
            do_one()
            break        # 只跳出 match,循环继续
        case _:
            do_default()

match 完全禁止 fallthrough:写进 match 的任何 case 体都会在生成期 fail-fast。

switch 语句

switch 是 C 风格的多分支语句(与 match 并列,语义更贴近 C):

switch value:
    case 1:
        do_one()
    case 2:
        do_two()
    default:
        do_default()

规则与 C 的 switch 基本一致:

  • 每个 case/default 体默认自动跳出 switch(不穿透);
  • 需要穿透时,在 case 体里写关键字 fallthrough,落到下一个 case 体:
switch value:
    case 1:
        do_one()
        fallthrough      # 不自动跳出:接着执行 case 2 的体
    case 2:
        do_two()
        break            # 跳出 switch(等价默认行为,用于提前退出)
    default:
        do_default()
  • case 体内可直接写 break,语义是跳出本 switch(不是跳出外层循环);
  • default: 是默认分支(等价于 match 的 case _,但书写为 default),只允许一个;
  • case 标签只支持常量字面量或枚举变体,可多值 case 1 | 2:;不接受序列/映射/捕获等结构化模式,也不支持 if 守卫——违反则在解析期 fail-fast;
  • switch 允许重复 case 标签(按书写顺序,先出现者生效);出现多个 default: 仍 fail-fast;
  • 与 switch 相反,match 不允许重复 case 标签(重复即 fail-fast);
  • fallthrough 只能出现在 switch 的 case 体内,写在别处(含 match 的 case 体)一律 fail-fast。

关键字性质

switch、match、struct、fallthrough 均为硬关键字(语句起始处不可再作标识符);case 仅在 match/switch 套件内消费,default 仅在 switch 套件内作默认分支关键字。

assert 语句

assert 编译为一次 testcheck.check 调用,并自动为该模块注入 import testcheck:

assert ptr != None, "null pointer"

等价于

testcheck.check(ptr != None, None, "null pointer")

口径:

  • 三个实参依次是 条件、None(ok_msg 传 None:条件成立时静默,不产生 PASS 计数)、信息;
  • 条件成立 → 静默通过;条件不成立 → 由 testcheck 记为 FAIL 并打印 FAIL: 信息;
  • 信息必须是字符串(字符串字面量 / f-string / str 变量或属性),否则 fail-fast;省略信息时用 "assertion failed";
  • 不中止程序(不再 printf AssertionError 或 exit(1));
  • testcheck 依赖 w32.win32console,在不支持 w32 的目标里使用 assert 会在链接期缺符号;
  • 仅在函数体内生效(模块顶层语句本就不翻译)。

with 语句

with 语句用于资源管理,要求对象实现 __enter__ 和 __exit__ 方法:

with File("/test.txt", FA_READ) as f:
    data: int = f.read()

等价 C 代码:

File* f = File_enter(File_new("/test.txt", FA_READ));
int data = File_read(f);
File_exit(f);

协程 async/await(已实现)

async def / await 编译为帧状态机(AsyncGenMixin),运行时由 coro 模块提供 coro_run / coro_sleep / coro_destroy / coro_exception / coro_exception_msg / coro_gather,async_test.vp 提供实证。

await 可与 for / try / except / finally / 自定义异常等组合使用。