Expand description
This crate provides a recursive interface to egg.
egg alrady comes with S-expression-based interface, but it has the following drawbacks:
- It uses
std::str::FromStrandstd::fmt::Displayto parse/format textual representation of ASTs.- These CAN be used for other purposes and this can cause a conflict with other applications.
- Parser favours the first clause for terminal variants with the same parameter.
- This can result in unexpected behaviour under the existence of ambiguity.
- ALL textual representation of ASTs fed to
egg::rewriteis checked at RUNTIME.- This means we can’t see syntax error until compilation;
- This further complicates the debugging process.
- S-expressions get harder and harder to be parsed by human eyes
This crate alleviates these problems by introducing a recursive interface to egg.
§Abstraction over Language
You can define a recursive language as a ordinary Self-referencing enum,
containing Boxes, [[Self; N]], or Vecs or other terminal other types.
Such language AST must implement Recursive trait and have a Signature type synonym.
This also provides Pat<L> for pattern matching, which can be converted to/from Pattern<AsLanguage<L>>.
We are providing a Language derive macro for automatically derive such types and impls.
use egg::*;
use egg_recursive::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Language)]
pub enum Arith {
Num(i32),
Neg(Box<Self>),
Add([Box<Self>; 2]),
Mul([Box<Self>; 2]),
}This generates the following entities:
Recursiveimpl forArith;- You can convert from/to
RecExpr<Signature<Arith, Id>>withFrominstances orRecursive::into_rec_expr/Recursive::from_rec_expr.
- You can convert from/to
EggArithtype alias forSignature<Arith, Id>, which implementsegg::Language;ArithPattype for recursive pattern ASTs.- It already implements
egg::Searcherandegg::Applier. - This is indeed a newtype wrapper of
Pat<AsLanguage<Arith>>.- We provide this as a newtype to allow (otherwise ophan) impls of utility traits for
Pats, (e.g.std::ops::Add,std::ops::Mul, etc).
- We provide this as a newtype to allow (otherwise ophan) impls of utility traits for
- This can be converted to/from
egg::Pattern<EggArith>withFrominstances.
- It already implements
ArithConstrait, which provides smart constructors forArithandArithPats.ArithConshas trait methods likenum(i64),add([Self; 2]),mul([Self; 2]),neg(Self), etc. It has just snake_cased variant of the original enum variants. If the snake_case version is reserved keyword, suffixed with_(e.g.Ifbecomesif_()).
An enum passed to self::Language should satisfy the following conditions:
- It MUST NOT have any generic parameters.
- Recursive variants MUST have only one field, which is one of the following (in any case, the type itself MUST be referenced by
Self, not a enum name itself):Box<Self>,[Box<Self>; N],Vec<Self>,T<Box<Self>>for someIntoLanguageChildrentypeT(described in the next section).
- Arguments to the non-recursive variants MUST implement at least
Eq,Ord,Hash, andClone.
§Helper Types for egg::LanguageChildren
Sometimes, the more the LanguageChildren has a components, the harder to get memorise the order/semantics of components.
To alleviates this situation, we introduce IntoLanguageChildren trait, which abstracts over view types of egg::LanguageChildren.
You don’t have to write it manually and it can generally be derived by self::LanguageChildren derive macro.
Suppose we want to add boolean operations and if-expressions:
use egg::*;
use egg_recursive::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, LanguageChildren)]
pub struct IfThenElse<T> {
pub cond: T,
pub then_branch: T,
pub else_branch: T,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Language)]
pub enum Arith {
Num(i32),
Bool(bool),
Neg(Box<Self>),
Add([Box<Self>; 2]),
Mul([Box<Self>; 2]),
IsZero(Box<Self>),
If(IfThenElse<Box<Self>>),
}This generates RawIfThenElse and IntoLanguageChildren instance to convert it to LanguageChildren.
You can call either IfThenElse::view or RawIfThenElse::unview to convert it to/from RawIfThenElse.
egg::LanguageChildren macro accepts types with the following conditions:
- It MUST be a struct with exactly one generic parameter.
- Every field must be one of the following (where
Tits only parameter):T,- [
[T; N]], or Vec<T>,
- AT MOST ONE
Vec<T>is allowed in its field.
§Writing Rewrite Rules
egg_recursive provides a redefined rewrite! macro to write rewrite rules.
This is almost the same as the original egg::rewrite! macro, but it allows you to write conditions in a more readable way.
Due to the ambiguity issue, it doesn’t support bidirectional rules (<=>) for the time being.
The following illustrates the usage of the macro:
pub fn make_rules() -> Vec<Rewrite<EggArith, ConstantFold>> {
let v = |s: &str| ArithPat::pat_var(s);
let x = || v("x");
let y = || v("y");
let x_var: Var = "?x".parse().unwrap();
vec![
rewrite!("add-comm"; x() + y() => y() + x()),
rewrite!("mul-comm"; x() * y() => y() * x()),
rewrite!("add-zero"; x() + ArithPat::float(0.0.into()) => x()),
rewrite!("add-zero"; x() => x() + ArithPat::float(0.0.into())),
rewrite!("mul-inv";
x() * x().inv() => ArithPat::float(1.0.into())
; if is_non_zero(x_var.clone())
),
]
}In the above, + and * comes from std::ops::Add and std::ops::Mul instances defined manually,
which is possible because ArithPat is a newtype, but not an alias.
Macros§
Enums§
- Pat
- Recursive AST for patterns in language
L. This can be converted to/fromPattern<AsLanguage<L>>.
Traits§
- Functor
- Into
Language Children - A trait for a type that can be converted from/to
egg::LanguageChildren.Self::RawDatamust be aegg::LanguageChildren. - Recursive
- A recursive language, which can be converted to and from a
RecExpr.
Type Aliases§
- AsLanguage
- A type synonym for
Signature<L, Id>, which should be an eggLanguage. - Lang
Children - RawData
- Signature
- A type synonym for
L::Container<T>, which corresponds to primitive terms ofLwith parameters inT. - View
Derive Macros§
- Language
- The macro to derive
Recursiveand correspondingLanguage,Patternsand smart constructor traits for a given recursive AST. - Language
Children - The macro to define a view type for a
LanguageChildrenand conversion mechanisms.