1use crate::{
5 Command, CoreOp, Ctx, FunctionDec, IConst, ICoreOp, IIndex, ILet, IMatch, IOp, IQuantifier,
6 ISort, ISymbol, IVar, Let, Logic, Quantifier, Sorted, Term, Void, IUF, UF,
7};
8pub use aws_smt_ir_derive::Fold;
9
10mod compose;
11pub use compose::{Compose, TryComposed};
12mod intra;
13pub use intra::IntraLogicFolder;
14mod inter;
15use crate::smt2parser::Numeral;
16pub use inter::InterLogicFolder;
17use smallvec::SmallVec;
18
19pub trait Folder<T: Logic, M = ()>: Compose {
107 type Output;
111
112 type Error;
114
115 fn context(&self) -> Option<&Ctx> {
120 None
121 }
122
123 fn context_mut(&mut self) -> Option<&mut Ctx> {
128 debug_assert!(
129 self.context().is_none(),
130 "context() and context_mut() should be implemented together"
131 );
132 None
133 }
134
135 fn fold_term(&mut self, term: Term<T>) -> Result<Self::Output, Self::Error> {
138 term.super_fold_with(self)
139 }
140
141 fn fold_const(&mut self, constant: IConst) -> Result<Self::Output, Self::Error>;
143
144 fn fold_var(&mut self, var: IVar<T::Var>) -> Result<Self::Output, Self::Error>;
146
147 fn fold_core_op(&mut self, op: ICoreOp<T>) -> Result<Self::Output, Self::Error>;
149
150 fn fold_theory_op(&mut self, op: IOp<T>) -> Result<Self::Output, Self::Error>;
152
153 fn fold_uninterpreted_func(&mut self, func: IUF<T>) -> Result<Self::Output, Self::Error>;
155
156 fn fold_let(&mut self, l: ILet<T>) -> Result<Self::Output, Self::Error>;
158
159 fn fold_match(&mut self, m: IMatch<T>) -> Result<Self::Output, Self::Error>;
161
162 fn fold_quantifier(&mut self, quantifier: IQuantifier<T>) -> Result<Self::Output, Self::Error>;
164
165 fn fold_set_logic(&mut self, logic: ISymbol) -> Result<Command<Self::Output>, Self::Error> {
168 Ok(Command::SetLogic { symbol: logic })
169 }
170
171 fn fold_assert(&mut self, asserted: Term<T>) -> Result<Command<Self::Output>, Self::Error> {
174 self.fold_term(asserted)
175 .map(|term| Command::Assert { term })
176 }
177
178 fn fold_declare_const(
181 &mut self,
182 symbol: ISymbol,
183 sort: ISort,
184 ) -> Result<Command<Self::Output>, Self::Error> {
185 Ok(Command::DeclareConst { symbol, sort })
186 }
187
188 fn fold_declare_fun(
191 &mut self,
192 symbol: ISymbol,
193 parameters: Vec<ISort>,
194 sort: ISort,
195 ) -> Result<Command<Self::Output>, Self::Error> {
196 Ok(Command::DeclareFun {
197 symbol,
198 parameters,
199 sort,
200 })
201 }
202
203 fn fold_declare_sort(
206 &mut self,
207 symbol: ISymbol,
208 arity: Numeral,
209 ) -> Result<Command<Self::Output>, Self::Error> {
210 Ok(Command::DeclareSort { symbol, arity })
211 }
212
213 fn fold_define_fun(
216 &mut self,
217 sig: FunctionDec,
218 body: Term<T>,
219 ) -> Result<Command<Self::Output>, Self::Error> {
220 let term = body.fold_with(self)?;
221 Ok(Command::DefineFun { sig, term })
222 }
223
224 fn fold_define_fun_rec(
227 &mut self,
228 sig: FunctionDec,
229 body: Term<T>,
230 ) -> Result<Command<Self::Output>, Self::Error> {
231 let term = body.fold_with(self)?;
232 Ok(Command::DefineFunRec { sig, term })
233 }
234
235 fn fold_define_funs_rec(
238 &mut self,
239 funs: Vec<(FunctionDec, Term<T>)>,
240 ) -> Result<Command<Self::Output>, Self::Error> {
241 let funs = funs
242 .into_iter()
243 .map(|(sig, body)| Ok((sig, body.fold_with(self)?)))
244 .collect::<Result<_, _>>()?;
245 Ok(Command::DefineFunsRec { funs })
246 }
247
248 fn fold_define_sort(
251 &mut self,
252 symbol: ISymbol,
253 parameters: Vec<ISymbol>,
254 sort: ISort,
255 ) -> Result<Command<Self::Output>, Self::Error> {
256 Ok(Command::DefineSort {
257 symbol,
258 parameters,
259 sort,
260 })
261 }
262
263 fn fold_get_value(
266 &mut self,
267 terms: Vec<Term<T>>,
268 ) -> Result<Command<Self::Output>, Self::Error> {
269 let terms = terms.fold_with(self)?;
270 Ok(Command::GetValue { terms })
271 }
272}
273
274pub trait Fold<T: Logic, Out> {
294 type Output;
296
297 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
302 where
303 F: Folder<T, M, Output = Out>;
304}
305
306pub trait SuperFold<T: Logic, Out> {
311 type Output;
313
314 fn super_fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
316 where
317 F: Folder<T, M, Output = Out>;
318}
319
320impl<T: Logic, Out> Fold<T, Out> for Term<T> {
321 type Output = Out;
322 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
323 where
324 F: Folder<T, M, Output = Out>,
325 {
326 folder.fold_term(self)
327 }
328}
329
330impl<T: Logic, Out> Fold<T, Out> for &Term<T> {
331 type Output = Out;
332 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
333 where
334 F: Folder<T, M, Output = Out>,
335 {
336 folder.fold_term(self.clone())
337 }
338}
339
340impl<T: Logic, Out> SuperFold<T, Out> for Term<T> {
341 type Output = Out;
342
343 fn super_fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
344 where
345 F: Folder<T, M, Output = Out>,
346 {
347 match self {
348 Self::Constant(c) => c.fold_with(folder),
349 Self::Variable(v) => v.fold_with(folder),
350 Self::CoreOp(op) => op.fold_with(folder),
351 Self::OtherOp(op) => op.fold_with(folder),
352 Self::UF(uf) => uf.fold_with(folder),
353 Self::Let(l) => l.fold_with(folder),
354 Self::Match(m) => m.fold_with(folder),
355 Self::Quantifier(q) => q.fold_with(folder),
356 }
357 }
358}
359
360impl<T: Logic, Out> SuperFold<T, Out> for &Term<T> {
361 type Output = Out;
362
363 fn super_fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
364 where
365 F: Folder<T, M, Output = Out>,
366 {
367 self.clone().super_fold_with(folder)
368 }
369}
370
371impl<T: Logic, Out> Fold<T, Out> for IConst {
372 type Output = Out;
373 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
374 where
375 F: Folder<T, M, Output = Out>,
376 {
377 folder.fold_const(self)
378 }
379}
380
381impl<T: Logic, Out> Fold<T, Out> for IVar<T::Var> {
382 type Output = Out;
383 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
384 where
385 F: Folder<T, M, Output = Out>,
386 {
387 folder.fold_var(self)
388 }
389}
390
391impl<T: Logic, Out> Fold<T, Out> for ICoreOp<T> {
393 type Output = Out;
394 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
395 where
396 F: Folder<T, M, Output = Out>,
397 {
398 folder.fold_core_op(self)
399 }
400}
401
402impl<T: Logic, Inner: Fold<T, Out>, Out> SuperFold<T, Out> for CoreOp<Inner> {
404 type Output = CoreOp<Inner::Output>;
405 fn super_fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
406 where
407 F: Folder<T, M, Output = Out>,
408 {
409 use CoreOp::*;
410 const STACK_RED_ZONE: usize = 32 * 1024;
411 const NEW_STACK_SIZE: usize = 1024 * 1024;
412 let op = match self {
413 True => True,
414 False => False,
415 Not(t) => Not(t.fold_with(folder)?),
416 And(args) => And(stacker::maybe_grow(STACK_RED_ZONE, NEW_STACK_SIZE, || {
417 args.fold_with(folder)
418 })?),
419 Or(args) => Or(stacker::maybe_grow(STACK_RED_ZONE, NEW_STACK_SIZE, || {
420 args.fold_with(folder)
421 })?),
422 Xor(args) => Xor(args.fold_with(folder)?),
423 Imp(args) => Imp(args.fold_with(folder)?),
424 Eq(args) => Eq(args.fold_with(folder)?),
425 Distinct(args) => Distinct(args.fold_with(folder)?),
426 Ite(i, t, e) => Ite(
427 i.fold_with(folder)?,
428 t.fold_with(folder)?,
429 e.fold_with(folder)?,
430 ),
431 };
432 Ok(op)
433 }
434}
435
436impl<L: Logic, Out> Fold<L, Out> for IOp<L> {
437 type Output = Out;
438 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
439 where
440 F: Folder<L, M, Output = Out>,
441 {
442 folder.fold_theory_op(self)
443 }
444}
445
446impl<T: Logic, Out> Fold<T, Out> for IUF<T> {
447 type Output = Out;
448 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
449 where
450 F: Folder<T, M, Output = Out>,
451 {
452 folder.fold_uninterpreted_func(self)
453 }
454}
455
456impl<T: Logic, Inner, Out> SuperFold<T, Out> for UF<Inner>
457where
458 Inner: Fold<T, Out>,
459{
460 type Output = UF<Inner::Output>;
461 fn super_fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
462 where
463 F: Folder<T, M, Output = Out>,
464 {
465 let (func, args) = (self.func.fold_with(folder)?, self.args.fold_with(folder)?);
466 Ok(UF { func, args })
467 }
468}
469
470impl<T: Logic, Out> Fold<T, Out> for IQuantifier<T> {
471 type Output = Out;
472 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
473 where
474 F: Folder<T, M, Output = Out>,
475 {
476 folder.fold_quantifier(self)
477 }
478}
479
480impl<T: Logic, Inner, Out> SuperFold<T, Out> for Quantifier<Inner>
481where
482 Inner: Fold<T, Out>,
483{
484 type Output = Quantifier<Inner::Output>;
485 fn super_fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
486 where
487 F: Folder<T, M, Output = Out>,
488 {
489 use Quantifier::*;
490 Ok(match self {
491 Forall(vars, t) => Forall(vars.fold_with(folder)?, t.fold_with(folder)?),
492 Exists(vars, t) => Exists(vars.fold_with(folder)?, t.fold_with(folder)?),
493 })
494 }
495}
496
497impl<T: Logic, Out> Fold<T, Out> for ILet<T> {
498 type Output = Out;
499
500 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
501 where
502 F: Folder<T, M, Output = Out>,
503 {
504 let old_bindings = if let Some(ctx) = folder.context_mut() {
505 self.bindings
506 .iter()
507 .map(|(sym, t)| {
508 let sort = t.sort(ctx).ok();
509 let old_sort = ctx.local.bind_var(sym.clone(), sort);
510 (sym.clone(), old_sort)
511 })
512 .collect()
513 } else {
514 vec![]
515 };
516 let res = folder.fold_let(self);
517 if let Some(ctx) = folder.context_mut() {
518 for (sym, old_sort) in old_bindings {
519 match old_sort {
520 None => ctx.local.unbind_var(&sym),
521 Some(sort) => {
522 ctx.local.bind_var(sym, sort);
523 }
524 }
525 }
526 }
527 res
528 }
529}
530
531impl<T: Logic, Inner: Fold<T, Out>, Out> SuperFold<T, Out> for Let<Inner> {
532 type Output = Let<Inner::Output>;
533
534 fn super_fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
535 where
536 F: Folder<T, M, Output = Out>,
537 {
538 Ok(Let {
539 bindings: self.bindings.fold_with(folder)?,
540 term: self.term.fold_with(folder)?,
541 })
542 }
543}
544
545impl<T: Logic, Out> Fold<T, Out> for Void {
546 type Output = Out;
547 fn fold_with<F: Folder<T, M>, M>(self, _folder: &mut F) -> Result<Self::Output, F::Error> {
548 match self {}
549 }
550}
551
552impl<T: Logic, Out> SuperFold<T, Out> for Void {
553 type Output = Void;
554 fn super_fold_with<F: Folder<T, M>, M>(
555 self,
556 _folder: &mut F,
557 ) -> Result<Self::Output, F::Error> {
558 match self {}
559 }
560}
561
562impl<T: Logic, Out> Fold<T, Out> for ISymbol {
563 type Output = Self;
564 fn fold_with<F, M>(self, _: &mut F) -> Result<Self::Output, F::Error>
565 where
566 F: Folder<T, M, Output = Out>,
567 {
568 Ok(self)
569 }
570}
571
572impl<T: Logic, Out> Fold<T, Out> for ISort {
573 type Output = Self;
574 fn fold_with<F, M>(self, _: &mut F) -> Result<Self::Output, F::Error>
575 where
576 F: Folder<T, M, Output = Out>,
577 {
578 Ok(self)
579 }
580}
581
582impl<T: Logic, Out, Inner: Fold<T, Out>> Fold<T, Out> for Vec<Inner> {
583 type Output = Vec<<Inner as Fold<T, Out>>::Output>;
584 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
585 where
586 F: Folder<T, M, Output = Out>,
587 {
588 self.into_iter().map(|t| t.fold_with(folder)).collect()
589 }
590}
591
592impl<T: Logic, Out, Inner: Fold<T, Out>, const N: usize> Fold<T, Out> for SmallVec<[Inner; N]>
593where
594 [Inner; N]: smallvec::Array<Item = Inner>,
595 [Inner::Output; N]: smallvec::Array<Item = Inner::Output>,
596{
597 type Output = SmallVec<[Inner::Output; N]>;
598 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
599 where
600 F: Folder<T, M, Output = Out>,
601 {
602 self.into_iter().map(|t| t.fold_with(folder)).collect()
603 }
604}
605
606impl<'a, T: Logic, Out, Inner, Output, const N: usize> Fold<T, Out> for &'a SmallVec<[Inner; N]>
607where
608 &'a Inner: Fold<T, Out, Output = Output>,
609 [Inner; N]: smallvec::Array<Item = Inner>,
610 [Output; N]: smallvec::Array<Item = Output>,
611{
612 type Output = SmallVec<[Output; N]>;
613 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
614 where
615 F: Folder<T, M, Output = Out>,
616 {
617 self.iter().map(|t| t.fold_with(folder)).collect()
618 }
619}
620
621impl<T: Logic, Out, Inner: Fold<T, Out>> Fold<T, Out> for Box<[Inner]> {
622 type Output = Box<[<Inner as Fold<T, Out>>::Output]>;
623 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
624 where
625 F: Folder<T, M, Output = Out>,
626 {
627 self.into_vec()
628 .into_iter()
629 .map(|t| t.fold_with(folder))
630 .collect()
631 }
632}
633
634impl<T: Logic, Out, const N: usize> Fold<T, Out> for [IIndex; N] {
635 type Output = Self;
636 fn fold_with<F, M>(self, _: &mut F) -> Result<Self::Output, F::Error>
637 where
638 F: Folder<T, M, Output = Out>,
639 {
640 Ok(self)
641 }
642}
643
644impl<T: Logic, Out, Inner, Output> Fold<T, Out> for &[Inner]
645where
646 for<'a> &'a Inner: Fold<T, Out, Output = Output>,
647{
648 type Output = Vec<Output>;
649 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
650 where
651 F: Folder<T, M, Output = Out>,
652 {
653 self.iter().map(|t| t.fold_with(folder)).collect()
654 }
655}
656
657impl<T: Logic, Out, Inner, Output> Fold<T, Out> for &Vec<Inner>
658where
659 for<'a> &'a Inner: Fold<T, Out, Output = Output>,
660{
661 type Output = Vec<Output>;
662 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
663 where
664 F: Folder<T, M, Output = Out>,
665 {
666 self.iter().map(|t| t.fold_with(folder)).collect()
667 }
668}
669
670macro_rules! impl_fold_tuple {
671 ($($x:ident),*) => {
672 impl<T: Logic, Out, $($x),*> Fold<T, Out> for ($($x),*)
673 where
674 $($x: Fold<T, Out>),*
675 {
676 type Output = ($($x::Output),*);
677 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
678 where
679 F: Folder<T, M, Output = Out>,
680 {
681 #[allow(non_snake_case)]
682 let ($($x),*) = self;
683 Ok(($($x.fold_with(folder)?),*))
684 }
685 }
686 };
687}
688
689impl_fold_tuple!(A, B);
690impl_fold_tuple!(A, B, C);
691impl_fold_tuple!(A, B, C, D);
692impl_fold_tuple!(A, B, C, D, E);
693
694impl<L: Logic, Out> Fold<L, Out> for Command<Term<L>> {
695 type Output = Command<Out>;
696
697 fn fold_with<F, M>(self, folder: &mut F) -> Result<Self::Output, F::Error>
698 where
699 F: Folder<L, M, Output = Out>,
700 {
701 use crate::smt2parser::concrete::Command::*;
702 if let Some(ctx) = folder.context_mut() {
703 ctx.process(&self);
704 }
705 let command = match self {
706 Assert { term } => folder.fold_assert(term)?,
707 CheckSat => CheckSat,
708 CheckSatAssuming { literals } => CheckSatAssuming { literals },
709 DeclareConst { symbol, sort } => folder.fold_declare_const(symbol, sort)?,
710 DeclareDatatype { symbol, datatype } => DeclareDatatype { symbol, datatype },
711 DeclareDatatypes { datatypes } => DeclareDatatypes { datatypes },
712 DeclareFun {
713 symbol,
714 parameters,
715 sort,
716 } => folder.fold_declare_fun(symbol, parameters, sort)?,
717 DeclareSort { symbol, arity } => folder.fold_declare_sort(symbol, arity)?,
718 DefineFun { sig, term } => folder.fold_define_fun(sig, term)?,
719 DefineFunRec { sig, term } => folder.fold_define_fun_rec(sig, term)?,
720 DefineFunsRec { funs } => folder.fold_define_funs_rec(funs)?,
721 DefineSort {
722 symbol,
723 parameters,
724 sort,
725 } => folder.fold_define_sort(symbol, parameters, sort)?,
726 Echo { message } => Echo { message },
727 Exit => Exit,
728 GetAssertions => GetAssertions,
729 GetAssignment => GetAssignment,
730 GetInfo { flag } => GetInfo { flag },
731 GetModel => GetModel,
732 GetOption { keyword } => GetOption { keyword },
733 GetProof => GetProof,
734 GetUnsatAssumptions => GetUnsatAssumptions,
735 GetUnsatCore => GetUnsatCore,
736 GetValue { terms } => folder.fold_get_value(terms)?,
737 Pop { level } => Pop { level },
738 Push { level } => Push { level },
739 Reset => Reset,
740 ResetAssertions => ResetAssertions,
741 SetInfo { keyword, value } => SetInfo { keyword, value },
742 SetLogic { symbol } => folder.fold_set_logic(symbol)?,
743 SetOption { keyword, value } => SetOption { keyword, value },
744 };
745 if let Some(ctx) = folder.context_mut() {
746 ctx.process(&command);
747 }
748 Ok(command)
749 }
750}