1use super::{combinator::*, identifier::*};
2use crate::ast::*;
3
4pub fn abstract_entity_declaration(input: &str) -> ParseResult<Constraint> {
6 tag("ABSTRACT")
7 .map(|_| Constraint::AbstractEntity)
8 .parse(input)
9}
10
11pub fn abstract_supertype_declaration(input: &str) -> ParseResult<Constraint> {
13 tuple((tag("ABSTRACT"), tag("SUPERTYPE"), opt(subtype_constraint)))
14 .map(|(_abstract, _supertype, expr)| Constraint::AbstractSuperType(expr))
15 .parse(input)
16}
17
18pub fn subsuper(input: &str) -> ParseResult<(Option<Constraint>, Option<SubTypeDecl>)> {
20 tuple((opt(supertype_constraint), opt(subtype_declaration))).parse(input)
21}
22
23pub fn subtype_declaration(input: &str) -> ParseResult<SubTypeDecl> {
25 tuple((
26 tag("SUBTYPE"),
27 tag("OF"),
28 char('('),
29 comma_separated(entity_ref),
30 char(')'),
31 ))
32 .map(|(_subtype, _of, _open, entity_references, _close)| SubTypeDecl { entity_references })
33 .parse(input)
34}
35
36pub fn subtype_constraint(input: &str) -> ParseResult<SuperTypeExpression> {
38 tuple((tag("OF"), char('('), supertype_expression, char(')')))
39 .map(|(_of, _open, expr, _close)| expr)
40 .parse(input)
41}
42
43pub fn supertype_constraint(input: &str) -> ParseResult<Constraint> {
45 alt((
46 abstract_supertype_declaration,
47 abstract_entity_declaration,
48 supertype_rule,
49 ))
50 .parse(input)
51}
52
53pub fn supertype_expression(input: &str) -> ParseResult<SuperTypeExpression> {
55 tuple((
56 supertype_factor,
57 many0(tuple((tag("ANDOR"), supertype_factor))),
58 ))
59 .map(|(first, tails)| {
60 if !tails.is_empty() {
61 let mut factors = vec![first];
62 for (_andor, factor) in tails {
63 factors.push(factor)
64 }
65 SuperTypeExpression::AndOr { factors }
66 } else {
67 first
68 }
69 })
70 .parse(input)
71}
72
73pub fn supertype_factor(input: &str) -> ParseResult<SuperTypeExpression> {
75 tuple((supertype_term, many0(tuple((tag("AND"), supertype_term)))))
76 .map(|(first, tails)| {
77 if !tails.is_empty() {
78 let mut terms = vec![first];
79 for (_and, term) in tails {
80 terms.push(term)
81 }
82 SuperTypeExpression::And { terms }
83 } else {
84 first
85 }
86 })
87 .parse(input)
88}
89
90pub fn supertype_term(input: &str) -> ParseResult<SuperTypeExpression> {
92 let expr =
93 tuple((char('('), supertype_expression, char(')'))).map(|(_open, expr, _close)| expr);
94 alt((entity_ref.map(SuperTypeExpression::Reference), one_of, expr)).parse(input)
95}
96
97pub fn supertype_rule(input: &str) -> ParseResult<Constraint> {
99 tuple((tag("SUPERTYPE"), subtype_constraint))
100 .map(|(_supertype, constraint)| Constraint::SuperTypeRule(constraint))
101 .parse(input)
102}
103
104pub fn one_of(input: &str) -> ParseResult<SuperTypeExpression> {
106 tuple((
107 tag("ONEOF"),
108 char('('),
109 comma_separated(supertype_expression),
110 char(')'),
111 ))
112 .map(|(_oneof, _open, exprs, _close)| SuperTypeExpression::OneOf { exprs })
113 .parse(input)
114}
115
116pub fn subtype_constraint_decl(input: &str) -> ParseResult<SubTypeConstraint> {
118 tuple((
119 subtype_constraint_head,
120 subtype_constraint_body,
121 tag("END_SUBTYPE_CONSTRAINT"),
122 char(';'),
123 ))
124 .map(
125 |((name, entity), (is_abstract, total_over, expr), _end, _semicolon)| SubTypeConstraint {
126 name,
127 entity,
128 is_abstract,
129 total_over,
130 expr,
131 },
132 )
133 .parse(input)
134}
135
136pub fn subtype_constraint_head(input: &str) -> ParseResult<(String, String)> {
138 tuple((
139 tag("SUBTYPE_CONSTRAINT"),
140 subtype_constraint_id,
141 tag("FOR"),
142 entity_ref,
143 char(';'),
144 ))
145 .map(|(_start, id, _for, entity, _semicolon)| (id, entity))
146 .parse(input)
147}
148
149pub fn subtype_constraint_body(
151 input: &str,
152) -> ParseResult<(bool, Option<Vec<String>>, Option<SuperTypeExpression>)> {
153 tuple((
154 opt(abstract_supertype).map(|opt| opt.is_some()),
155 opt(total_over),
156 opt(tuple((supertype_expression, char(';'))).map(|(expr, _semicolon)| expr)),
157 ))
158 .parse(input)
159}
160
161pub fn total_over(input: &str) -> ParseResult<Vec<String>> {
163 tuple((
164 tag("TOTAL_OVER"),
165 char('('),
166 many1(entity_ref),
167 char(')'),
168 char(';'),
169 ))
170 .map(|(_start, _open, references, _close, _semicolon)| references)
171 .parse(input)
172}
173
174pub fn abstract_supertype(input: &str) -> ParseResult<()> {
176 tuple((tag("ABSTRACT"), tag("SUPERTYPE"), char(';')))
177 .map(|(_abstract, _supertype, _semicolon)| ())
178 .parse(input)
179}
180
181#[cfg(test)]
182mod tests {
183 use nom::Finish;
184
185 #[test]
186 fn subtype_constraint_oneof() {
187 let exp_str = r#"
188 SUBTYPE_CONSTRAINT separate_species FOR pet;
189 ABSTRACT SUPERTYPE;
190 ONEOF(cat, rabbit, dog);
191 END_SUBTYPE_CONSTRAINT;
192 "#
193 .trim();
194
195 let (residual, (entity, _remark)) =
196 super::subtype_constraint_decl(exp_str).finish().unwrap();
197 dbg!(&entity);
198 assert_eq!(residual, "");
199 }
200}