1use std::sync::LazyLock;
18
19use rustc_hash::FxHashSet;
20
21use super::ast::*;
22use super::error::{ParseError, ParseErrors};
23use super::lexer::Lexer;
24use super::precedence::Precedence;
25use super::token::{Position, Token, TokenType};
26
27static RESERVED_KEYWORDS: LazyLock<FxHashSet<&'static str>> = LazyLock::new(|| {
29 [
30 "SELECT",
32 "FROM",
33 "WHERE",
34 "AND",
35 "OR",
36 "NOT",
37 "INSERT",
38 "INTO",
39 "VALUES",
40 "UPDATE",
41 "SET",
42 "DELETE",
43 "CREATE",
44 "DROP",
45 "TABLE",
46 "INDEX",
47 "VIEW",
48 "EXTENSION",
49 "PLANNER",
50 "SUPPORT",
51 "ALTER",
52 "ADD",
53 "PRIMARY",
54 "KEY",
55 "FOREIGN",
56 "REFERENCES",
57 "NULL",
58 "TRUE",
59 "FALSE",
60 "AS",
61 "ON",
62 "JOIN",
63 "INNER",
66 "OUTER",
67 "FULL",
68 "CROSS",
69 "GROUP",
70 "BY",
71 "ORDER",
72 "HAVING",
73 "LIMIT",
74 "OFFSET",
75 "UNION",
76 "INTERSECT",
77 "EXCEPT",
78 "CASE",
79 "WHEN",
80 "THEN",
81 "ELSE",
82 "END",
83 "DISTINCT",
84 "ALL",
85 "EXISTS",
86 "IN",
87 "BETWEEN",
88 "LIKE",
89 "GLOB",
90 "REGEXP",
91 "RLIKE",
92 "IS",
93 "ASC",
94 "DESC",
95 "NULLS",
96 "BEGIN",
99 "COMMIT",
100 "ROLLBACK",
101 "SAVEPOINT",
102 "RELEASE",
103 "IF",
104 "WITH",
105 "RECURSIVE",
106 ]
107 .into_iter()
108 .collect()
109});
110
111const MAX_EXPRESSION_NESTING: usize = 128;
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub(crate) enum PositionalParameterStyle {
115 Anonymous,
116 Explicit,
117}
118
119pub struct Parser {
121 pub(crate) source: Box<str>,
123 lexer: Lexer,
125 pub(crate) cur_token: Token,
127 pub(crate) peek_token: Token,
129 errors: Vec<ParseError>,
131 pub(crate) current_clause: String,
133 parameter_counter: usize,
135 pub(crate) positional_parameter_style: Option<PositionalParameterStyle>,
137 pub(crate) expression_depth: usize,
139 pub(crate) procedural_definition_depth: usize,
141 pub(crate) token_count: usize,
143}
144
145impl Parser {
146 fn next_parser_token(lexer: &mut Lexer) -> Token {
147 loop {
148 let token = lexer.next_token();
149 if token.token_type != TokenType::Comment {
150 return token;
151 }
152 }
153 }
154
155 pub fn new(input: &str) -> Self {
157 let normalized = if input.contains('\r') {
158 input.replace("\r\n", "\n").replace('\r', "\n")
159 } else {
160 input.to_owned()
161 };
162 let mut lexer = Lexer::new(&normalized);
163 let cur_token = Self::next_parser_token(&mut lexer);
164 let peek_token = Self::next_parser_token(&mut lexer);
165
166 Parser {
167 source: normalized.into(),
168 lexer,
169 cur_token,
170 peek_token,
171 errors: Vec::new(),
172 current_clause: String::new(),
173 parameter_counter: 1,
174 positional_parameter_style: None,
175 expression_depth: 0,
176 procedural_definition_depth: 0,
177 token_count: 2,
178 }
179 }
180
181 pub fn parse_program(&mut self) -> Result<Program, ParseErrors> {
183 let mut statements = Vec::with_capacity(1);
185
186 while !self.cur_token_is(TokenType::Eof) {
187 if self.cur_token_is(TokenType::Comment) {
189 self.next_token();
190 continue;
191 }
192
193 if let Some(stmt) = self.parse_statement() {
194 statements.push(stmt);
195 }
196
197 if self.peek_token_is_punctuator(";") {
198 while self.peek_token_is_punctuator(";") {
201 self.next_token();
202 }
203 self.next_token();
204 } else if self.peek_token_is(TokenType::Eof) {
205 self.next_token();
206 } else {
207 self.add_error(format!(
208 "expected ';' between statements before {}",
209 Self::format_token_for_error(&self.peek_token)
210 ));
211 break;
212 }
213 self.parameter_counter = 1;
214 self.positional_parameter_style = None;
215 }
216
217 if !self.errors.is_empty() {
218 return Err(ParseErrors::from_errors_with_sql(
219 self.errors.clone(),
220 self.source.as_ref(),
221 ));
222 }
223
224 Ok(Program { statements })
225 }
226
227 pub(crate) fn next_token(&mut self) {
229 let next = Self::next_parser_token(&mut self.lexer);
230 self.cur_token = std::mem::replace(&mut self.peek_token, next);
231 self.token_count = self.token_count.saturating_add(1);
232 if self.procedural_definition_depth > 0
233 && self.cur_token.token_type == TokenType::Parameter
234 && !self.cur_token.literal.starts_with(':')
235 {
236 self.add_error_at(
237 "stored procedural source cannot contain external '$n' or '?' parameters"
238 .to_string(),
239 self.cur_token.position,
240 );
241 }
242 }
243
244 pub(crate) fn cur_token_is(&self, t: TokenType) -> bool {
246 self.cur_token.token_type == t
247 }
248
249 pub(crate) fn peek_token_is(&self, t: TokenType) -> bool {
251 self.peek_token.token_type == t
252 }
253
254 pub(crate) fn cur_token_is_identifier_like(&self) -> bool {
257 match self.cur_token.token_type {
258 TokenType::Identifier => true,
259 TokenType::Keyword => {
260 !Self::is_reserved_keyword(&self.cur_token.literal)
263 }
264 _ => false,
265 }
266 }
267
268 pub(crate) fn cur_token_as_column_identifier(&self) -> Identifier {
271 Identifier::new(self.cur_token.clone(), self.cur_token.literal.clone())
272 }
273
274 pub(crate) fn parse_relation_identifier_current(&mut self) -> Option<Identifier> {
285 if !matches!(
286 self.cur_token.token_type,
287 TokenType::Identifier | TokenType::Keyword
288 ) {
289 self.add_error(format!(
290 "expected relation name, got {}",
291 Self::format_token_for_error(&self.cur_token)
292 ));
293 return None;
294 }
295
296 let token = self.cur_token.clone();
297 let mut value = self.cur_token.literal.clone();
298 while self.peek_token_is_punctuator(".") {
299 self.next_token();
300 if !self.expect_peek_identifier_like() {
301 return None;
302 }
303 value.push('.');
304 value.push_str(&self.cur_token.literal);
305 }
306 Some(Identifier::new(token, value))
307 }
308
309 pub(crate) fn is_reserved_keyword(keyword: &str) -> bool {
314 RESERVED_KEYWORDS.contains(keyword.to_uppercase().as_str())
317 }
318
319 pub(crate) fn cur_token_is_keyword(&self, keyword: &str) -> bool {
321 self.cur_token.token_type == TokenType::Keyword
322 && self.cur_token.literal.eq_ignore_ascii_case(keyword)
323 }
324
325 pub(crate) fn peek_token_is_keyword(&self, keyword: &str) -> bool {
327 self.peek_token.token_type == TokenType::Keyword
328 && self.peek_token.literal.eq_ignore_ascii_case(keyword)
329 }
330
331 pub(crate) fn cur_token_is_punctuator(&self, punc: &str) -> bool {
333 self.cur_token.token_type == TokenType::Punctuator && self.cur_token.literal == punc
334 }
335
336 pub(crate) fn peek_token_is_punctuator(&self, punc: &str) -> bool {
338 self.peek_token.token_type == TokenType::Punctuator && self.peek_token.literal == punc
339 }
340
341 pub(crate) fn peek_token_is_operator(&self, op: &str) -> bool {
343 self.peek_token.token_type == TokenType::Operator && self.peek_token.literal == op
344 }
345
346 pub(crate) fn peek_token_is_identifier_like(&self) -> bool {
348 match self.peek_token.token_type {
349 TokenType::Identifier => true,
350 TokenType::Keyword => !Self::is_reserved_keyword(&self.peek_token.literal),
351 _ => false,
352 }
353 }
354
355 pub(crate) fn expect_peek_identifier_like(&mut self) -> bool {
357 if self.peek_token_is_identifier_like() {
358 self.next_token();
359 true
360 } else {
361 self.peek_error(TokenType::Identifier);
362 false
363 }
364 }
365
366 pub(crate) fn expect_peek(&mut self, t: TokenType) -> bool {
368 if self.peek_token_is(t) {
369 self.next_token();
370 true
371 } else {
372 self.peek_error(t);
373 false
374 }
375 }
376
377 pub(crate) fn expect_keyword(&mut self, keyword: &str) -> bool {
379 if self.peek_token_is_keyword(keyword) {
380 self.next_token();
381 true
382 } else {
383 self.add_error(format!(
384 "expected {} after {}, got {}",
385 keyword,
386 self.cur_token.literal,
387 Self::format_token_for_error(&self.peek_token)
388 ));
389 false
390 }
391 }
392
393 pub(crate) fn peek_precedence(&self) -> Precedence {
395 match self.peek_token.token_type {
396 TokenType::Operator => Precedence::for_operator(&self.peek_token.literal),
397 TokenType::Keyword => Precedence::for_operator(&self.peek_token.literal),
398 TokenType::Punctuator => {
399 if self.peek_token.literal == "." {
400 Precedence::Dot
401 } else if self.peek_token.literal == "(" {
402 Precedence::Call
403 } else if self.peek_token.literal == "[" {
404 Precedence::Index
405 } else {
406 Precedence::Lowest
407 }
408 }
409 _ => Precedence::Lowest,
410 }
411 }
412
413 pub(crate) fn cur_precedence(&self) -> Precedence {
415 match self.cur_token.token_type {
416 TokenType::Operator => Precedence::for_operator(&self.cur_token.literal),
417 TokenType::Keyword => Precedence::for_operator(&self.cur_token.literal),
418 TokenType::Punctuator => {
419 if self.cur_token.literal == "." {
420 Precedence::Dot
421 } else if self.cur_token.literal == "(" {
422 Precedence::Call
423 } else if self.cur_token.literal == "[" {
424 Precedence::Index
425 } else {
426 Precedence::Lowest
427 }
428 }
429 _ => Precedence::Lowest,
430 }
431 }
432
433 pub(crate) fn peek_error(&mut self, expected: TokenType) {
435 let position = self.peek_token.position;
436 let expected_desc = match expected {
437 TokenType::Identifier => "identifier (name)",
438 TokenType::Keyword => "keyword",
439 TokenType::Punctuator => "'(' or ')'",
440 TokenType::String => "string literal",
441 TokenType::Integer => "integer",
442 TokenType::Float => "number",
443 _ => "token",
444 };
445
446 if self.peek_token.token_type == TokenType::Eof {
447 if !self.current_clause.is_empty() {
448 self.add_error_at(
449 format!("expected {} after {}", expected_desc, self.current_clause),
450 position,
451 );
452 } else {
453 self.add_error_at(
454 format!("unexpected end of input, expected {}", expected_desc),
455 position,
456 );
457 }
458 } else if expected == TokenType::Identifier
459 && self.peek_token.token_type == TokenType::Keyword
460 && Self::is_reserved_keyword(&self.peek_token.literal)
461 {
462 self.add_error_at(
463 format!(
464 "'{}' is a reserved keyword and cannot be used as an identifier. \
465 Use double quotes to escape it: \"{}\"",
466 self.peek_token.literal.to_uppercase(),
467 self.peek_token.literal
468 ),
469 position,
470 );
471 } else {
472 self.add_error_at(
473 format!(
474 "expected {}, got {}",
475 expected_desc,
476 Self::format_token_for_error(&self.peek_token)
477 ),
478 position,
479 );
480 }
481 }
482
483 pub(crate) fn format_token_for_error(token: &Token) -> String {
485 if token.token_type == TokenType::Eof {
486 "end of input".to_string()
487 } else {
488 format!("'{}'", token.literal)
489 }
490 }
491
492 pub(crate) fn add_error(&mut self, msg: String) {
494 self.add_error_at(msg, self.cur_token.position);
495 }
496
497 pub(crate) fn add_error_at(&mut self, msg: String, position: super::token::Position) {
498 self.errors.push(ParseError::new(msg, position));
499 }
500
501 pub(crate) fn source_range_from(&self, start: Position) -> SourceRange {
502 SourceRange::new(start, self.peek_token.position)
503 }
504
505 pub(crate) fn source_range_through_peek_from(&self, start: Position) -> SourceRange {
506 let mut end = self.peek_token.position;
507 end.offset = end.offset.saturating_add(self.peek_token.literal.len());
508 end.column = end
509 .column
510 .saturating_add(self.peek_token.literal.chars().count());
511 SourceRange::new(start, end)
512 }
513
514 pub(crate) fn normalized_source_for(&self, range: &SourceRange) -> String {
515 let start = range.start.offset.min(self.source.len());
516 let end = range.end.offset.min(self.source.len());
517 self.source[start..end].to_owned()
518 }
519
520 pub(crate) fn enter_expression(&mut self) -> bool {
521 if self.expression_depth >= MAX_EXPRESSION_NESTING {
522 self.add_error(format!(
523 "expression nesting depth exceeds limit of {MAX_EXPRESSION_NESTING}"
524 ));
525 return false;
526 }
527 self.expression_depth += 1;
528 true
529 }
530
531 pub fn errors(&self) -> &[ParseError] {
533 &self.errors
534 }
535
536 pub(crate) fn next_parameter_index(&mut self) -> usize {
538 let idx = self.parameter_counter;
539 self.parameter_counter += 1;
540 idx
541 }
542}
543
544#[cfg(test)]
545mod tests {
546 use super::*;
547
548 #[test]
549 fn test_parser_creation() {
550 let parser = Parser::new("SELECT * FROM users");
551 assert!(parser.cur_token_is_keyword("SELECT"));
552 }
553
554 #[test]
555 fn test_next_token() {
556 let mut parser = Parser::new("SELECT * FROM users");
557 assert!(parser.cur_token_is_keyword("SELECT"));
558 parser.next_token();
559 assert!(parser.cur_token_is(TokenType::Operator));
560 assert_eq!(parser.cur_token.literal, "*");
561 }
562
563 #[test]
564 fn test_peek_token() {
565 let parser = Parser::new("SELECT * FROM users");
566 assert!(parser.cur_token_is_keyword("SELECT"));
567 assert!(parser.peek_token_is_operator("*"));
568 }
569}