diff --git a/cranelift/isle/TODO b/cranelift/isle/TODO index fc799f256c..86bf62c88a 100644 --- a/cranelift/isle/TODO +++ b/cranelift/isle/TODO @@ -1,4 +1,3 @@ -- `and` combinator in input. - inputs to external extractors? "polarity" of args? - "extractor macros" rather than full rule reversal? (rule ...) and (pattern ...)? - Document semantics carefully, especially wrt extractors. diff --git a/cranelift/isle/isle_examples/test4.isle b/cranelift/isle/isle_examples/test4.isle new file mode 100644 index 0000000000..085d2bee3b --- /dev/null +++ b/cranelift/isle/isle_examples/test4.isle @@ -0,0 +1,17 @@ +(type u32 (primitive u32)) +(type A (enum (A1 (x u32)))) + +(decl Ext1 (u32) A) +(decl Ext2 (u32) A) +(extractor Ext1 ext1) +(extractor Ext2 ext2) + +(decl Lower (A) A) + +(rule + (Lower + (and + a + (Ext1 x) + (Ext2 =x))) + a) diff --git a/cranelift/isle/src/ast.rs b/cranelift/isle/src/ast.rs index b0c06b68ae..e216ca9b82 100644 --- a/cranelift/isle/src/ast.rs +++ b/cranelift/isle/src/ast.rs @@ -83,6 +83,8 @@ pub enum Pattern { Term { sym: Ident, args: Vec }, /// An operator that matches anything. Wildcard, + /// N sub-patterns that must all match. + And { subpats: Vec }, } /// An expression: the right-hand side of a rule. diff --git a/cranelift/isle/src/ir.rs b/cranelift/isle/src/ir.rs index 9f7a7210b8..7951c1175e 100644 --- a/cranelift/isle/src/ir.rs +++ b/cranelift/isle/src/ir.rs @@ -253,6 +253,13 @@ impl PatternSequence { } } } + &Pattern::And(_ty, ref children) => { + let input = input.unwrap(); + for child in children { + self.gen_pattern(Some(input), typeenv, termenv, child, vars); + } + None + } &Pattern::Wildcard(_ty) => { // Nothing! None diff --git a/cranelift/isle/src/parser.rs b/cranelift/isle/src/parser.rs index b02f833068..e5265adc76 100644 --- a/cranelift/isle/src/parser.rs +++ b/cranelift/isle/src/parser.rs @@ -305,13 +305,23 @@ impl<'a> Parser<'a> { } } else if self.is_lparen() { self.lparen()?; - let sym = self.parse_ident()?; - let mut args = vec![]; - while !self.is_rparen() { - args.push(self.parse_pattern()?); + if self.is_sym_str("and") { + self.symbol()?; + let mut subpats = vec![]; + while !self.is_rparen() { + subpats.push(self.parse_pattern()?); + } + self.rparen()?; + Ok(Pattern::And { subpats }) + } else { + let sym = self.parse_ident()?; + let mut args = vec![]; + while !self.is_rparen() { + args.push(self.parse_pattern()?); + } + self.rparen()?; + Ok(Pattern::Term { sym, args }) } - self.rparen()?; - Ok(Pattern::Term { sym, args }) } else { Err(self.error(pos.unwrap(), "Unexpected pattern".into())) } diff --git a/cranelift/isle/src/sema.rs b/cranelift/isle/src/sema.rs index 40789ded0d..f3d9049180 100644 --- a/cranelift/isle/src/sema.rs +++ b/cranelift/isle/src/sema.rs @@ -123,6 +123,7 @@ pub enum Pattern { ConstInt(TypeId, i64), Term(TypeId, TermId, Vec), Wildcard(TypeId), + And(TypeId, Vec), } #[derive(Clone, Debug, PartialEq, Eq)] @@ -141,6 +142,7 @@ impl Pattern { &Self::ConstInt(t, ..) => t, &Self::Term(t, ..) => t, &Self::Wildcard(t, ..) => t, + &Self::And(t, ..) => t, } } } @@ -293,11 +295,13 @@ impl TypeEnv { } } +#[derive(Clone)] struct Bindings { next_var: usize, vars: Vec, } +#[derive(Clone)] struct BoundVar { name: Sym, id: VarId, @@ -548,6 +552,21 @@ impl TermEnv { })?; Ok((Pattern::Wildcard(ty), ty)) } + &ast::Pattern::And { ref subpats } => { + let mut expected_ty = expected_ty; + let mut children = vec![]; + for subpat in subpats { + let (subpat, ty) = + self.translate_pattern(tyenv, pos, &*subpat, expected_ty, bindings)?; + expected_ty = expected_ty.or(Some(ty)); + children.push(subpat); + } + if expected_ty.is_none() { + return Err(tyenv.error(pos, "No type for (and ...) form.".to_string())); + } + let ty = expected_ty.unwrap(); + Ok((Pattern::And(ty, children), ty)) + } &ast::Pattern::BindPattern { ref var, ref subpat,