pub mod check_shadowing;
pub mod desugar;
mod expr;
mod parse;
pub mod proof_global_remover;
pub mod remove_globals;
use crate::core::{
GenericAtom, GenericAtomTerm, GenericExprExt, HeadOrEq, Query, ResolvedCall, ResolvedCoreRule,
};
use crate::util::sanitize_internal_name;
use crate::*;
pub use egglog_ast::generic_ast::{
Change, GenericAction, GenericActions, GenericExpr, GenericFact, GenericRule, Literal,
};
pub use egglog_ast::span::{RustSpan, Span};
use egglog_ast::util::ListDisplay;
pub use expr::*;
pub use parse::*;
#[derive(Clone, Debug)]
pub(crate) enum Ruleset {
Rules(IndexMap<String, (ResolvedCoreRule, egglog_bridge::RuleId)>),
Combined(Vec<String>),
}
pub type NCommand = GenericNCommand<String, String>;
pub(crate) type ResolvedNCommand = GenericNCommand<ResolvedCall, ResolvedVar>;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum GenericNCommand<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
Sort(
Span,
String,
Option<(String, Vec<GenericExpr<String, String>>)>,
),
Function(GenericFunctionDecl<Head, Leaf>),
AddRuleset(Span, String),
UnstableCombinedRuleset(Span, String, Vec<String>),
NormRule {
rule: GenericRule<Head, Leaf>,
},
CoreAction(GenericAction<Head, Leaf>),
Extract(Span, GenericExpr<Head, Leaf>, GenericExpr<Head, Leaf>),
RunSchedule(GenericSchedule<Head, Leaf>),
PrintOverallStatistics(Span, Option<String>),
Check(Span, Vec<GenericFact<Head, Leaf>>),
PrintFunction(
Span,
String,
Option<usize>,
Option<String>,
PrintFunctionMode,
),
PrintSize(Span, Option<String>),
Output {
span: Span,
file: String,
exprs: Vec<GenericExpr<Head, Leaf>>,
},
Push(usize),
Pop(Span, usize),
Fail(Span, Box<GenericNCommand<Head, Leaf>>),
Input {
span: Span,
name: String,
file: String,
},
UserDefined(Span, String, Vec<Expr>),
}
impl<Head, Leaf> GenericNCommand<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub fn to_command(&self) -> GenericCommand<Head, Leaf> {
match self {
GenericNCommand::Sort(span, name, params) => {
GenericCommand::Sort(span.clone(), name.clone(), params.clone())
}
GenericNCommand::Function(f) => match f.subtype {
FunctionSubtype::Constructor => GenericCommand::Constructor {
span: f.span.clone(),
name: f.name.clone(),
schema: f.schema.clone(),
cost: f.cost,
unextractable: f.unextractable,
},
FunctionSubtype::Relation => GenericCommand::Relation {
span: f.span.clone(),
name: f.name.clone(),
inputs: f.schema.input.clone(),
},
FunctionSubtype::Custom => GenericCommand::Function {
span: f.span.clone(),
schema: f.schema.clone(),
name: f.name.clone(),
merge: f.merge.clone(),
},
},
GenericNCommand::AddRuleset(span, name) => {
GenericCommand::AddRuleset(span.clone(), name.clone())
}
GenericNCommand::UnstableCombinedRuleset(span, name, others) => {
GenericCommand::UnstableCombinedRuleset(span.clone(), name.clone(), others.clone())
}
GenericNCommand::NormRule { rule } => GenericCommand::Rule { rule: rule.clone() },
GenericNCommand::RunSchedule(schedule) => GenericCommand::RunSchedule(schedule.clone()),
GenericNCommand::PrintOverallStatistics(span, file) => {
GenericCommand::PrintOverallStatistics(span.clone(), file.clone())
}
GenericNCommand::CoreAction(action) => GenericCommand::Action(action.clone()),
GenericNCommand::Extract(span, expr, variants) => {
GenericCommand::Extract(span.clone(), expr.clone(), variants.clone())
}
GenericNCommand::Check(span, facts) => {
GenericCommand::Check(span.clone(), facts.clone())
}
GenericNCommand::PrintFunction(span, name, n, file, mode) => {
GenericCommand::PrintFunction(span.clone(), name.clone(), *n, file.clone(), *mode)
}
GenericNCommand::PrintSize(span, name) => {
GenericCommand::PrintSize(span.clone(), name.clone())
}
GenericNCommand::Output { span, file, exprs } => GenericCommand::Output {
span: span.clone(),
file: file.to_string(),
exprs: exprs.clone(),
},
GenericNCommand::Push(n) => GenericCommand::Push(*n),
GenericNCommand::Pop(span, n) => GenericCommand::Pop(span.clone(), *n),
GenericNCommand::Fail(span, cmd) => {
GenericCommand::Fail(span.clone(), Box::new(cmd.to_command()))
}
GenericNCommand::Input { span, name, file } => GenericCommand::Input {
span: span.clone(),
name: name.clone(),
file: file.clone(),
},
GenericNCommand::UserDefined(span, name, exprs) => {
GenericCommand::UserDefined(span.clone(), name.clone(), exprs.clone())
}
}
}
pub fn visit_exprs(
self,
f: &mut impl FnMut(GenericExpr<Head, Leaf>) -> GenericExpr<Head, Leaf>,
) -> Self {
match self {
GenericNCommand::Sort(span, name, params) => GenericNCommand::Sort(span, name, params),
GenericNCommand::Function(func) => GenericNCommand::Function(func.visit_exprs(f)),
GenericNCommand::AddRuleset(span, name) => GenericNCommand::AddRuleset(span, name),
GenericNCommand::UnstableCombinedRuleset(span, name, rulesets) => {
GenericNCommand::UnstableCombinedRuleset(span, name, rulesets)
}
GenericNCommand::NormRule { rule } => GenericNCommand::NormRule {
rule: rule.visit_exprs(f),
},
GenericNCommand::RunSchedule(schedule) => {
GenericNCommand::RunSchedule(schedule.visit_exprs(f))
}
GenericNCommand::PrintOverallStatistics(span, file) => {
GenericNCommand::PrintOverallStatistics(span, file)
}
GenericNCommand::CoreAction(action) => {
GenericNCommand::CoreAction(action.visit_exprs(f))
}
GenericNCommand::Extract(span, expr, variants) => {
GenericNCommand::Extract(span, expr.visit_exprs(f), variants.visit_exprs(f))
}
GenericNCommand::Check(span, facts) => GenericNCommand::Check(
span,
facts.into_iter().map(|fact| fact.visit_exprs(f)).collect(),
),
GenericNCommand::PrintFunction(span, name, n, file, mode) => {
GenericNCommand::PrintFunction(span, name, n, file, mode)
}
GenericNCommand::PrintSize(span, name) => GenericNCommand::PrintSize(span, name),
GenericNCommand::Output { span, file, exprs } => GenericNCommand::Output {
span,
file,
exprs: exprs.into_iter().map(f).collect(),
},
GenericNCommand::Push(n) => GenericNCommand::Push(n),
GenericNCommand::Pop(span, n) => GenericNCommand::Pop(span, n),
GenericNCommand::Fail(span, cmd) => {
GenericNCommand::Fail(span, Box::new(cmd.visit_exprs(f)))
}
GenericNCommand::Input { span, name, file } => {
GenericNCommand::Input { span, name, file }
}
GenericNCommand::UserDefined(span, name, exprs) => {
GenericNCommand::UserDefined(span, name, exprs)
}
}
}
}
pub type Schedule = GenericSchedule<String, String>;
pub(crate) type ResolvedSchedule = GenericSchedule<ResolvedCall, ResolvedVar>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericSchedule<Head, Leaf> {
Saturate(Span, Box<GenericSchedule<Head, Leaf>>),
Repeat(Span, usize, Box<GenericSchedule<Head, Leaf>>),
Run(Span, GenericRunConfig<Head, Leaf>),
Sequence(Span, Vec<GenericSchedule<Head, Leaf>>),
}
impl<Head, Leaf> GenericSchedule<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
fn visit_exprs(
self,
f: &mut impl FnMut(GenericExpr<Head, Leaf>) -> GenericExpr<Head, Leaf>,
) -> Self {
match self {
GenericSchedule::Saturate(span, sched) => {
GenericSchedule::Saturate(span, Box::new(sched.visit_exprs(f)))
}
GenericSchedule::Repeat(span, size, sched) => {
GenericSchedule::Repeat(span, size, Box::new(sched.visit_exprs(f)))
}
GenericSchedule::Run(span, config) => GenericSchedule::Run(span, config.visit_exprs(f)),
GenericSchedule::Sequence(span, scheds) => GenericSchedule::Sequence(
span,
scheds.into_iter().map(|s| s.visit_exprs(f)).collect(),
),
}
}
pub fn make_unresolved(self) -> GenericSchedule<String, String> {
match self {
GenericSchedule::Saturate(span, sched) => {
GenericSchedule::Saturate(span, Box::new(sched.make_unresolved()))
}
GenericSchedule::Repeat(span, size, sched) => {
GenericSchedule::Repeat(span, size, Box::new(sched.make_unresolved()))
}
GenericSchedule::Run(span, config) => {
GenericSchedule::Run(span, config.make_unresolved())
}
GenericSchedule::Sequence(span, scheds) => GenericSchedule::Sequence(
span,
scheds
.into_iter()
.map(|sched| sched.make_unresolved())
.collect(),
),
}
}
}
impl<Head: Display, Leaf: Display> Display for GenericSchedule<Head, Leaf> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
GenericSchedule::Saturate(_ann, sched) => write!(f, "(saturate {sched})"),
GenericSchedule::Repeat(_ann, size, sched) => write!(f, "(repeat {size} {sched})"),
GenericSchedule::Run(_ann, config) => write!(f, "{config}"),
GenericSchedule::Sequence(_ann, scheds) => {
write!(f, "(seq {})", ListDisplay(scheds, " "))
}
}
}
}
pub type Command = GenericCommand<String, String>;
pub type ResolvedCommand = GenericCommand<ResolvedCall, ResolvedVar>;
pub type Subsume = bool;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Subdatatypes {
Variants(Vec<Variant>),
NewSort(String, Vec<Expr>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PrintFunctionMode {
Default,
CSV,
}
impl Display for PrintFunctionMode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
PrintFunctionMode::Default => write!(f, "default"),
PrintFunctionMode::CSV => write!(f, "csv"),
}
}
}
#[derive(Debug, Clone)]
pub enum GenericCommand<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
Sort(Span, String, Option<(String, Vec<Expr>)>),
Datatype {
span: Span,
name: String,
variants: Vec<Variant>,
},
Datatypes {
span: Span,
datatypes: Vec<(Span, String, Subdatatypes)>,
},
Constructor {
span: Span,
name: String,
schema: Schema,
cost: Option<DefaultCost>,
unextractable: bool,
},
Relation {
span: Span,
name: String,
inputs: Vec<String>,
},
Function {
span: Span,
name: String,
schema: Schema,
merge: Option<GenericExpr<Head, Leaf>>,
},
AddRuleset(Span, String),
UnstableCombinedRuleset(Span, String, Vec<String>),
Rule { rule: GenericRule<Head, Leaf> },
Rewrite(String, GenericRewrite<Head, Leaf>, Subsume),
BiRewrite(String, GenericRewrite<Head, Leaf>),
Action(GenericAction<Head, Leaf>),
Extract(Span, GenericExpr<Head, Leaf>, GenericExpr<Head, Leaf>),
RunSchedule(GenericSchedule<Head, Leaf>),
PrintOverallStatistics(Span, Option<String>),
Check(Span, Vec<GenericFact<Head, Leaf>>),
PrintFunction(
Span,
String,
Option<usize>,
Option<String>,
PrintFunctionMode,
),
PrintSize(Span, Option<String>),
Input {
span: Span,
name: String,
file: String,
},
Output {
span: Span,
file: String,
exprs: Vec<GenericExpr<Head, Leaf>>,
},
Push(usize),
Pop(Span, usize),
Fail(Span, Box<GenericCommand<Head, Leaf>>),
Include(Span, String),
UserDefined(Span, String, Vec<Expr>),
}
impl<Head, Leaf> Display for GenericCommand<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
GenericCommand::Rewrite(name, rewrite, subsume) => {
rewrite.fmt_with_ruleset(f, name, false, *subsume)
}
GenericCommand::BiRewrite(name, rewrite) => {
rewrite.fmt_with_ruleset(f, name, true, false)
}
GenericCommand::Datatype {
span: _,
name,
variants,
} => {
let name = sanitize_internal_name(name);
write!(f, "(datatype {name} {})", ListDisplay(variants, " "))
}
GenericCommand::Action(a) => write!(f, "{a}"),
GenericCommand::Extract(_span, expr, variants) => {
write!(f, "(extract {expr} {variants})")
}
GenericCommand::Sort(_span, name, None) => {
let name = sanitize_internal_name(name);
write!(f, "(sort {name})")
}
GenericCommand::Sort(_span, name, Some((name2, args))) => {
let name = sanitize_internal_name(name);
write!(f, "(sort {name} ({name2} {}))", ListDisplay(args, " "))
}
GenericCommand::Function {
span: _,
name,
schema,
merge,
} => {
let name = sanitize_internal_name(name);
write!(f, "(function {name} {schema}")?;
if let Some(merge) = &merge {
write!(f, " :merge {merge}")?;
} else {
write!(f, " :no-merge")?;
}
write!(f, ")")
}
GenericCommand::Constructor {
span: _,
name,
schema,
cost,
unextractable,
} => {
let name = sanitize_internal_name(name);
write!(f, "(constructor {name} {schema}")?;
if let Some(cost) = cost {
write!(f, " :cost {cost}")?;
}
if *unextractable {
write!(f, " :unextractable")?;
}
write!(f, ")")
}
GenericCommand::Relation {
span: _,
name,
inputs,
} => {
let name = sanitize_internal_name(name);
write!(f, "(relation {name} ({}))", ListDisplay(inputs, " "))
}
GenericCommand::AddRuleset(_span, name) => {
let name = sanitize_internal_name(name);
write!(f, "(ruleset {name})")
}
GenericCommand::UnstableCombinedRuleset(_span, name, others) => {
let name = sanitize_internal_name(name);
let others: Vec<_> = others
.iter()
.map(|other| sanitize_internal_name(other).into_owned())
.collect();
write!(
f,
"(unstable-combined-ruleset {name} {})",
ListDisplay(&others, " ")
)
}
GenericCommand::Rule { rule } => rule.fmt(f),
GenericCommand::RunSchedule(sched) => write!(f, "(run-schedule {sched})"),
GenericCommand::PrintOverallStatistics(_span, file) => match file {
Some(file) => write!(f, "(print-stats :file {file})"),
None => write!(f, "(print-stats)"),
},
GenericCommand::Check(_ann, facts) => {
write!(f, "(check {})", ListDisplay(facts, "\n"))
}
GenericCommand::Push(n) => write!(f, "(push {n})"),
GenericCommand::Pop(_span, n) => write!(f, "(pop {n})"),
GenericCommand::PrintFunction(_span, name, n, file, mode) => {
let name = sanitize_internal_name(name);
write!(f, "(print-function {name}")?;
if let Some(n) = n {
write!(f, " {n}")?;
}
if let Some(file) = file {
write!(f, " :file {file:?}")?;
}
match mode {
PrintFunctionMode::Default => {}
PrintFunctionMode::CSV => write!(f, " :mode csv")?,
}
write!(f, ")")
}
GenericCommand::PrintSize(_span, name) => {
let name: Option<_> = name
.as_ref()
.map(|value| sanitize_internal_name(value).into_owned());
write!(f, "(print-size {})", ListDisplay(name, " "))
}
GenericCommand::Input {
span: _,
name,
file,
} => {
let name = sanitize_internal_name(name);
write!(f, "(input {name} {file:?})")
}
GenericCommand::Output {
span: _,
file,
exprs,
} => write!(f, "(output {file:?} {})", ListDisplay(exprs, " ")),
GenericCommand::Fail(_span, cmd) => write!(f, "(fail {cmd})"),
GenericCommand::Include(_span, file) => write!(f, "(include {file:?})"),
GenericCommand::Datatypes { span: _, datatypes } => {
let datatypes: Vec<_> = datatypes
.iter()
.map(|(_, name, variants)| {
let name = sanitize_internal_name(name);
match variants {
Subdatatypes::Variants(variants) => {
format!("({name} {})", ListDisplay(variants, " "))
}
Subdatatypes::NewSort(head, args) => {
format!("(sort {name} ({head} {}))", ListDisplay(args, " "))
}
}
})
.collect();
write!(f, "(datatype* {})", ListDisplay(datatypes, " "))
}
GenericCommand::UserDefined(_span, name, exprs) => {
let name = sanitize_internal_name(name);
write!(f, "({name} {})", ListDisplay(exprs, " "))
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct IdentSort {
pub ident: String,
pub sort: String,
}
impl Display for IdentSort {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "({} {})", self.ident, self.sort)
}
}
pub type RunConfig = GenericRunConfig<String, String>;
pub(crate) type ResolvedRunConfig = GenericRunConfig<ResolvedCall, ResolvedVar>;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct GenericRunConfig<Head, Leaf> {
pub ruleset: String,
pub until: Option<Vec<GenericFact<Head, Leaf>>>,
}
impl<Head, Leaf> GenericRunConfig<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub fn visit_exprs(
self,
f: &mut impl FnMut(GenericExpr<Head, Leaf>) -> GenericExpr<Head, Leaf>,
) -> Self {
Self {
ruleset: self.ruleset,
until: self
.until
.map(|until| until.into_iter().map(|fact| fact.visit_exprs(f)).collect()),
}
}
pub fn make_unresolved(self) -> GenericRunConfig<String, String> {
GenericRunConfig {
ruleset: self.ruleset,
until: self.until.map(|facts| {
facts
.into_iter()
.map(|fact| fact.make_unresolved())
.collect()
}),
}
}
}
impl<Head: Display, Leaf: Display> Display for GenericRunConfig<Head, Leaf>
where
Head: Display,
Leaf: Display,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "(run")?;
let ruleset = sanitize_internal_name(&self.ruleset);
if !ruleset.is_empty() {
write!(f, " {ruleset}")?;
}
if let Some(until) = &self.until {
write!(f, " :until {}", ListDisplay(until, " "))?;
}
write!(f, ")")
}
}
pub type FunctionDecl = GenericFunctionDecl<String, String>;
pub(crate) type ResolvedFunctionDecl = GenericFunctionDecl<ResolvedCall, ResolvedVar>;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FunctionSubtype {
Constructor,
Relation,
Custom,
}
impl Display for FunctionSubtype {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
FunctionSubtype::Constructor => write!(f, "constructor"),
FunctionSubtype::Relation => write!(f, "relation"),
FunctionSubtype::Custom => write!(f, "function"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct GenericFunctionDecl<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub name: String,
pub subtype: FunctionSubtype,
pub schema: Schema,
pub resolved_schema: Head,
pub merge: Option<GenericExpr<Head, Leaf>>,
pub cost: Option<DefaultCost>,
pub unextractable: bool,
pub let_binding: bool,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Variant {
pub span: Span,
pub name: String,
pub types: Vec<String>,
pub cost: Option<DefaultCost>,
pub unextractable: bool,
}
impl Display for Variant {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
let name = sanitize_internal_name(&self.name);
write!(f, "({name}")?;
if !self.types.is_empty() {
write!(f, " {}", ListDisplay(&self.types, " "))?;
}
if let Some(cost) = self.cost {
write!(f, " :cost {cost}")?;
}
write!(f, ")")
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Schema {
pub input: Vec<String>,
pub output: String,
}
impl Display for Schema {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "({}) {}", ListDisplay(&self.input, " "), self.output)
}
}
impl Schema {
pub fn new(input: Vec<String>, output: String) -> Self {
Self { input, output }
}
}
impl FunctionDecl {
pub fn function(
span: Span,
name: String,
schema: Schema,
merge: Option<GenericExpr<String, String>>,
) -> Self {
Self {
name,
subtype: FunctionSubtype::Custom,
schema,
resolved_schema: String::new(),
merge,
cost: None,
unextractable: true,
let_binding: false,
span,
}
}
pub fn constructor(
span: Span,
name: String,
schema: Schema,
cost: Option<DefaultCost>,
unextractable: bool,
) -> Self {
Self {
name,
subtype: FunctionSubtype::Constructor,
resolved_schema: String::new(),
schema,
merge: None,
cost,
unextractable,
let_binding: false,
span,
}
}
pub fn relation(span: Span, name: String, input: Vec<String>) -> Self {
Self {
name,
subtype: FunctionSubtype::Relation,
schema: Schema {
input,
output: String::from("Unit"),
},
resolved_schema: String::new(),
merge: None,
cost: None,
unextractable: true,
let_binding: false,
span,
}
}
}
impl<Head, Leaf> GenericFunctionDecl<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub fn visit_exprs(
self,
f: &mut impl FnMut(GenericExpr<Head, Leaf>) -> GenericExpr<Head, Leaf>,
) -> GenericFunctionDecl<Head, Leaf> {
GenericFunctionDecl {
name: self.name,
subtype: self.subtype,
schema: self.schema,
resolved_schema: self.resolved_schema,
merge: self.merge.map(|expr| expr.visit_exprs(f)),
cost: self.cost,
unextractable: self.unextractable,
let_binding: self.let_binding,
span: self.span,
}
}
}
pub type Fact = GenericFact<String, String>;
pub type ResolvedFact = GenericFact<ResolvedCall, ResolvedVar>;
pub(crate) type MappedFact<Head, Leaf> = GenericFact<CorrespondingVar<Head, Leaf>, Leaf>;
pub struct Facts<Head, Leaf>(pub Vec<GenericFact<Head, Leaf>>);
impl<Head, Leaf> Facts<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub(crate) fn to_query(
&self,
typeinfo: &TypeInfo,
fresh_gen: &mut impl FreshGen<Head, Leaf>,
) -> (Query<HeadOrEq<Head>, Leaf>, Vec<MappedFact<Head, Leaf>>) {
let mut atoms = vec![];
let mut new_body = vec![];
for fact in self.0.iter() {
match fact {
GenericFact::Eq(span, e1, e2) => {
let mut to_equate = vec![];
let mut process = |expr: &GenericExpr<Head, Leaf>| {
let (child_atoms, expr) = expr.to_query(typeinfo, fresh_gen);
atoms.extend(child_atoms);
to_equate.push(expr.get_corresponding_var_or_lit(typeinfo));
expr
};
let e1 = process(e1);
let e2 = process(e2);
atoms.push(GenericAtom {
span: span.clone(),
head: HeadOrEq::Eq,
args: to_equate,
});
new_body.push(GenericFact::Eq(span.clone(), e1, e2));
}
GenericFact::Fact(expr) => {
let (child_atoms, expr) = expr.to_query(typeinfo, fresh_gen);
atoms.extend(child_atoms);
new_body.push(GenericFact::Fact(expr));
}
}
}
(Query { atoms }, new_body)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CorrespondingVar<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub head: Head,
pub to: Leaf,
}
impl<Head, Leaf> CorrespondingVar<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub fn new(head: Head, leaf: Leaf) -> Self {
Self { head, to: leaf }
}
}
impl<Head, Leaf> Display for CorrespondingVar<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "{} -> {}", self.head, self.to)
}
}
pub type Action = GenericAction<String, String>;
pub(crate) type MappedAction = GenericAction<CorrespondingVar<String, String>, String>;
pub(crate) type ResolvedAction = GenericAction<ResolvedCall, ResolvedVar>;
pub type Actions = GenericActions<String, String>;
pub(crate) type ResolvedActions = GenericActions<ResolvedCall, ResolvedVar>;
pub(crate) type MappedActions<Head, Leaf> = GenericActions<CorrespondingVar<Head, Leaf>, Leaf>;
pub type Rule = GenericRule<String, String>;
pub(crate) type ResolvedRule = GenericRule<ResolvedCall, ResolvedVar>;
pub type Rewrite = GenericRewrite<String, String>;
#[derive(Clone, Debug)]
pub struct GenericRewrite<Head, Leaf> {
pub span: Span,
pub lhs: GenericExpr<Head, Leaf>,
pub rhs: GenericExpr<Head, Leaf>,
pub conditions: Vec<GenericFact<Head, Leaf>>,
}
impl<Head, Leaf> GenericRewrite<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub fn make_unresolved(self) -> GenericRewrite<String, String> {
GenericRewrite {
span: self.span,
lhs: self.lhs.make_unresolved(),
rhs: self.rhs.make_unresolved(),
conditions: self
.conditions
.into_iter()
.map(|fact| fact.make_unresolved())
.collect(),
}
}
}
impl<Head: Display, Leaf: Display> GenericRewrite<Head, Leaf> {
pub fn fmt_with_ruleset(
&self,
f: &mut Formatter,
ruleset: &str,
is_bidirectional: bool,
subsume: bool,
) -> std::fmt::Result {
let direction = if is_bidirectional {
"birewrite"
} else {
"rewrite"
};
write!(f, "({direction} {} {}", self.lhs, self.rhs)?;
if subsume {
write!(f, " :subsume")?;
}
if !self.conditions.is_empty() {
write!(f, " :when ({})", ListDisplay(&self.conditions, " "))?;
}
if !ruleset.is_empty() {
let ruleset = sanitize_internal_name(ruleset);
write!(f, " :ruleset {ruleset}")?;
}
write!(f, ")")
}
}
pub(crate) trait MappedExprExt<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
fn get_corresponding_var_or_lit(&self, typeinfo: &TypeInfo) -> GenericAtomTerm<Leaf>;
}
impl<Head, Leaf> MappedExprExt<Head, Leaf> for MappedExpr<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
fn get_corresponding_var_or_lit(&self, typeinfo: &TypeInfo) -> GenericAtomTerm<Leaf> {
match self {
GenericExpr::Var(span, v) => {
if typeinfo.is_global(&v.to_string()) {
GenericAtomTerm::Global(span.clone(), v.clone())
} else {
GenericAtomTerm::Var(span.clone(), v.clone())
}
}
GenericExpr::Lit(span, lit) => GenericAtomTerm::Literal(span.clone(), lit.clone()),
GenericExpr::Call(span, head, _) => GenericAtomTerm::Var(span.clone(), head.to.clone()),
}
}
}
impl<Head, Leaf> GenericCommand<Head, Leaf>
where
Head: Clone + Display,
Leaf: Clone + PartialEq + Eq + Display + Hash,
{
pub fn make_unresolved(self) -> GenericCommand<String, String> {
match self {
GenericCommand::Sort(span, name, params) => GenericCommand::Sort(span, name, params),
GenericCommand::Datatype {
span,
name,
variants,
} => GenericCommand::Datatype {
span,
name,
variants,
},
GenericCommand::Datatypes { span, datatypes } => {
GenericCommand::Datatypes { span, datatypes }
}
GenericCommand::Constructor {
span,
name,
schema,
cost,
unextractable,
} => GenericCommand::Constructor {
span,
name,
schema,
cost,
unextractable,
},
GenericCommand::Relation { span, name, inputs } => {
GenericCommand::Relation { span, name, inputs }
}
GenericCommand::Function {
span,
name,
schema,
merge,
} => GenericCommand::Function {
span,
name,
schema,
merge: merge.map(|expr| expr.make_unresolved()),
},
GenericCommand::AddRuleset(span, name) => GenericCommand::AddRuleset(span, name),
GenericCommand::UnstableCombinedRuleset(span, name, others) => {
GenericCommand::UnstableCombinedRuleset(span, name, others)
}
GenericCommand::Rule { rule } => GenericCommand::Rule {
rule: rule.make_unresolved(),
},
GenericCommand::Rewrite(name, rewrite, subsume) => {
GenericCommand::Rewrite(name, rewrite.make_unresolved(), subsume)
}
GenericCommand::BiRewrite(name, rewrite) => {
GenericCommand::BiRewrite(name, rewrite.make_unresolved())
}
GenericCommand::Action(action) => GenericCommand::Action(action.make_unresolved()),
GenericCommand::Extract(span, expr, variants) => {
GenericCommand::Extract(span, expr.make_unresolved(), variants.make_unresolved())
}
GenericCommand::RunSchedule(schedule) => {
GenericCommand::RunSchedule(schedule.make_unresolved())
}
GenericCommand::PrintOverallStatistics(span, file) => {
GenericCommand::PrintOverallStatistics(span, file)
}
GenericCommand::Check(span, facts) => GenericCommand::Check(
span,
facts
.into_iter()
.map(|fact| fact.make_unresolved())
.collect(),
),
GenericCommand::PrintFunction(span, name, n, file, mode) => {
GenericCommand::PrintFunction(span, name, n, file, mode)
}
GenericCommand::PrintSize(span, name) => GenericCommand::PrintSize(span, name),
GenericCommand::Input { span, name, file } => {
GenericCommand::Input { span, name, file }
}
GenericCommand::Output { span, file, exprs } => GenericCommand::Output {
span,
file,
exprs: exprs
.into_iter()
.map(|expr| expr.make_unresolved())
.collect(),
},
GenericCommand::Push(n) => GenericCommand::Push(n),
GenericCommand::Pop(span, n) => GenericCommand::Pop(span, n),
GenericCommand::Fail(span, cmd) => {
GenericCommand::Fail(span, Box::new(cmd.make_unresolved()))
}
GenericCommand::Include(span, file) => GenericCommand::Include(span, file),
GenericCommand::UserDefined(span, name, exprs) => {
GenericCommand::UserDefined(span, name, exprs)
}
}
}
pub fn visit_actions(
self,
f: &mut impl FnMut(GenericAction<Head, Leaf>) -> GenericAction<Head, Leaf>,
) -> Self {
match self {
GenericCommand::Rule { rule } => GenericCommand::Rule {
rule: rule.visit_actions(f),
},
GenericCommand::Action(action) => GenericCommand::Action(f(action)),
GenericCommand::Fail(span, cmd) => {
GenericCommand::Fail(span, Box::new(cmd.visit_actions(f)))
}
other => other,
}
}
}