use super::{
IntoChildNodes, Node, Rule, RuleMatcher,
literal::{visit_integer_literal, visit_quoted_string_literal, visit_value_literal},
visit_identifier,
};
use crate::{
annotation::{
Abstract, Annotation, Cardinality, CardinalityRange, Cascade, Distinct, Doc, Independent, Key, Meta, Range,
Regex, Subkey, Unique, Values,
},
common::{Spanned, error::TypeQLError},
value::Literal,
};
pub(super) fn visit_annotations(node: Node<'_>) -> Vec<Annotation> {
debug_assert_eq!(node.as_rule(), Rule::annotations);
node.into_children().map(visit_annotation).collect()
}
fn visit_annotation(node: Node<'_>) -> Annotation {
debug_assert_eq!(node.as_rule(), Rule::annotation);
let span = node.span();
let child = node.into_child();
match child.as_rule() {
Rule::ANNOTATION_ABSTRACT => Annotation::Abstract(Abstract::new(span)),
Rule::ANNOTATION_CASCADE => Annotation::Cascade(Cascade::new(span)),
Rule::ANNOTATION_DISTINCT => Annotation::Distinct(Distinct::new(span)),
Rule::ANNOTATION_INDEPENDENT => Annotation::Independent(Independent::new(span)),
Rule::ANNOTATION_KEY => Annotation::Key(Key::new(span)),
Rule::ANNOTATION_UNIQUE => Annotation::Unique(Unique::new(span)),
Rule::annotation_card => Annotation::Cardinality(visit_annotation_card(child)),
Rule::annotation_doc => Annotation::Doc(visit_annotation_doc(child)),
Rule::annotation_meta => Annotation::Meta(visit_annotation_meta(child)),
Rule::annotation_range => Annotation::Range(visit_annotation_range(child)),
Rule::annotation_regex => Annotation::Regex(visit_annotation_regex(child)),
Rule::annotation_subkey => Annotation::Subkey(visit_annotation_subkey(child)),
Rule::annotation_values => Annotation::Values(visit_annotation_values(child)),
_ => unreachable!("{}", TypeQLError::IllegalGrammar { input: child.as_str().to_owned() }),
}
}
fn visit_annotation_card(node: Node<'_>) -> Cardinality {
debug_assert_eq!(node.as_rule(), Rule::annotation_card);
let span = node.span();
let mut children = node.into_children();
children.skip_expected(Rule::ANNOTATION_CARD);
let child = children.consume_any();
let inner = match child.as_rule() {
Rule::cardinality_exact => visit_cardinality_exact(child),
Rule::cardinality_range => visit_cardinality_range(child),
_ => unreachable!("{}", TypeQLError::IllegalGrammar { input: child.as_str().to_owned() }),
};
debug_assert_eq!(children.try_consume_any(), None);
Cardinality::new(span, inner)
}
fn visit_cardinality_exact(node: Node<'_>) -> CardinalityRange {
debug_assert_eq!(node.as_rule(), Rule::cardinality_exact);
CardinalityRange::Exact(visit_integer_literal(node.into_child()))
}
fn visit_cardinality_range(node: Node<'_>) -> CardinalityRange {
debug_assert_eq!(node.as_rule(), Rule::cardinality_range);
let mut children = node.into_children();
let min = visit_integer_literal(children.consume_expected(Rule::integer_literal));
let max = children.try_consume_expected(Rule::integer_literal).map(visit_integer_literal);
debug_assert_eq!(children.try_consume_any(), None);
CardinalityRange::Range(min, max)
}
fn visit_annotation_doc(node: Node<'_>) -> Doc {
debug_assert_eq!(node.as_rule(), Rule::annotation_doc);
let span = node.span();
let mut children = node.into_children();
children.consume_expected(Rule::ANNOTATION_DOC);
let doc = visit_quoted_string_literal(children.consume_expected(Rule::quoted_string_literal));
debug_assert_eq!(children.try_consume_any(), None);
Doc::new(span, doc)
}
fn visit_annotation_meta(node: Node<'_>) -> Meta {
debug_assert_eq!(node.as_rule(), Rule::annotation_meta);
let span = node.span();
let mut children = node.into_children();
children.consume_expected(Rule::ANNOTATION_META);
let key = visit_quoted_string_literal(children.consume_expected(Rule::quoted_string_literal));
let value = visit_quoted_string_literal(children.consume_expected(Rule::quoted_string_literal));
debug_assert_eq!(children.try_consume_any(), None);
Meta::new(span, key, value)
}
fn visit_annotation_range(node: Node<'_>) -> Range {
debug_assert_eq!(node.as_rule(), Rule::annotation_range);
let span = node.span();
let mut children = node.into_children();
let (lower, upper) = visit_range(children.skip_expected(Rule::ANNOTATION_RANGE).consume_expected(Rule::range));
debug_assert_eq!(children.try_consume_any(), None);
Range::new(span, lower, upper)
}
fn visit_range(node: Node<'_>) -> (Option<Literal>, Option<Literal>) {
debug_assert_eq!(node.as_rule(), Rule::range);
let child = node.into_child();
match child.as_rule() {
Rule::range_full => visit_range_full(child),
Rule::range_from => visit_range_from(child),
Rule::range_to => visit_range_to(child),
_ => unreachable!("{}", TypeQLError::IllegalGrammar { input: child.as_str().to_owned() }),
}
}
fn visit_range_full(node: Node<'_>) -> (Option<Literal>, Option<Literal>) {
debug_assert_eq!(node.as_rule(), Rule::range_full);
let mut children = node.into_children();
let lower = visit_value_literal(children.consume_expected(Rule::value_literal));
let upper = visit_value_literal(children.consume_expected(Rule::value_literal));
debug_assert_eq!(children.try_consume_any(), None);
(Some(lower), Some(upper))
}
fn visit_range_from(node: Node<'_>) -> (Option<Literal>, Option<Literal>) {
debug_assert_eq!(node.as_rule(), Rule::range_from);
let mut children = node.into_children();
let lower = visit_value_literal(children.consume_expected(Rule::value_literal));
debug_assert_eq!(children.try_consume_any(), None);
(Some(lower), None)
}
fn visit_range_to(node: Node<'_>) -> (Option<Literal>, Option<Literal>) {
debug_assert_eq!(node.as_rule(), Rule::range_to);
let mut children = node.into_children();
let upper = visit_value_literal(children.consume_expected(Rule::value_literal));
debug_assert_eq!(children.try_consume_any(), None);
(None, Some(upper))
}
fn visit_annotation_subkey(node: Node<'_>) -> Subkey {
debug_assert_eq!(node.as_rule(), Rule::annotation_subkey);
let span = node.span();
let mut children = node.into_children();
children.consume_expected(Rule::ANNOTATION_SUBKEY);
let ident = visit_identifier(children.consume_expected(Rule::identifier));
debug_assert_eq!(children.try_consume_any(), None);
Subkey::new(span, ident)
}
fn visit_annotation_regex(node: Node<'_>) -> Regex {
debug_assert_eq!(node.as_rule(), Rule::annotation_regex);
let span = node.span();
let mut children = node.into_children();
children.consume_expected(Rule::ANNOTATION_REGEX);
let regex = visit_quoted_string_literal(children.consume_expected(Rule::quoted_string_literal));
debug_assert_eq!(children.try_consume_any(), None);
Regex::new(span, regex)
}
fn visit_annotation_values(node: Node<'_>) -> Values {
debug_assert_eq!(node.as_rule(), Rule::annotation_values);
let span = node.span();
let values = node.into_children().skip_expected(Rule::ANNOTATION_VALUES).map(visit_value_literal).collect();
Values::new(span, values)
}