diff --git a/lib/vast_c/vast_c.c b/lib/vast_c/vast_c.c index a304044..7553a56 100644 --- a/lib/vast_c/vast_c.c +++ b/lib/vast_c/vast_c.c @@ -4329,6 +4329,9 @@ static PyObject *ParseFor(Parser *P, int IsAsync); static PyObject *ParseTry(Parser *P); static PyObject *ParseWith(Parser *P, int IsAsync); static PyObject *ParseMatch(Parser *P); +static PyObject *ParseSwitch(Parser *P); +static PyObject *ParseFallThrough(Parser *P); +static int SwitchPatAllowed(PyObject *Pat); static PyObject *ParseFunctionDef(Parser *P, int IsAsync, PyObject *Decorators); static PyObject *ParseClassDef(Parser *P, PyObject *Decorators); static PyObject *ParseExprList(Parser *P); @@ -4430,9 +4433,8 @@ static PyObject *ParseStatement(Parser *P) { if (TokIsName(T, "class")) { return ParseClassDef(P, NULL); } - /* struct 纯数据类型定义(软关键字:仅"语句起始 + 后随标识符"生效, - * 故 `struct = 5` / `x.struct` 作标识符的写法不受影响) */ - if (TokIsName(T, "struct") && PeekTok(P, 1)->Kind == TK_NAME) { + /* struct 纯数据类型定义(硬关键字:语句起始一律按 struct 定义解析) */ + if (TokIsName(T, "struct")) { return ParseStructDef(P, NULL); } if (TokIsName(T, "if")) { @@ -4450,18 +4452,18 @@ static PyObject *ParseStatement(Parser *P) { if (TokIsName(T, "with")) { return ParseWith(P, 0); } + /* match 多模式匹配(硬关键字:语句起始一律按 match 语句解析) */ if (TokIsName(T, "match")) { - int SaveIdx = P->Idx; - PyObject *M = ParseMatch(P); - if (M != NULL) { - return M; - } - if (PyErr_Occurred()) { - return NULL; - } - P->Idx = SaveIdx; - P->Error = 0; - /* 回退为表达式语句 */ + return ParseMatch(P); + } + /* switch 多分支(硬关键字,C switch 语义):desugar 为 is_switch=True 的 Match */ + if (TokIsName(T, "switch")) { + return ParseSwitch(P); + } + /* fallthrough 关键字(硬):仅在 switch 的 case 体内合法,脱糖为 + * `c.NoBreak()` 标记调用,由 switch 生成侧消费 */ + if (TokIsName(T, "fallthrough")) { + return ParseFallThrough(P); } if (TokIsName(T, "return")) { Token *Start = NextTok(P); @@ -6433,8 +6435,8 @@ static PyObject *ParseMatch(Parser *P) { Py_DECREF(Subject); return NULL; } - PyObject *Argv[2] = { Subject, Cases }; - PyObject *Node = NewNode(P, "Match", Argv, 2); + PyObject *Argv[3] = { Subject, Cases, Py_False }; + PyObject *Node = NewNode(P, "Match", Argv, 3); Py_DECREF(Subject); Py_DECREF(Cases); if (Node != NULL) { @@ -6443,6 +6445,216 @@ static PyObject *ParseMatch(Parser *P) { return Node; } +/* switch 的 case 标签是否合法:只允许常量 / 枚举变体 / 多值或模式 + * (MatchValue / MatchSingleton / MatchClass / MatchOr<上述>) */ +static int SwitchPatAllowed(PyObject *Pat) { + if (Pat == NULL) { + return 0; + } + const char *N = Py_TYPE(Pat)->tp_name; + if (strcmp(N, "MatchValue") == 0 || strcmp(N, "MatchSingleton") == 0 + || strcmp(N, "MatchClass") == 0) { + return 1; + } + if (strcmp(N, "MatchOr") == 0) { + PyObject *Pats = PyObject_GetAttrString(Pat, "patterns"); + if (Pats == NULL) { + PyErr_Clear(); + return 0; + } + if (!PyList_Check(Pats)) { + Py_DECREF(Pats); + return 0; + } + Py_ssize_t Count = PyList_Size(Pats); + int Ok = (Count > 0); + for (Py_ssize_t I = 0; I < Count && Ok; I++) { + if (!SwitchPatAllowed(PyList_GetItem(Pats, I))) { + Ok = 0; + } + } + Py_DECREF(Pats); + return Ok; + } + return 0; +} + +/* switch 语句(C switch 语义):脱糖为 is_switch=True 的 Match + * + * switch : + * case <常量 | 枚举变体>: # 可 `case 1 | 2:` 多值 + * default: + * + * case 标签只支持常量 / 枚举变体 / 多值或模式,不支持 if 守卫。 */ +static PyObject *ParseSwitch(Parser *P) { + Token *Start = NextTok(P); /* switch */ + PyObject *Subject = ParseExpr(P); + if (Subject == NULL) { + return NULL; + } + if (!ExpectOp(P, ":")) { + Py_DECREF(Subject); + return NULL; + } + if (!ExpectNEWLINE(P)) { + Py_DECREF(Subject); + return NULL; + } + Token *IndentTok = NextTok(P); + if (IndentTok->Kind != TK_INDENT) { + SyntaxErrorAt(P, IndentTok, "expected INDENT"); + Py_DECREF(Subject); + return NULL; + } + PyObject *Cases = NewList(); + if (Cases == NULL) { + Py_DECREF(Subject); + return NULL; + } + SkipNEWLINE(P); + while (1) { + PyObject *Pattern = NULL; + Token *CaseStart = NULL; + if (AtName(P, "case")) { + CaseStart = NextTok(P); /* case */ + Pattern = ParsePattern(P); + if (Pattern == NULL) { + Py_DECREF(Cases); + Py_DECREF(Subject); + return NULL; + } + if (!SwitchPatAllowed(Pattern)) { + SyntaxErrorAt(P, CaseStart, + "switch case label must be a constant or enum variant"); + Py_DECREF(Pattern); + Py_DECREF(Cases); + Py_DECREF(Subject); + return NULL; + } + if (AtName(P, "if")) { + SyntaxErrorAt(P, PeekTok(P, 0), "switch case does not support if guard"); + Py_DECREF(Pattern); + Py_DECREF(Cases); + Py_DECREF(Subject); + return NULL; + } + } else if (AtName(P, "default") && TokIsOp(PeekTok(P, 1), ":")) { + CaseStart = NextTok(P); /* default */ + PyObject *WildArgv[2] = { Py_None, Py_None }; + Pattern = NewNode(P, "MatchAs", WildArgv, 2); + if (Pattern == NULL) { + Py_DECREF(Cases); + Py_DECREF(Subject); + return NULL; + } + FixLoc(P, Pattern, CaseStart); + } else { + break; + } + if (!ExpectOp(P, ":")) { + Py_DECREF(Pattern); + Py_DECREF(Cases); + Py_DECREF(Subject); + return NULL; + } + PyObject *CaseBody = ParseSuite(P); + if (CaseBody == NULL) { + Py_DECREF(Pattern); + Py_DECREF(Cases); + Py_DECREF(Subject); + return NULL; + } + PyObject *McArgv[3] = { Pattern, Py_None, CaseBody }; + PyObject *Mc = NewNode(P, "match_case", McArgv, 3); + Py_DECREF(Pattern); + Py_DECREF(CaseBody); + if (Mc == NULL) { + Py_DECREF(Cases); + Py_DECREF(Subject); + return NULL; + } + PyList_Append(Cases, Mc); + Py_DECREF(Mc); + SkipNEWLINE(P); + } + Token *DedentTok = NextTok(P); + if (DedentTok->Kind != TK_DEDENT) { + SyntaxErrorAt(P, DedentTok, "expected DEDENT"); + Py_DECREF(Cases); + Py_DECREF(Subject); + return NULL; + } + PyObject *Argv[3] = { Subject, Cases, Py_True }; + PyObject *Node = NewNode(P, "Match", Argv, 3); + Py_DECREF(Subject); + Py_DECREF(Cases); + if (Node != NULL) { + FixLoc(P, Node, Start); + } + return Node; +} + +/* `fallthrough` 脱糖为 `c.NoBreak()`(switch 生成侧识别的 fallthrough 标记) */ +static PyObject *ParseFallThrough(Parser *P) { + Token *Start = NextTok(P); /* fallthrough */ + PyObject *Load1 = MakeCtx(P, "Load"); + PyObject *IdC = Load1 ? PyUnicode_FromString("c") : NULL; + if (Load1 == NULL || IdC == NULL) { + Py_XDECREF(Load1); + Py_XDECREF(IdC); + return NULL; + } + PyObject *NameArgv[2] = { IdC, Load1 }; + PyObject *NameNode = NewNode(P, "Name", NameArgv, 2); + Py_DECREF(IdC); + Py_DECREF(Load1); + if (NameNode == NULL) { + return NULL; + } + FixLoc(P, NameNode, Start); + PyObject *Load2 = MakeCtx(P, "Load"); + PyObject *AttrStr = Load2 ? PyUnicode_FromString("NoBreak") : NULL; + if (Load2 == NULL || AttrStr == NULL) { + Py_XDECREF(Load2); + Py_XDECREF(AttrStr); + Py_DECREF(NameNode); + return NULL; + } + PyObject *AttrArgv[3] = { NameNode, AttrStr, Load2 }; + PyObject *AttrNode = NewNode(P, "Attribute", AttrArgv, 3); + Py_DECREF(AttrStr); + Py_DECREF(Load2); + Py_DECREF(NameNode); + if (AttrNode == NULL) { + return NULL; + } + FixLoc(P, AttrNode, Start); + PyObject *Args = NewList(); + PyObject *Keywords = NewList(); + if (Args == NULL || Keywords == NULL) { + Py_XDECREF(Args); + Py_XDECREF(Keywords); + Py_DECREF(AttrNode); + return NULL; + } + PyObject *CallArgv[3] = { AttrNode, Args, Keywords }; + PyObject *CallNode = NewNode(P, "Call", CallArgv, 3); + Py_DECREF(Args); + Py_DECREF(Keywords); + Py_DECREF(AttrNode); + if (CallNode == NULL) { + return NULL; + } + FixLoc(P, CallNode, Start); + PyObject *ExprArgv[1] = { CallNode }; + PyObject *ExprNode = NewNode(P, "Expr", ExprArgv, 1); + Py_DECREF(CallNode); + if (ExprNode != NULL) { + FixLoc(P, ExprNode, Start); + } + return ExprNode; +} + /* 模式(顶层,处理 | 或模式) */ static PyObject *ParsePattern(Parser *P) { Token *Start = PeekTok(P, 0);