feat(switch): 新增 switch 语句并禁止 match 内 fallthrough
- MatchGenMixin:case 体按 node.is_switch 置 _in_switch_case;_has_no_break 只认 FallThrough 节点(去掉 c.NoBreak() 兼容路径) - StmtGenDeclMixin:translate_fallthrough 只在 switch 的 case 体内合法,match/switch 之外 fail-fast - Translator:_in_match_case 更名 _in_switch_case(语义 = 当前 case 体属于 switch) - FuncGenDef / FuncGenMixin:函数体 / 嵌套函数 / lambda 入口隔离并恢复 _in_switch_case - 因 match 改为硬关键字,重命名同名局部变量 match -> Matched(StubMergerStore / ImportsGenMixin / ExprGenAttr / CallGenBase)
This commit is contained in:
1 parent
38860a6313
commit
fabd92adc7
9 files changed
+78
-84
No files matched your search
@@ -554,14 +554,14 @@ def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||||
local_len: sizet = colon - ci
|
||||
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
|
||||
# 比较 local_name == alias
|
||||
match: int = 1
|
||||
Matched: int = 1
|
||||
li: sizet = 0
|
||||
while li < alias_len:
|
||||
if from_imports[ci + li] != alias[li]:
|
||||
match = 0
|
||||
Matched = 0
|
||||
break
|
||||
li += 1
|
||||
if match == 1:
|
||||
if Matched == 1:
|
||||
# 提取 module(colon+1 到下一个 ':' 或空格)
|
||||
m_start: sizet = colon + 1
|
||||
m_end: sizet = m_start
|
||||
@@ -609,14 +609,14 @@ def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||||
local_len: sizet = colon - ci
|
||||
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
|
||||
# 比较 local_name == alias
|
||||
match: int = 1
|
||||
Matched: int = 1
|
||||
li: sizet = 0
|
||||
while li < alias_len:
|
||||
if from_imports[ci + li] != alias[li]:
|
||||
match = 0
|
||||
Matched = 0
|
||||
break
|
||||
li += 1
|
||||
if match == 1:
|
||||
if Matched == 1:
|
||||
# 提取 module(colon+1 到下一个 ':' 或空格)
|
||||
m_start: sizet = colon + 1
|
||||
m_end: sizet = m_start
|
||||
|
||||
@@ -603,12 +603,12 @@ novirtual class CallGenBase:
|
||||
if cur_len > name_len + 1:
|
||||
suffix_start: sizet = cur_len - name_len
|
||||
if cur_name[suffix_start - 1] == '.':
|
||||
match: int = 1
|
||||
Matched: int = 1
|
||||
for i in range(name_len):
|
||||
if cur_name[suffix_start + i] != name[i]:
|
||||
match = 0
|
||||
Matched = 0
|
||||
break
|
||||
if match == 1:
|
||||
if Matched == 1:
|
||||
# 首个任意后缀命中(原第三遍兜底)
|
||||
if any_hit is None:
|
||||
any_hit = cur
|
||||
|
||||
@@ -50,12 +50,12 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if cur_len > name_len + 1:
|
||||
suffix_start: sizet = cur_len - name_len
|
||||
if cur.Name[suffix_start - 1] == '.':
|
||||
match: int = 1
|
||||
Matched: int = 1
|
||||
for i in range(name_len):
|
||||
if cur.Name[suffix_start + i] != name[i]:
|
||||
match = 0
|
||||
Matched = 0
|
||||
break
|
||||
if match == 1:
|
||||
if Matched == 1:
|
||||
return cur
|
||||
cur = cur.Next
|
||||
return None
|
||||
|
||||
@@ -896,14 +896,14 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
# 否则嵌套函数体内的 break/continue 会继承外层函数(甚至跨函数)的 br 目标
|
||||
old_break_bb: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
old_continue_bb: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||||
old_inmc: int = trans._in_match_case
|
||||
old_insw: int = trans._in_switch_case
|
||||
|
||||
trans._cur_func = func
|
||||
trans._cur_builder = func_builder
|
||||
trans.CurFuncRetAnnot = fd.returns
|
||||
trans._break_bb = None
|
||||
trans._continue_bb = None
|
||||
trans._in_match_case = 0
|
||||
trans._in_switch_case = 0
|
||||
# 清空 global/nonlocal 名称集合(新函数作用域)
|
||||
GenApi.clear_scope_names(trans)
|
||||
# 重置链内 nonlocal 堆预建标志(每函数只建一次;多嵌套函数定义
|
||||
@@ -1050,7 +1050,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
trans._cur_builder = old_builder
|
||||
trans._break_bb = old_break_bb
|
||||
trans._continue_bb = old_continue_bb
|
||||
trans._in_match_case = old_inmc
|
||||
trans._in_switch_case = old_insw
|
||||
trans._global_name_count = old_global_count
|
||||
trans._nonlocal_name_count = old_nonlocal_count
|
||||
trans._closure_env_count = old_env_count
|
||||
|
||||
@@ -185,7 +185,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
# 否则嵌套函数体内的 break/continue 会继承外层函数的跳转目标(跨函数 br)
|
||||
old_break_bb: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
old_continue_bb: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||||
old_inmc: int = trans._in_match_case
|
||||
old_insw: int = trans._in_switch_case
|
||||
# nonlocal 集合独立缓冲:嵌套函数注册 nonlocal 写入共享缓冲 [0] 会
|
||||
# 覆盖父函数集合(ClosureTest2 Test 7 不同变量场景:level2 的 b 覆盖
|
||||
# level1 的 a → level1 env[0] 存错)。嵌套函数用独立缓冲,翻译完恢复。
|
||||
@@ -199,7 +199,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
GenApi.clear_scope_names(trans)
|
||||
trans._break_bb = None
|
||||
trans._continue_bb = None
|
||||
trans._in_match_case = 0
|
||||
trans._in_switch_case = 0
|
||||
# 嵌套函数独立 nonlocal 缓冲(避免覆盖父函数集合)
|
||||
trans._nonlocal_names = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8)
|
||||
trans._nonlocal_types = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8)
|
||||
@@ -264,7 +264,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
trans._cur_builder = old_builder
|
||||
trans._break_bb = old_break_bb
|
||||
trans._continue_bb = old_continue_bb
|
||||
trans._in_match_case = old_inmc
|
||||
trans._in_switch_case = old_insw
|
||||
if dbg_pushed_n != 0:
|
||||
DebugInfoGen.PopFunction(func_builder)
|
||||
# NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值
|
||||
@@ -1163,14 +1163,14 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
# 否则 lambda 体内的 break/continue 会继承外层函数的跳转目标(跨函数 br)
|
||||
old_break_bb: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
old_continue_bb: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||||
old_inmc: int = trans._in_match_case
|
||||
old_insw: int = trans._in_switch_case
|
||||
trans._cur_func = func
|
||||
trans._cur_builder = func_builder
|
||||
trans._cur_func_name = mangled_promoted
|
||||
GenApi.clear_scope_names(trans)
|
||||
trans._break_bb = None
|
||||
trans._continue_bb = None
|
||||
trans._in_match_case = 0
|
||||
trans._in_switch_case = 0
|
||||
|
||||
# 9. 捕获变量:从 env 堆槽加载值到局部 alloca
|
||||
for ci in range(cap_count):
|
||||
@@ -1237,7 +1237,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
trans._cur_builder = old_builder
|
||||
trans._break_bb = old_break_bb
|
||||
trans._continue_bb = old_continue_bb
|
||||
trans._in_match_case = old_inmc
|
||||
trans._in_switch_case = old_insw
|
||||
trans._cur_func_name = old_func_name
|
||||
trans._global_name_count = old_global_count
|
||||
trans._nonlocal_name_count = old_nonlocal_count
|
||||
|
||||
@@ -220,12 +220,12 @@ novirtual class ImportsGenMixin:
|
||||
ci += 1
|
||||
word_len: sizet = ci - word_start
|
||||
if word_len == name_len:
|
||||
match: int = 1
|
||||
Matched: int = 1
|
||||
for ei in range(name_len):
|
||||
if cur[word_start + ei] != name[ei]:
|
||||
match = 0
|
||||
Matched = 0
|
||||
break
|
||||
if match == 1:
|
||||
if Matched == 1:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -348,14 +348,14 @@ novirtual class ImportsGenMixin:
|
||||
continue
|
||||
# 比较名称
|
||||
if entry_name_len == name_len:
|
||||
match: int = 1
|
||||
Matched: int = 1
|
||||
ei: sizet = 0
|
||||
while ei < name_len:
|
||||
if cur[ci + ei] != local_name[ei]:
|
||||
match = 0
|
||||
Matched = 0
|
||||
break
|
||||
ei += 1
|
||||
if match == 1:
|
||||
if Matched == 1:
|
||||
# 找到匹配,检查是否有第三个字段(原始名)
|
||||
pos: sizet = colon1 + 1
|
||||
# 跳过模块名
|
||||
@@ -440,14 +440,14 @@ novirtual class ImportsGenMixin:
|
||||
star_mod = cur + mod_start
|
||||
# 比较名称
|
||||
elif entry_name_len == name_len:
|
||||
match: int = 1
|
||||
Matched: int = 1
|
||||
ei: sizet = 0
|
||||
while ei < name_len:
|
||||
if cur[ci + ei] != name[ei]:
|
||||
match = 0
|
||||
Matched = 0
|
||||
break
|
||||
ei += 1
|
||||
if match == 1:
|
||||
if Matched == 1:
|
||||
mod_start2: sizet = colon_pos + 1
|
||||
mod_end2: sizet = mod_start2
|
||||
# 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符)
|
||||
|
||||
@@ -91,8 +91,14 @@ novirtual class MatchGenMixin:
|
||||
m_node: ast.Match* = ast.Match*(node)
|
||||
|
||||
# 重名 case 检测(fail-fast):C 的 switch 不允许重复 case 标签(重复标签让
|
||||
# 某个臂永远不可达,且常意味着漏改的分支);`case _`(default)只允许一个。
|
||||
# 在任何 IR 产出之前检查,保证报错即终止。
|
||||
# 某个臂永远不可达,且常意味着漏改的分支);通配臂(match 的 `case _` /
|
||||
# switch 的 `default`)只允许一个。在任何 IR 产出之前检查,保证报错即终止。
|
||||
# 报文前缀按 is_switch 区分(switch / match),便于定位。
|
||||
kind_label: str = "match"
|
||||
default_label: str = "`case _`"
|
||||
if m_node.is_switch != 0:
|
||||
kind_label = "switch"
|
||||
default_label = "`default`"
|
||||
cases_chk: list[ast.AST*]* = m_node.cases
|
||||
if cases_chk is not None:
|
||||
ccn: sizet = len(cases_chk)
|
||||
@@ -114,13 +120,13 @@ novirtual class MatchGenMixin:
|
||||
dpat2: ast.AST* = rawptr[ast.MatchCase](dcase2).pattern
|
||||
if self._case_label_same(dpat, dpat2) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(dcase2,
|
||||
f"match 出现重名 case:第 {dci} 与第 {dcj} 个 case 的标签相同(C switch 不允许重复 case 标签)",
|
||||
f"{kind_label} 出现重名 case:第 {dci} 与第 {dcj} 个 case 的标签相同(C switch 不允许重复 case 标签)",
|
||||
"SyntaxError")
|
||||
dcj = dcj + 1
|
||||
dci = dci + 1
|
||||
if default_cnt > 1:
|
||||
self.Gen.TypeGenErr.fatal_error(node,
|
||||
f"match 出现 {default_cnt} 个 `case _`(default 只允许一个)", "SyntaxError")
|
||||
f"{kind_label} 出现 {default_cnt} 个 {default_label}(通配/default 只允许一个)", "SyntaxError")
|
||||
|
||||
# 1. 求值 subject
|
||||
subject_node: ast.AST* = m_node.subject
|
||||
@@ -330,9 +336,9 @@ novirtual class MatchGenMixin:
|
||||
# ============================================================
|
||||
# _has_no_break - 检测 case body 是否要求 fallthrough(落到下一个 case)
|
||||
#
|
||||
# 两种写法等价:
|
||||
# ① 软关键字语句 `fallthrough`(ASTKind.FallThrough)
|
||||
# ② 兼容写法 `c.NoBreak()`:Expr(Call(Attribute(Name('c'), 'NoBreak')))
|
||||
# 只认 `fallthrough` 关键字语句(ASTKind.FallThrough)。该语句只可能在 switch
|
||||
# 的 case 体内出现(translate_fallthrough 已对 match / switch 之外 fail-fast),
|
||||
# 故此处无需再判上下文。
|
||||
# ============================================================
|
||||
def _has_no_break(self, body_list: list[ast.AST*]*) -> int:
|
||||
if body_list is None:
|
||||
@@ -343,22 +349,6 @@ novirtual class MatchGenMixin:
|
||||
stmt: ast.AST* = body_list.get(i)
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.FallThrough:
|
||||
return 1
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.Expr:
|
||||
expr_node: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
|
||||
val: ast.AST* = expr_node.value
|
||||
if val is not None and val.kind() == ast.ASTKind.Call:
|
||||
call_node: ast.Call* = ast.Call*(val)
|
||||
fn: ast.AST* = call_node.func
|
||||
if fn is not None and fn.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = (ast.Attribute*)(fn)
|
||||
if at.value is not None \
|
||||
and at.value.kind() == ast.ASTKind.Name:
|
||||
base_nm: ast.Name* = (ast.Name*)(at.value)
|
||||
if base_nm.id is not None \
|
||||
and string.strcmp(base_nm.id, "c") == 0 \
|
||||
and at.attr is not None \
|
||||
and string.strcmp(at.attr, "NoBreak") == 0:
|
||||
return 1
|
||||
i = i + 1
|
||||
return 0
|
||||
|
||||
@@ -681,8 +671,8 @@ novirtual class MatchGenMixin:
|
||||
# break 目标并覆盖为 match 的 end_bb,出 case 时恢复。
|
||||
rmb_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
trans._break_bb = end_bb
|
||||
rmb_old_inmc: int = trans._in_match_case
|
||||
trans._in_match_case = 1
|
||||
rmb_old_inmc: int = trans._in_switch_case
|
||||
trans._in_switch_case = node.is_switch
|
||||
|
||||
# 进入 case 作用域(变体字段绑定隔离)
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
@@ -733,7 +723,7 @@ novirtual class MatchGenMixin:
|
||||
# 退出 case 作用域,并恢复 break 目标 / match-case 标记
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = rmb_old_break
|
||||
trans._in_match_case = rmb_old_inmc
|
||||
trans._in_switch_case = rmb_old_inmc
|
||||
|
||||
# 若未终止:默认跳 end;含 fallthrough(`fallthrough` 标记或兼容的
|
||||
# c.NoBreak())则落到下一个 case 的 body(跳过其模式检查)。
|
||||
@@ -774,8 +764,8 @@ novirtual class MatchGenMixin:
|
||||
# default 臂同样按 match-case 语义:break = 跳出 match
|
||||
rmd_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
trans._break_bb = end_bb
|
||||
rmd_old_inmc: int = trans._in_match_case
|
||||
trans._in_match_case = 1
|
||||
rmd_old_inmc: int = trans._in_switch_case
|
||||
trans._in_switch_case = 1
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||||
@@ -791,7 +781,7 @@ novirtual class MatchGenMixin:
|
||||
dj3 = dj3 + 1
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = rmd_old_break
|
||||
trans._in_match_case = rmd_old_inmc
|
||||
trans._in_switch_case = rmd_old_inmc
|
||||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||||
and self._case_tail_unreachable(trans, builder, dbody3) == 0:
|
||||
@@ -1172,8 +1162,8 @@ novirtual class MatchGenMixin:
|
||||
# case 体内 break = 跳出 match(C switch 语义):暂存/覆盖 _break_bb
|
||||
sqb_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
trans._break_bb = end_bb
|
||||
sqb_old_inmc: int = trans._in_match_case
|
||||
trans._in_match_case = 1
|
||||
sqb_old_inmc: int = trans._in_switch_case
|
||||
trans._in_switch_case = 1
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
body_list2: list[ast.AST*]* = mc3.children
|
||||
if body_list2 is not None:
|
||||
@@ -1186,7 +1176,7 @@ novirtual class MatchGenMixin:
|
||||
bi = bi + 1
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = sqb_old_break
|
||||
trans._in_match_case = sqb_old_inmc
|
||||
trans._in_switch_case = sqb_old_inmc
|
||||
# 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||||
and self._case_tail_unreachable(trans, builder, body_list2) == 0:
|
||||
@@ -1218,8 +1208,8 @@ novirtual class MatchGenMixin:
|
||||
# default 臂同样按 match-case 语义:break = 跳出 match
|
||||
sqd_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
trans._break_bb = end_bb
|
||||
sqd_old_inmc: int = trans._in_match_case
|
||||
trans._in_match_case = 1
|
||||
sqd_old_inmc: int = trans._in_switch_case
|
||||
trans._in_switch_case = 1
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||||
@@ -1236,7 +1226,7 @@ novirtual class MatchGenMixin:
|
||||
dj3 = dj3 + 1
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = sqd_old_break
|
||||
trans._in_match_case = sqd_old_inmc
|
||||
trans._in_switch_case = sqd_old_inmc
|
||||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||||
and self._case_tail_unreachable(trans, builder, dbody) == 0:
|
||||
@@ -1429,8 +1419,8 @@ novirtual class MatchGenMixin:
|
||||
# case 体内 break = 跳出 match(C switch 语义):暂存/覆盖 _break_bb
|
||||
smb_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
trans._break_bb = end_bb
|
||||
smb_old_inmc: int = trans._in_match_case
|
||||
trans._in_match_case = 1
|
||||
smb_old_inmc: int = trans._in_switch_case
|
||||
trans._in_switch_case = 1
|
||||
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
|
||||
@@ -1446,7 +1436,7 @@ novirtual class MatchGenMixin:
|
||||
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = smb_old_break
|
||||
trans._in_match_case = smb_old_inmc
|
||||
trans._in_switch_case = smb_old_inmc
|
||||
|
||||
# 若未终止:默认跳 end;含 fallthrough(`fallthrough` 标记或兼容的
|
||||
# c.NoBreak())则落到下一个 case 的 body(跳过其模式检查)。
|
||||
@@ -1486,8 +1476,8 @@ novirtual class MatchGenMixin:
|
||||
# default 臂同样按 match-case 语义:break = 跳出 match
|
||||
smd_old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
|
||||
trans._break_bb = end_bb
|
||||
smd_old_inmc: int = trans._in_match_case
|
||||
trans._in_match_case = 1
|
||||
smd_old_inmc: int = trans._in_switch_case
|
||||
trans._in_switch_case = node.is_switch
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||||
@@ -1503,7 +1493,7 @@ novirtual class MatchGenMixin:
|
||||
dj3 = dj3 + 1
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = smd_old_break
|
||||
trans._in_match_case = smd_old_inmc
|
||||
trans._in_switch_case = smd_old_inmc
|
||||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||||
and self._case_tail_unreachable(trans, builder, dbody3) == 0:
|
||||
|
||||
@@ -266,11 +266,11 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
|
||||
# 发射 br 到 break 目标(_break_bb 由循环或 match-case 生成侧设置)
|
||||
# 发射 br 到 break 目标(_break_bb 由循环 / switch / match 的 case 生成侧设置)
|
||||
if trans._break_bb is None:
|
||||
# fail-fast:没有循环 / match-case 时 break 无处可跳,禁止静默无效果
|
||||
# fail-fast:没有循环 / switch / match 时 break 无处可跳,禁止静默无效果
|
||||
self.Gen.TypeGenErr.fatal_error(node,
|
||||
"break 只能用在循环或 match-case 体内(当前没有可跳出的目标)", "SyntaxError")
|
||||
"break 只能用在循环或 switch/match 的 case 体内(当前没有可跳出的目标)", "SyntaxError")
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, trans._break_bb)
|
||||
|
||||
@@ -284,17 +284,19 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
return 0
|
||||
|
||||
def translate_fallthrough(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
"""翻译 `fallthrough` 标记语句:本身不产出任何 IR
|
||||
"""翻译 `fallthrough` 语句:本身不产出任何 IR
|
||||
|
||||
语义由 match 生成侧消费——case 体含该标记时末尾不自动 break,直接落到
|
||||
下一个 case 体(对齐 C 的 [[fallthrough]])。合法位置只有 match-case
|
||||
语句体;出现在别处只会静默无效果,故 fail-fast 暴露。
|
||||
语义由 switch 生成侧消费——case 体含该标记时末尾不自动跳出 switch,直接
|
||||
落到下一个 case 体(对齐 C 的 [[fallthrough]])。合法位置**只有 switch 的
|
||||
case 语句体**;写进 match 的 case 体(match 完全禁止 fallthrough)或
|
||||
switch 之外一律 fail-fast,绝不静默无效果。
|
||||
"""
|
||||
if trans is None:
|
||||
return 0
|
||||
if trans._in_match_case == 0:
|
||||
if trans._in_switch_case == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node,
|
||||
"fallthrough 只能用在 match-case 语句体内(语义是落到下一个 case)", "SyntaxError")
|
||||
"fallthrough 只能用在 switch 的 case 体内(match 完全禁止 fallthrough,"
|
||||
"语义是落到下一个 case)", "SyntaxError")
|
||||
return 0
|
||||
|
||||
def translate_continue(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
|
||||
@@ -176,9 +176,11 @@ novirtual class Translator:
|
||||
_break_bb: rawptr[llvmlite.BasicBlock]
|
||||
_continue_bb: rawptr[llvmlite.BasicBlock]
|
||||
|
||||
# 是否正处于 match-case 语句体内(1=是)。供 `fallthrough` 语句判定合法性
|
||||
# (只在 case 体内合法,别处 fail-fast),由 MatchGenMixin 进出 case 时置位。
|
||||
_in_match_case: int
|
||||
# 当前是否处于 **switch** 的 case 语句体内(1=是)。供 `fallthrough` 语句判定
|
||||
# 合法性:只在 switch 的 case 体内合法;写进 match 的 case 体或 switch 之外
|
||||
# 一律 fail-fast(match 完全禁止 fallthrough)。由 MatchGenMixin 进出 case 时
|
||||
# 置为 `node.is_switch`(真 match=0,switch=1),出 case 恢复。
|
||||
_in_switch_case: int
|
||||
|
||||
# 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调)
|
||||
_label_counter: int
|
||||
@@ -297,7 +299,7 @@ novirtual class Translator:
|
||||
self._cur_builder = None
|
||||
self._break_bb = None
|
||||
self._continue_bb = None
|
||||
self._in_match_case = 0
|
||||
self._in_switch_case = 0
|
||||
self._label_counter = 0
|
||||
self._imported_modules = None
|
||||
self._from_imports = None
|
||||
|
||||
Reference in new issue
Block a user