@@ -13,9 +13,14 @@ namespace sql_parser {
1313enum class Precedence : uint8_t {
1414 NONE = 0 ,
1515 OR , // OR
16+ XOR , // XOR
1617 AND , // AND
1718 NOT , // NOT (prefix)
1819 COMPARISON , // =, <, >, <=, >=, !=, <>, IS, LIKE, IN, BETWEEN
20+ BIT_OR , // |
21+ BIT_XOR , // ^
22+ BIT_AND , // &
23+ SHIFT , // <<, >>
1924 ADDITION , // +, -
2025 MULTIPLICATION ,// *, /, %
2126 UNARY , // - (prefix), NOT
@@ -77,7 +82,12 @@ class ExpressionParser {
7782 if (tok_.peek ().type == TokenType::TK_RPAREN ) tok_.skip ();
7883 } else {
7984 // Legacy: skip to matching paren
80- skip_to_matching_paren ();
85+ const char * start = tok_.peek ().text .ptr ;
86+ const char * end = skip_to_matching_paren ();
87+ if (start && end && end >= start) {
88+ node->set_value (StringRef{start,
89+ static_cast <uint32_t >(end - start)});
90+ }
8191 }
8292 return node;
8393 }
@@ -112,6 +122,12 @@ class ExpressionParser {
112122 tok_.skip ();
113123 return make_node (arena_, NodeType::NODE_IDENTIFIER , t.text );
114124 }
125+ case TokenType::TK_INTERVAL : {
126+ return parse_interval_literal (t);
127+ }
128+ case TokenType::TK_ALL : {
129+ return parse_quantified_subquery (t);
130+ }
115131 case TokenType::TK_ASTERISK : {
116132 tok_.skip ();
117133 return make_node (arena_, NodeType::NODE_ASTERISK , t.text );
@@ -336,6 +352,7 @@ class ExpressionParser {
336352 static Precedence infix_precedence (TokenType type) {
337353 switch (type) {
338354 case TokenType::TK_OR : return Precedence::OR ;
355+ case TokenType::TK_XOR : return Precedence::XOR ;
339356 case TokenType::TK_AND : return Precedence::AND ;
340357 case TokenType::TK_NOT : return Precedence::COMPARISON ; // NOT IN/BETWEEN/LIKE
341358 case TokenType::TK_EQUAL :
@@ -344,15 +361,25 @@ class ExpressionParser {
344361 case TokenType::TK_GREATER :
345362 case TokenType::TK_LESS_EQUAL :
346363 case TokenType::TK_GREATER_EQUAL :
364+ case TokenType::TK_REGEXP :
365+ case TokenType::TK_SOUNDS :
366+ case TokenType::TK_MEMBER :
347367 case TokenType::TK_LIKE : return Precedence::COMPARISON ;
348368 case TokenType::TK_IS : return Precedence::COMPARISON ;
349369 case TokenType::TK_IN : return Precedence::COMPARISON ;
350370 case TokenType::TK_BETWEEN : return Precedence::COMPARISON ;
371+ case TokenType::TK_PIPE : return Precedence::BIT_OR ;
372+ case TokenType::TK_CARET : return Precedence::BIT_XOR ;
373+ case TokenType::TK_AMPERSAND : return Precedence::BIT_AND ;
374+ case TokenType::TK_SHIFT_LEFT :
375+ case TokenType::TK_SHIFT_RIGHT : return Precedence::SHIFT ;
351376 case TokenType::TK_PLUS :
352377 case TokenType::TK_MINUS : return Precedence::ADDITION ;
353378 case TokenType::TK_ASTERISK :
354379 case TokenType::TK_SLASH :
355- case TokenType::TK_PERCENT : return Precedence::MULTIPLICATION ;
380+ case TokenType::TK_PERCENT :
381+ case TokenType::TK_DIV :
382+ case TokenType::TK_MOD : return Precedence::MULTIPLICATION ;
356383 case TokenType::TK_DOUBLE_PIPE : return Precedence::ADDITION ; // string concat
357384 default : return Precedence::NONE ;
358385 }
@@ -363,7 +390,7 @@ class ExpressionParser {
363390
364391 switch (op.type ) {
365392 case TokenType::TK_NOT : {
366- // NOT IN / NOT BETWEEN / NOT LIKE — compound negated infix
393+ // NOT IN / NOT BETWEEN / NOT LIKE / NOT REGEXP — compound negated infix
367394 Token actual_op = tok_.peek ();
368395 if (actual_op.type == TokenType::TK_IN ) {
369396 tok_.skip ();
@@ -380,7 +407,8 @@ class ExpressionParser {
380407 not_node->add_child (between_node);
381408 return not_node;
382409 }
383- if (actual_op.type == TokenType::TK_LIKE ) {
410+ if (actual_op.type == TokenType::TK_LIKE ||
411+ actual_op.type == TokenType::TK_REGEXP ) {
384412 tok_.skip ();
385413 AstNode* right = parse (prec);
386414 AstNode* like_node = make_node (arena_, NodeType::NODE_BINARY_OP , actual_op.text );
@@ -422,6 +450,10 @@ class ExpressionParser {
422450 return parse_in (left);
423451 case TokenType::TK_BETWEEN :
424452 return parse_between (left);
453+ case TokenType::TK_SOUNDS :
454+ return parse_sounds_like (left, op, prec);
455+ case TokenType::TK_MEMBER :
456+ return parse_member_of (left, op, prec);
425457 default : {
426458 // Standard binary operator
427459 AstNode* right = parse (prec);
@@ -459,6 +491,54 @@ class ExpressionParser {
459491 return node;
460492 }
461493
494+ AstNode* parse_sounds_like (AstNode* left, const Token& sounds, Precedence prec) {
495+ Token like = tok_.peek ();
496+ StringRef op_text = sounds.text ;
497+ if (like.type == TokenType::TK_LIKE ) {
498+ tok_.skip ();
499+ op_text = StringRef{sounds.text .ptr ,
500+ static_cast <uint32_t >((like.text .ptr + like.text .len ) - sounds.text .ptr )};
501+ }
502+ AstNode* right = parse (prec);
503+ AstNode* node = make_node (arena_, NodeType::NODE_BINARY_OP , op_text);
504+ node->add_child (left);
505+ if (right) node->add_child (right);
506+ return node;
507+ }
508+
509+ AstNode* parse_member_of (AstNode* left, const Token& member, Precedence prec) {
510+ Token of = tok_.peek ();
511+ StringRef op_text = member.text ;
512+ if (of.type == TokenType::TK_OF ) {
513+ tok_.skip ();
514+ op_text = StringRef{member.text .ptr ,
515+ static_cast <uint32_t >((of.text .ptr + of.text .len ) - member.text .ptr )};
516+ }
517+
518+ AstNode* right = nullptr ;
519+ if (tok_.peek ().type == TokenType::TK_LPAREN ) {
520+ tok_.skip ();
521+ AstNode* tuple = make_node (arena_, NodeType::NODE_TUPLE );
522+ if (tok_.peek ().type != TokenType::TK_RPAREN ) {
523+ while (true ) {
524+ AstNode* elem = parse ();
525+ if (elem) tuple->add_child (elem);
526+ if (tok_.peek ().type == TokenType::TK_COMMA ) tok_.skip ();
527+ else break ;
528+ }
529+ }
530+ if (tok_.peek ().type == TokenType::TK_RPAREN ) tok_.skip ();
531+ right = tuple;
532+ } else {
533+ right = parse (prec);
534+ }
535+
536+ AstNode* node = make_node (arena_, NodeType::NODE_BINARY_OP , op_text);
537+ node->add_child (left);
538+ if (right) node->add_child (right);
539+ return node;
540+ }
541+
462542 // BETWEEN low AND high
463543 AstNode* parse_between (AstNode* left) {
464544 AstNode* node = make_node (arena_, NodeType::NODE_BETWEEN );
@@ -473,6 +553,38 @@ class ExpressionParser {
473553 return node;
474554 }
475555
556+ AstNode* parse_interval_literal (const Token& interval) {
557+ tok_.skip ();
558+ Token amount = tok_.next_token ();
559+ if (amount.type == TokenType::TK_EOF || amount.type == TokenType::TK_ERROR ) {
560+ return make_node (arena_, NodeType::NODE_IDENTIFIER , interval.text );
561+ }
562+ Token unit = tok_.next_token ();
563+ if (unit.type == TokenType::TK_EOF || unit.type == TokenType::TK_ERROR ) {
564+ StringRef span{interval.text .ptr ,
565+ static_cast <uint32_t >((amount.text .ptr + amount.text .len ) - interval.text .ptr )};
566+ return make_node (arena_, NodeType::NODE_IDENTIFIER , span);
567+ }
568+ StringRef span{interval.text .ptr ,
569+ static_cast <uint32_t >((unit.text .ptr + unit.text .len ) - interval.text .ptr )};
570+ return make_node (arena_, NodeType::NODE_IDENTIFIER , span);
571+ }
572+
573+ AstNode* parse_quantified_subquery (const Token& quantifier) {
574+ tok_.skip ();
575+ if (tok_.peek ().type == TokenType::TK_LPAREN ) {
576+ tok_.skip ();
577+ if (tok_.peek ().type == TokenType::TK_SELECT ) {
578+ const char * close = skip_to_matching_paren ();
579+ const char * end = close ? close + 1 : tok_.input_end ();
580+ return make_node (arena_, NodeType::NODE_IDENTIFIER ,
581+ StringRef{quantifier.text .ptr ,
582+ static_cast <uint32_t >(end - quantifier.text .ptr )});
583+ }
584+ }
585+ return make_node (arena_, NodeType::NODE_IDENTIFIER , quantifier.text );
586+ }
587+
476588 // CASE [expr] WHEN ... THEN ... [ELSE ...] END
477589 AstNode* parse_case () {
478590 AstNode* node = make_node (arena_, NodeType::NODE_CASE_WHEN );
@@ -607,14 +719,18 @@ class ExpressionParser {
607719 }
608720
609721 // Skip tokens until matching closing paren (handles nesting)
610- void skip_to_matching_paren () {
722+ const char * skip_to_matching_paren () {
611723 int depth = 1 ;
612724 while (depth > 0 ) {
613725 Token t = tok_.next_token ();
614726 if (t.type == TokenType::TK_LPAREN ) ++depth;
615- else if (t.type == TokenType::TK_RPAREN ) --depth;
727+ else if (t.type == TokenType::TK_RPAREN ) {
728+ --depth;
729+ if (depth == 0 ) return t.text .ptr ;
730+ }
616731 else if (t.type == TokenType::TK_EOF ) break ;
617732 }
733+ return tok_.input_end ();
618734 }
619735
620736 // Some keywords can appear as identifiers in expression context
@@ -698,6 +814,8 @@ class ExpressionParser {
698814 case TokenType::TK_PARTITION :
699815 case TokenType::TK_RECURSIVE :
700816 case TokenType::TK_REPLACE :
817+ case TokenType::TK_DIV :
818+ case TokenType::TK_MOD :
701819 return true ;
702820 default :
703821 return false ;
0 commit comments