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 relation_identifier_from_object_name(name: &ObjectName) -> Identifier {
311 Identifier::new(
312 name.components[0].token.clone(),
313 name.components
314 .iter()
315 .map(|component| component.value.as_str())
316 .collect::<Vec<_>>()
317 .join("."),
318 )
319 }
320
321 pub(crate) fn reject_unsupported_qualified_alter(
322 &mut self,
323 is_qualified: bool,
324 operation: AlterTableOperation,
325 ) -> bool {
326 if is_qualified && operation != AlterTableOperation::AddConstraint {
327 self.add_error("qualified ALTER TABLE supports only OWNER or ADD CONSTRAINT".into());
328 true
329 } else {
330 false
331 }
332 }
333
334 pub(crate) fn is_reserved_keyword(keyword: &str) -> bool {
339 RESERVED_KEYWORDS.contains(keyword.to_uppercase().as_str())
342 }
343
344 pub(crate) fn cur_token_is_keyword(&self, keyword: &str) -> bool {
346 self.cur_token.token_type == TokenType::Keyword
347 && self.cur_token.literal.eq_ignore_ascii_case(keyword)
348 }
349
350 pub(crate) fn peek_token_is_keyword(&self, keyword: &str) -> bool {
352 self.peek_token.token_type == TokenType::Keyword
353 && self.peek_token.literal.eq_ignore_ascii_case(keyword)
354 }
355
356 pub(crate) fn cur_token_is_punctuator(&self, punc: &str) -> bool {
358 self.cur_token.token_type == TokenType::Punctuator && self.cur_token.literal == punc
359 }
360
361 pub(crate) fn peek_token_is_punctuator(&self, punc: &str) -> bool {
363 self.peek_token.token_type == TokenType::Punctuator && self.peek_token.literal == punc
364 }
365
366 pub(crate) fn peek_token_is_operator(&self, op: &str) -> bool {
368 self.peek_token.token_type == TokenType::Operator && self.peek_token.literal == op
369 }
370
371 pub(crate) fn peek_token_is_identifier_like(&self) -> bool {
373 match self.peek_token.token_type {
374 TokenType::Identifier => true,
375 TokenType::Keyword => !Self::is_reserved_keyword(&self.peek_token.literal),
376 _ => false,
377 }
378 }
379
380 pub(crate) fn expect_peek_identifier_like(&mut self) -> bool {
382 if self.peek_token_is_identifier_like() {
383 self.next_token();
384 true
385 } else {
386 self.peek_error(TokenType::Identifier);
387 false
388 }
389 }
390
391 pub(crate) fn expect_peek(&mut self, t: TokenType) -> bool {
393 if self.peek_token_is(t) {
394 self.next_token();
395 true
396 } else {
397 self.peek_error(t);
398 false
399 }
400 }
401
402 pub(crate) fn expect_keyword(&mut self, keyword: &str) -> bool {
404 if self.peek_token_is_keyword(keyword) {
405 self.next_token();
406 true
407 } else {
408 self.add_error(format!(
409 "expected {} after {}, got {}",
410 keyword,
411 self.cur_token.literal,
412 Self::format_token_for_error(&self.peek_token)
413 ));
414 false
415 }
416 }
417
418 pub(crate) fn peek_precedence(&self) -> Precedence {
420 match self.peek_token.token_type {
421 TokenType::Operator => Precedence::for_operator(&self.peek_token.literal),
422 TokenType::Keyword => Precedence::for_operator(&self.peek_token.literal),
423 TokenType::Punctuator => {
424 if self.peek_token.literal == "." {
425 Precedence::Dot
426 } else if self.peek_token.literal == "(" {
427 Precedence::Call
428 } else if self.peek_token.literal == "[" {
429 Precedence::Index
430 } else {
431 Precedence::Lowest
432 }
433 }
434 _ => Precedence::Lowest,
435 }
436 }
437
438 pub(crate) fn cur_precedence(&self) -> Precedence {
440 match self.cur_token.token_type {
441 TokenType::Operator => Precedence::for_operator(&self.cur_token.literal),
442 TokenType::Keyword => Precedence::for_operator(&self.cur_token.literal),
443 TokenType::Punctuator => {
444 if self.cur_token.literal == "." {
445 Precedence::Dot
446 } else if self.cur_token.literal == "(" {
447 Precedence::Call
448 } else if self.cur_token.literal == "[" {
449 Precedence::Index
450 } else {
451 Precedence::Lowest
452 }
453 }
454 _ => Precedence::Lowest,
455 }
456 }
457
458 pub(crate) fn peek_error(&mut self, expected: TokenType) {
460 let position = self.peek_token.position;
461 let expected_desc = match expected {
462 TokenType::Identifier => "identifier (name)",
463 TokenType::Keyword => "keyword",
464 TokenType::Punctuator => "'(' or ')'",
465 TokenType::String => "string literal",
466 TokenType::Integer => "integer",
467 TokenType::Float => "number",
468 _ => "token",
469 };
470
471 if self.peek_token.token_type == TokenType::Eof {
472 if !self.current_clause.is_empty() {
473 self.add_error_at(
474 format!("expected {} after {}", expected_desc, self.current_clause),
475 position,
476 );
477 } else {
478 self.add_error_at(
479 format!("unexpected end of input, expected {}", expected_desc),
480 position,
481 );
482 }
483 } else if expected == TokenType::Identifier
484 && self.peek_token.token_type == TokenType::Keyword
485 && Self::is_reserved_keyword(&self.peek_token.literal)
486 {
487 self.add_error_at(
488 format!(
489 "'{}' is a reserved keyword and cannot be used as an identifier. \
490 Use double quotes to escape it: \"{}\"",
491 self.peek_token.literal.to_uppercase(),
492 self.peek_token.literal
493 ),
494 position,
495 );
496 } else {
497 self.add_error_at(
498 format!(
499 "expected {}, got {}",
500 expected_desc,
501 Self::format_token_for_error(&self.peek_token)
502 ),
503 position,
504 );
505 }
506 }
507
508 pub(crate) fn format_token_for_error(token: &Token) -> String {
510 if token.token_type == TokenType::Eof {
511 "end of input".to_string()
512 } else {
513 format!("'{}'", token.literal)
514 }
515 }
516
517 pub(crate) fn add_error(&mut self, msg: String) {
519 self.add_error_at(msg, self.cur_token.position);
520 }
521
522 pub(crate) fn add_error_at(&mut self, msg: String, position: super::token::Position) {
523 self.errors.push(ParseError::new(msg, position));
524 }
525
526 pub(crate) fn source_range_from(&self, start: Position) -> SourceRange {
527 SourceRange::new(start, self.peek_token.position)
528 }
529
530 pub(crate) fn source_range_through_peek_from(&self, start: Position) -> SourceRange {
531 let mut end = self.peek_token.position;
532 end.offset = end.offset.saturating_add(self.peek_token.literal.len());
533 end.column = end
534 .column
535 .saturating_add(self.peek_token.literal.chars().count());
536 SourceRange::new(start, end)
537 }
538
539 pub(crate) fn normalized_source_for(&self, range: &SourceRange) -> String {
540 let start = range.start.offset.min(self.source.len());
541 let end = range.end.offset.min(self.source.len());
542 self.source[start..end].to_owned()
543 }
544
545 pub(crate) fn enter_expression(&mut self) -> bool {
546 if self.expression_depth >= MAX_EXPRESSION_NESTING {
547 self.add_error(format!(
548 "expression nesting depth exceeds limit of {MAX_EXPRESSION_NESTING}"
549 ));
550 return false;
551 }
552 self.expression_depth += 1;
553 true
554 }
555
556 pub fn errors(&self) -> &[ParseError] {
558 &self.errors
559 }
560
561 pub(crate) fn next_parameter_index(&mut self) -> usize {
563 let idx = self.parameter_counter;
564 self.parameter_counter += 1;
565 idx
566 }
567}
568
569#[cfg(test)]
570mod tests {
571 use super::*;
572
573 #[test]
574 fn test_parser_creation() {
575 let parser = Parser::new("SELECT * FROM users");
576 assert!(parser.cur_token_is_keyword("SELECT"));
577 }
578
579 #[test]
580 fn test_next_token() {
581 let mut parser = Parser::new("SELECT * FROM users");
582 assert!(parser.cur_token_is_keyword("SELECT"));
583 parser.next_token();
584 assert!(parser.cur_token_is(TokenType::Operator));
585 assert_eq!(parser.cur_token.literal, "*");
586 }
587
588 #[test]
589 fn test_peek_token() {
590 let parser = Parser::new("SELECT * FROM users");
591 assert!(parser.cur_token_is_keyword("SELECT"));
592 assert!(parser.peek_token_is_operator("*"));
593 }
594}