1pub mod check_shadowing;
2pub mod desugar;
3mod expr;
4mod parse;
5pub mod remove_globals;
6
7use crate::core::{
8 GenericAtom, GenericAtomTerm, GenericExprExt, HeadOrEq, Query, ResolvedCall, ResolvedCoreRule,
9};
10use crate::util::sanitize_internal_name;
11use crate::*;
12pub use egglog_ast::generic_ast::{
13 Change, GenericAction, GenericActions, GenericExpr, GenericFact, GenericRule, Literal,
14};
15pub use egglog_ast::span::{RustSpan, Span};
16use egglog_ast::util::ListDisplay;
17pub use expr::*;
18pub use parse::*;
19
20#[derive(Clone, Debug)]
21pub(crate) enum Ruleset {
23 Rules(IndexMap<String, (ResolvedCoreRule, egglog_bridge::RuleId)>),
25 Combined(Vec<String>),
27}
28
29pub type NCommand = GenericNCommand<String, String>;
30pub(crate) type ResolvedNCommand = GenericNCommand<ResolvedCall, ResolvedVar>;
34
35#[derive(Debug, Clone, Eq, PartialEq, Hash)]
47pub enum GenericNCommand<Head, Leaf>
48where
49 Head: Clone + Display,
50 Leaf: Clone + PartialEq + Eq + Display + Hash,
51{
52 Sort(
53 Span,
54 String,
55 Option<(String, Vec<GenericExpr<String, String>>)>,
56 ),
57 Function(GenericFunctionDecl<Head, Leaf>),
58 AddRuleset(Span, String),
59 UnstableCombinedRuleset(Span, String, Vec<String>),
60 NormRule {
61 rule: GenericRule<Head, Leaf>,
62 },
63 CoreAction(GenericAction<Head, Leaf>),
64 Extract(Span, GenericExpr<Head, Leaf>, GenericExpr<Head, Leaf>),
65 RunSchedule(GenericSchedule<Head, Leaf>),
66 PrintOverallStatistics(Span, Option<String>),
67 Check(Span, Vec<GenericFact<Head, Leaf>>),
68 PrintFunction(
69 Span,
70 String,
71 Option<usize>,
72 Option<String>,
73 PrintFunctionMode,
74 ),
75 PrintSize(Span, Option<String>),
76 Output {
77 span: Span,
78 file: String,
79 exprs: Vec<GenericExpr<Head, Leaf>>,
80 },
81 Push(usize),
82 Pop(Span, usize),
83 Fail(Span, Box<GenericNCommand<Head, Leaf>>),
84 Input {
85 span: Span,
86 name: String,
87 file: String,
88 },
89 UserDefined(Span, String, Vec<Expr>),
90}
91
92impl<Head, Leaf> GenericNCommand<Head, Leaf>
93where
94 Head: Clone + Display,
95 Leaf: Clone + PartialEq + Eq + Display + Hash,
96{
97 pub fn to_command(&self) -> GenericCommand<Head, Leaf> {
98 match self {
99 GenericNCommand::Sort(span, name, params) => {
100 GenericCommand::Sort(span.clone(), name.clone(), params.clone())
101 }
102 GenericNCommand::Function(f) => match f.subtype {
103 FunctionSubtype::Constructor => GenericCommand::Constructor {
104 span: f.span.clone(),
105 name: f.name.clone(),
106 schema: f.schema.clone(),
107 cost: f.cost,
108 unextractable: f.unextractable,
109 },
110 FunctionSubtype::Relation => GenericCommand::Relation {
111 span: f.span.clone(),
112 name: f.name.clone(),
113 inputs: f.schema.input.clone(),
114 },
115 FunctionSubtype::Custom => GenericCommand::Function {
116 span: f.span.clone(),
117 schema: f.schema.clone(),
118 name: f.name.clone(),
119 merge: f.merge.clone(),
120 },
121 },
122 GenericNCommand::AddRuleset(span, name) => {
123 GenericCommand::AddRuleset(span.clone(), name.clone())
124 }
125 GenericNCommand::UnstableCombinedRuleset(span, name, others) => {
126 GenericCommand::UnstableCombinedRuleset(span.clone(), name.clone(), others.clone())
127 }
128 GenericNCommand::NormRule { rule } => GenericCommand::Rule { rule: rule.clone() },
129 GenericNCommand::RunSchedule(schedule) => GenericCommand::RunSchedule(schedule.clone()),
130 GenericNCommand::PrintOverallStatistics(span, file) => {
131 GenericCommand::PrintOverallStatistics(span.clone(), file.clone())
132 }
133 GenericNCommand::CoreAction(action) => GenericCommand::Action(action.clone()),
134 GenericNCommand::Extract(span, expr, variants) => {
135 GenericCommand::Extract(span.clone(), expr.clone(), variants.clone())
136 }
137 GenericNCommand::Check(span, facts) => {
138 GenericCommand::Check(span.clone(), facts.clone())
139 }
140 GenericNCommand::PrintFunction(span, name, n, file, mode) => {
141 GenericCommand::PrintFunction(span.clone(), name.clone(), *n, file.clone(), *mode)
142 }
143 GenericNCommand::PrintSize(span, name) => {
144 GenericCommand::PrintSize(span.clone(), name.clone())
145 }
146 GenericNCommand::Output { span, file, exprs } => GenericCommand::Output {
147 span: span.clone(),
148 file: file.to_string(),
149 exprs: exprs.clone(),
150 },
151 GenericNCommand::Push(n) => GenericCommand::Push(*n),
152 GenericNCommand::Pop(span, n) => GenericCommand::Pop(span.clone(), *n),
153 GenericNCommand::Fail(span, cmd) => {
154 GenericCommand::Fail(span.clone(), Box::new(cmd.to_command()))
155 }
156 GenericNCommand::Input { span, name, file } => GenericCommand::Input {
157 span: span.clone(),
158 name: name.clone(),
159 file: file.clone(),
160 },
161 GenericNCommand::UserDefined(span, name, exprs) => {
162 GenericCommand::UserDefined(span.clone(), name.clone(), exprs.clone())
163 }
164 }
165 }
166
167 pub fn visit_exprs(
168 self,
169 f: &mut impl FnMut(GenericExpr<Head, Leaf>) -> GenericExpr<Head, Leaf>,
170 ) -> Self {
171 match self {
172 GenericNCommand::Sort(span, name, params) => GenericNCommand::Sort(span, name, params),
173 GenericNCommand::Function(func) => GenericNCommand::Function(func.visit_exprs(f)),
174 GenericNCommand::AddRuleset(span, name) => GenericNCommand::AddRuleset(span, name),
175 GenericNCommand::UnstableCombinedRuleset(span, name, rulesets) => {
176 GenericNCommand::UnstableCombinedRuleset(span, name, rulesets)
177 }
178 GenericNCommand::NormRule { rule } => GenericNCommand::NormRule {
179 rule: rule.visit_exprs(f),
180 },
181 GenericNCommand::RunSchedule(schedule) => {
182 GenericNCommand::RunSchedule(schedule.visit_exprs(f))
183 }
184 GenericNCommand::PrintOverallStatistics(span, file) => {
185 GenericNCommand::PrintOverallStatistics(span, file)
186 }
187 GenericNCommand::CoreAction(action) => {
188 GenericNCommand::CoreAction(action.visit_exprs(f))
189 }
190 GenericNCommand::Extract(span, expr, variants) => {
191 GenericNCommand::Extract(span, expr.visit_exprs(f), variants.visit_exprs(f))
192 }
193 GenericNCommand::Check(span, facts) => GenericNCommand::Check(
194 span,
195 facts.into_iter().map(|fact| fact.visit_exprs(f)).collect(),
196 ),
197 GenericNCommand::PrintFunction(span, name, n, file, mode) => {
198 GenericNCommand::PrintFunction(span, name, n, file, mode)
199 }
200 GenericNCommand::PrintSize(span, name) => GenericNCommand::PrintSize(span, name),
201 GenericNCommand::Output { span, file, exprs } => GenericNCommand::Output {
202 span,
203 file,
204 exprs: exprs.into_iter().map(f).collect(),
205 },
206 GenericNCommand::Push(n) => GenericNCommand::Push(n),
207 GenericNCommand::Pop(span, n) => GenericNCommand::Pop(span, n),
208 GenericNCommand::Fail(span, cmd) => {
209 GenericNCommand::Fail(span, Box::new(cmd.visit_exprs(f)))
210 }
211 GenericNCommand::Input { span, name, file } => {
212 GenericNCommand::Input { span, name, file }
213 }
214 GenericNCommand::UserDefined(span, name, exprs) => {
215 GenericNCommand::UserDefined(span, name, exprs)
217 }
218 }
219 }
220}
221
222pub type Schedule = GenericSchedule<String, String>;
223pub(crate) type ResolvedSchedule = GenericSchedule<ResolvedCall, ResolvedVar>;
224
225#[derive(Debug, Clone, PartialEq, Eq, Hash)]
226pub enum GenericSchedule<Head, Leaf> {
227 Saturate(Span, Box<GenericSchedule<Head, Leaf>>),
228 Repeat(Span, usize, Box<GenericSchedule<Head, Leaf>>),
229 Run(Span, GenericRunConfig<Head, Leaf>),
230 Sequence(Span, Vec<GenericSchedule<Head, Leaf>>),
231}
232
233impl<Head, Leaf> GenericSchedule<Head, Leaf>
234where
235 Head: Clone + Display,
236 Leaf: Clone + PartialEq + Eq + Display + Hash,
237{
238 fn visit_exprs(
239 self,
240 f: &mut impl FnMut(GenericExpr<Head, Leaf>) -> GenericExpr<Head, Leaf>,
241 ) -> Self {
242 match self {
243 GenericSchedule::Saturate(span, sched) => {
244 GenericSchedule::Saturate(span, Box::new(sched.visit_exprs(f)))
245 }
246 GenericSchedule::Repeat(span, size, sched) => {
247 GenericSchedule::Repeat(span, size, Box::new(sched.visit_exprs(f)))
248 }
249 GenericSchedule::Run(span, config) => GenericSchedule::Run(span, config.visit_exprs(f)),
250 GenericSchedule::Sequence(span, scheds) => GenericSchedule::Sequence(
251 span,
252 scheds.into_iter().map(|s| s.visit_exprs(f)).collect(),
253 ),
254 }
255 }
256}
257
258impl<Head: Display, Leaf: Display> Display for GenericSchedule<Head, Leaf> {
259 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
260 match self {
261 GenericSchedule::Saturate(_ann, sched) => write!(f, "(saturate {sched})"),
262 GenericSchedule::Repeat(_ann, size, sched) => write!(f, "(repeat {size} {sched})"),
263 GenericSchedule::Run(_ann, config) => write!(f, "{config}"),
264 GenericSchedule::Sequence(_ann, scheds) => {
265 write!(f, "(seq {})", ListDisplay(scheds, " "))
266 }
267 }
268 }
269}
270
271pub type Command = GenericCommand<String, String>;
272
273pub type Subsume = bool;
274
275#[derive(Debug, Clone, PartialEq, Eq)]
276pub enum Subdatatypes {
277 Variants(Vec<Variant>),
278 NewSort(String, Vec<Expr>),
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
285pub enum PrintFunctionMode {
286 Default,
287 CSV,
288}
289
290impl Display for PrintFunctionMode {
291 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
292 match self {
293 PrintFunctionMode::Default => write!(f, "default"),
294 PrintFunctionMode::CSV => write!(f, "csv"),
295 }
296 }
297}
298
299#[derive(Debug, Clone)]
311pub enum GenericCommand<Head, Leaf>
312where
313 Head: Clone + Display,
314 Leaf: Clone + PartialEq + Eq + Display + Hash,
315{
316 Sort(Span, String, Option<(String, Vec<Expr>)>),
332
333 Datatype {
372 span: Span,
373 name: String,
374 variants: Vec<Variant>,
375 },
376 Datatypes {
377 span: Span,
378 datatypes: Vec<(Span, String, Subdatatypes)>,
379 },
380
381 Constructor {
388 span: Span,
389 name: String,
390 schema: Schema,
391 cost: Option<DefaultCost>,
392 unextractable: bool,
393 },
394
395 Relation {
402 span: Span,
403 name: String,
404 inputs: Vec<String>,
405 },
406
407 Function {
447 span: Span,
448 name: String,
449 schema: Schema,
450 merge: Option<GenericExpr<Head, Leaf>>,
451 },
452
453 AddRuleset(Span, String),
469 UnstableCombinedRuleset(Span, String, Vec<String>),
488 Rule { rule: GenericRule<Head, Leaf> },
509 Rewrite(String, GenericRewrite<Head, Leaf>, Subsume),
549 BiRewrite(String, GenericRewrite<Head, Leaf>),
566 Action(GenericAction<Head, Leaf>),
573 Extract(Span, GenericExpr<Head, Leaf>, GenericExpr<Head, Leaf>),
579 RunSchedule(GenericSchedule<Head, Leaf>),
594 PrintOverallStatistics(Span, Option<String>),
597 Check(Span, Vec<GenericFact<Head, Leaf>>),
618 PrintFunction(
636 Span,
637 String,
638 Option<usize>,
639 Option<String>,
640 PrintFunctionMode,
641 ),
642 PrintSize(Span, Option<String>),
644 Input {
646 span: Span,
647 name: String,
648 file: String,
649 },
650 Output {
652 span: Span,
653 file: String,
654 exprs: Vec<GenericExpr<Head, Leaf>>,
655 },
656 Push(usize),
659 Pop(Span, usize),
662 Fail(Span, Box<GenericCommand<Head, Leaf>>),
664 Include(Span, String),
666 UserDefined(Span, String, Vec<Expr>),
668}
669
670impl<Head, Leaf> Display for GenericCommand<Head, Leaf>
671where
672 Head: Clone + Display,
673 Leaf: Clone + PartialEq + Eq + Display + Hash,
674{
675 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
676 match self {
677 GenericCommand::Rewrite(name, rewrite, subsume) => {
678 rewrite.fmt_with_ruleset(f, name, false, *subsume)
679 }
680 GenericCommand::BiRewrite(name, rewrite) => {
681 rewrite.fmt_with_ruleset(f, name, true, false)
682 }
683 GenericCommand::Datatype {
684 span: _,
685 name,
686 variants,
687 } => {
688 let name = sanitize_internal_name(name);
689 write!(f, "(datatype {name} {})", ListDisplay(variants, " "))
690 }
691 GenericCommand::Action(a) => write!(f, "{a}"),
692 GenericCommand::Extract(_span, expr, variants) => {
693 write!(f, "(extract {expr} {variants})")
694 }
695 GenericCommand::Sort(_span, name, None) => {
696 let name = sanitize_internal_name(name);
697 write!(f, "(sort {name})")
698 }
699 GenericCommand::Sort(_span, name, Some((name2, args))) => {
700 let name = sanitize_internal_name(name);
701 write!(f, "(sort {name} ({name2} {}))", ListDisplay(args, " "))
702 }
703 GenericCommand::Function {
704 span: _,
705 name,
706 schema,
707 merge,
708 } => {
709 let name = sanitize_internal_name(name);
710 write!(f, "(function {name} {schema}")?;
711 if let Some(merge) = &merge {
712 write!(f, " :merge {merge}")?;
713 } else {
714 write!(f, " :no-merge")?;
715 }
716 write!(f, ")")
717 }
718 GenericCommand::Constructor {
719 span: _,
720 name,
721 schema,
722 cost,
723 unextractable,
724 } => {
725 let name = sanitize_internal_name(name);
726 write!(f, "(constructor {name} {schema}")?;
727 if let Some(cost) = cost {
728 write!(f, " :cost {cost}")?;
729 }
730 if *unextractable {
731 write!(f, " :unextractable")?;
732 }
733 write!(f, ")")
734 }
735 GenericCommand::Relation {
736 span: _,
737 name,
738 inputs,
739 } => {
740 let name = sanitize_internal_name(name);
741 write!(f, "(relation {name} ({}))", ListDisplay(inputs, " "))
742 }
743 GenericCommand::AddRuleset(_span, name) => {
744 let name = sanitize_internal_name(name);
745 write!(f, "(ruleset {name})")
746 }
747 GenericCommand::UnstableCombinedRuleset(_span, name, others) => {
748 let name = sanitize_internal_name(name);
749 let others: Vec<_> = others
750 .iter()
751 .map(|other| sanitize_internal_name(other).into_owned())
752 .collect();
753 write!(
754 f,
755 "(unstable-combined-ruleset {name} {})",
756 ListDisplay(&others, " ")
757 )
758 }
759 GenericCommand::Rule { rule } => rule.fmt(f),
760 GenericCommand::RunSchedule(sched) => write!(f, "(run-schedule {sched})"),
761 GenericCommand::PrintOverallStatistics(_span, file) => match file {
762 Some(file) => write!(f, "(print-stats :file {file})"),
763 None => write!(f, "(print-stats)"),
764 },
765 GenericCommand::Check(_ann, facts) => {
766 write!(f, "(check {})", ListDisplay(facts, "\n"))
767 }
768 GenericCommand::Push(n) => write!(f, "(push {n})"),
769 GenericCommand::Pop(_span, n) => write!(f, "(pop {n})"),
770 GenericCommand::PrintFunction(_span, name, n, file, mode) => {
771 let name = sanitize_internal_name(name);
772 write!(f, "(print-function {name}")?;
773 if let Some(n) = n {
774 write!(f, " {n}")?;
775 }
776 if let Some(file) = file {
777 write!(f, " :file {file:?}")?;
778 }
779 match mode {
780 PrintFunctionMode::Default => {}
781 PrintFunctionMode::CSV => write!(f, " :mode csv")?,
782 }
783 write!(f, ")")
784 }
785 GenericCommand::PrintSize(_span, name) => {
786 let name: Option<_> = name
787 .as_ref()
788 .map(|value| sanitize_internal_name(value).into_owned());
789 write!(f, "(print-size {})", ListDisplay(name, " "))
790 }
791 GenericCommand::Input {
792 span: _,
793 name,
794 file,
795 } => {
796 let name = sanitize_internal_name(name);
797 write!(f, "(input {name} {file:?})")
798 }
799 GenericCommand::Output {
800 span: _,
801 file,
802 exprs,
803 } => write!(f, "(output {file:?} {})", ListDisplay(exprs, " ")),
804 GenericCommand::Fail(_span, cmd) => write!(f, "(fail {cmd})"),
805 GenericCommand::Include(_span, file) => write!(f, "(include {file:?})"),
806 GenericCommand::Datatypes { span: _, datatypes } => {
807 let datatypes: Vec<_> = datatypes
808 .iter()
809 .map(|(_, name, variants)| {
810 let name = sanitize_internal_name(name);
811 match variants {
812 Subdatatypes::Variants(variants) => {
813 format!("({name} {})", ListDisplay(variants, " "))
814 }
815 Subdatatypes::NewSort(head, args) => {
816 format!("(sort {name} ({head} {}))", ListDisplay(args, " "))
817 }
818 }
819 })
820 .collect();
821 write!(f, "(datatype* {})", ListDisplay(datatypes, " "))
822 }
823 GenericCommand::UserDefined(_span, name, exprs) => {
824 let name = sanitize_internal_name(name);
825 write!(f, "({name} {})", ListDisplay(exprs, " "))
826 }
827 }
828 }
829}
830
831#[derive(Clone, Debug, PartialEq, Eq, Hash)]
832pub struct IdentSort {
833 pub ident: String,
834 pub sort: String,
835}
836
837impl Display for IdentSort {
838 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
839 write!(f, "({} {})", self.ident, self.sort)
840 }
841}
842
843pub type RunConfig = GenericRunConfig<String, String>;
844pub(crate) type ResolvedRunConfig = GenericRunConfig<ResolvedCall, ResolvedVar>;
845
846#[derive(Clone, Debug, PartialEq, Eq, Hash)]
847pub struct GenericRunConfig<Head, Leaf> {
848 pub ruleset: String,
849 pub until: Option<Vec<GenericFact<Head, Leaf>>>,
850}
851
852impl<Head, Leaf> GenericRunConfig<Head, Leaf>
853where
854 Head: Clone + Display,
855 Leaf: Clone + PartialEq + Eq + Display + Hash,
856{
857 pub fn visit_exprs(
858 self,
859 f: &mut impl FnMut(GenericExpr<Head, Leaf>) -> GenericExpr<Head, Leaf>,
860 ) -> Self {
861 Self {
862 ruleset: self.ruleset,
863 until: self
864 .until
865 .map(|until| until.into_iter().map(|fact| fact.visit_exprs(f)).collect()),
866 }
867 }
868}
869
870impl<Head: Display, Leaf: Display> Display for GenericRunConfig<Head, Leaf>
871where
872 Head: Display,
873 Leaf: Display,
874{
875 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
876 write!(f, "(run")?;
877 let ruleset = sanitize_internal_name(&self.ruleset);
878 if !ruleset.is_empty() {
879 write!(f, " {ruleset}")?;
880 }
881 if let Some(until) = &self.until {
882 write!(f, " :until {}", ListDisplay(until, " "))?;
883 }
884 write!(f, ")")
885 }
886}
887
888pub type FunctionDecl = GenericFunctionDecl<String, String>;
889pub(crate) type ResolvedFunctionDecl = GenericFunctionDecl<ResolvedCall, ResolvedVar>;
890
891#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
892pub enum FunctionSubtype {
893 Constructor,
894 Relation,
895 Custom,
896}
897
898impl Display for FunctionSubtype {
899 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
900 match self {
901 FunctionSubtype::Constructor => write!(f, "constructor"),
902 FunctionSubtype::Relation => write!(f, "relation"),
903 FunctionSubtype::Custom => write!(f, "function"),
904 }
905 }
906}
907
908#[derive(Clone, Debug, PartialEq, Eq, Hash)]
911pub struct GenericFunctionDecl<Head, Leaf>
912where
913 Head: Clone + Display,
914 Leaf: Clone + PartialEq + Eq + Display + Hash,
915{
916 pub name: String,
917 pub subtype: FunctionSubtype,
918 pub schema: Schema,
919 pub merge: Option<GenericExpr<Head, Leaf>>,
920 pub cost: Option<DefaultCost>,
921 pub unextractable: bool,
922 pub let_binding: bool,
925 pub span: Span,
926}
927
928#[derive(Clone, Debug, PartialEq, Eq, Hash)]
929pub struct Variant {
930 pub span: Span,
931 pub name: String,
932 pub types: Vec<String>,
933 pub cost: Option<DefaultCost>,
934 pub unextractable: bool,
935}
936
937impl Display for Variant {
938 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
939 let name = sanitize_internal_name(&self.name);
940 write!(f, "({name}")?;
941 if !self.types.is_empty() {
942 write!(f, " {}", ListDisplay(&self.types, " "))?;
943 }
944 if let Some(cost) = self.cost {
945 write!(f, " :cost {cost}")?;
946 }
947 write!(f, ")")
948 }
949}
950
951#[derive(Clone, Debug, PartialEq, Eq, Hash)]
952pub struct Schema {
953 pub input: Vec<String>,
954 pub output: String,
955}
956
957impl Display for Schema {
958 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
959 write!(f, "({}) {}", ListDisplay(&self.input, " "), self.output)
960 }
961}
962
963impl Schema {
964 pub fn new(input: Vec<String>, output: String) -> Self {
965 Self { input, output }
966 }
967}
968
969impl FunctionDecl {
970 pub fn function(
972 span: Span,
973 name: String,
974 schema: Schema,
975 merge: Option<GenericExpr<String, String>>,
976 ) -> Self {
977 Self {
978 name,
979 subtype: FunctionSubtype::Custom,
980 schema,
981 merge,
982 cost: None,
983 unextractable: true,
984 let_binding: false,
985 span,
986 }
987 }
988
989 pub fn constructor(
991 span: Span,
992 name: String,
993 schema: Schema,
994 cost: Option<DefaultCost>,
995 unextractable: bool,
996 ) -> Self {
997 Self {
998 name,
999 subtype: FunctionSubtype::Constructor,
1000 schema,
1001 merge: None,
1002 cost,
1003 unextractable,
1004 let_binding: false,
1005 span,
1006 }
1007 }
1008
1009 pub fn relation(span: Span, name: String, input: Vec<String>) -> Self {
1011 Self {
1012 name,
1013 subtype: FunctionSubtype::Relation,
1014 schema: Schema {
1015 input,
1016 output: String::from("Unit"),
1017 },
1018 merge: None,
1019 cost: None,
1020 unextractable: true,
1021 let_binding: false,
1022 span,
1023 }
1024 }
1025}
1026
1027impl<Head, Leaf> GenericFunctionDecl<Head, Leaf>
1028where
1029 Head: Clone + Display,
1030 Leaf: Clone + PartialEq + Eq + Display + Hash,
1031{
1032 pub fn visit_exprs(
1033 self,
1034 f: &mut impl FnMut(GenericExpr<Head, Leaf>) -> GenericExpr<Head, Leaf>,
1035 ) -> GenericFunctionDecl<Head, Leaf> {
1036 GenericFunctionDecl {
1037 name: self.name,
1038 subtype: self.subtype,
1039 schema: self.schema,
1040 merge: self.merge.map(|expr| expr.visit_exprs(f)),
1041 cost: self.cost,
1042 unextractable: self.unextractable,
1043 let_binding: self.let_binding,
1044 span: self.span,
1045 }
1046 }
1047}
1048
1049pub type Fact = GenericFact<String, String>;
1050pub(crate) type ResolvedFact = GenericFact<ResolvedCall, ResolvedVar>;
1051pub(crate) type MappedFact<Head, Leaf> = GenericFact<CorrespondingVar<Head, Leaf>, Leaf>;
1052
1053pub struct Facts<Head, Leaf>(pub Vec<GenericFact<Head, Leaf>>);
1054
1055impl<Head, Leaf> Facts<Head, Leaf>
1056where
1057 Head: Clone + Display,
1058 Leaf: Clone + PartialEq + Eq + Display + Hash,
1059{
1060 pub(crate) fn to_query(
1068 &self,
1069 typeinfo: &TypeInfo,
1070 fresh_gen: &mut impl FreshGen<Head, Leaf>,
1071 ) -> (Query<HeadOrEq<Head>, Leaf>, Vec<MappedFact<Head, Leaf>>) {
1072 let mut atoms = vec![];
1073 let mut new_body = vec![];
1074
1075 for fact in self.0.iter() {
1076 match fact {
1077 GenericFact::Eq(span, e1, e2) => {
1078 let mut to_equate = vec![];
1079 let mut process = |expr: &GenericExpr<Head, Leaf>| {
1080 let (child_atoms, expr) = expr.to_query(typeinfo, fresh_gen);
1081 atoms.extend(child_atoms);
1082 to_equate.push(expr.get_corresponding_var_or_lit(typeinfo));
1083 expr
1084 };
1085 let e1 = process(e1);
1086 let e2 = process(e2);
1087 atoms.push(GenericAtom {
1088 span: span.clone(),
1089 head: HeadOrEq::Eq,
1090 args: to_equate,
1091 });
1092 new_body.push(GenericFact::Eq(span.clone(), e1, e2));
1093 }
1094 GenericFact::Fact(expr) => {
1095 let (child_atoms, expr) = expr.to_query(typeinfo, fresh_gen);
1096 atoms.extend(child_atoms);
1097 new_body.push(GenericFact::Fact(expr));
1098 }
1099 }
1100 }
1101 (Query { atoms }, new_body)
1102 }
1103}
1104
1105#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1106pub struct CorrespondingVar<Head, Leaf>
1107where
1108 Head: Clone + Display,
1109 Leaf: Clone + PartialEq + Eq + Display + Hash,
1110{
1111 pub head: Head,
1112 pub to: Leaf,
1113}
1114
1115impl<Head, Leaf> CorrespondingVar<Head, Leaf>
1116where
1117 Head: Clone + Display,
1118 Leaf: Clone + PartialEq + Eq + Display + Hash,
1119{
1120 pub fn new(head: Head, leaf: Leaf) -> Self {
1121 Self { head, to: leaf }
1122 }
1123}
1124
1125impl<Head, Leaf> Display for CorrespondingVar<Head, Leaf>
1126where
1127 Head: Clone + Display,
1128 Leaf: Clone + PartialEq + Eq + Display + Hash,
1129{
1130 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1131 write!(f, "{} -> {}", self.head, self.to)
1132 }
1133}
1134pub type Action = GenericAction<String, String>;
1135pub(crate) type MappedAction = GenericAction<CorrespondingVar<String, String>, String>;
1136pub(crate) type ResolvedAction = GenericAction<ResolvedCall, ResolvedVar>;
1137
1138pub type Actions = GenericActions<String, String>;
1139pub(crate) type ResolvedActions = GenericActions<ResolvedCall, ResolvedVar>;
1140pub(crate) type MappedActions<Head, Leaf> = GenericActions<CorrespondingVar<Head, Leaf>, Leaf>;
1141
1142pub type Rule = GenericRule<String, String>;
1143pub(crate) type ResolvedRule = GenericRule<ResolvedCall, ResolvedVar>;
1144
1145pub type Rewrite = GenericRewrite<String, String>;
1146
1147#[derive(Clone, Debug)]
1148pub struct GenericRewrite<Head, Leaf> {
1149 pub span: Span,
1150 pub lhs: GenericExpr<Head, Leaf>,
1151 pub rhs: GenericExpr<Head, Leaf>,
1152 pub conditions: Vec<GenericFact<Head, Leaf>>,
1153}
1154
1155impl<Head: Display, Leaf: Display> GenericRewrite<Head, Leaf> {
1156 pub fn fmt_with_ruleset(
1158 &self,
1159 f: &mut Formatter,
1160 ruleset: &str,
1161 is_bidirectional: bool,
1162 subsume: bool,
1163 ) -> std::fmt::Result {
1164 let direction = if is_bidirectional {
1165 "birewrite"
1166 } else {
1167 "rewrite"
1168 };
1169 write!(f, "({direction} {} {}", self.lhs, self.rhs)?;
1170 if subsume {
1171 write!(f, " :subsume")?;
1172 }
1173 if !self.conditions.is_empty() {
1174 write!(f, " :when ({})", ListDisplay(&self.conditions, " "))?;
1175 }
1176 if !ruleset.is_empty() {
1177 let ruleset = sanitize_internal_name(ruleset);
1178 write!(f, " :ruleset {ruleset}")?;
1179 }
1180 write!(f, ")")
1181 }
1182}
1183
1184pub(crate) trait MappedExprExt<Head, Leaf>
1185where
1186 Head: Clone + Display,
1187 Leaf: Clone + PartialEq + Eq + Display + Hash,
1188{
1189 fn get_corresponding_var_or_lit(&self, typeinfo: &TypeInfo) -> GenericAtomTerm<Leaf>;
1190}
1191
1192impl<Head, Leaf> MappedExprExt<Head, Leaf> for MappedExpr<Head, Leaf>
1193where
1194 Head: Clone + Display,
1195 Leaf: Clone + PartialEq + Eq + Display + Hash,
1196{
1197 fn get_corresponding_var_or_lit(&self, typeinfo: &TypeInfo) -> GenericAtomTerm<Leaf> {
1198 match self {
1202 GenericExpr::Var(span, v) => {
1203 if typeinfo.is_global(&v.to_string()) {
1204 GenericAtomTerm::Global(span.clone(), v.clone())
1205 } else {
1206 GenericAtomTerm::Var(span.clone(), v.clone())
1207 }
1208 }
1209 GenericExpr::Lit(span, lit) => GenericAtomTerm::Literal(span.clone(), lit.clone()),
1210 GenericExpr::Call(span, head, _) => GenericAtomTerm::Var(span.clone(), head.to.clone()),
1211 }
1212 }
1213}