feat(match): fallthrough 软关键字 + case 内 break 跳出 match
- vast/Parser:语句位置识别裸 `fallthrough`(仅整条语句命中),脱糖为 c.NoBreak() 标记调用;作标识符的写法不受影响 - HandlesBody:`c.NoBreak()` 标记语句不产出 IR(语义由 HandlesMatch 消费) - HandlesMatch:新增 _HandleMatchCaseBody(case 内 break 目标 = match 的 AfterBB, 经 loop_break_targets 压栈/出栈,不影响外层循环)与 _FallThroughTarget; 9 处 fallthrough 由"只留无终结符块"改为显式 br 下一个 case body
This commit is contained in:
1 parent
9ff301d747
commit
cc0615e519
3 files changed
+107
-10
No files matched your search
@@ -19,7 +19,13 @@ class BodyHandle(BaseHandle):
|
||||
Gen._set_node_info(Node)
|
||||
try:
|
||||
if isinstance(Node, ast.Expr):
|
||||
self.HandleExprLlvm(Node.value)
|
||||
# `fallthrough`(vast 软关键字已脱糖为 c.NoBreak())是 match 的
|
||||
# 标记语句,本身不产出 IR,语义由 HandlesMatch 消费;后续步骤
|
||||
# (含 _EmitTempFrees)保持原样执行。
|
||||
if self._IsNoBreakMarkerStmt(Node):
|
||||
pass
|
||||
else:
|
||||
self.HandleExprLlvm(Node.value)
|
||||
elif isinstance(Node, ast.Return):
|
||||
self.Trans.ReturnHandler._HandleReturnLlvm(Node)
|
||||
elif isinstance(Node, ast.Assign):
|
||||
@@ -79,6 +85,15 @@ class BodyHandle(BaseHandle):
|
||||
if Gen.builder and not Gen.builder.block.is_terminated:
|
||||
Gen._EmitTempFrees()
|
||||
|
||||
@staticmethod
|
||||
def _IsNoBreakMarkerStmt(Node: ast.stmt) -> bool:
|
||||
"""是否 `c.NoBreak()` 标记语句(`fallthrough` 软关键字的脱糖形态)"""
|
||||
if not isinstance(Node, ast.Expr) or not isinstance(Node.value, ast.Call):
|
||||
return False
|
||||
Fn: ast.expr = Node.value.func
|
||||
return (isinstance(Fn, ast.Attribute) and isinstance(Fn.value, ast.Name)
|
||||
and Fn.value.id == 'c' and Fn.attr == 'NoBreak')
|
||||
|
||||
def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None,
|
||||
ConstWidthHint: int | None = None) -> ir.Value | None:
|
||||
return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType, ConstWidthHint)
|
||||
@@ -239,43 +239,53 @@ class MatchHandle(BaseHandle):
|
||||
for j in range(NumSubCases):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchClass):
|
||||
# 兜底处理:MatchClass 在非 REnum 路径的 case body 生成
|
||||
# case 收集阶段已创建 CaseBB,此处生成 body
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
if not HasDefault:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
@@ -285,6 +295,32 @@ class MatchHandle(BaseHandle):
|
||||
Gen.builder.branch(AfterBB)
|
||||
Gen.builder.position_at_start(AfterBB)
|
||||
|
||||
def _HandleMatchCaseBody(self, Gen: "Translator.LlvmGen",
|
||||
Body: list[ast.stmt], AfterBB: ir.Block) -> None:
|
||||
"""翻译 match case 体:case 体内的 break 目标是 match 的 AfterBB
|
||||
|
||||
C switch 语义——case 内 break 跳出 **match**(而非外层循环)。故翻译前把
|
||||
AfterBB 压入 loop_break_targets,翻译完弹出(外层循环目标不受影响)。
|
||||
"""
|
||||
Targets: list = Gen.loop_break_targets
|
||||
Targets.append(AfterBB)
|
||||
try:
|
||||
self.HandleBodyLlvm(Body)
|
||||
finally:
|
||||
Targets.pop()
|
||||
|
||||
@staticmethod
|
||||
def _FallThroughTarget(CaseBBs: list[ir.Block], CaseIdx: int, AfterBB: ir.Block) -> ir.Block:
|
||||
"""fallthrough 的落点:下一个 case 的 body(无后继槽位时落到 AfterBB)
|
||||
|
||||
`fallthrough`(vast 软关键字,脱糖为 c.NoBreak())表示"本 case 不自动
|
||||
break",直接落到下一个 case 的 body(对齐 C 的 [[fallthrough]])。
|
||||
"""
|
||||
NextIdx: int = CaseIdx + 1
|
||||
if 0 <= NextIdx < len(CaseBBs):
|
||||
return CaseBBs[NextIdx]
|
||||
return AfterBB
|
||||
|
||||
def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType):
|
||||
@@ -455,36 +491,44 @@ class MatchHandle(BaseHandle):
|
||||
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
|
||||
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast")
|
||||
Gen.variables[bind_name] = elem_ptr
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
for bind_name, _, _, _ in bindings:
|
||||
if bind_name in Gen.variables:
|
||||
del Gen.variables[bind_name]
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchValue):
|
||||
if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB:
|
||||
Gen.builder.position_at_start(CaseBBs[CaseIdx])
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchAs):
|
||||
if pattern.pattern is None:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
elif isinstance(pattern, ast.MatchSequence):
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
self.HandleBodyLlvm(case.body)
|
||||
self._HandleMatchCaseBody(Gen, case.body, AfterBB)
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if not HasNoBreak[i]:
|
||||
Gen.builder.branch(AfterBB)
|
||||
else:
|
||||
Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB))
|
||||
CaseIdx += 1
|
||||
if not HasDefault:
|
||||
Gen.builder.position_at_start(DefaultBB)
|
||||
|
||||
@@ -82,6 +82,11 @@ _STRUCT_EXAMPLE: str = (
|
||||
'struct Node(Base): value: int'
|
||||
)
|
||||
|
||||
# fallthrough 软关键字(语句级):仅当整条语句就是 `fallthrough` 时命中,
|
||||
# 脱糖为 `c.NoBreak()` 标记调用(match 生成侧据此让 case 体不自动 break,
|
||||
# 落到下一个 case)。作标识符/属性的写法逐字不变。
|
||||
_FALLTHROUGH_KEYWORD: str = 'fallthrough'
|
||||
|
||||
|
||||
class Parser(ExprParserMixin):
|
||||
"""Viper/Python 完整语法分析器。"""
|
||||
@@ -186,6 +191,13 @@ class Parser(ExprParserMixin):
|
||||
return self._ParseMatch()
|
||||
except SyntaxError:
|
||||
self.Idx = save
|
||||
# fallthrough 软关键字(语句级):仅当整条语句就是 `fallthrough`
|
||||
# (后随 NEWLINE / ';' / ENDMARKER)时命中,脱糖为 `c.NoBreak()`
|
||||
# 标记调用,由 match 生成侧消费(case 体因此不自动 break)。
|
||||
# 作标识符/属性的写法(fallthrough = 1 / fallthrough(x) /
|
||||
# d.fallthrough)不命中,逐字不变。
|
||||
if v == _FALLTHROUGH_KEYWORD and self._IsFallThroughStmt():
|
||||
return self._ParseFallThrough()
|
||||
if v == 'return':
|
||||
return self._ParseReturn()
|
||||
if v == 'raise':
|
||||
@@ -224,6 +236,32 @@ class Parser(ExprParserMixin):
|
||||
return self._ParseDecorated()
|
||||
return self._ParseSimpleStmt()
|
||||
|
||||
# ==================================================================
|
||||
# fallthrough 软关键字(语句级)
|
||||
# ==================================================================
|
||||
def _IsFallThroughStmt(self) -> bool:
|
||||
"""当前语句是否为软关键字 `fallthrough`(后随 NEWLINE / ';' / ENDMARKER)
|
||||
|
||||
只在"整条语句就是 fallthrough"时命中;`fallthrough = 1`(赋值)、
|
||||
`fallthrough(x)`(调用)、`d.fallthrough`(属性)都不命中。
|
||||
"""
|
||||
nxt: Token = self._Peek(1)
|
||||
if nxt.Type == NEWLINE or nxt.Type == ENDMARKER:
|
||||
return True
|
||||
return nxt.Type == OP and nxt.Value == ';'
|
||||
|
||||
def _ParseFallThrough(self) -> N.stmt:
|
||||
"""`fallthrough` 脱糖为 `c.NoBreak()`(match 生成侧识别的 fallthrough 标记)"""
|
||||
tok: Token = self._Peek()
|
||||
self._Next()
|
||||
marker: N.Call = N.Call(
|
||||
func=N.Attribute(value=N.Name(id='c', ctx=N.Load()),
|
||||
attr='NoBreak', ctx=N.Load()),
|
||||
args=[], keywords=[])
|
||||
node: N.Expr = N.Expr(value=marker)
|
||||
self._FixLoc(node, tok)
|
||||
return node
|
||||
|
||||
# ==================================================================
|
||||
# 简单语句
|
||||
# ==================================================================
|
||||
|
||||
Reference in new issue
Block a user