{"record":{"id":"ca6af8de65c2cf48","repo":"oracle/graal","slug":"didn-t-consume-all-tokens","errorCode":null,"errorMessage":"didn't consume all tokens","messagePattern":"didn't consume all tokens","errorType":"validation","errorClass":"RuleParseError","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/core/match/processor/MatchProcessor.java","lineNumber":132,"sourceCode":"        private Set<String> requiredPackages = new LinkedHashSet<>();\n\n        RuleParser(String rule) {\n            Matcher m = tokenizer.matcher(rule);\n            List<String> list = new ArrayList<>();\n            int end = 0;\n            while (m.lookingAt()) {\n                list.add(m.group(1));\n                end = m.end();\n                m.region(m.end(), m.regionEnd());\n            }\n            if (end != m.regionEnd()) {\n                throw new RuleParseError(\"Unexpected tokens :\" + rule.substring(m.end(), m.regionEnd()));\n            }\n            tokens = list.toArray(new String[0]);\n\n            matchDescriptor = parseExpression();\n            if (!done()) {\n                throw new RuleParseError(\"didn't consume all tokens\");\n            }\n            capturedNames.add(0, \"root\");\n            capturedTypes.add(0, matchDescriptor.nodeType);\n        }\n\n        String next() {\n            return tokens[current++];\n        }\n\n        String peek(String name) {\n            if (current >= tokens.length) {\n                if (name == null) {\n                    throw new RuleParseError(\"Out of tokens\");\n                }\n                throw new RuleParseError(\"Out of tokens looking for %s\", name);\n            }\n            return tokens[current];\n        }","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/core/match/processor/MatchProcessor.java#L114-L150","documentation":"Thrown by RuleParser in MatchProcessor after tokenizing succeeded but the recursive-descent parseExpression() stopped before consuming all tokens. It means the front of the rule parsed as a complete expression, yet extra tokens remain — typically a top-level parenthesis closed too early or a second pattern where only one is allowed.","triggerScenarios":"A @MatchRule value like \"Add(x) y\" where 'Add(x)' completes and 'y' is left over, or \"(Add(x)) (Constant)\" — two expressions at top level. done() returns current == tokens.length; anything short of that triggers this RuleParseError.","commonSituations":"Nesting mistakes when composing complex match patterns; forgetting that only a single top-level node expression is permitted; refactoring a rule and leaving an orphaned sub-pattern.","solutions":["Wrap the leftover tokens into the existing expression (add the missing '(' earlier) or remove them.","Re-read the rule as a tree: exactly one root node whose inputs fill its parentheses.","Split genuine multi-pattern matching into separate @MatchRule methods."],"exampleFix":"// before\n@MatchRule(\"(Add(x)) (Constant)\")\n\n// after\n@MatchRule(\"Add(x, Constant)\")","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"No runtime catch: this is a RuleParseError raised inside javac annotation processing. Treat the compiler error as the signal; CI should treat any 'RuleParseError' string in build output as a hard failure.","preventionTips":["One root expression per @MatchRule; balance parentheses before saving.","Split separate patterns into separate @MatchRule methods.","Use an editor paren-matching aid when editing long S-expression rules."],"tags":["graalvm","match-rules","annotation-processing","compile-time"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}