fix(switch): case 标签支持裸名(按值引用)并给出常量标签 fail-fast

- 裸名在 match 里是捕获模式(MatchAs),switch 里对齐 C 的 `case NAME:` 语义,
  三端解析均归一为 MatchValue(Name);`_` 仍作通配(等价 default)
- includes/ast/parser.vp、lib/vast/Parser.py、lib/vast_c/vast_c.c 同步实现
- HandlesMatch:case 标签求值非编译期常量时 fail-fast(原先会因取 .constant 崩成
  AttributeError),报文明确“case 标签必须是编译期常量”
This commit is contained in:
TermiNexus committed 2026-10-03 00:14:51 +08:00
1 parent 61df58334f
commit d6eefcbece
3 files changed
+90

No files matched your search

+58
View File
@@ -6456,6 +6456,17 @@ static int SwitchPatAllowed(PyObject *Pat) {
|| strcmp(N, "MatchClass") == 0) {
return 1;
}
/* 通配 `case _`(MatchAs 无子模式)等价 default */
if (strcmp(N, "MatchAs") == 0) {
PyObject *Inner = PyObject_GetAttrString(Pat, "pattern");
if (Inner == NULL) {
PyErr_Clear();
return 0;
}
int IsWild = (Inner == Py_None);
Py_DECREF(Inner);
return IsWild;
}
if (strcmp(N, "MatchOr") == 0) {
PyObject *Pats = PyObject_GetAttrString(Pat, "patterns");
if (Pats == NULL) {
@@ -6479,6 +6490,52 @@ static int SwitchPatAllowed(PyObject *Pat) {
return 0;
}
/* switch 的 case 标签修正:裸名按**值引用**处理
*
* match 里裸名是捕获模式(MatchAs,pattern=None),switch 里对齐 C 的 `case NAME:`
* 语义 —— 归一为 MatchValue(Name(name, Load));`_`(name=None)仍是通配,原样保留。 */
static PyObject *SwitchLabelFromPattern(Parser *P, PyObject *Pat) {
if (Pat == NULL || strcmp(Py_TYPE(Pat)->tp_name, "MatchAs") != 0) {
return Pat;
}
PyObject *Inner = PyObject_GetAttrString(Pat, "pattern");
PyObject *NameStr = PyObject_GetAttrString(Pat, "name");
if (Inner == NULL || NameStr == NULL) {
PyErr_Clear();
Py_XDECREF(Inner);
Py_XDECREF(NameStr);
return Pat;
}
int IsBareName = (Inner == Py_None && NameStr != Py_None);
Py_DECREF(Inner);
if (!IsBareName) {
Py_DECREF(NameStr);
return Pat;
}
PyObject *Load = MakeCtx(P, "Load");
if (Load == NULL) {
Py_DECREF(NameStr);
return Pat;
}
PyObject *NameArgv[2] = { NameStr, Load };
PyObject *NameNode = NewNode(P, "Name", NameArgv, 2);
Py_DECREF(Load);
if (NameNode == NULL) {
Py_DECREF(NameStr);
return Pat;
}
/* Name 文本已在 NameNode 内自持,可安全释放 */
Py_DECREF(NameStr);
PyObject *MvArgv[1] = { NameNode };
PyObject *Mv = NewNode(P, "MatchValue", MvArgv, 1);
Py_DECREF(NameNode);
if (Mv == NULL) {
return Pat;
}
Py_DECREF(Pat);
return Mv;
}
/* switch 语句(C switch 语义):脱糖为 is_switch=True 的 Match
*
* switch <expr>:
@@ -6523,6 +6580,7 @@ static PyObject *ParseSwitch(Parser *P) {
Py_DECREF(Subject);
return NULL;
}
Pattern = SwitchLabelFromPattern(P, Pattern);
if (!SwitchPatAllowed(Pattern)) {
SyntaxErrorAt(P, CaseStart,
"switch case label must be a constant or enum variant");