后台的节点下拉是一张 C/Python 混在一起的 15 条表,整份铺给每种语言。给 C 题选到 只有 Python 有的 list_comprehension、f-string,规则存得进去,判题时拿裸名去比节点 类型,C 的语法树里永远不存在它——「必须使用列表推导式」永远失败、「不能使用 f-string」永远通过,两头都不报错,只有学生受着。反过来 mappings 支持的 do_while、 switch、struct、include 在表里没有,编辑器根本选不到。 标签表改成按语言分组,和判题机 mappings 的键集逐条对齐;保存时校验规则与语言是否 匹配,不匹配给中文提示。C 的 target 从 8 个可用变成 14 个。 C++ 接上了 tree-sitter-cpp,386 道 C++ 题从此能配规则。它继承 tree-sitter-c 的语法, C 那 14 个 target 实测全部通用,另加范围 for、类定义、try-catch、throw、namespace、 模板、lambda、using 共 22 个。调用形态和 C/Python 都不同,一并处理:a.push_back() 和 p->push_back() 是 call_expression + field_expression,不是 Python 的 attribute; std::sort(...) 的 function 是 qualified_identifier 而不是 identifier,所以额外比一次 :: 末段,否则学生写没写 using namespace std 会得到不同判定。 一起收掉的几处: - Java/Golang/JavaScript 配的规则一条都不会跑,题目页却照常把它们渲染成「要求」 挂给学生看。现在后台不给这些语言开 tab,下发给学生的要求也按语言过滤。 - 「出现次数」不填数字存下来是一条恒真规则,描述还退化成光秃秃一个「for 循环」。 切换引擎时给默认值,保存时拦下,读取时整条丢弃。 - 次数规则失败只说「if 条件 出现 2 次 ✗」,学生不知道自己写了几次,补上「当前 N 次」。 旧栈的引擎其实算了这个数,但 checker 只取 describe,算完就扔。 - must_have_nesting 的文案没走标签表,学生看到的是「必须使用 for_loop 嵌套」。 - 运算符文案给的是逻辑名,C 题的学生看到「必须使用 and 运算符」,而 C 里写的是 &&。 语义校验放在 astRulesError() 而不是 zod 的 refine 上:astRulesSchema 同时用于读后台 题目详情,在读路径上抛错会让历史脏数据把整个题目详情打不开。保存前先 pickAstRules() 剔除够不着的分组再校验,否则早年配过 C++ 规则的题会把老师锁死——tab 里看不到那组 规则,保存却被拦下。 生产库那 17 条规则(全是 Python3 的 must_exist_node / count_node)行为不变,逐条实跑 核对过。C++ 的 22 个节点 target、25 个运算符也逐个跑了,没有恒假的哑弹。改了带 wasm 内嵌的 ast.ts,dev 和编译两种形态都验过。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
27
CLAUDE.md
27
CLAUDE.md
@@ -102,6 +102,33 @@ dev 直接起不来。
|
||||
这些整数是**落库的值**:12 万条历史提交的 `submission.result` 就是它们,判题沙箱回的也是
|
||||
这套编码,所以只能新增、不能改已有的含义。题目表情 reaction 的语义 key 同理。
|
||||
|
||||
### AST 代码规则有两张表,必须同增同减
|
||||
|
||||
契约的 `AST_NODE_TARGETS_BY_LANGUAGE`(target → 中文名)决定后台下拉能选什么,
|
||||
`apps/api/src/judge/ast.ts` 的 `mappings`(target → tree-sitter 节点类型)决定判题机
|
||||
认得什么。**加节点类型时两边都要加**,运算符表 `AST_OPERATOR_TARGETS_BY_LANGUAGE` 同理。
|
||||
|
||||
只加一边是**静默错判**:判题机 `mapping[target] ?? target` 拿裸名去比节点类型,
|
||||
C 的语法树里永远不存在 `list_comprehension`,于是「必须使用列表推导式」永远失败、
|
||||
「不能使用 f-string」永远通过,两头都不报错,只有学生受着。原来那张表是 C/Python
|
||||
混在一起的 15 条,整份铺成下拉,给 C 题也能选到 Python 专有节点——就是这么来的。
|
||||
|
||||
判题机只认 `AST_SUPPORTED_LANGUAGES` 里的语言(C / C++ / Python3)。别的语言配了规则
|
||||
一条都不会跑,所以后台不给它们开 tab,题目页也不把它们的规则展示成「要求」——
|
||||
**看得见却不检查**比没有更糟。
|
||||
|
||||
C++ 的语法表是「C 的全集 + C++ 独有的几条」,因为 tree-sitter-cpp 继承 tree-sitter-c,
|
||||
C 那 14 个 target 在 C++ 树里逐个实测通用。但**调用形态两者不同**,加语言时必须一起看:
|
||||
`a.push_back()` 和 `p->push_back()` 在 C++ 都是 `call_expression` + `field_expression`,
|
||||
不是 Python 的 `attribute`;`std::sort(...)` 的 function 是 `qualified_identifier`
|
||||
而不是 `identifier`,所以 `functionCalls` 对 C++ 额外比一次 `::` 末段——否则学生写了
|
||||
`using namespace std` 与否会得到不同的判定结果。
|
||||
|
||||
规则的语义校验在 `astRulesError()`,不在 zod 的 refine 上:`astRulesSchema` 同时用于
|
||||
**读**后台题目详情,在读路径上抛错会让历史脏数据把整个题目详情打不开。同理,保存前
|
||||
先 `pickAstRules()` 剔除够不着的分组再校验,否则早年配过 C++ 规则的题会把老师锁死
|
||||
——tab 里看不到那组规则,保存却被拦下。
|
||||
|
||||
### 比赛只有 ACM 模式
|
||||
|
||||
没有 OI。上一代残留的 OI 分支在阶段 0 已经砍掉,不要"顺手补回来"。
|
||||
|
||||
Reference in New Issue
Block a user