1use crate::prelude::*;
5use std::fmt;
6
7#[derive(Clone)]
8pub enum ExistFactEnum {
9 ExistFact(ExistFactBody),
10 ExistUniqueFact(ExistFactBody),
11 NotExistFact(ExistFactBody),
12}
13
14#[derive(Clone)]
15pub struct ExistFactBody {
16 pub params_def_with_type: ParamDefWithType,
17 pub facts: Vec<ExistBodyFact>,
18 pub line_file: LineFile,
19}
20
21#[derive(Clone)]
22pub enum ExistBodyFact {
23 AtomicFact(AtomicFact),
24 AndFact(AndFact),
25 ChainFact(ChainFact),
26 OrFact(OrFact),
27 InlineForall(ForallFact),
28}
29
30impl ExistFactBody {
31 pub fn new(
32 params_def_with_type: ParamDefWithType,
33 facts: Vec<ExistBodyFact>,
34 line_file: LineFile,
35 ) -> Result<Self, RuntimeError> {
36 let body = ExistFactBody {
37 params_def_with_type,
38 facts,
39 line_file,
40 };
41 check_exist_fact_has_no_duplicate_exist_free_parameter(&ExistFactEnum::ExistFact(
42 body.clone(),
43 ))?;
44 Ok(body)
45 }
46
47 pub fn exist_fact_string_without_exist_as_prefix(&self) -> String {
48 exist_fact_string_without_exist_as_prefix(&self.params_def_with_type, &self.facts)
49 }
50
51 pub fn get_args_from_fact(&self) -> Vec<Obj> {
52 let mut args: Vec<Obj> = Vec::new();
53 for param_def_with_type in self.params_def_with_type.groups.iter() {
54 if let ParamType::Obj(obj) = ¶m_def_with_type.param_type {
55 args.push(obj.clone());
56 }
57 }
58
59 for fact in self.facts.iter() {
60 for arg in fact.get_args_from_fact() {
61 args.push(arg);
62 }
63 }
64
65 args
66 }
67}
68
69impl ExistBodyFact {
70 pub fn key(&self) -> String {
71 match self {
72 ExistBodyFact::AtomicFact(a) => a.key(),
73 ExistBodyFact::AndFact(a) => a.key(),
74 ExistBodyFact::ChainFact(c) => c.key(),
75 ExistBodyFact::OrFact(o) => o.key(),
76 ExistBodyFact::InlineForall(f) => inline_forall_fact_string(f),
77 }
78 }
79
80 pub fn line_file(&self) -> LineFile {
81 match self {
82 ExistBodyFact::AtomicFact(a) => a.line_file(),
83 ExistBodyFact::AndFact(a) => a.line_file(),
84 ExistBodyFact::ChainFact(c) => c.line_file(),
85 ExistBodyFact::OrFact(o) => o.line_file.clone(),
86 ExistBodyFact::InlineForall(f) => f.line_file.clone(),
87 }
88 }
89
90 pub fn get_args_from_fact(&self) -> Vec<Obj> {
91 match self {
92 ExistBodyFact::AtomicFact(a) => a.get_args_from_fact(),
93 ExistBodyFact::AndFact(a) => a.get_args_from_fact(),
94 ExistBodyFact::ChainFact(c) => c.get_args_from_fact(),
95 ExistBodyFact::OrFact(o) => o.get_args_from_fact(),
96 ExistBodyFact::InlineForall(f) => forall_fact_args(f),
97 }
98 }
99
100 pub fn to_fact(self) -> Fact {
101 match self {
102 ExistBodyFact::AtomicFact(a) => a.into(),
103 ExistBodyFact::AndFact(a) => a.into(),
104 ExistBodyFact::ChainFact(c) => c.into(),
105 ExistBodyFact::OrFact(o) => o.into(),
106 ExistBodyFact::InlineForall(f) => f.into(),
107 }
108 }
109
110 pub fn from_ref_to_cloned_fact(&self) -> Fact {
111 self.clone().to_fact()
112 }
113
114 pub fn replace_bound_identifier(self, from: &str, to: &str) -> Self {
115 match self {
116 ExistBodyFact::AtomicFact(a) => {
117 ExistBodyFact::AtomicFact(a.replace_bound_identifier(from, to))
118 }
119 ExistBodyFact::AndFact(a) => ExistBodyFact::AndFact(AndFact::new(
120 a.facts
121 .into_iter()
122 .map(|x| x.replace_bound_identifier(from, to))
123 .collect(),
124 a.line_file,
125 )),
126 ExistBodyFact::ChainFact(c) => ExistBodyFact::ChainFact(ChainFact::new(
127 c.objs
128 .into_iter()
129 .map(|o| Obj::replace_bound_identifier(o, from, to))
130 .collect(),
131 c.prop_names,
132 c.line_file,
133 )),
134 ExistBodyFact::OrFact(o) => ExistBodyFact::OrFact(OrFact::new(
135 o.facts
136 .into_iter()
137 .map(|x| x.replace_bound_identifier(from, to))
138 .collect(),
139 o.line_file,
140 )),
141 ExistBodyFact::InlineForall(f) => {
142 ExistBodyFact::InlineForall(replace_in_inline_forall_for_exist_alpha(f, from, to))
143 }
144 }
145 }
146}
147
148impl fmt::Display for ExistBodyFact {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 match self {
151 ExistBodyFact::AtomicFact(a) => write!(f, "{}", a),
152 ExistBodyFact::AndFact(a) => write!(f, "{}", a),
153 ExistBodyFact::ChainFact(c) => write!(f, "{}", c),
154 ExistBodyFact::OrFact(o) => write!(f, "{}", o),
155 ExistBodyFact::InlineForall(forall_fact) => {
156 write!(f, "{}", inline_forall_fact_string(forall_fact))
157 }
158 }
159 }
160}
161
162impl From<OrAndChainAtomicFact> for ExistBodyFact {
163 fn from(fact: OrAndChainAtomicFact) -> Self {
164 match fact {
165 OrAndChainAtomicFact::AtomicFact(a) => ExistBodyFact::AtomicFact(a),
166 OrAndChainAtomicFact::AndFact(a) => ExistBodyFact::AndFact(a),
167 OrAndChainAtomicFact::ChainFact(c) => ExistBodyFact::ChainFact(c),
168 OrAndChainAtomicFact::OrFact(o) => ExistBodyFact::OrFact(o),
169 }
170 }
171}
172
173impl From<AtomicFact> for ExistBodyFact {
174 fn from(atomic_fact: AtomicFact) -> Self {
175 ExistBodyFact::AtomicFact(atomic_fact)
176 }
177}
178
179impl From<EqualFact> for ExistBodyFact {
180 fn from(equal_fact: EqualFact) -> Self {
181 ExistBodyFact::AtomicFact(equal_fact.into())
182 }
183}
184
185fn forall_fact_args(forall_fact: &ForallFact) -> Vec<Obj> {
186 let mut args: Vec<Obj> = Vec::new();
187 for param_def_with_type in forall_fact.params_def_with_type.groups.iter() {
188 if let ParamType::Obj(obj) = ¶m_def_with_type.param_type {
189 args.push(obj.clone());
190 }
191 }
192 for fact in forall_fact.dom_facts.iter() {
193 match fact {
194 Fact::AtomicFact(a) => args.extend(a.get_args_from_fact()),
195 Fact::ExistFact(e) => args.extend(e.get_args_from_fact()),
196 Fact::OrFact(o) => args.extend(o.get_args_from_fact()),
197 Fact::AndFact(a) => args.extend(a.get_args_from_fact()),
198 Fact::ChainFact(c) => args.extend(c.get_args_from_fact()),
199 Fact::ForallFact(f) => args.extend(forall_fact_args(f)),
200 Fact::ForallFactWithIff(_) | Fact::NotForall(_) => {}
201 }
202 }
203 for fact in forall_fact.then_facts.iter() {
204 match fact {
205 ExistOrAndChainAtomicFact::AtomicFact(a) => args.extend(a.get_args_from_fact()),
206 ExistOrAndChainAtomicFact::AndFact(a) => args.extend(a.get_args_from_fact()),
207 ExistOrAndChainAtomicFact::ChainFact(c) => args.extend(c.get_args_from_fact()),
208 ExistOrAndChainAtomicFact::OrFact(o) => args.extend(o.get_args_from_fact()),
209 ExistOrAndChainAtomicFact::ExistFact(e) => args.extend(e.get_args_from_fact()),
210 }
211 }
212 args
213}
214
215fn inline_forall_fact_string(forall_fact: &ForallFact) -> String {
216 let then_facts = curly_braced_vec_to_string_with_sep(
217 &forall_fact
218 .then_facts
219 .iter()
220 .map(|fact| fact.to_string())
221 .collect::<Vec<String>>(),
222 format!("{} ", COMMA),
223 );
224 if forall_fact.dom_facts.is_empty() {
225 return format!(
226 "{} {}{} {}",
227 FORALL_BANG, forall_fact.params_def_with_type, COLON, then_facts
228 );
229 }
230 format!(
231 "{} {}{} {} {} {}",
232 FORALL_BANG,
233 forall_fact.params_def_with_type,
234 COLON,
235 vec_to_string_join_by_comma(
236 &forall_fact
237 .dom_facts
238 .iter()
239 .map(inline_fact_string)
240 .collect::<Vec<String>>()
241 ),
242 RIGHT_ARROW,
243 then_facts
244 )
245}
246
247fn inline_fact_string(fact: &Fact) -> String {
248 match fact {
249 Fact::ForallFact(forall_fact) => inline_forall_fact_string(forall_fact),
250 Fact::NotForall(not_forall) => {
251 format!(
252 "{} {}",
253 NOT,
254 inline_forall_fact_string(¬_forall.forall_fact)
255 )
256 }
257 _ => fact.to_string(),
258 }
259}
260
261fn replace_in_inline_forall_for_exist_alpha(
262 forall_fact: ForallFact,
263 from: &str,
264 to: &str,
265) -> ForallFact {
266 let binds_same_name = forall_fact
267 .params_def_with_type
268 .collect_param_names()
269 .iter()
270 .any(|name| name == from);
271 if binds_same_name {
272 return forall_fact;
273 }
274
275 let dom_facts = forall_fact
276 .dom_facts
277 .into_iter()
278 .map(|fact| replace_in_fact_for_exist_alpha(fact, from, to))
279 .collect();
280 let then_facts = forall_fact
281 .then_facts
282 .into_iter()
283 .map(|fact| replace_in_exist_or_and_chain_for_exist_alpha(fact, from, to))
284 .collect();
285
286 ForallFact::new(
287 forall_fact.params_def_with_type,
288 dom_facts,
289 then_facts,
290 forall_fact.line_file,
291 )
292 .expect("alpha replacement preserves inline forall validity")
293}
294
295fn replace_in_fact_for_exist_alpha(fact: Fact, from: &str, to: &str) -> Fact {
296 match fact {
297 Fact::AtomicFact(a) => a.replace_bound_identifier(from, to).into(),
298 Fact::ExistFact(e) => e.into(),
299 Fact::OrFact(o) => OrFact::new(
300 o.facts
301 .into_iter()
302 .map(|x| x.replace_bound_identifier(from, to))
303 .collect(),
304 o.line_file,
305 )
306 .into(),
307 Fact::AndFact(a) => AndFact::new(
308 a.facts
309 .into_iter()
310 .map(|x| x.replace_bound_identifier(from, to))
311 .collect(),
312 a.line_file,
313 )
314 .into(),
315 Fact::ChainFact(c) => ChainFact::new(
316 c.objs
317 .into_iter()
318 .map(|o| Obj::replace_bound_identifier(o, from, to))
319 .collect(),
320 c.prop_names,
321 c.line_file,
322 )
323 .into(),
324 Fact::ForallFact(f) => replace_in_inline_forall_for_exist_alpha(f, from, to).into(),
325 Fact::ForallFactWithIff(f) => f.into(),
326 Fact::NotForall(f) => f.into(),
327 }
328}
329
330fn replace_in_exist_or_and_chain_for_exist_alpha(
331 fact: ExistOrAndChainAtomicFact,
332 from: &str,
333 to: &str,
334) -> ExistOrAndChainAtomicFact {
335 match fact {
336 ExistOrAndChainAtomicFact::AtomicFact(a) => a.replace_bound_identifier(from, to).into(),
337 ExistOrAndChainAtomicFact::AndFact(a) => AndFact::new(
338 a.facts
339 .into_iter()
340 .map(|x| x.replace_bound_identifier(from, to))
341 .collect(),
342 a.line_file,
343 )
344 .into(),
345 ExistOrAndChainAtomicFact::ChainFact(c) => ChainFact::new(
346 c.objs
347 .into_iter()
348 .map(|o| Obj::replace_bound_identifier(o, from, to))
349 .collect(),
350 c.prop_names,
351 c.line_file,
352 )
353 .into(),
354 ExistOrAndChainAtomicFact::OrFact(o) => OrFact::new(
355 o.facts
356 .into_iter()
357 .map(|x| x.replace_bound_identifier(from, to))
358 .collect(),
359 o.line_file,
360 )
361 .into(),
362 ExistOrAndChainAtomicFact::ExistFact(e) => e.into(),
363 }
364}
365
366impl ExistFactEnum {
367 pub fn body(&self) -> &ExistFactBody {
368 match self {
369 ExistFactEnum::ExistFact(b)
370 | ExistFactEnum::ExistUniqueFact(b)
371 | ExistFactEnum::NotExistFact(b) => b,
372 }
373 }
374
375 pub fn is_exist_unique(&self) -> bool {
376 matches!(self, ExistFactEnum::ExistUniqueFact(_))
377 }
378
379 pub fn is_not_exist(&self) -> bool {
380 matches!(self, ExistFactEnum::NotExistFact(_))
381 }
382
383 pub fn is_plain_exist(&self) -> bool {
384 matches!(self, ExistFactEnum::ExistFact(_))
385 }
386
387 pub fn keyword_prefix(&self) -> String {
388 if self.is_not_exist() {
389 format!("{} {}", NOT, EXIST)
390 } else if self.is_exist_unique() {
391 EXIST_BANG.to_string()
392 } else {
393 EXIST.to_string()
394 }
395 }
396
397 pub fn can_be_used_to_verify_goal(&self, goal: &ExistFactEnum) -> bool {
400 match self {
401 ExistFactEnum::ExistFact(_) => goal.is_plain_exist(),
402 ExistFactEnum::ExistUniqueFact(_) => goal.is_plain_exist() || goal.is_exist_unique(),
403 ExistFactEnum::NotExistFact(_) => goal.is_not_exist(),
404 }
405 }
406
407 pub fn exist_fact_string_without_exist_as_prefix(&self) -> String {
408 self.body().exist_fact_string_without_exist_as_prefix()
409 }
410
411 pub fn key(&self) -> String {
412 let head = self.keyword_prefix();
413 let b = self.body();
414 format!(
415 "{} {}{}{}",
416 head,
417 LEFT_CURLY_BRACE,
418 vec_to_string_join_by_comma(
419 &b.facts
420 .iter()
421 .map(|fact| fact.key())
422 .collect::<Vec<String>>()
423 ),
424 RIGHT_CURLY_BRACE
425 )
426 }
427
428 pub fn alpha_normalized_key(&self) -> String {
431 let b = self.body();
432 let names = b.params_def_with_type.collect_param_names();
433 let mut normalized_facts: Vec<ExistBodyFact> = b.facts.clone();
434 for (i, name) in names.iter().enumerate() {
435 let ph = format!("#{}", i);
436 normalized_facts = normalized_facts
437 .into_iter()
438 .map(|f| f.replace_bound_identifier(name, &ph))
439 .collect();
440 }
441 let head = self.keyword_prefix();
442 format!(
443 "{} {}{}{}",
444 head,
445 LEFT_CURLY_BRACE,
446 vec_to_string_join_by_comma(
447 &normalized_facts
448 .iter()
449 .map(|fact| fact.key())
450 .collect::<Vec<String>>()
451 ),
452 RIGHT_CURLY_BRACE
453 )
454 }
455
456 pub fn line_file(&self) -> LineFile {
457 self.body().line_file.clone()
458 }
459
460 pub fn params_def_with_type(&self) -> &ParamDefWithType {
461 &self.body().params_def_with_type
462 }
463
464 pub fn facts(&self) -> &Vec<ExistBodyFact> {
465 &self.body().facts
466 }
467
468 pub fn get_args_from_fact(&self) -> Vec<Obj> {
469 self.body().get_args_from_fact()
470 }
471}
472
473fn exist_fact_string_without_exist_as_prefix(
474 param_defs: &ParamDefWithType,
475 facts: &Vec<ExistBodyFact>,
476) -> String {
477 format!(
478 "{} {} {}",
479 param_defs.to_string(),
480 ST,
481 curly_braced_vec_to_string_with_sep(
482 &facts
483 .iter()
484 .map(|fact| fact.to_string())
485 .collect::<Vec<String>>(),
486 format!("{} ", COMMA)
487 )
488 )
489}
490
491impl fmt::Display for ExistFactEnum {
492 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493 let head = self.keyword_prefix();
494 write!(
495 f,
496 "{} {}",
497 head,
498 self.exist_fact_string_without_exist_as_prefix()
499 )
500 }
501}