{"record":{"id":"02964799fb52470b","repo":"babalae/better-genshin-impact","slug":"error-029647","errorCode":null,"errorMessage":"缺少右括号","messagePattern":"缺少右括号","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/AutoFight/Script/ConditionEvaluator.cs","lineNumber":341,"sourceCode":"        {\n            var op = tokens[pos].Value; pos++;\n            return new UnaryOpNode(op, ParseUnaryExpr(tokens, ref pos));\n        }\n        if (tokens[pos].Type == TokenType.Minus)\n        {\n            pos++;\n            return new UnaryOpNode(\"-u\", ParseUnaryExpr(tokens, ref pos));\n        }\n        return ParsePrimary(tokens, ref pos);\n    }\n\n    private static AstNode ParsePrimary(List<Token> tokens, ref int pos)\n    {\n        if (tokens[pos].Type == TokenType.LParen)\n        {\n            pos++;\n            var node = ParseOrExpr(tokens, ref pos);\n            if (tokens[pos].Type != TokenType.RParen) throw new InvalidOperationException(\"缺少右括号\");\n            pos++;\n            return node;\n        }\n\n        if (tokens[pos].Type == TokenType.Identifier)\n        {\n            var name = tokens[pos].Value; pos++;\n            if (tokens[pos].Type == TokenType.LParen)\n            {\n                pos++;\n                var args = new List<AstNode>();\n                if (tokens[pos].Type != TokenType.RParen)\n                {\n                    args.Add(ParseOrExpr(tokens, ref pos));\n                    while (tokens[pos].Type == TokenType.Comma)\n                    {\n                        pos++;\n                        args.Add(ParseOrExpr(tokens, ref pos));","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/AutoFight/Script/ConditionEvaluator.cs#L323-L359","documentation":"Thrown by ConditionEvaluator.ParsePrimary when a parenthesized sub-expression (opened with '(') is parsed but the closing ')' is not found at the expected position. This is a syntax error in the condition expression: an unbalanced '('. When called via Evaluate(), this is caught internally and Evaluate returns false.","triggerScenarios":"A condition expression with an unclosed parenthesis, e.g. `(q-ready() && low-hp` or `since(1 > 5`. The parser enters ParsePrimary expecting ')' after the inner expression, but finds a different token (End, or another operator/identifier).","commonSituations":"User writes a JSON strategy condition with a missing ')', or has unbalanced parentheses from manual editing. For example: `\"condition\": \"(q-ready() && low-hp\"` — the outer '(' is never closed.","solutions":["Count and balance all '(' and ')' in the condition expression.","The expression engine does not support implicit grouping — every '(' must have a matching ')'.","Simplify complex nested expressions and rebuild them incrementally, testing each part.","Use the Evaluate method in a dry-run with logging to identify the exact failure point."],"exampleFix":"// before (unclosed paren)\n\"condition\": \"(q-ready() && low-hp\"\n\n// after\n\"condition\": \"(q-ready() && low-hp())\"","handlingStrategy":"try-catch","validationCode":"// Quick balance check for parentheses in a condition expression\nstatic bool AreParensBalanced(string expr)\n{\n    int depth = 0;\n    foreach (var c in expr)\n    {\n        if (c == '(') depth++;\n        if (c == ')') depth--;\n        if (depth < 0) return false;\n    }\n    return depth == 0;\n}\n\nif (!AreParensBalanced(conditionExpr))\n    Log.LogWarning(\"条件表达式括号不平衡: {Expr}\", conditionExpr);","typeGuard":null,"tryCatchPattern":"// Evaluate catches this internally (line 147-151) and returns false.\n// No additional try-catch needed when using Evaluate.\n// For safety, log the expression when Evaluate returns unexpected false:\nvar result = evaluator.Evaluate(expr, index, charName, actionName);\nif (!result && /* expected true context */)\n    Logger.LogWarning(\"条件求值返回false，可能表达式有语法错误: {Expr}\", expr);","preventionTips":["The Evaluate method already handles this — it returns false rather than throwing.","When debugging conditions that always evaluate false, check for unbalanced parentheses.","Use a parenthesis counter when writing complex nested conditions.","Log the expression string alongside the Evaluate result to correlate failures."],"tags":["condition-evaluator","parser","expression","parentheses"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}