use super::{combinator::*, identifier::*};
use crate::ast::*;
pub fn abstract_entity_declaration(input: &str) -> ParseResult<Constraint> {
tag("ABSTRACT")
.map(|_| Constraint::AbstractEntity)
.parse(input)
}
pub fn abstract_supertype_declaration(input: &str) -> ParseResult<Constraint> {
tuple((tag("ABSTRACT"), tag("SUPERTYPE"), opt(subtype_constraint)))
.map(|(_abstract, _supertype, expr)| Constraint::AbstractSuperType(expr))
.parse(input)
}
pub fn subsuper(input: &str) -> ParseResult<(Option<Constraint>, Option<SubTypeDecl>)> {
tuple((opt(supertype_constraint), opt(subtype_declaration))).parse(input)
}
pub fn subtype_declaration(input: &str) -> ParseResult<SubTypeDecl> {
tuple((
tag("SUBTYPE"),
tag("OF"),
char('('),
comma_separated(entity_ref),
char(')'),
))
.map(|(_subtype, _of, _open, entity_references, _close)| SubTypeDecl { entity_references })
.parse(input)
}
pub fn subtype_constraint(input: &str) -> ParseResult<SuperTypeExpression> {
tuple((tag("OF"), char('('), supertype_expression, char(')')))
.map(|(_of, _open, expr, _close)| expr)
.parse(input)
}
pub fn supertype_constraint(input: &str) -> ParseResult<Constraint> {
alt((
abstract_supertype_declaration,
abstract_entity_declaration,
supertype_rule,
))
.parse(input)
}
pub fn supertype_expression(input: &str) -> ParseResult<SuperTypeExpression> {
tuple((
supertype_factor,
many0(tuple((tag("ANDOR"), supertype_factor))),
))
.map(|(first, tails)| {
if !tails.is_empty() {
let mut factors = vec![first];
for (_andor, factor) in tails {
factors.push(factor)
}
SuperTypeExpression::AndOr { factors }
} else {
first
}
})
.parse(input)
}
pub fn supertype_factor(input: &str) -> ParseResult<SuperTypeExpression> {
tuple((supertype_term, many0(tuple((tag("AND"), supertype_term)))))
.map(|(first, tails)| {
if !tails.is_empty() {
let mut terms = vec![first];
for (_and, term) in tails {
terms.push(term)
}
SuperTypeExpression::And { terms }
} else {
first
}
})
.parse(input)
}
pub fn supertype_term(input: &str) -> ParseResult<SuperTypeExpression> {
let expr =
tuple((char('('), supertype_expression, char(')'))).map(|(_open, expr, _close)| expr);
alt((entity_ref.map(SuperTypeExpression::Reference), one_of, expr)).parse(input)
}
pub fn supertype_rule(input: &str) -> ParseResult<Constraint> {
tuple((tag("SUPERTYPE"), subtype_constraint))
.map(|(_supertype, constraint)| Constraint::SuperTypeRule(constraint))
.parse(input)
}
pub fn one_of(input: &str) -> ParseResult<SuperTypeExpression> {
tuple((
tag("ONEOF"),
char('('),
comma_separated(supertype_expression),
char(')'),
))
.map(|(_oneof, _open, exprs, _close)| SuperTypeExpression::OneOf { exprs })
.parse(input)
}
pub fn subtype_constraint_decl(input: &str) -> ParseResult<SubTypeConstraint> {
tuple((
subtype_constraint_head,
subtype_constraint_body,
tag("END_SUBTYPE_CONSTRAINT"),
char(';'),
))
.map(
|((name, entity), (is_abstract, total_over, expr), _end, _semicolon)| SubTypeConstraint {
name,
entity,
is_abstract,
total_over,
expr,
},
)
.parse(input)
}
pub fn subtype_constraint_head(input: &str) -> ParseResult<(String, String)> {
tuple((
tag("SUBTYPE_CONSTRAINT"),
subtype_constraint_id,
tag("FOR"),
entity_ref,
char(';'),
))
.map(|(_start, id, _for, entity, _semicolon)| (id, entity))
.parse(input)
}
pub fn subtype_constraint_body(
input: &str,
) -> ParseResult<(bool, Option<Vec<String>>, Option<SuperTypeExpression>)> {
tuple((
opt(abstract_supertype).map(|opt| opt.is_some()),
opt(total_over),
opt(tuple((supertype_expression, char(';'))).map(|(expr, _semicolon)| expr)),
))
.parse(input)
}
pub fn total_over(input: &str) -> ParseResult<Vec<String>> {
tuple((
tag("TOTAL_OVER"),
char('('),
many1(entity_ref),
char(')'),
char(';'),
))
.map(|(_start, _open, references, _close, _semicolon)| references)
.parse(input)
}
pub fn abstract_supertype(input: &str) -> ParseResult<()> {
tuple((tag("ABSTRACT"), tag("SUPERTYPE"), char(';')))
.map(|(_abstract, _supertype, _semicolon)| ())
.parse(input)
}
#[cfg(test)]
mod tests {
use nom::Finish;
#[test]
fn subtype_constraint_oneof() {
let exp_str = r#"
SUBTYPE_CONSTRAINT separate_species FOR pet;
ABSTRACT SUPERTYPE;
ONEOF(cat, rabbit, dog);
END_SUBTYPE_CONSTRAINT;
"#
.trim();
let (residual, (entity, _remark)) =
super::subtype_constraint_decl(exp_str).finish().unwrap();
dbg!(&entity);
assert_eq!(residual, "");
}
}