egglog/ast/
expr.rs

1use egglog_ast::generic_ast::GenericExpr;
2use std::fmt::{Display, Formatter};
3use std::hash::Hash;
4use std::hash::Hasher;
5
6use crate::ast::CorrespondingVar;
7use crate::core::ResolvedCall;
8use crate::{ArcSort, sort};
9
10#[derive(Debug, Clone)]
11pub struct ResolvedVar {
12    pub name: String,
13    pub sort: ArcSort,
14    /// Is this a reference to a global variable?
15    /// After the `remove_globals` pass, this should be `false`.
16    ///
17    /// NB: we distinguish between a global reference and a global binding.
18    /// The current implementation of `Eq` and `Hash` does not take this field
19    /// into consideration.
20    /// Overall, the definition of equality between two ResolvedVars is dicey.
21    pub is_global_ref: bool,
22}
23
24impl PartialEq for ResolvedVar {
25    fn eq(&self, other: &Self) -> bool {
26        self.name == other.name && self.sort.name() == other.sort.name()
27    }
28}
29
30impl Eq for ResolvedVar {}
31
32impl Hash for ResolvedVar {
33    fn hash<H: Hasher>(&self, state: &mut H) {
34        self.name.hash(state);
35        self.sort.name().hash(state);
36    }
37}
38
39impl Display for ResolvedVar {
40    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41        write!(f, "{}", self.name)
42    }
43}
44
45pub type Expr = GenericExpr<String, String>;
46/// A generated expression is an expression that is generated by the system
47/// and does not have annotations.
48pub type ResolvedExpr = GenericExpr<ResolvedCall, ResolvedVar>;
49/// A [`MappedExpr`] arises naturally when you want a mapping between an expression
50/// and its flattened form. It records this mapping by annotating each `Head`
51/// with a `Leaf`, which it maps to in the flattened form.
52/// A useful operation on `MappedExpr`s is [`MappedExprExt::get_corresponding_var_or_lit``].
53pub(crate) type MappedExpr<Head, Leaf> = GenericExpr<CorrespondingVar<Head, Leaf>, Leaf>;
54
55pub(crate) trait ResolvedExprExt {
56    fn output_type(&self) -> ArcSort;
57    fn get_global_var(&self) -> Option<ResolvedVar>;
58}
59
60impl ResolvedExprExt for ResolvedExpr {
61    fn output_type(&self) -> ArcSort {
62        match self {
63            ResolvedExpr::Lit(_, lit) => sort::literal_sort(lit),
64            ResolvedExpr::Var(_, resolved_var) => resolved_var.sort.clone(),
65            ResolvedExpr::Call(_, resolved_call, _) => resolved_call.output().clone(),
66        }
67    }
68
69    fn get_global_var(&self) -> Option<ResolvedVar> {
70        match self {
71            ResolvedExpr::Var(_, v) if v.is_global_ref => Some(v.clone()),
72            _ => None,
73        }
74    }
75}
76
77#[macro_export]
78macro_rules! call {
79    ($func:expr, $args:expr) => {
80        $crate::ast::GenericExpr::Call($crate::span!(), $func.into(), $args.into_iter().collect())
81    };
82}
83
84#[macro_export]
85macro_rules! lit {
86    ($lit:expr) => {
87        $crate::ast::GenericExpr::Lit($crate::span!(), $lit.into())
88    };
89}
90
91#[macro_export]
92macro_rules! var {
93    ($var:expr) => {
94        $crate::ast::GenericExpr::Var($crate::span!(), $var.into())
95    };
96}
97
98// Rust macro annoyance; see stackoverflow.com/questions/26731243/how-do-i-use-a-macro-across-module-files
99pub use {call, lit, var};