use std::{
collections::{HashMap, HashSet},
fmt::{self, Display, Formatter},
ops::RangeInclusive,
rc::Rc,
sync::Arc,
};
use ordermap::OrderSet;
use antlr_rust::tree::ParseTree;
use derive_more::derive::From;
use crate::antlr::strip_numeric_separators;
use super::clause::{FromClause, TableReference};
use super::identifier::Identifier;
use super::node::{Span, Spannable};
use super::query::push_datasets_for_table_reference;
use crate::tree::options::TemplateParameterKind;
use crate::{
antlr::{
hamelinparser::{
ExactlyContextAttrs, NestedContext, NestedContextAttrs, PatternContextAll,
QuantifiedContext, QuantifiedContextAttrs, QuantifierContextAll,
},
interval,
},
err::TranslationError,
tree::ast::context::{FromCst, ParseContext},
};
#[derive(Debug, Clone)]
pub struct Pattern {
pub span: Span,
pub kind: PatternKind,
}
impl PartialEq for Pattern {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind
}
}
impl Spannable for Pattern {
fn span(&self) -> Option<RangeInclusive<usize>> {
self.span.to_range()
}
}
impl From<PatternKind> for Pattern {
fn from(kind: PatternKind) -> Self {
Self {
span: Span::NONE,
kind,
}
}
}
impl Pattern {
pub fn has_template_parameters(&self) -> bool {
match &self.kind {
PatternKind::Quantified(qp) => qp.from_clause.table_reference().is_templated(),
PatternKind::Nested(np) => np.patterns.iter().any(|p| p.has_template_parameters()),
PatternKind::Error(_) => false,
}
}
pub fn extract_datasets(
&self,
cte_names: &HashSet<Identifier>,
datasets: &mut OrderSet<Identifier>,
template_parameters: Option<&HashMap<String, TemplateParameterKind>>,
) -> Result<(), Arc<TranslationError>> {
match &self.kind {
PatternKind::Quantified(qp) => {
let table_ref = qp.from_clause.table_reference();
push_datasets_for_table_reference(
&table_ref,
cte_names,
datasets,
template_parameters,
)?;
}
PatternKind::Nested(np) => {
for pattern in &np.patterns {
pattern.extract_datasets(cte_names, datasets, template_parameters)?;
}
}
PatternKind::Error(_) => {}
}
Ok(())
}
}
impl FromCst<Rc<PatternContextAll<'static>>> for Pattern {
fn from_cst_with_context(cst: Rc<PatternContextAll<'static>>, ctx: &mut ParseContext) -> Self {
let kind = PatternKind::from_cst_with_context(Rc::clone(&cst), ctx);
Self {
span: interval(cst.as_ref()).into(),
kind,
}
}
}
#[derive(Debug, Clone, From, PartialEq)]
pub enum PatternKind {
Quantified(QuantifiedPattern),
Nested(NestedPattern),
Error(Arc<TranslationError>),
}
impl Spannable for PatternKind {
fn span(&self) -> Option<RangeInclusive<usize>> {
match self {
PatternKind::Quantified(p) => p.span(),
PatternKind::Nested(p) => p.span(),
PatternKind::Error(_) => None,
}
}
}
impl FromCst<Rc<PatternContextAll<'static>>> for PatternKind {
fn from_cst_with_context(cst: Rc<PatternContextAll<'static>>, ctx: &mut ParseContext) -> Self {
match cst.as_ref() {
PatternContextAll::QuantifiedContext(qctx) => {
QuantifiedPattern::from_ast_with_context(qctx, ctx).into()
}
PatternContextAll::NestedContext(nctx) => {
NestedPattern::from_ast_with_context(nctx, ctx).into()
}
PatternContextAll::Error(_) => ctx.error("parse error").at(cst.as_ref()).emit().into(),
}
}
}
#[derive(Debug, Clone)]
pub struct QuantifiedPattern {
pub span: Span,
pub from_clause: Arc<FromClause>,
pub quantifier: Option<Arc<Quantifier>>,
}
impl PartialEq for QuantifiedPattern {
fn eq(&self, other: &Self) -> bool {
self.from_clause == other.from_clause && self.quantifier == other.quantifier
}
}
impl Spannable for QuantifiedPattern {
fn span(&self) -> Option<RangeInclusive<usize>> {
self.span.to_range()
}
}
impl QuantifiedPattern {
fn from_ast_with_context(qctx: &QuantifiedContext<'static>, ctx: &mut ParseContext) -> Self {
let from_clause = Arc::new(
qctx.fromClause()
.map(|fc| FromClause::from_cst_with_context(fc, ctx))
.unwrap_or_else(|| {
TableReference {
span: Span::NONE,
target: ctx
.error("missing from clause in quantified pattern")
.at(qctx)
.emit()
.into(),
}
.into()
}),
);
let quantifier = qctx
.quantifier()
.map(|q| Arc::new(Quantifier::from_cst_with_context(q, ctx)));
Self {
span: interval(qctx).into(),
from_clause,
quantifier,
}
}
}
#[derive(Debug, Clone)]
pub struct NestedPattern {
pub span: Span,
pub patterns: Vec<Arc<Pattern>>,
pub quantifier: Arc<Quantifier>,
}
impl PartialEq for NestedPattern {
fn eq(&self, other: &Self) -> bool {
self.patterns == other.patterns && self.quantifier == other.quantifier
}
}
impl Spannable for NestedPattern {
fn span(&self) -> Option<RangeInclusive<usize>> {
self.span.to_range()
}
}
impl NestedPattern {
fn from_ast_with_context(nctx: &NestedContext<'static>, ctx: &mut ParseContext) -> Self {
let patterns = nctx
.pattern_all()
.into_iter()
.map(|p| Arc::new(Pattern::from_cst_with_context(p, ctx)))
.collect();
let quantifier = Arc::new(
nctx.quantifier()
.map(|q| Quantifier::from_cst_with_context(q, ctx))
.unwrap_or_else(|| {
ctx.error("missing quantifier in nested pattern")
.at(nctx)
.emit()
.into()
}),
);
Self {
span: interval(nctx).into(),
patterns,
quantifier,
}
}
}
#[derive(Debug, Clone)]
pub struct Quantifier {
pub span: Span,
pub kind: QuantifierKind,
}
impl PartialEq for Quantifier {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind
}
}
impl Spannable for Quantifier {
fn span(&self) -> Option<RangeInclusive<usize>> {
self.span.to_range()
}
}
impl From<QuantifierKind> for Quantifier {
fn from(kind: QuantifierKind) -> Self {
Self {
span: Span::NONE,
kind,
}
}
}
impl From<Arc<TranslationError>> for Quantifier {
fn from(error: Arc<TranslationError>) -> Self {
Self {
span: Span::NONE,
kind: QuantifierKind::Error(error),
}
}
}
impl FromCst<Rc<QuantifierContextAll<'static>>> for Quantifier {
fn from_cst_with_context(
cst: Rc<QuantifierContextAll<'static>>,
ctx: &mut ParseContext,
) -> Self {
let kind = QuantifierKind::from_cst_with_context(Rc::clone(&cst), ctx);
Self {
span: interval(cst.as_ref()).into(),
kind,
}
}
}
#[derive(Debug, Clone, From, PartialEq)]
pub enum QuantifierKind {
AtLeastOne, AnyNumber, ZeroOrOne, Exactly(String), Error(Arc<TranslationError>),
}
impl FromCst<Rc<QuantifierContextAll<'static>>> for QuantifierKind {
fn from_cst_with_context(
cst: Rc<QuantifierContextAll<'static>>,
ctx: &mut ParseContext,
) -> Self {
match cst.as_ref() {
QuantifierContextAll::AtLeastOneContext(_) => QuantifierKind::AtLeastOne,
QuantifierContextAll::AnyNumberContext(_) => QuantifierKind::AnyNumber,
QuantifierContextAll::ZeroOrOneContext(_) => QuantifierKind::ZeroOrOne,
QuantifierContextAll::ExactlyContext(ectx) => match ectx.INTEGER_VALUE() {
Some(v) => {
QuantifierKind::Exactly(strip_numeric_separators(&v.get_text()).into_owned())
}
None => ctx
.error("missing integer value in exact quantifier")
.at(ectx)
.emit()
.into(),
},
QuantifierContextAll::Error(_) => {
ctx.error("parse error").at(cst.as_ref()).emit().into()
}
}
}
}
impl Pattern {
pub fn fmt_indented(&self, f: &mut Formatter<'_>, indentation: usize) -> fmt::Result {
self.kind.fmt_indented(f, indentation)
}
}
impl Display for Pattern {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.fmt_indented(f, 0)
}
}
impl PatternKind {
pub fn fmt_indented(&self, f: &mut Formatter<'_>, indentation: usize) -> fmt::Result {
match self {
PatternKind::Quantified(q) => q.fmt_indented(f, indentation),
PatternKind::Nested(n) => n.fmt_indented(f, indentation),
PatternKind::Error(_) => write!(f, "?!"),
}
}
}
impl QuantifiedPattern {
pub fn fmt_indented(&self, f: &mut Formatter<'_>, indentation: usize) -> fmt::Result {
self.from_clause.fmt_indented(f, indentation)?;
if let Some(q) = &self.quantifier {
write!(f, "{}", q)?;
}
Ok(())
}
}
impl NestedPattern {
pub fn fmt_indented(&self, f: &mut Formatter<'_>, indentation: usize) -> fmt::Result {
write!(f, "(")?;
for (i, pat) in self.patterns.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
pat.fmt_indented(f, indentation + 1)?;
}
write!(f, ")")?;
write!(f, "{}", self.quantifier)
}
}
impl Display for Quantifier {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kind)
}
}
impl Display for QuantifierKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
QuantifierKind::AtLeastOne => write!(f, "+"),
QuantifierKind::AnyNumber => write!(f, "*"),
QuantifierKind::ZeroOrOne => write!(f, "?"),
QuantifierKind::Exactly(n) => write!(f, "{{{}}}", n),
QuantifierKind::Error(_) => write!(f, "?!"),
}
}
}