@@ -20,6 +20,9 @@ public sealed class Parser
2020
2121 private Token Next ( ) => _tokens [ _position ++ ] ;
2222
23+ private static bool IsIdentifierToken ( Token token ) =>
24+ token . Kind is TokenKind . Ident or TokenKind . Keyword ;
25+
2326 private bool Accept ( string text )
2427 {
2528 if ( ! Peek . Is ( text ) ) return false ;
@@ -36,7 +39,7 @@ private void Expect(string text)
3639 private string Identifier ( )
3740 {
3841 Token token = Next ( ) ;
39- if ( token . Kind != TokenKind . Ident && token . Kind != TokenKind . Keyword )
42+ if ( ! IsIdentifierToken ( token ) )
4043 throw new SqlException ( $ "expected identifier but found '{ token . Text } '") ;
4144 return token . Text ;
4245 }
@@ -345,16 +348,11 @@ private Expr ParsePrimary()
345348 return new Literal ( null ) ;
346349 }
347350
348- // Identifier() accepts keyword tokens in schema/projection contexts. The
349- // same stored column must remain addressable in predicates and assignment
350- // expressions; otherwise CREATE TABLE ... (order INT) succeeds but
351- // WHERE order = 1 fails to parse. Literal keywords are handled above.
352- if ( token . Kind == TokenKind . Ident || token . Kind == TokenKind . Keyword )
353- {
354- _position ++ ;
355- return new ColumnRef ( token . Text ) ;
356- }
351+ // Schema, projection, assignment, and expression contexts must use one
352+ // identifier-token rule. Literal keywords are consumed above first.
353+ if ( IsIdentifierToken ( token ) )
354+ return new ColumnRef ( Identifier ( ) ) ;
357355
358356 throw new SqlException ( $ "unexpected token '{ token . Text } ' in expression") ;
359357 }
360- }
358+ }
0 commit comments