{"record":{"id":"bf7f036045d60c63","repo":"rust-lang/rust-analyzer","slug":"expected-ident","errorCode":null,"errorMessage":"expected ident","messagePattern":"expected ident","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/ungrammar/src/parser.rs","lineNumber":92,"sourceCode":"            grammar.nodes.push(NodeData { name, rule: DUMMY_RULE });\n            Node(len)\n        })\n    }\n    fn intern_token(&mut self, name: String) -> Token {\n        let len = self.token_table.len();\n        let grammar = &mut self.grammar;\n        *self.token_table.entry(name.clone()).or_insert_with(|| {\n            grammar.tokens.push(TokenData { name });\n            Token(len)\n        })\n    }\n}\n\nfn node(p: &mut Parser) -> Result<()> {\n    let token = p.bump()?;\n    let node = match token.kind {\n        TokenKind::Node(it) => p.intern_node(it),\n        _ => bail!(token.loc, \"expected ident\"),\n    };\n    p.expect(TokenKind::Eq, \"=\")?;\n    if !matches!(p.grammar[node].rule, DUMMY_RULE) {\n        bail!(token.loc, \"duplicate rule: `{}`\", p.grammar[node].name)\n    }\n\n    let rule = rule(p)?;\n    p.grammar.nodes[node.0].rule = rule;\n    Ok(())\n}\n\nfn rule(p: &mut Parser) -> Result<Rule> {\n    if let Some(lexer::Token { kind: TokenKind::Pipe, loc }) = p.peek() {\n        bail!(\n            *loc,\n            \"The first element in a sequence of productions or alternatives \\\n            must not have a leading pipe (`|`)\"\n        );","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/lib/ungrammar/src/parser.rs#L74-L110","documentation":"The ungrammar parser's `node` function throws `expected ident` when the token that should start a node definition (the left-hand side of `Node = Rule`) is not an identifier token. Node definitions in a `.ungram` grammar must begin with an identifier followed by `=`. Any other token (operators, punctuation, EOF) reaching this position fails the grammar's structural invariant that a node name comes first.","triggerScenarios":"Calling `parse` on a `.ungram` file where a token at a node-definition position is not an identifier: e.g. a grammar starting with `= Foo`, a stray token like `|` or `(` where a node name is expected, or a truncated file where the lexer emitted a non-ident token.","commonSituations":"Hand-edited ungrammar files with typos before `=`, copy-pasted snippets losing the node name, accidentally deleted identifier leaving punctuation behind, or a mis-ordered file where content precedes the first node declaration.","solutions":["Open the .ungram file at the reported token location and make sure the line is of the form `NodeName = rule` with a valid identifier before `=`.","Remove or quote any stray punctuation/tokens that are not part of a rule body.","If the file was truncated or merged badly, restore the missing node name.","Validate the grammar with a quick parse (e.g. rust-analyzer's codegen or ungrammar CLI) before committing."],"exampleFix":"// before (.ungram)\n= RecordField\n\n// after (.ungram)\nRecordField = 'Name' ':' SyntaxToken","handlingStrategy":"validation","validationCode":"// before parsing, sanity-check the grammar text\nfn first_node_token_ok(src: &str) -> bool {\n    src.trim_start().chars().next().map_or(false, |c| c.is_ascii_alphabetic() || c == '_')\n}","typeGuard":"fn is_ident(s: &str) -> bool {\n    let mut cs = s.chars();\n    cs.next().is_some_and(|c| c.is_ascii_alphabetic() || c == '_') && cs.all(|c| c.is_ascii_alphanumeric() || c == '_')\n}","tryCatchPattern":"match ungrammar::parse(src) {\n    Ok(g) => g,\n    Err(e) if e.to_string().contains(\"expected ident\") => {\n        eprintln!(\"grammar error: {}\", e);\n        return Err( GrammarError::Syntax(e));\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Keep every top-level definition in the form `Name = rule` with a valid identifier first.","Run the grammar through the parser in CI (codegen check) before committing .ungram edits.","Avoid editing grammar files with tools that may mangle or truncate identifiers."],"tags":["parser","ungrammar","grammar-syntax"],"backgroundTag":"grammar-parse-error","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}