feat(match): case 内 break 跳出 match,并落地 fallthrough
- Translator:新增 _in_match_case(FallThrough 合法性判定用);_break_bb 注释补充 case 内 break 语义 - StmtGenDeclMixin:新增 translate_fallthrough(本身不产出 IR;非 case 体内 fail-fast) - StmtGenMixin:FallThrough 语句分派 - MatchGenMixin:进出 case 体(含 default 臂)时暂存/覆盖 _break_bb = match end_bb, 使 case 内 break 跳出 match 而非外层循环;_has_no_break 兼容 FallThrough 标记; REnum / simple 两条 switch 路径的 fallthrough 由"只留无终结符块"改为显式 br 下一个 case body(原实现产出非法 IR)
This commit is contained in:
1 parent
0b7f7a50c7
commit
43d25e58b9
4 files changed
+106
-9
No files matched your search
@@ -215,9 +215,11 @@ novirtual class MatchGenMixin:
|
||||
return self.Gen.ClassGenEnum._lookup_renum_variant(variant_name)
|
||||
|
||||
# ============================================================
|
||||
# _has_no_break - 检测 case body 是否含 c.NoBreak() 调用
|
||||
# _has_no_break - 检测 case body 是否要求 fallthrough(落到下一个 case)
|
||||
#
|
||||
# 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak')))
|
||||
# 两种写法等价:
|
||||
# ① 软关键字语句 `fallthrough`(ASTKind.FallThrough)
|
||||
# ② 兼容写法 `c.NoBreak()`:Expr(Call(Attribute(Name('c'), 'NoBreak')))
|
||||
# ============================================================
|
||||
def _has_no_break(self, body_list: list[ast.AST*]*) -> int:
|
||||
if body_list is None:
|
||||
@@ -226,6 +228,8 @@ novirtual class MatchGenMixin:
|
||||
i: int = 0
|
||||
while i < n:
|
||||
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
|
||||
@@ -560,6 +564,13 @@ novirtual class MatchGenMixin:
|
||||
# 定位到 case BB
|
||||
llvmlite.position_at_end(builder, case_bb)
|
||||
|
||||
# case 体内 break = 跳出 match(C switch 语义):暂存外层循环的
|
||||
# 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
|
||||
|
||||
# 进入 case 作用域(变体字段绑定隔离)
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
|
||||
@@ -606,15 +617,29 @@ novirtual class MatchGenMixin:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||||
bi = bi + 1
|
||||
|
||||
# 退出 case 作用域
|
||||
# 退出 case 作用域,并恢复 break 目标 / match-case 标记
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = rmb_old_break
|
||||
trans._in_match_case = rmb_old_inmc
|
||||
|
||||
# 若未终止且无 NoBreak,跳到 end
|
||||
# 若未终止:默认跳 end;含 fallthrough(`fallthrough` 标记或兼容的
|
||||
# c.NoBreak())则落到下一个 case 的 body(跳过其模式检查)。
|
||||
# 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||||
and nb == 0 \
|
||||
and self._case_tail_unreachable(trans, builder, body_list) == 0:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
if nb == 0:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
else:
|
||||
rmb_ft_nj: int = i + 1
|
||||
while rmb_ft_nj < collected and def_arr[rmb_ft_nj] != 0:
|
||||
rmb_ft_nj = rmb_ft_nj + 1
|
||||
if rmb_ft_nj < collected:
|
||||
rmb_ft_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](bb_arr[rmb_ft_nj])
|
||||
llvmlite.build_br(builder, rmb_ft_bb)
|
||||
elif has_default != 0:
|
||||
llvmlite.build_br(builder, default_bb)
|
||||
else:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
trans._ctrl_merge_reachable = 1
|
||||
rm_merge_reach = 1
|
||||
|
||||
@@ -633,6 +658,11 @@ novirtual class MatchGenMixin:
|
||||
# (不再经 def_arr 槽位反查 cases_list:collected 下标与原始下标
|
||||
# 在"有臂被跳过"时会错位,default_bb 随之空转)
|
||||
dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node)
|
||||
# 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
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||||
@@ -647,6 +677,8 @@ novirtual class MatchGenMixin:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt3)
|
||||
dj3 = dj3 + 1
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = rmd_old_break
|
||||
trans._in_match_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:
|
||||
@@ -1024,6 +1056,11 @@ novirtual class MatchGenMixin:
|
||||
llvmlite.position_at_end(builder, bbb3)
|
||||
cnode2: ast.AST* = cases_list.get(ci)
|
||||
mc3: rawptr[ast.MatchCase] = (rawptr[ast.MatchCase])(cnode2)
|
||||
# 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
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
body_list2: list[ast.AST*]* = mc3.children
|
||||
if body_list2 is not None:
|
||||
@@ -1035,6 +1072,8 @@ novirtual class MatchGenMixin:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||||
bi = bi + 1
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = sqb_old_break
|
||||
trans._in_match_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:
|
||||
@@ -1063,6 +1102,11 @@ novirtual class MatchGenMixin:
|
||||
# 直接翻译 pass1 记录的 `case _` 臂(不再经 def_arr 槽位反查 cases_list:
|
||||
# collected 下标与原始下标在"有臂被跳过"时会错位,default_bb 随之空转)
|
||||
dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node)
|
||||
# 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
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||||
@@ -1078,6 +1122,8 @@ novirtual class MatchGenMixin:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt3)
|
||||
dj3 = dj3 + 1
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = sqd_old_break
|
||||
trans._in_match_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:
|
||||
@@ -1267,6 +1313,12 @@ novirtual class MatchGenMixin:
|
||||
|
||||
llvmlite.position_at_end(builder, case_bb)
|
||||
|
||||
# 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
|
||||
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
@@ -1280,12 +1332,27 @@ novirtual class MatchGenMixin:
|
||||
bi = bi + 1
|
||||
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = smb_old_break
|
||||
trans._in_match_case = smb_old_inmc
|
||||
|
||||
# 若未终止:默认跳 end;含 fallthrough(`fallthrough` 标记或兼容的
|
||||
# c.NoBreak())则落到下一个 case 的 body(跳过其模式检查)。
|
||||
# 末句控制流全 return → 补 unreachable(不 br end_bb)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
|
||||
and nb == 0 \
|
||||
and self._case_tail_unreachable(trans, builder, body_list) == 0:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
if nb == 0:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
else:
|
||||
sm_ft_nj: int = i + 1
|
||||
while sm_ft_nj < collected and def_arr[sm_ft_nj] != 0:
|
||||
sm_ft_nj = sm_ft_nj + 1
|
||||
if sm_ft_nj < collected:
|
||||
sm_ft_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](bb_arr[sm_ft_nj])
|
||||
llvmlite.build_br(builder, sm_ft_bb)
|
||||
elif has_default != 0:
|
||||
llvmlite.build_br(builder, default_bb)
|
||||
else:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
trans._ctrl_merge_reachable = 1
|
||||
sm_merge_reach = 1
|
||||
|
||||
@@ -1303,6 +1370,11 @@ novirtual class MatchGenMixin:
|
||||
# 直接翻译 pass1 记录的 `case _` 臂(不再经 def_arr 槽位反查 cases_list:
|
||||
# collected 下标与原始下标在"有臂被跳过"时会错位,default_bb 随之空转)
|
||||
dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node)
|
||||
# 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
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。
|
||||
@@ -1317,6 +1389,8 @@ novirtual class MatchGenMixin:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt3)
|
||||
dj3 = dj3 + 1
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
trans._break_bb = smd_old_break
|
||||
trans._in_match_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:
|
||||
|
||||
@@ -280,6 +280,20 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
llvmlite.position_at_end(builder, dead_bb)
|
||||
return 0
|
||||
|
||||
def translate_fallthrough(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
"""翻译 `fallthrough` 标记语句:本身不产出任何 IR
|
||||
|
||||
语义由 match 生成侧消费——case 体含该标记时末尾不自动 break,直接落到
|
||||
下一个 case 体(对齐 C 的 [[fallthrough]])。合法位置只有 match-case
|
||||
语句体;出现在别处只会静默无效果,故 fail-fast 暴露。
|
||||
"""
|
||||
if trans is None:
|
||||
return 0
|
||||
if trans._in_match_case == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node,
|
||||
"fallthrough 只能用在 match-case 语句体内(语义是落到下一个 case)", "SyntaxError")
|
||||
return 0
|
||||
|
||||
def translate_continue(self, trans: HT.Translator*) -> int:
|
||||
"""翻译 continue 语句:跳转到循环 cond/incr 块"""
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
|
||||
@@ -90,6 +90,8 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
return self.translate_break(trans)
|
||||
elif k == ast.ASTKind.Continue:
|
||||
return self.translate_continue(trans)
|
||||
elif k == ast.ASTKind.FallThrough:
|
||||
return self.translate_fallthrough(trans, node)
|
||||
elif k == ast.ASTKind.Match:
|
||||
return self.Gen.MatchGen.translate_match(trans, node)
|
||||
elif k == ast.ASTKind.Delete:
|
||||
|
||||
@@ -170,10 +170,16 @@ novirtual class Translator:
|
||||
# 的直接值」时才用 CurFuncRetAnnot(嵌套调用如 return f(Stack()) 不推断)。
|
||||
CurRetNode: ast.AST*
|
||||
|
||||
# 循环控制流目标(break/continue)
|
||||
# 循环控制流目标(break/continue)。注意 match-case 体内的 break 语义是
|
||||
# "跳出 match":MatchGenMixin 进出 case 体时暂存并把 _break_bb 覆盖为 match
|
||||
# 的 end_bb(出 case 恢复),故 case 内 break 不会误跳外层循环。
|
||||
_break_bb: rawptr[llvmlite.BasicBlock]
|
||||
_continue_bb: rawptr[llvmlite.BasicBlock]
|
||||
|
||||
# 是否正处于 match-case 语句体内(1=是)。供 `fallthrough` 语句判定合法性
|
||||
# (只在 case 体内合法,别处 fail-fast),由 MatchGenMixin 进出 case 时置位。
|
||||
_in_match_case: int
|
||||
|
||||
# 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调)
|
||||
_label_counter: int
|
||||
|
||||
@@ -291,6 +297,7 @@ novirtual class Translator:
|
||||
self._cur_builder = None
|
||||
self._break_bb = None
|
||||
self._continue_bb = None
|
||||
self._in_match_case = 0
|
||||
self._label_counter = 0
|
||||
self._imported_modules = None
|
||||
self._from_imports = None
|
||||
|
||||
Reference in new issue
Block a user