use sql_dialect_fmt_syntax::SyntaxKind::*;
use crate::parser::{ContextualKeyword, Parser};
use super::{
balanced_parens, column_list, expr, name_ref, order_by_clause, partition_by_clause, select_item,
};
pub(super) fn match_recognize(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); if !p.eat(L_PAREN) {
p.error("expected '(' after MATCH_RECOGNIZE");
m.complete(p, MATCH_RECOGNIZE);
return;
}
while !p.at(R_PAREN) && !p.at_eof() {
if p.at(PARTITION_KW) {
partition_by_clause(p);
} else if p.at(ORDER_KW) {
order_by_clause(p);
} else if p.nth_contextual(0, ContextualKeyword::Measures) {
measures_clause(p);
} else if p.nth_contextual(0, ContextualKeyword::Pattern) {
pattern_clause(p);
} else if p.nth_contextual(0, ContextualKeyword::Define) {
define_clause(p);
} else if p.nth_contextual(0, ContextualKeyword::Subset) {
subset_clause(p);
} else if at_row_match_clause(p) {
row_match_clause(p);
} else if p.at(AFTER_KW) {
after_match_clause(p);
} else {
p.bump_any(); }
}
p.expect(R_PAREN);
m.complete(p, MATCH_RECOGNIZE);
}
fn measures_clause(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); measure_item(p);
while p.eat(COMMA) {
measure_item(p);
}
m.complete(p, MEASURES_CLAUSE);
}
fn measure_item(p: &mut Parser) {
if p.nth_contextual(0, ContextualKeyword::Final)
|| p.nth_contextual(0, ContextualKeyword::Running)
{
p.bump_as(CONTEXTUAL_KEYWORD);
}
select_item(p);
}
fn pattern_clause(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); if p.at(L_PAREN) {
let b = p.start();
balanced_parens(p);
b.complete(p, PATTERN_BODY);
} else {
p.error("expected '(' after PATTERN");
}
m.complete(p, PATTERN_CLAUSE);
}
fn define_clause(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); define_item(p);
while p.eat(COMMA) {
define_item(p);
}
m.complete(p, DEFINE_CLAUSE);
}
fn define_item(p: &mut Parser) {
let m = p.start();
name_ref(p); p.expect(AS_KW);
expr(p); m.complete(p, DEFINE_ITEM);
}
fn subset_clause(p: &mut Parser) {
let m = p.start();
p.bump_as(CONTEXTUAL_KEYWORD); loop {
name_ref(p);
p.expect(EQ);
if p.at(L_PAREN) {
column_list(p);
}
if !p.eat(COMMA) {
break;
}
}
m.complete(p, SUBSET_CLAUSE);
}
fn at_row_match_clause(p: &Parser) -> bool {
(p.nth_contextual(0, ContextualKeyword::One) || p.at(ALL_KW))
&& (p.nth_at(1, ROW_KW) || p.nth_at(1, ROWS_KW))
}
fn row_match_clause(p: &mut Parser) {
let m = p.start();
if p.at(ALL_KW) {
p.bump(ALL_KW);
} else {
p.bump_as(CONTEXTUAL_KEYWORD); }
while !p.at(R_PAREN) && !p.at_eof() && !at_mr_clause_start(p) {
soft_keyword_word(p);
}
m.complete(p, ROW_MATCH_CLAUSE);
}
fn after_match_clause(p: &mut Parser) {
let m = p.start();
p.bump(AFTER_KW);
if p.nth_contextual(0, ContextualKeyword::Match) {
p.bump_as(CONTEXTUAL_KEYWORD); }
if p.nth_contextual(0, ContextualKeyword::Skip) {
p.bump_as(CONTEXTUAL_KEYWORD); }
if p.nth_contextual(0, ContextualKeyword::Past) {
p.bump_as(CONTEXTUAL_KEYWORD); p.eat(LAST_KW);
p.eat(ROW_KW);
} else if p.nth_contextual(0, ContextualKeyword::To) {
p.bump_as(CONTEXTUAL_KEYWORD); if p.nth_contextual(0, ContextualKeyword::Next) {
p.bump_as(CONTEXTUAL_KEYWORD); p.eat(ROW_KW);
} else {
if p.at(FIRST_KW) || p.at(LAST_KW) {
p.bump_any();
}
if p.at_name() {
name_ref(p); }
}
}
m.complete(p, AFTER_MATCH_CLAUSE);
}
fn at_mr_clause_start(p: &Parser) -> bool {
p.at(PARTITION_KW)
|| p.at(ORDER_KW)
|| p.at(AFTER_KW)
|| p.nth_contextual(0, ContextualKeyword::Measures)
|| p.nth_contextual(0, ContextualKeyword::Pattern)
|| p.nth_contextual(0, ContextualKeyword::Define)
|| p.nth_contextual(0, ContextualKeyword::Subset)
|| at_row_match_clause(p)
}
fn soft_keyword_word(p: &mut Parser) {
if p.at_ident_like() {
p.bump_as(CONTEXTUAL_KEYWORD);
} else {
p.bump_any();
}
}