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        let display_name = crate::util::sanitize_internal_name(&self.name);
42        write!(f, "{}", display_name)
43    }
44}
45
46pub type Expr = GenericExpr<String, String>;
47/// A generated expression is an expression that is generated by the system
48/// and does not have annotations.
49pub(crate) type ResolvedExpr = GenericExpr<ResolvedCall, ResolvedVar>;
50/// A [`MappedExpr`] arises naturally when you want a mapping between an expression
51/// and its flattened form. It records this mapping by annotating each `Head`
52/// with a `Leaf`, which it maps to in the flattened form.
53/// A useful operation on `MappedExpr`s is [`MappedExprExt::get_corresponding_var_or_lit``].
54pub(crate) type MappedExpr<Head, Leaf> = GenericExpr<CorrespondingVar<Head, Leaf>, Leaf>;
55
56pub(crate) trait ResolvedExprExt {
57    fn output_type(&self) -> ArcSort;
58    fn get_global_var(&self) -> Option<ResolvedVar>;
59}
60
61impl ResolvedExprExt for ResolvedExpr {
62    fn output_type(&self) -> ArcSort {
63        match self {
64            ResolvedExpr::Lit(_, lit) => sort::literal_sort(lit),
65            ResolvedExpr::Var(_, resolved_var) => resolved_var.sort.clone(),
66            ResolvedExpr::Call(_, resolved_call, _) => resolved_call.output().clone(),
67        }
68    }
69
70    fn get_global_var(&self) -> Option<ResolvedVar> {
71        match self {
72            ResolvedExpr::Var(_, v) if v.is_global_ref => Some(v.clone()),
73            _ => None,
74        }
75    }
76}
77
78#[macro_export]
79macro_rules! call {
80    ($func:expr, $args:expr) => {
81        $crate::ast::GenericExpr::Call($crate::span!(), $func.into(), $args.into_iter().collect())
82    };
83}
84
85#[macro_export]
86macro_rules! lit {
87    ($lit:expr) => {
88        $crate::ast::GenericExpr::Lit($crate::span!(), $lit.into())
89    };
90}
91
92#[macro_export]
93macro_rules! var {
94    ($var:expr) => {
95        $crate::ast::GenericExpr::Var($crate::span!(), $var.into())
96    };
97}
98
99// Rust macro annoyance; see stackoverflow.com/questions/26731243/how-do-i-use-a-macro-across-module-files
100pub use {call, lit, var};