use std::iter::zip;
use std::ops::{Deref, DerefMut};
use ahash::AHashSet;
use crate::dialects::syntax::{SyntaxKind, SyntaxSet};
use crate::errors::SQLParseError;
use crate::helpers::ToMatchable;
use crate::parser::context::ParseContext;
use crate::parser::match_algorithms::{
resolve_bracket, skip_start_index_forward_to_code, skip_stop_index_backward_to_code,
trim_to_terminator,
};
use crate::parser::match_result::{MatchResult, Matched, Span};
use crate::parser::matchable::{
next_matchable_cache_key, Matchable, MatchableCacheKey, MatchableTrait,
};
use crate::parser::segments::base::ErasedSegment;
use crate::parser::types::ParseMode;
fn flush_metas(
tpre_nc_idx: u32,
post_nc_idx: u32,
meta_buffer: Vec<SyntaxKind>,
_segments: &[ErasedSegment],
) -> Vec<(u32, SyntaxKind)> {
let meta_idx = if meta_buffer.iter().all(|it| it.indent_val() >= 0) {
tpre_nc_idx
} else {
post_nc_idx
};
meta_buffer.into_iter().map(|it| (meta_idx, it)).collect()
}
#[derive(Debug, Clone)]
pub struct Sequence {
elements: Vec<Matchable>,
pub parse_mode: ParseMode,
pub allow_gaps: bool,
is_optional: bool,
pub terminators: Vec<Matchable>,
cache_key: MatchableCacheKey,
}
impl Sequence {
pub fn disallow_gaps(&mut self) {
self.allow_gaps = false;
}
}
impl Sequence {
pub fn new(elements: Vec<Matchable>) -> Self {
Self {
elements,
allow_gaps: true,
is_optional: false,
parse_mode: ParseMode::Strict,
terminators: Vec::new(),
cache_key: next_matchable_cache_key(),
}
}
pub fn optional(&mut self) {
self.is_optional = true;
}
pub fn terminators(mut self, terminators: Vec<Matchable>) -> Self {
self.terminators = terminators;
self
}
pub fn parse_mode(&mut self, mode: ParseMode) {
self.parse_mode = mode;
}
pub fn allow_gaps(mut self, allow_gaps: bool) -> Self {
self.allow_gaps = allow_gaps;
self
}
}
impl PartialEq for Sequence {
fn eq(&self, other: &Self) -> bool {
zip(&self.elements, &other.elements).all(|(a, b)| a == b)
}
}
impl MatchableTrait for Sequence {
fn elements(&self) -> &[Matchable] {
&self.elements
}
fn is_optional(&self) -> bool {
self.is_optional
}
fn simple(
&self,
parse_context: &ParseContext,
crumbs: Option<Vec<&str>>,
) -> Option<(AHashSet<String>, SyntaxSet)> {
let mut simple_raws = AHashSet::new();
let mut simple_types = SyntaxSet::EMPTY;
for opt in &self.elements {
let (raws, types) = opt.simple(parse_context, crumbs.clone())?;
simple_raws.extend(raws);
simple_types.extend(types);
if !opt.is_optional() {
return Some((simple_raws, simple_types));
}
}
(simple_raws, simple_types).into()
}
fn match_segments(
&self,
segments: &[ErasedSegment],
mut idx: u32,
parse_context: &mut ParseContext,
) -> Result<MatchResult, SQLParseError> {
let start_idx = idx;
let mut matched_idx = idx;
let mut max_idx = segments.len() as u32;
let mut insert_segments = Vec::new();
let mut child_matches = Vec::new();
let mut first_match = true;
let mut meta_buffer = Vec::new();
if self.parse_mode == ParseMode::Greedy {
let terminators =
[self.terminators.clone(), parse_context.terminators.clone()].concat();
max_idx = trim_to_terminator(segments, idx, &terminators, parse_context)?;
}
for elem in &self.elements {
if let Some(indent) = elem.as_conditional() {
let match_result = indent.match_segments(segments, matched_idx, parse_context)?;
for (_, submatch) in match_result.insert_segments {
meta_buffer.push(submatch);
}
continue;
} else if let Some(indent) = elem.as_indent() {
meta_buffer.push(indent.kind);
continue;
}
idx = if self.allow_gaps {
skip_start_index_forward_to_code(segments, matched_idx, max_idx)
} else {
matched_idx
};
if idx >= max_idx {
if elem.is_optional() {
continue;
}
if self.parse_mode == ParseMode::Strict || matched_idx == start_idx {
return Ok(MatchResult::empty_at(idx));
}
insert_segments.extend(meta_buffer.into_iter().map(|meta| (matched_idx, meta)));
return Ok(MatchResult {
span: Span {
start: start_idx,
end: matched_idx,
},
insert_segments,
child_matches,
matched: Matched::SyntaxKind(SyntaxKind::Unparsable).into(),
});
}
let mut elem_match = parse_context.deeper_match(false, &[], |ctx| {
elem.match_segments(&segments[..max_idx as usize], idx, ctx)
})?;
if !elem_match.has_match() {
if elem.is_optional() {
continue;
}
if self.parse_mode == ParseMode::Strict {
return Ok(MatchResult::empty_at(idx));
}
if self.parse_mode == ParseMode::GreedyOnceStarted && matched_idx == start_idx {
return Ok(MatchResult::empty_at(idx));
}
if matched_idx == start_idx {
return Ok(MatchResult {
span: Span {
start: start_idx,
end: max_idx,
},
matched: Matched::SyntaxKind(SyntaxKind::Unparsable).into(),
..MatchResult::default()
});
}
child_matches.push(MatchResult {
span: Span {
start: skip_start_index_forward_to_code(segments, matched_idx, max_idx),
end: max_idx,
},
matched: Matched::SyntaxKind(SyntaxKind::Unparsable).into(),
..MatchResult::default()
});
return Ok(MatchResult {
span: Span {
start: start_idx,
end: max_idx,
},
insert_segments,
child_matches,
matched: None,
});
}
let meta_buffer = std::mem::take(&mut meta_buffer);
insert_segments.append(&mut flush_metas(matched_idx, idx, meta_buffer, segments));
matched_idx = elem_match.span.end;
if first_match && self.parse_mode == ParseMode::GreedyOnceStarted {
let terminators =
[self.terminators.clone(), parse_context.terminators.clone()].concat();
max_idx = trim_to_terminator(segments, matched_idx, &terminators, parse_context)?;
first_match = false;
}
if elem_match.matched.is_some() {
child_matches.push(elem_match);
continue;
}
child_matches.append(&mut elem_match.child_matches);
insert_segments.append(&mut elem_match.insert_segments);
}
insert_segments.extend(meta_buffer.into_iter().map(|meta| (matched_idx, meta)));
if matches!(
self.parse_mode,
ParseMode::Greedy | ParseMode::GreedyOnceStarted
) && max_idx > matched_idx
{
let idx = skip_start_index_forward_to_code(segments, matched_idx, max_idx);
let stop_idx = skip_stop_index_backward_to_code(segments, max_idx, idx);
if stop_idx > idx {
child_matches.push(MatchResult {
span: Span {
start: idx,
end: stop_idx,
},
matched: Matched::SyntaxKind(SyntaxKind::Unparsable).into(),
..Default::default()
});
matched_idx = stop_idx;
}
}
Ok(MatchResult {
span: Span {
start: start_idx,
end: matched_idx,
},
matched: None,
insert_segments,
child_matches,
})
}
fn cache_key(&self) -> MatchableCacheKey {
self.cache_key
}
fn copy(
&self,
insert: Option<Vec<Matchable>>,
at: Option<usize>,
before: Option<Matchable>,
remove: Option<Vec<Matchable>>,
terminators: Vec<Matchable>,
replace_terminators: bool,
) -> Matchable {
let mut new_elements = self.elements.clone();
if let Some(insert_elements) = insert {
if let Some(before_element) = before {
if let Some(index) = self.elements.iter().position(|e| e == &before_element) {
new_elements.splice(index..index, insert_elements);
} else {
panic!("Element for insertion before not found");
}
} else if let Some(at_index) = at {
new_elements.splice(at_index..at_index, insert_elements);
} else {
new_elements.extend(insert_elements);
}
}
if let Some(remove_elements) = remove {
new_elements.retain(|elem| !remove_elements.contains(elem));
}
let mut new_grammar = self.clone();
new_grammar.elements = new_elements;
new_grammar.terminators = if replace_terminators {
terminators
} else {
[self.terminators.clone(), terminators].concat()
};
new_grammar.to_matchable()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Bracketed {
pub bracket_type: &'static str,
pub bracket_pairs_set: &'static str,
allow_gaps: bool,
pub this: Sequence,
}
impl Bracketed {
pub fn new(args: Vec<Matchable>) -> Self {
Self {
bracket_type: "round",
bracket_pairs_set: "bracket_pairs",
allow_gaps: true,
this: Sequence::new(args),
}
}
}
type BracketInfo = Result<(Matchable, Matchable, bool), String>;
impl Bracketed {
pub fn bracket_type(&mut self, bracket_type: &'static str) {
self.bracket_type = bracket_type;
}
fn get_bracket_from_dialect(&self, parse_context: &ParseContext) -> BracketInfo {
let bracket_pairs = parse_context.dialect().bracket_sets(self.bracket_pairs_set);
for (bracket_type, start_ref, end_ref, persists) in bracket_pairs {
if bracket_type == self.bracket_type {
let start_bracket = parse_context.dialect().r#ref(start_ref);
let end_bracket = parse_context.dialect().r#ref(end_ref);
return Ok((start_bracket, end_bracket, persists));
}
}
Err(format!(
"bracket_type {:?} not found in bracket_pairs ({}) of {:?} dialect.",
self.bracket_type,
self.bracket_pairs_set,
parse_context.dialect().name
))
}
}
impl Deref for Bracketed {
type Target = Sequence;
fn deref(&self) -> &Self::Target {
&self.this
}
}
impl DerefMut for Bracketed {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.this
}
}
impl MatchableTrait for Bracketed {
fn elements(&self) -> &[Matchable] {
&self.elements
}
fn is_optional(&self) -> bool {
self.this.is_optional()
}
fn simple(
&self,
parse_context: &ParseContext,
crumbs: Option<Vec<&str>>,
) -> Option<(AHashSet<String>, SyntaxSet)> {
let (start_bracket, _, _) = self.get_bracket_from_dialect(parse_context).unwrap();
start_bracket.simple(parse_context, crumbs)
}
fn match_segments(
&self,
segments: &[ErasedSegment],
idx: u32,
parse_context: &mut ParseContext,
) -> Result<MatchResult, SQLParseError> {
let (start_bracket, end_bracket, bracket_persists) =
self.get_bracket_from_dialect(parse_context).unwrap();
let start_match = parse_context.deeper_match(false, &[], |ctx| {
start_bracket.match_segments(segments, idx, ctx)
})?;
if !start_match.has_match() {
return Ok(MatchResult::empty_at(idx));
}
let start_match_span = start_match.span;
let bracketed_match = resolve_bracket(
segments,
start_match,
start_bracket.clone(),
&[start_bracket],
&[end_bracket.clone()],
&[bracket_persists],
parse_context,
false,
)?;
let mut idx = start_match_span.end;
let mut end_idx = bracketed_match.span.end - 1;
if self.allow_gaps {
idx = skip_start_index_forward_to_code(segments, idx, segments.len() as u32);
end_idx = skip_stop_index_backward_to_code(segments, end_idx, idx);
}
let mut content_match =
parse_context.deeper_match(true, &[end_bracket.clone()], |ctx| {
self.this
.match_segments(&segments[..end_idx as usize], idx, ctx)
})?;
if content_match.span.end != end_idx && self.parse_mode == ParseMode::Strict {
return Ok(MatchResult::empty_at(idx));
}
let intermediate_slice = Span {
start: content_match.span.end,
end: bracketed_match.span.end - 1,
};
if !self.allow_gaps && intermediate_slice.start == intermediate_slice.end {
unimplemented!()
}
let mut child_matches = bracketed_match.child_matches;
if content_match.matched.is_some() {
child_matches.push(content_match);
} else {
child_matches.append(&mut content_match.child_matches);
}
Ok(MatchResult {
child_matches,
..bracketed_match
})
}
fn cache_key(&self) -> MatchableCacheKey {
self.this.cache_key()
}
}