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:
@@ -4,6 +4,6 @@
|
|||||||
// mod generated_code;` trick either.
|
// mod generated_code;` trick either.
|
||||||
#![allow(dead_code, unreachable_code, unreachable_patterns)]
|
#![allow(dead_code, unreachable_code, unreachable_patterns)]
|
||||||
#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]
|
#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]
|
||||||
#![allow(irrefutable_let_patterns)]
|
#![allow(irrefutable_let_patterns, unused_assignments, non_camel_case_types)]
|
||||||
|
|
||||||
include!(concat!(env!("ISLE_DIR"), "/isle_aarch64.rs"));
|
include!(concat!(env!("ISLE_DIR"), "/isle_aarch64.rs"));
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
// mod generated_code;` trick either.
|
// mod generated_code;` trick either.
|
||||||
#![allow(dead_code, unreachable_code, unreachable_patterns)]
|
#![allow(dead_code, unreachable_code, unreachable_patterns)]
|
||||||
#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]
|
#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]
|
||||||
#![allow(irrefutable_let_patterns)]
|
#![allow(irrefutable_let_patterns, unused_assignments, non_camel_case_types)]
|
||||||
|
|
||||||
include!(concat!(env!("ISLE_DIR"), "/isle_s390x.rs"));
|
include!(concat!(env!("ISLE_DIR"), "/isle_s390x.rs"));
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
// mod generated_code;` trick either.
|
// mod generated_code;` trick either.
|
||||||
#![allow(dead_code, unreachable_code, unreachable_patterns)]
|
#![allow(dead_code, unreachable_code, unreachable_patterns)]
|
||||||
#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]
|
#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]
|
||||||
#![allow(irrefutable_let_patterns)]
|
#![allow(irrefutable_let_patterns, unused_assignments, non_camel_case_types)]
|
||||||
|
|
||||||
include!(concat!(env!("ISLE_DIR"), "/isle_x64.rs"));
|
include!(concat!(env!("ISLE_DIR"), "/isle_x64.rs"));
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
(type u32 (primitive u32))
|
||||||
|
|
||||||
|
(decl multi A (u32) u32)
|
||||||
|
(extractor (A x) x)
|
||||||
@@ -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))
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
14
cranelift/isle/isle/isle_examples/link/multi_extractor.isle
Normal file
14
cranelift/isle/isle/isle_examples/link/multi_extractor.isle
Normal 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)
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -72,6 +72,10 @@ pub struct Decl {
|
|||||||
pub ret_ty: Ident,
|
pub ret_ty: Ident,
|
||||||
/// Whether this term's constructor is pure.
|
/// Whether this term's constructor is pure.
|
||||||
pub pure: bool,
|
pub pure: bool,
|
||||||
|
/// Whether this term can exist with some multiplicity: an
|
||||||
|
/// extractor or a constructor that matches multiple times, or
|
||||||
|
/// produces multiple values.
|
||||||
|
pub multi: bool,
|
||||||
pub pos: Pos,
|
pub pos: Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,35 +87,66 @@ impl<'a> Codegen<'a> {
|
|||||||
"#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]"
|
"#![allow(unused_imports, unused_variables, non_snake_case, unused_mut)]"
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
writeln!(code, "#![allow(irrefutable_let_patterns)]").unwrap();
|
writeln!(
|
||||||
|
code,
|
||||||
|
"#![allow(irrefutable_let_patterns, unused_assignments, non_camel_case_types)]"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(code, "\nuse super::*; // Pulls in all external types.").unwrap();
|
writeln!(code, "\nuse super::*; // Pulls in all external types.").unwrap();
|
||||||
|
writeln!(code, "use std::marker::PhantomData;").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_trait_sig(&self, code: &mut String, indent: &str, sig: &ExternalSig) {
|
fn generate_trait_sig(&self, code: &mut String, indent: &str, sig: &ExternalSig) {
|
||||||
writeln!(
|
let ret_tuple = format!(
|
||||||
code,
|
"{open_paren}{rets}{close_paren}",
|
||||||
"{indent}fn {name}(&mut self, {params}) -> {opt_start}{open_paren}{rets}{close_paren}{opt_end};",
|
|
||||||
indent = indent,
|
|
||||||
name = sig.func_name,
|
|
||||||
params = sig.param_tys
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, &ty)| format!("arg{}: {}", i, self.type_name(ty, /* by_ref = */ true)))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", "),
|
|
||||||
opt_start = if sig.infallible { "" } else { "Option<" },
|
|
||||||
open_paren = if sig.ret_tys.len() != 1 { "(" } else { "" },
|
open_paren = if sig.ret_tys.len() != 1 { "(" } else { "" },
|
||||||
rets = sig.ret_tys
|
rets = sig
|
||||||
|
.ret_tys
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&ty| self.type_name(ty, /* by_ref = */ false))
|
.map(|&ty| self.type_name(ty, /* by_ref = */ false))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "),
|
.join(", "),
|
||||||
close_paren = if sig.ret_tys.len() != 1 { ")" } else { "" },
|
close_paren = if sig.ret_tys.len() != 1 { ")" } else { "" },
|
||||||
opt_end = if sig.infallible { "" } else { ">" },
|
);
|
||||||
|
|
||||||
|
let ret_ty = match (sig.multi, sig.infallible) {
|
||||||
|
(false, false) => format!("Option<{}>", ret_tuple),
|
||||||
|
(false, true) => format!("{}", ret_tuple),
|
||||||
|
(true, false) => format!("Option<Self::{}_iter>", sig.func_name),
|
||||||
|
_ => panic!(
|
||||||
|
"Unsupported multiplicity/infallible combo: {:?}, {}",
|
||||||
|
sig.multi, sig.infallible
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
"{indent}fn {name}(&mut self, {params}) -> {ret_ty};",
|
||||||
|
indent = indent,
|
||||||
|
name = sig.func_name,
|
||||||
|
params = sig
|
||||||
|
.param_tys
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, &ty)| format!("arg{}: {}", i, self.type_name(ty, /* by_ref = */ true)))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", "),
|
||||||
|
ret_ty = ret_ty,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
if sig.multi {
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
"{indent}type {name}_iter: ContextIter<Context = Self, Output = {output}>;",
|
||||||
|
indent = indent,
|
||||||
|
name = sig.func_name,
|
||||||
|
output = ret_tuple,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_ctx_trait(&self, code: &mut String) {
|
fn generate_ctx_trait(&self, code: &mut String) {
|
||||||
@@ -147,6 +178,34 @@ impl<'a> Codegen<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(code, "}}").unwrap();
|
writeln!(code, "}}").unwrap();
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
r#"
|
||||||
|
pub trait ContextIter {{
|
||||||
|
type Context;
|
||||||
|
type Output;
|
||||||
|
fn next(&mut self, ctx: &mut Self::Context) -> Option<Self::Output>;
|
||||||
|
}}
|
||||||
|
|
||||||
|
pub struct ContextIterWrapper<Item, I: Iterator < Item = Item>, C: Context> {{
|
||||||
|
iter: I,
|
||||||
|
_ctx: PhantomData<C>,
|
||||||
|
}}
|
||||||
|
impl<Item, I: Iterator<Item = Item>, C: Context> From<I> for ContextIterWrapper<Item, I, C> {{
|
||||||
|
fn from(iter: I) -> Self {{
|
||||||
|
Self {{ iter, _ctx: PhantomData }}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
impl<Item, I: Iterator<Item = Item>, C: Context> ContextIter for ContextIterWrapper<Item, I, C> {{
|
||||||
|
type Context = C;
|
||||||
|
type Output = Item;
|
||||||
|
fn next(&mut self, _ctx: &mut Self::Context) -> Option<Self::Output> {{
|
||||||
|
self.iter.next()
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_internal_types(&self, code: &mut String) {
|
fn generate_internal_types(&self, code: &mut String) {
|
||||||
@@ -299,6 +358,11 @@ impl<'a> Codegen<'a> {
|
|||||||
.join(", ");
|
.join(", ");
|
||||||
assert_eq!(sig.ret_tys.len(), 1);
|
assert_eq!(sig.ret_tys.len(), 1);
|
||||||
let ret = self.type_name(sig.ret_tys[0], false);
|
let ret = self.type_name(sig.ret_tys[0], false);
|
||||||
|
let ret = if sig.multi {
|
||||||
|
format!("impl ContextIter<Context = C, Output = {}>", ret)
|
||||||
|
} else {
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
|
||||||
writeln!(
|
writeln!(
|
||||||
code,
|
code,
|
||||||
@@ -313,11 +377,29 @@ impl<'a> Codegen<'a> {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
if sig.multi {
|
||||||
|
writeln!(code, "let mut returns = ConstructorVec::new();").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
let mut body_ctx: BodyContext = Default::default();
|
let mut body_ctx: BodyContext = Default::default();
|
||||||
let returned =
|
let returned = self.generate_body(
|
||||||
self.generate_body(code, /* depth = */ 0, trie, " ", &mut body_ctx);
|
code,
|
||||||
|
/* depth = */ 0,
|
||||||
|
trie,
|
||||||
|
" ",
|
||||||
|
&mut body_ctx,
|
||||||
|
sig.multi,
|
||||||
|
);
|
||||||
if !returned {
|
if !returned {
|
||||||
writeln!(code, " return None;").unwrap();
|
if sig.multi {
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
" return Some(ContextIterWrapper::from(returns.into_iter()));"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
writeln!(code, " return None;").unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(code, "}}").unwrap();
|
writeln!(code, "}}").unwrap();
|
||||||
@@ -332,8 +414,9 @@ impl<'a> Codegen<'a> {
|
|||||||
indent: &str,
|
indent: &str,
|
||||||
ctx: &mut BodyContext,
|
ctx: &mut BodyContext,
|
||||||
returns: &mut Vec<(usize, String)>,
|
returns: &mut Vec<(usize, String)>,
|
||||||
) {
|
) -> bool {
|
||||||
log!("generate_expr_inst: {:?}", inst);
|
log!("generate_expr_inst: {:?}", inst);
|
||||||
|
let mut new_scope = false;
|
||||||
match inst {
|
match inst {
|
||||||
&ExprInst::ConstInt { ty, val } => {
|
&ExprInst::ConstInt { ty, val } => {
|
||||||
let value = Value::Expr {
|
let value = Value::Expr {
|
||||||
@@ -422,6 +505,7 @@ impl<'a> Codegen<'a> {
|
|||||||
ref inputs,
|
ref inputs,
|
||||||
term,
|
term,
|
||||||
infallible,
|
infallible,
|
||||||
|
multi,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut input_exprs = vec![];
|
let mut input_exprs = vec![];
|
||||||
@@ -442,17 +526,36 @@ impl<'a> Codegen<'a> {
|
|||||||
let termdata = &self.termenv.terms[term.index()];
|
let termdata = &self.termenv.terms[term.index()];
|
||||||
let sig = termdata.constructor_sig(self.typeenv).unwrap();
|
let sig = termdata.constructor_sig(self.typeenv).unwrap();
|
||||||
assert_eq!(input_exprs.len(), sig.param_tys.len());
|
assert_eq!(input_exprs.len(), sig.param_tys.len());
|
||||||
let fallible_try = if infallible { "" } else { "?" };
|
|
||||||
writeln!(
|
if !multi {
|
||||||
code,
|
let fallible_try = if infallible { "" } else { "?" };
|
||||||
"{}let {} = {}(ctx, {}){};",
|
writeln!(
|
||||||
indent,
|
code,
|
||||||
outputname,
|
"{}let {} = {}(ctx, {}){};",
|
||||||
sig.full_name,
|
indent,
|
||||||
input_exprs.join(", "),
|
outputname,
|
||||||
fallible_try,
|
sig.full_name,
|
||||||
)
|
input_exprs.join(", "),
|
||||||
.unwrap();
|
fallible_try,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
"{}let mut it = {}(ctx, {})?;",
|
||||||
|
indent,
|
||||||
|
sig.full_name,
|
||||||
|
input_exprs.join(", "),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
"{}while let Some({}) = it.next(ctx) {{",
|
||||||
|
indent, outputname,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
new_scope = true;
|
||||||
|
}
|
||||||
self.define_val(&output, ctx, /* is_ref = */ false, termdata.ret_ty);
|
self.define_val(&output, ctx, /* is_ref = */ false, termdata.ret_ty);
|
||||||
}
|
}
|
||||||
&ExprInst::Return {
|
&ExprInst::Return {
|
||||||
@@ -462,6 +565,8 @@ impl<'a> Codegen<'a> {
|
|||||||
returns.push((index, value_expr));
|
returns.push((index, value_expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_scope
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_variant_binders(
|
fn match_variant_binders(
|
||||||
@@ -489,7 +594,7 @@ impl<'a> Codegen<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a `bool` indicating whether this pattern inst is
|
/// Returns a `bool` indicating whether this pattern inst is
|
||||||
/// infallible.
|
/// infallible, and the number of scopes opened.
|
||||||
fn generate_pattern_inst(
|
fn generate_pattern_inst(
|
||||||
&self,
|
&self,
|
||||||
code: &mut String,
|
code: &mut String,
|
||||||
@@ -497,7 +602,7 @@ impl<'a> Codegen<'a> {
|
|||||||
inst: &PatternInst,
|
inst: &PatternInst,
|
||||||
indent: &str,
|
indent: &str,
|
||||||
ctx: &mut BodyContext,
|
ctx: &mut BodyContext,
|
||||||
) -> bool {
|
) -> (bool, usize) {
|
||||||
match inst {
|
match inst {
|
||||||
&PatternInst::Arg { index, ty } => {
|
&PatternInst::Arg { index, ty } => {
|
||||||
let output = Value::Pattern {
|
let output = Value::Pattern {
|
||||||
@@ -519,13 +624,13 @@ impl<'a> Codegen<'a> {
|
|||||||
is_ref,
|
is_ref,
|
||||||
ty,
|
ty,
|
||||||
);
|
);
|
||||||
true
|
(true, 0)
|
||||||
}
|
}
|
||||||
&PatternInst::MatchEqual { ref a, ref b, .. } => {
|
&PatternInst::MatchEqual { ref a, ref b, .. } => {
|
||||||
let a = self.value_by_ref(a, ctx);
|
let a = self.value_by_ref(a, ctx);
|
||||||
let b = self.value_by_ref(b, ctx);
|
let b = self.value_by_ref(b, ctx);
|
||||||
writeln!(code, "{}if {} == {} {{", indent, a, b).unwrap();
|
writeln!(code, "{}if {} == {} {{", indent, a, b).unwrap();
|
||||||
false
|
(false, 1)
|
||||||
}
|
}
|
||||||
&PatternInst::MatchInt {
|
&PatternInst::MatchInt {
|
||||||
ref input,
|
ref input,
|
||||||
@@ -536,13 +641,13 @@ impl<'a> Codegen<'a> {
|
|||||||
let int_val = self.const_int(int_val, ty);
|
let int_val = self.const_int(int_val, ty);
|
||||||
let input = self.value_by_val(input, ctx);
|
let input = self.value_by_val(input, ctx);
|
||||||
writeln!(code, "{}if {} == {} {{", indent, input, int_val).unwrap();
|
writeln!(code, "{}if {} == {} {{", indent, input, int_val).unwrap();
|
||||||
false
|
(false, 1)
|
||||||
}
|
}
|
||||||
&PatternInst::MatchPrim { ref input, val, .. } => {
|
&PatternInst::MatchPrim { ref input, val, .. } => {
|
||||||
let input = self.value_by_val(input, ctx);
|
let input = self.value_by_val(input, ctx);
|
||||||
let sym = &self.typeenv.syms[val.index()];
|
let sym = &self.typeenv.syms[val.index()];
|
||||||
writeln!(code, "{}if {} == {} {{", indent, input, sym).unwrap();
|
writeln!(code, "{}if {} == {} {{", indent, input, sym).unwrap();
|
||||||
false
|
(false, 1)
|
||||||
}
|
}
|
||||||
&PatternInst::MatchVariant {
|
&PatternInst::MatchVariant {
|
||||||
ref input,
|
ref input,
|
||||||
@@ -570,13 +675,14 @@ impl<'a> Codegen<'a> {
|
|||||||
indent, ty_name, variantname, args, input
|
indent, ty_name, variantname, args, input
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
false
|
(false, 1)
|
||||||
}
|
}
|
||||||
&PatternInst::Extract {
|
&PatternInst::Extract {
|
||||||
ref inputs,
|
ref inputs,
|
||||||
ref output_tys,
|
ref output_tys,
|
||||||
term,
|
term,
|
||||||
infallible,
|
infallible,
|
||||||
|
multi,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let termdata = &self.termenv.terms[term.index()];
|
let termdata = &self.termenv.terms[term.index()];
|
||||||
@@ -599,32 +705,61 @@ impl<'a> Codegen<'a> {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if infallible {
|
let bind_pattern = format!(
|
||||||
writeln!(
|
"{open_paren}{vars}{close_paren}",
|
||||||
code,
|
open_paren = if output_binders.len() == 1 { "" } else { "(" },
|
||||||
"{indent}let {open_paren}{vars}{close_paren} = {name}(ctx, {args});",
|
vars = output_binders.join(", "),
|
||||||
indent = indent,
|
close_paren = if output_binders.len() == 1 { "" } else { ")" }
|
||||||
open_paren = if output_binders.len() == 1 { "" } else { "(" },
|
);
|
||||||
vars = output_binders.join(", "),
|
let etor_call = format!(
|
||||||
close_paren = if output_binders.len() == 1 { "" } else { ")" },
|
"{name}(ctx, {args})",
|
||||||
name = sig.full_name,
|
name = sig.full_name,
|
||||||
args = input_values.join(", "),
|
args = input_values.join(", ")
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
true
|
match (infallible, multi) {
|
||||||
} else {
|
(_, true) => {
|
||||||
writeln!(
|
writeln!(
|
||||||
code,
|
code,
|
||||||
"{indent}if let Some({open_paren}{vars}{close_paren}) = {name}(ctx, {args}) {{",
|
"{indent}if let Some(mut iter) = {etor_call} {{",
|
||||||
indent = indent,
|
indent = indent,
|
||||||
open_paren = if output_binders.len() == 1 { "" } else { "(" },
|
etor_call = etor_call,
|
||||||
vars = output_binders.join(", "),
|
)
|
||||||
close_paren = if output_binders.len() == 1 { "" } else { ")" },
|
.unwrap();
|
||||||
name = sig.full_name,
|
writeln!(
|
||||||
args = input_values.join(", "),
|
code,
|
||||||
)
|
"{indent} while let Some({bind_pattern}) = iter.next(ctx) {{",
|
||||||
.unwrap();
|
indent = indent,
|
||||||
false
|
bind_pattern = bind_pattern,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
(false, 2)
|
||||||
|
}
|
||||||
|
(false, false) => {
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
"{indent}if let Some({bind_pattern}) = {etor_call} {{",
|
||||||
|
indent = indent,
|
||||||
|
bind_pattern = bind_pattern,
|
||||||
|
etor_call = etor_call,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
(false, 1)
|
||||||
|
}
|
||||||
|
(true, false) => {
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
"{indent}let {bind_pattern} = {etor_call};",
|
||||||
|
indent = indent,
|
||||||
|
bind_pattern = bind_pattern,
|
||||||
|
etor_call = etor_call,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
(true, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&PatternInst::Expr {
|
&PatternInst::Expr {
|
||||||
@@ -646,7 +781,7 @@ impl<'a> Codegen<'a> {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.define_val(&output, ctx, /* is_ref = */ false, ty);
|
self.define_val(&output, ctx, /* is_ref = */ false, ty);
|
||||||
true
|
(true, 0)
|
||||||
}
|
}
|
||||||
&PatternInst::Expr {
|
&PatternInst::Expr {
|
||||||
ref seq, output_ty, ..
|
ref seq, output_ty, ..
|
||||||
@@ -658,7 +793,15 @@ impl<'a> Codegen<'a> {
|
|||||||
let mut returns = vec![];
|
let mut returns = vec![];
|
||||||
for (id, inst) in seq.insts.iter().enumerate() {
|
for (id, inst) in seq.insts.iter().enumerate() {
|
||||||
let id = InstId(id);
|
let id = InstId(id);
|
||||||
self.generate_expr_inst(code, id, inst, &subindent, &mut subctx, &mut returns);
|
let new_scope = self.generate_expr_inst(
|
||||||
|
code,
|
||||||
|
id,
|
||||||
|
inst,
|
||||||
|
&subindent,
|
||||||
|
&mut subctx,
|
||||||
|
&mut returns,
|
||||||
|
);
|
||||||
|
assert!(!new_scope);
|
||||||
}
|
}
|
||||||
assert_eq!(returns.len(), 1);
|
assert_eq!(returns.len(), 1);
|
||||||
writeln!(code, "{}return Some({});", subindent, returns[0].1).unwrap();
|
writeln!(code, "{}return Some({});", subindent, returns[0].1).unwrap();
|
||||||
@@ -678,7 +821,7 @@ impl<'a> Codegen<'a> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
self.define_val(&output, ctx, /* is_ref = */ false, output_ty);
|
self.define_val(&output, ctx, /* is_ref = */ false, output_ty);
|
||||||
|
|
||||||
false
|
(false, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -690,6 +833,7 @@ impl<'a> Codegen<'a> {
|
|||||||
trie: &TrieNode,
|
trie: &TrieNode,
|
||||||
indent: &str,
|
indent: &str,
|
||||||
ctx: &mut BodyContext,
|
ctx: &mut BodyContext,
|
||||||
|
is_multi: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
log!("generate_body:\n{}", trie.pretty());
|
log!("generate_body:\n{}", trie.pretty());
|
||||||
let mut returned = false;
|
let mut returned = false;
|
||||||
@@ -704,21 +848,37 @@ impl<'a> Codegen<'a> {
|
|||||||
output.pos.pretty_print_line(&self.typeenv.filenames[..])
|
output.pos.pretty_print_line(&self.typeenv.filenames[..])
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// If this is a leaf node, generate the ExprSequence and return.
|
// If this is a leaf node, generate the ExprSequence and return.
|
||||||
let mut returns = vec![];
|
let mut returns = vec![];
|
||||||
|
let mut scopes = 0;
|
||||||
|
let mut indent = indent.to_string();
|
||||||
|
let orig_indent = indent.clone();
|
||||||
for (id, inst) in output.insts.iter().enumerate() {
|
for (id, inst) in output.insts.iter().enumerate() {
|
||||||
let id = InstId(id);
|
let id = InstId(id);
|
||||||
self.generate_expr_inst(code, id, inst, indent, ctx, &mut returns);
|
let new_scope =
|
||||||
|
self.generate_expr_inst(code, id, inst, &indent[..], ctx, &mut returns);
|
||||||
|
if new_scope {
|
||||||
|
scopes += 1;
|
||||||
|
indent.push_str(" ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(returns.len(), 1);
|
assert_eq!(returns.len(), 1);
|
||||||
writeln!(code, "{}return Some({});", indent, returns[0].1).unwrap();
|
if is_multi {
|
||||||
|
writeln!(code, "{}returns.push({});", indent, returns[0].1).unwrap();
|
||||||
|
} else {
|
||||||
|
writeln!(code, "{}return Some({});", indent, returns[0].1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
returned = true;
|
for _ in 0..scopes {
|
||||||
|
writeln!(code, "{}}}", orig_indent).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
returned = !is_multi;
|
||||||
}
|
}
|
||||||
|
|
||||||
&TrieNode::Decision { ref edges } => {
|
&TrieNode::Decision { ref edges } => {
|
||||||
let subindent = format!("{} ", indent);
|
|
||||||
// If this is a decision node, generate each match op
|
// If this is a decision node, generate each match op
|
||||||
// in turn (in priority order). Gather together
|
// in turn (in priority order). Gather together
|
||||||
// adjacent MatchVariant ops with the same input and
|
// adjacent MatchVariant ops with the same input and
|
||||||
@@ -764,7 +924,14 @@ impl<'a> Codegen<'a> {
|
|||||||
// (possibly an empty one). Only use a `match` form if there
|
// (possibly an empty one). Only use a `match` form if there
|
||||||
// are at least two adjacent options.
|
// are at least two adjacent options.
|
||||||
if last - i > 1 {
|
if last - i > 1 {
|
||||||
self.generate_body_matches(code, depth, &edges[i..last], indent, ctx);
|
self.generate_body_matches(
|
||||||
|
code,
|
||||||
|
depth,
|
||||||
|
&edges[i..last],
|
||||||
|
indent,
|
||||||
|
ctx,
|
||||||
|
is_multi,
|
||||||
|
);
|
||||||
i = last;
|
i = last;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
@@ -777,16 +944,32 @@ impl<'a> Codegen<'a> {
|
|||||||
|
|
||||||
match symbol {
|
match symbol {
|
||||||
&TrieSymbol::EndOfMatch => {
|
&TrieSymbol::EndOfMatch => {
|
||||||
returned = self.generate_body(code, depth + 1, node, indent, ctx);
|
returned = self.generate_body(
|
||||||
|
code,
|
||||||
|
depth + 1,
|
||||||
|
node,
|
||||||
|
indent,
|
||||||
|
ctx,
|
||||||
|
is_multi,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
&TrieSymbol::Match { ref op } => {
|
&TrieSymbol::Match { ref op } => {
|
||||||
let id = InstId(depth);
|
let id = InstId(depth);
|
||||||
let infallible =
|
let (infallible, new_scopes) =
|
||||||
self.generate_pattern_inst(code, id, op, indent, ctx);
|
self.generate_pattern_inst(code, id, op, indent, ctx);
|
||||||
let i = if infallible { indent } else { &subindent[..] };
|
let mut subindent = indent.to_string();
|
||||||
let sub_returned =
|
for _ in 0..new_scopes {
|
||||||
self.generate_body(code, depth + 1, node, i, ctx);
|
subindent.push_str(" ");
|
||||||
if !infallible {
|
}
|
||||||
|
let sub_returned = self.generate_body(
|
||||||
|
code,
|
||||||
|
depth + 1,
|
||||||
|
node,
|
||||||
|
&subindent[..],
|
||||||
|
ctx,
|
||||||
|
is_multi,
|
||||||
|
);
|
||||||
|
for _ in 0..new_scopes {
|
||||||
writeln!(code, "{}}}", indent).unwrap();
|
writeln!(code, "{}}}", indent).unwrap();
|
||||||
}
|
}
|
||||||
if infallible && sub_returned {
|
if infallible && sub_returned {
|
||||||
@@ -810,6 +993,7 @@ impl<'a> Codegen<'a> {
|
|||||||
edges: &[TrieEdge],
|
edges: &[TrieEdge],
|
||||||
indent: &str,
|
indent: &str,
|
||||||
ctx: &mut BodyContext,
|
ctx: &mut BodyContext,
|
||||||
|
is_multi: bool,
|
||||||
) {
|
) {
|
||||||
let (input, input_ty) = match &edges[0].symbol {
|
let (input, input_ty) = match &edges[0].symbol {
|
||||||
&TrieSymbol::Match {
|
&TrieSymbol::Match {
|
||||||
@@ -874,12 +1058,12 @@ impl<'a> Codegen<'a> {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let subindent = format!("{} ", indent);
|
let subindent = format!("{} ", indent);
|
||||||
self.generate_body(code, depth + 1, node, &subindent, ctx);
|
self.generate_body(code, depth + 1, node, &subindent, ctx, is_multi);
|
||||||
writeln!(code, "{} }}", indent).unwrap();
|
writeln!(code, "{} }}", indent).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always add a catchall, because we don't do exhaustiveness
|
// Always add a catchall, because we don't do exhaustiveness
|
||||||
// checking on the MatcHVariants.
|
// checking on the MatchVariants.
|
||||||
writeln!(code, "{} _ => {{}}", indent).unwrap();
|
writeln!(code, "{} _ => {{}}", indent).unwrap();
|
||||||
|
|
||||||
writeln!(code, "{}}}", indent).unwrap();
|
writeln!(code, "{}}}", indent).unwrap();
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ pub enum PatternInst {
|
|||||||
output_tys: Vec<TypeId>,
|
output_tys: Vec<TypeId>,
|
||||||
/// This extractor's term.
|
/// This extractor's term.
|
||||||
term: TermId,
|
term: TermId,
|
||||||
|
/// Is this a multi-extractor?
|
||||||
|
multi: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
// NB: This has to go last, since it is infallible, so that when we sort
|
// NB: This has to go last, since it is infallible, so that when we sort
|
||||||
@@ -162,6 +164,8 @@ pub enum ExprInst {
|
|||||||
term: TermId,
|
term: TermId,
|
||||||
/// Whether this constructor is infallible or not.
|
/// Whether this constructor is infallible or not.
|
||||||
infallible: bool,
|
infallible: bool,
|
||||||
|
/// Is this a multi-constructor?
|
||||||
|
multi: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Set the Nth return value. Produces no values.
|
/// Set the Nth return value. Produces no values.
|
||||||
@@ -305,6 +309,7 @@ impl PatternSequence {
|
|||||||
output_tys: Vec<TypeId>,
|
output_tys: Vec<TypeId>,
|
||||||
term: TermId,
|
term: TermId,
|
||||||
infallible: bool,
|
infallible: bool,
|
||||||
|
multi: bool,
|
||||||
) -> Vec<Value> {
|
) -> Vec<Value> {
|
||||||
let inst = InstId(self.insts.len());
|
let inst = InstId(self.insts.len());
|
||||||
let mut outs = vec![];
|
let mut outs = vec![];
|
||||||
@@ -319,6 +324,7 @@ impl PatternSequence {
|
|||||||
output_tys,
|
output_tys,
|
||||||
term,
|
term,
|
||||||
infallible,
|
infallible,
|
||||||
|
multi,
|
||||||
});
|
});
|
||||||
outs
|
outs
|
||||||
}
|
}
|
||||||
@@ -429,10 +435,11 @@ impl PatternSequence {
|
|||||||
panic!("Should have been expanded away")
|
panic!("Should have been expanded away")
|
||||||
}
|
}
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
extractor_kind:
|
extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
|
||||||
Some(ExtractorKind::ExternalExtractor { infallible, .. }),
|
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
let ext_sig = termdata.extractor_sig(typeenv).unwrap();
|
||||||
|
|
||||||
// Evaluate all `input` args.
|
// Evaluate all `input` args.
|
||||||
let mut inputs = vec![];
|
let mut inputs = vec![];
|
||||||
let mut input_tys = vec![];
|
let mut input_tys = vec![];
|
||||||
@@ -451,7 +458,8 @@ impl PatternSequence {
|
|||||||
input_tys,
|
input_tys,
|
||||||
output_tys,
|
output_tys,
|
||||||
term,
|
term,
|
||||||
*infallible,
|
ext_sig.infallible,
|
||||||
|
ext_sig.multi,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (pat, &val) in output_pats.iter().zip(arg_values.iter()) {
|
for (pat, &val) in output_pats.iter().zip(arg_values.iter()) {
|
||||||
@@ -521,6 +529,7 @@ impl ExprSequence {
|
|||||||
ty: TypeId,
|
ty: TypeId,
|
||||||
term: TermId,
|
term: TermId,
|
||||||
infallible: bool,
|
infallible: bool,
|
||||||
|
multi: bool,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
let inst = InstId(self.insts.len());
|
let inst = InstId(self.insts.len());
|
||||||
let inputs = inputs.iter().cloned().collect();
|
let inputs = inputs.iter().cloned().collect();
|
||||||
@@ -529,6 +538,7 @@ impl ExprSequence {
|
|||||||
ty,
|
ty,
|
||||||
term,
|
term,
|
||||||
infallible,
|
infallible,
|
||||||
|
multi,
|
||||||
});
|
});
|
||||||
Value::Expr { inst, output: 0 }
|
Value::Expr { inst, output: 0 }
|
||||||
}
|
}
|
||||||
@@ -581,6 +591,7 @@ impl ExprSequence {
|
|||||||
}
|
}
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
constructor_kind: Some(ConstructorKind::InternalConstructor),
|
constructor_kind: Some(ConstructorKind::InternalConstructor),
|
||||||
|
multi,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.add_construct(
|
self.add_construct(
|
||||||
@@ -588,11 +599,13 @@ impl ExprSequence {
|
|||||||
ty,
|
ty,
|
||||||
term,
|
term,
|
||||||
/* infallible = */ false,
|
/* infallible = */ false,
|
||||||
|
*multi,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }),
|
constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }),
|
||||||
pure,
|
pure,
|
||||||
|
multi,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.add_construct(
|
self.add_construct(
|
||||||
@@ -600,6 +613,7 @@ impl ExprSequence {
|
|||||||
ty,
|
ty,
|
||||||
term,
|
term,
|
||||||
/* infallible = */ !pure,
|
/* infallible = */ !pure,
|
||||||
|
*multi,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
|
|||||||
@@ -290,6 +290,12 @@ impl<'a> Parser<'a> {
|
|||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
let multi = if self.is_sym_str("multi") {
|
||||||
|
self.symbol()?;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
let term = self.parse_ident()?;
|
let term = self.parse_ident()?;
|
||||||
|
|
||||||
@@ -307,6 +313,7 @@ impl<'a> Parser<'a> {
|
|||||||
arg_tys,
|
arg_tys,
|
||||||
ret_ty,
|
ret_ty,
|
||||||
pure,
|
pure,
|
||||||
|
multi,
|
||||||
pos,
|
pos,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,6 +236,8 @@ pub enum TermKind {
|
|||||||
Decl {
|
Decl {
|
||||||
/// Whether the term is marked as `pure`.
|
/// Whether the term is marked as `pure`.
|
||||||
pure: bool,
|
pure: bool,
|
||||||
|
/// Whether the term is marked as `multi`.
|
||||||
|
multi: bool,
|
||||||
/// The kind of this term's constructor, if any.
|
/// The kind of this term's constructor, if any.
|
||||||
constructor_kind: Option<ConstructorKind>,
|
constructor_kind: Option<ConstructorKind>,
|
||||||
/// The kind of this term's extractor, if any.
|
/// The kind of this term's extractor, if any.
|
||||||
@@ -290,6 +292,9 @@ pub struct ExternalSig {
|
|||||||
pub ret_tys: Vec<TypeId>,
|
pub ret_tys: Vec<TypeId>,
|
||||||
/// Whether this signature is infallible or not.
|
/// Whether this signature is infallible or not.
|
||||||
pub infallible: bool,
|
pub infallible: bool,
|
||||||
|
/// "Multiplicity": does the function return multiple values (via
|
||||||
|
/// an iterator)?
|
||||||
|
pub multi: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Term {
|
impl Term {
|
||||||
@@ -353,6 +358,7 @@ impl Term {
|
|||||||
pub fn extractor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
|
pub fn extractor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
|
multi,
|
||||||
extractor_kind:
|
extractor_kind:
|
||||||
Some(ExtractorKind::ExternalExtractor {
|
Some(ExtractorKind::ExternalExtractor {
|
||||||
name, infallible, ..
|
name, infallible, ..
|
||||||
@@ -363,7 +369,8 @@ impl Term {
|
|||||||
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
||||||
param_tys: vec![self.ret_ty],
|
param_tys: vec![self.ret_ty],
|
||||||
ret_tys: self.arg_tys.clone(),
|
ret_tys: self.arg_tys.clone(),
|
||||||
infallible: *infallible,
|
infallible: *infallible && !*multi,
|
||||||
|
multi: *multi,
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@@ -374,6 +381,7 @@ impl Term {
|
|||||||
match &self.kind {
|
match &self.kind {
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
constructor_kind: Some(ConstructorKind::ExternalConstructor { name }),
|
constructor_kind: Some(ConstructorKind::ExternalConstructor { name }),
|
||||||
|
multi,
|
||||||
pure,
|
pure,
|
||||||
..
|
..
|
||||||
} => Some(ExternalSig {
|
} => Some(ExternalSig {
|
||||||
@@ -381,10 +389,12 @@ impl Term {
|
|||||||
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
||||||
param_tys: self.arg_tys.clone(),
|
param_tys: self.arg_tys.clone(),
|
||||||
ret_tys: vec![self.ret_ty],
|
ret_tys: vec![self.ret_ty],
|
||||||
infallible: !pure,
|
infallible: !pure && !*multi,
|
||||||
|
multi: *multi,
|
||||||
}),
|
}),
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
constructor_kind: Some(ConstructorKind::InternalConstructor { .. }),
|
constructor_kind: Some(ConstructorKind::InternalConstructor { .. }),
|
||||||
|
multi,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let name = format!("constructor_{}", tyenv.syms[self.name.index()]);
|
let name = format!("constructor_{}", tyenv.syms[self.name.index()]);
|
||||||
@@ -398,6 +408,7 @@ impl Term {
|
|||||||
// matching at the toplevel (an entry point can
|
// matching at the toplevel (an entry point can
|
||||||
// fail to rewrite).
|
// fail to rewrite).
|
||||||
infallible: false,
|
infallible: false,
|
||||||
|
multi: *multi,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -854,6 +865,7 @@ impl TermEnv {
|
|||||||
constructor_kind: None,
|
constructor_kind: None,
|
||||||
extractor_kind: None,
|
extractor_kind: None,
|
||||||
pure: decl.pure,
|
pure: decl.pure,
|
||||||
|
multi: decl.multi,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1014,8 +1026,18 @@ impl TermEnv {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TermKind::Decl { extractor_kind, .. } => match extractor_kind {
|
TermKind::Decl {
|
||||||
|
multi,
|
||||||
|
extractor_kind,
|
||||||
|
..
|
||||||
|
} => match extractor_kind {
|
||||||
None => {
|
None => {
|
||||||
|
if *multi {
|
||||||
|
tyenv.report_error(
|
||||||
|
ext.pos,
|
||||||
|
"A term declared with `multi` cannot have an internal extractor.".to_string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
*extractor_kind = Some(ExtractorKind::InternalExtractor { template });
|
*extractor_kind = Some(ExtractorKind::InternalExtractor { template });
|
||||||
}
|
}
|
||||||
Some(ext_kind) => {
|
Some(ext_kind) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user