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:
1 parent
61df58334f
commit
d6eefcbece
3 files changed
+90
No files matched your search
@@ -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");
|
||||
|
||||
Reference in new issue
Block a user