ISLE: add support for multi-extractors and multi-constructors. (#4908)

* ISLE: add support for multi-extractors and multi-constructors.

This support allows for rules that process multiple matching values per
extractor call on the left-hand side, and as a result, can produce
multiple values from the constructor whose body they define.

This is useful in situations where we are matching on an input data
structure that can have multiple "nodes" for a given value or ID, for
example in an e-graph.

* Review feedback: all multi-ctors and multi-etors return iterators; no `Vec` case.

* Add additional warning suppressions to generated-code toplevels to be consistent with new islec output.
This commit is contained in:
Chris Fallin
2022-09-21 16:36:50 -07:00
committed by GitHub
parent b167172715
commit b652ce2fb1
13 changed files with 455 additions and 88 deletions

View File

@@ -0,0 +1,4 @@
(type u32 (primitive u32))
(decl multi A (u32) u32)
(extractor (A x) x)

View File

@@ -0,0 +1,15 @@
(type u32 (primitive u32))
(decl multi A (u32) u32)
(decl multi B (u32) u32)
(decl multi C (u32) u32)
(decl multi D (u32) u32)
(extern constructor B ctor_B)
(extern extractor C etor_C)
(rule (A x)
(B x))
(rule (D (C x))
(B x))

View File

@@ -0,0 +1,57 @@
mod multi_constructor;
pub(crate) type ConstructorVec<T> = Vec<T>;
struct Context;
struct It {
i: u32,
limit: u32,
}
impl multi_constructor::ContextIter for It {
type Context = Context;
type Output = u32;
fn next(&mut self, _ctx: &mut Self::Context) -> Option<u32> {
if self.i >= self.limit {
None
} else {
let i = self.i;
self.i += 1;
Some(i)
}
}
}
impl multi_constructor::Context for Context {
type etor_C_iter = It;
fn etor_C(&mut self, value: u32) -> Option<It> {
Some(It { i: 0, limit: value })
}
type ctor_B_iter = multi_constructor::ContextIterWrapper<u32, std::vec::IntoIter<u32>, Context>;
fn ctor_B(&mut self, value: u32) -> Option<Self::ctor_B_iter> {
Some((0..value).rev().collect::<Vec<_>>().into_iter().into())
}
}
struct IterWithContext<'a, Item, I: multi_constructor::ContextIter<Output = Item, Context = Context>> {
ctx: &'a mut Context,
it: I,
}
impl<'a, Item, I: multi_constructor::ContextIter<Output = Item, Context = Context>> Iterator for IterWithContext<'a, Item, I> {
type Item = Item;
fn next(&mut self) -> Option<Self::Item> {
self.it.next(self.ctx)
}
}
fn main() {
let mut ctx = Context;
let l1 = multi_constructor::constructor_A(&mut ctx, 10).unwrap();
let l2 = multi_constructor::constructor_D(&mut ctx, 5).unwrap();
let l1 = IterWithContext { ctx: &mut ctx, it: l1 }.collect::<Vec<_>>();
let l2 = IterWithContext { ctx: &mut ctx, it: l2 }.collect::<Vec<_>>();
println!("l1 = {:?} l2 = {:?}", l1, l2);
}

View File

@@ -0,0 +1,14 @@
(type u32 (primitive u32))
(type A extern (enum (B) (C)))
(decl multi E1 (A u32) u32)
(extern extractor E1 e1_etor)
(decl Rule (u32) u32)
(rule (Rule (E1 a idx))
(if-let (A.B) a)
idx)
(rule (Rule _)
32)

View File

@@ -0,0 +1,46 @@
mod multi_extractor;
#[derive(Clone)]
pub enum A {
B,
C,
}
struct It {
i: u32,
arg: u32,
}
impl multi_extractor::ContextIter for It {
type Context = Context;
type Output = (A, u32);
fn next(&mut self, _ctx: &mut Self::Context) -> Option<Self::Output> {
if self.i >= 32 {
None
} else {
let idx = self.i;
self.i += 1;
let a = if self.arg & (1u32 << idx) != 0 {
A::B
} else {
A::C
};
Some((a, idx))
}
}
}
struct Context;
impl multi_extractor::Context for Context {
type e1_etor_iter = It;
fn e1_etor(&mut self, arg0: u32) -> Option<It> {
Some(It { i: 0, arg: arg0 })
}
}
fn main() {
let mut ctx = Context;
let x = multi_extractor::constructor_Rule(&mut ctx, 0xf0);
let y = multi_extractor::constructor_Rule(&mut ctx, 0);
println!("x = {:?} y = {:?}", x, y);
}