1use crate::{common::keywords::GREATER_EQUAL, prelude::*, stmt::parameter_def::ParamDefWithType};
2use std::fmt;
3
4#[derive(Clone)]
5pub struct HaveFnByInducNestedCase {
6 pub case_fact: AndChainAtomicFact,
7 pub equal_to: Obj,
8}
9
10#[derive(Clone)]
11pub enum HaveFnByInducLastCase {
12 EqualTo(Obj),
13 NestedCases(Vec<HaveFnByInducNestedCase>),
14}
15
16#[derive(Clone)]
23pub struct HaveFnByInducStmt {
24 pub induc_from: Obj,
25 pub name: String,
26 pub param: String,
27 pub ret_set: Obj,
28 pub special_cases_equal_tos: Vec<Obj>,
29 pub last_case: HaveFnByInducLastCase,
30 pub line_file: LineFile,
31}
32
33#[derive(Clone)]
34pub struct DefAbstractPropStmt {
35 pub name: String,
36 pub params: Vec<String>,
37 pub line_file: LineFile,
38}
39
40impl DefAbstractPropStmt {
41 pub fn new(name: String, params: Vec<String>, line_file: LineFile) -> Self {
42 DefAbstractPropStmt {
43 name,
44 params,
45 line_file,
46 }
47 }
48}
49
50#[derive(Clone)]
51pub struct DefStructStmt {
52 pub name: String,
53 pub param_defs: ParamDefWithType,
54 pub dom_facts: Vec<OrAndChainAtomicFact>,
55 pub fields: Vec<(String, ParamType)>,
56 pub facts: Vec<OrAndChainAtomicFact>,
57 pub line_file: LineFile,
58}
59
60#[derive(Clone)]
61pub struct DefFamilyStmt {
62 pub name: String,
63 pub params_def_with_type: ParamDefWithType,
64 pub dom_facts: Vec<OrAndChainAtomicFact>,
65 pub equal_to: Obj,
66 pub line_file: LineFile,
67}
68
69#[derive(Clone)]
72pub struct FnSetClause {
73 pub params_def_with_set: Vec<ParamGroupWithSet>,
74 pub dom_facts: Vec<OrAndChainAtomicFact>,
75 pub ret_set: Obj,
76}
77
78#[derive(Clone)]
79pub struct HaveFnEqualCaseByCaseStmt {
80 pub name: String,
81 pub fn_set_clause: FnSetClause,
82 pub cases: Vec<AndChainAtomicFact>,
83 pub equal_tos: Vec<Obj>,
84 pub line_file: LineFile,
85}
86
87#[derive(Clone)]
88pub struct HaveFnEqualStmt {
89 pub name: String,
90 pub fn_set_clause: FnSetClause,
91 pub equal_to: Obj,
92 pub line_file: LineFile,
93}
94
95#[derive(Clone)]
96pub struct HaveByExistStmt {
97 pub equal_tos: Vec<String>,
98 pub exist_fact_in_have_obj_st: ExistFact,
99 pub line_file: LineFile,
100}
101
102#[derive(Clone)]
103pub struct HaveObjEqualStmt {
104 pub param_def: ParamDefWithType,
105 pub objs_equal_to: Vec<Obj>,
106 pub line_file: LineFile,
107}
108
109#[derive(Clone)]
110pub struct HaveObjInNonemptySetOrParamTypeStmt {
111 pub param_def: ParamDefWithType,
112 pub line_file: LineFile,
113}
114
115#[derive(Clone)]
116pub struct DefLetStmt {
117 pub param_def: ParamDefWithType,
118 pub facts: Vec<Fact>,
119 pub line_file: LineFile,
120}
121
122#[derive(Clone)]
123pub struct DefPropStmt {
124 pub name: String,
125 pub params_def_with_type: ParamDefWithType,
126 pub iff_facts: Vec<Fact>,
127 pub line_file: LineFile,
128}
129
130impl fmt::Display for DefAbstractPropStmt {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 write!(
133 f,
134 "{} {}{}{}{}",
135 ABSTRACT_PROP,
136 self.name,
137 LEFT_BRACE,
138 vec_to_string_join_by_comma(&self.params),
139 RIGHT_BRACE
140 )
141 }
142}
143
144impl fmt::Display for DefStructStmt {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 let implicit_prefix_len = self.param_defs.number_of_params();
149 let fields_str: String = self
150 .fields
151 .iter()
152 .skip(implicit_prefix_len)
153 .map(|(name, or_val)| format!("{} {}", name, or_val))
154 .collect::<Vec<_>>()
155 .join("\n");
156 let fields_indented =
157 to_string_and_add_four_spaces_at_beginning_of_each_line(&fields_str, 1);
158 let equiv_line = add_four_spaces_at_beginning(format!("{}{}", EQUIVALENT_SIGN, COLON), 1);
159 let facts_indented = vec_to_string_add_four_spaces_at_beginning_of_each_line(
160 &self
161 .facts
162 .iter()
163 .skip(implicit_prefix_len)
164 .cloned()
165 .collect(),
166 1,
167 );
168 write!(
169 f,
170 "{} {}{}{}{} {}\n{}\n{}\n{}",
171 STRUCT,
172 self.name,
173 LEFT_BRACE,
174 self.param_defs.to_string(),
175 RIGHT_BRACE,
176 COLON,
177 fields_indented,
178 equiv_line,
179 facts_indented
180 )
181 }
182}
183
184impl DefPropStmt {
185 pub fn new(
186 name: String,
187 params_def_with_type: ParamDefWithType,
188 iff_facts: Vec<Fact>,
189 line_file: LineFile,
190 ) -> Self {
191 DefPropStmt {
192 name,
193 params_def_with_type,
194 iff_facts,
195 line_file,
196 }
197 }
198}
199
200impl fmt::Display for DefPropStmt {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 match self.iff_facts.len() {
203 0 => write!(
204 f,
205 "{} {}{}",
206 PROP,
207 self.name,
208 braced_string(&self.params_def_with_type)
209 ),
210 _ => write!(
211 f,
212 "{} {}{}{}\n{}",
213 PROP,
214 self.name,
215 braced_string(&self.params_def_with_type),
216 COLON,
217 vec_to_string_add_four_spaces_at_beginning_of_each_line(&self.iff_facts, 1)
218 ),
219 }
220 }
221}
222
223impl DefLetStmt {
224 pub fn new(param_def: ParamDefWithType, facts: Vec<Fact>, line_file: LineFile) -> Self {
225 DefLetStmt {
226 param_def,
227 facts,
228 line_file,
229 }
230 }
231}
232
233impl fmt::Display for DefLetStmt {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 let param_str = self.param_def.to_string();
236 match self.facts.len() {
237 0 => write!(f, "{} {}", LET, param_str),
238 _ => write!(
239 f,
240 "{} {}{}\n{}",
241 LET,
242 param_str,
243 COLON,
244 vec_to_string_add_four_spaces_at_beginning_of_each_line(&self.facts, 1)
245 ),
246 }
247 }
248}
249
250impl HaveObjInNonemptySetOrParamTypeStmt {
251 pub fn new(param_def: ParamDefWithType, line_file: LineFile) -> Self {
252 HaveObjInNonemptySetOrParamTypeStmt {
253 param_def,
254 line_file,
255 }
256 }
257}
258
259impl fmt::Display for HaveObjInNonemptySetOrParamTypeStmt {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 write!(f, "{} {}", HAVE, self.param_def.to_string())
262 }
263}
264
265impl HaveObjEqualStmt {
266 pub fn new(param_def: ParamDefWithType, objs_equal_to: Vec<Obj>, line_file: LineFile) -> Self {
267 HaveObjEqualStmt {
268 param_def,
269 objs_equal_to,
270 line_file,
271 }
272 }
273}
274
275impl fmt::Display for HaveObjEqualStmt {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 write!(
278 f,
279 "{} {} {} {}",
280 HAVE,
281 self.param_def.to_string(),
282 EQUAL,
283 vec_to_string_join_by_comma(&self.objs_equal_to)
284 )
285 }
286}
287
288impl HaveByExistStmt {
289 pub fn new(
290 equal_tos: Vec<String>,
291 exist_fact_in_have_obj_st: ExistFact,
292 line_file: LineFile,
293 ) -> Self {
294 HaveByExistStmt {
295 equal_tos,
296 exist_fact_in_have_obj_st,
297 line_file,
298 }
299 }
300}
301
302impl fmt::Display for HaveByExistStmt {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 write!(
305 f,
306 "{} {} {} {} {}",
307 HAVE,
308 BY,
309 self.exist_fact_in_have_obj_st,
310 COLON,
311 vec_to_string_join_by_comma(&self.equal_tos),
312 )
313 }
314}
315
316impl HaveFnEqualStmt {
317 pub fn new(
318 name: String,
319 fn_set_clause: FnSetClause,
320 equal_to: Obj,
321 line_file: LineFile,
322 ) -> Self {
323 HaveFnEqualStmt {
324 name,
325 fn_set_clause,
326 equal_to,
327 line_file,
328 }
329 }
330}
331
332impl fmt::Display for HaveFnEqualStmt {
333 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334 write!(
335 f,
336 "{} {} {}{} {} {}",
337 HAVE,
338 FN_LOWER_CASE,
339 self.name,
340 brace_vec_colon_vec_to_string(
341 &self.fn_set_clause.params_def_with_set,
342 &self.fn_set_clause.dom_facts
343 ),
344 EQUAL,
345 self.equal_to
346 )
347 }
348}
349
350impl fmt::Display for HaveFnEqualCaseByCaseStmt {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 let cases_and_proofs = self
353 .cases
354 .iter()
355 .enumerate()
356 .map(|(i, case)| {
357 to_string_and_add_four_spaces_at_beginning_of_each_line(
358 &format!(
359 "{} {}{} {}{} {} {}",
360 CASE,
361 case,
362 COMMA,
363 self.name,
364 braced_vec_to_string(&ParamGroupWithSet::collect_param_names(
365 &self.fn_set_clause.params_def_with_set,
366 )),
367 EQUAL,
368 self.equal_tos[i]
369 ),
370 1,
371 )
372 })
373 .collect::<Vec<String>>();
374
375 write!(
376 f,
377 "{} {} {}{} {} {}\n{}",
378 HAVE,
379 FN_LOWER_CASE,
380 self.name,
381 brace_vec_colon_vec_to_string(
382 &self.fn_set_clause.params_def_with_set,
383 &self.fn_set_clause.dom_facts
384 ),
385 EQUAL,
386 COLON,
387 vec_to_string_with_sep(&cases_and_proofs, "\n".to_string())
388 )
389 }
390}
391
392impl HaveFnEqualCaseByCaseStmt {
393 pub fn new(
394 name: String,
395 fn_set_clause: FnSetClause,
396 cases: Vec<AndChainAtomicFact>,
397 equal_tos: Vec<Obj>,
398 line_file: LineFile,
399 ) -> Self {
400 HaveFnEqualCaseByCaseStmt {
401 name,
402 fn_set_clause,
403 cases,
404 equal_tos,
405 line_file,
406 }
407 }
408}
409
410pub fn induc_obj_plus_offset(induc_from: &Obj, offset: usize) -> Obj {
411 if offset == 0 {
412 induc_from.clone()
413 } else {
414 Add::new(induc_from.clone(), Number::new(offset.to_string()).into()).into()
415 }
416}
417
418fn flatten_and_chain_to_atomic_facts(c: &AndChainAtomicFact) -> Vec<AtomicFact> {
419 match c {
420 AndChainAtomicFact::AtomicFact(a) => vec![a.clone()],
421 AndChainAtomicFact::AndFact(af) => af.facts.clone(),
422 AndChainAtomicFact::ChainFact(cf) => cf.facts().unwrap(),
423 }
424}
425
426fn merge_two_and_chain_clauses(
427 a: AndChainAtomicFact,
428 b: AndChainAtomicFact,
429 line_file: LineFile,
430) -> AndChainAtomicFact {
431 let mut atoms = flatten_and_chain_to_atomic_facts(&a);
432 atoms.extend(flatten_and_chain_to_atomic_facts(&b));
433 AndChainAtomicFact::AndFact(AndFact::new(atoms, line_file))
434}
435
436impl HaveFnByInducStmt {
437 pub fn fn_user_fn_set_clause(&self) -> FnSetClause {
439 FnSetClause {
440 params_def_with_set: vec![ParamGroupWithSet::new(
441 vec![self.param.clone()],
442 StandardSet::Z.into(),
443 )],
444 dom_facts: vec![OrAndChainAtomicFact::AtomicFact(
445 GreaterEqualFact::new(
446 self.param.clone().into(),
447 self.induc_from.clone(),
448 self.line_file.clone(),
449 )
450 .into(),
451 )],
452 ret_set: self.ret_set.clone(),
453 }
454 }
455
456 pub fn forall_fn_base_dom_exist_or_facts(&self) -> Vec<Fact> {
458 vec![GreaterEqualFact::new(
459 self.param.clone().into(),
460 self.induc_from.clone(),
461 self.line_file.clone(),
462 )
463 .into()]
464 }
465
466 pub fn new(
467 name: String,
468 param: String,
469 ret_set: Obj,
470 induc_from: Obj,
471 special_cases_equal_tos: Vec<Obj>,
472 last_case: HaveFnByInducLastCase,
473 line_file: LineFile,
474 ) -> Self {
475 HaveFnByInducStmt {
476 name,
477 param,
478 ret_set,
479 induc_from,
480 special_cases_equal_tos,
481 last_case,
482 line_file,
483 }
484 }
485
486 pub fn to_have_fn_equal_case_by_case_stmt(&self) -> HaveFnEqualCaseByCaseStmt {
488 let line_file = self.line_file.clone();
489 let left_id: Obj = self.param.clone().into();
490 let n = self.special_cases_equal_tos.len();
491 let mut cases: Vec<AndChainAtomicFact> = Vec::new();
492 let mut equal_tos: Vec<Obj> = Vec::new();
493 for i in 0..n {
494 let when = AndChainAtomicFact::AtomicFact(
495 EqualFact::new(
496 left_id.clone(),
497 induc_obj_plus_offset(&self.induc_from, i),
498 line_file.clone(),
499 )
500 .into(),
501 );
502 cases.push(when);
503 equal_tos.push(self.special_cases_equal_tos[i].clone());
504 }
505 let step = AndChainAtomicFact::AtomicFact(
506 EqualFact::new(
507 left_id.clone(),
508 induc_obj_plus_offset(&self.induc_from, n),
509 line_file.clone(),
510 )
511 .into(),
512 );
513 match &self.last_case {
514 HaveFnByInducLastCase::EqualTo(eq) => {
515 cases.push(step);
516 equal_tos.push(eq.clone());
517 }
518 HaveFnByInducLastCase::NestedCases(last_pairs) => {
519 for nested in last_pairs {
520 let merged = merge_two_and_chain_clauses(
521 step.clone(),
522 nested.case_fact.clone(),
523 line_file.clone(),
524 );
525 cases.push(merged);
526 equal_tos.push(nested.equal_to.clone());
527 }
528 }
529 }
530 HaveFnEqualCaseByCaseStmt::new(
531 self.name.clone(),
532 self.fn_user_fn_set_clause(),
533 cases,
534 equal_tos,
535 line_file,
536 )
537 }
538}
539
540impl fmt::Display for HaveFnByInducStmt {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
543 let n = self.special_cases_equal_tos.len();
544 write!(
545 f,
546 "{} {} {} {} {} {} {}{}",
547 HAVE, FN_LOWER_CASE, BY, INDUC, FROM, " ", self.induc_from, COLON,
548 )?;
549 write!(f, " {} {}{}", self.name, LEFT_BRACE, self.param)?;
550 write!(
551 f,
552 " {} {} {} {} {} {} {} {} {} {} {} {}",
553 Z,
554 COLON,
555 " ",
556 self.param,
557 " ",
558 GREATER_EQUAL,
559 " ",
560 self.induc_from,
561 RIGHT_BRACE,
562 " ",
563 self.ret_set,
564 COLON,
565 )?;
566 for (i, eq) in self.special_cases_equal_tos.iter().enumerate() {
567 writeln!(f)?;
568 write!(f, " {} {}: {}", CASE, i, eq)?;
569 }
570 writeln!(f)?;
571 match &self.last_case {
572 HaveFnByInducLastCase::EqualTo(eq) => {
573 write!(f, " {} {} {}: {}", CASE, GREATER_EQUAL, n, eq)?;
574 }
575 HaveFnByInducLastCase::NestedCases(nested) => {
576 write!(f, " {} {} {}:", CASE, GREATER_EQUAL, n)?;
577 for nc in nested {
578 writeln!(f)?;
579 write!(f, " {} {}: {}", CASE, nc.case_fact, nc.equal_to)?;
580 }
581 }
582 }
583 Ok(())
584 }
585}
586
587impl DefFamilyStmt {
588 pub fn new(
589 name: String,
590 params_def_with_type: ParamDefWithType,
591 dom_facts: Vec<OrAndChainAtomicFact>,
592 equal_to: Obj,
593 line_file: LineFile,
594 ) -> Self {
595 DefFamilyStmt {
596 name,
597 params_def_with_type,
598 dom_facts,
599 equal_to,
600 line_file,
601 }
602 }
603}
604
605impl fmt::Display for DefFamilyStmt {
606 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
607 write!(
608 f,
609 "{} {}{}{} {} {}{} {} {}",
610 FAMILY,
611 self.name,
612 LEFT_BRACE,
613 self.params_def_with_type.to_string(),
614 COLON,
615 vec_to_string_join_by_comma(&self.dom_facts),
616 RIGHT_BRACE,
617 EQUAL,
618 self.equal_to
619 )
620 }
621}
622
623impl DefStructStmt {
624 pub fn new(
625 name: String,
626 param_defs: ParamDefWithType,
627 dom_facts: Vec<OrAndChainAtomicFact>,
628 fields: Vec<(String, ParamType)>,
629 facts: Vec<OrAndChainAtomicFact>,
630 line_file: LineFile,
631 ) -> Self {
632 if fields.len() <= 1 {
633 unreachable!();
634 }
635
636 DefStructStmt {
637 name,
638 param_defs,
639 dom_facts,
640 fields,
641 facts,
642 line_file,
643 }
644 }
645
646 pub fn number_of_params(&self) -> usize {
647 self.param_defs.number_of_params()
648 }
649
650 pub fn get_params(&self) -> Vec<String> {
652 self.param_defs.collect_param_names()
653 }
654}