committed by
Chris Fallin
parent
fddff6ee2d
commit
7f8cb75e54
@@ -117,8 +117,12 @@ impl<'a> Codegen<'a> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
writeln!(code, "pub trait Context {{").unwrap();
|
writeln!(code, "pub trait Context {{").unwrap();
|
||||||
for term in &self.termenv.terms {
|
for term in &self.termenv.terms {
|
||||||
if term.is_external() {
|
if term.has_external_extractor() {
|
||||||
let ext_sig = term.to_sig(self.typeenv).unwrap();
|
let ext_sig = term.extractor_sig(self.typeenv).unwrap();
|
||||||
|
self.generate_trait_sig(code, " ", &ext_sig);
|
||||||
|
}
|
||||||
|
if term.has_external_constructor() {
|
||||||
|
let ext_sig = term.constructor_sig(self.typeenv).unwrap();
|
||||||
self.generate_trait_sig(code, " ", &ext_sig);
|
self.generate_trait_sig(code, " ", &ext_sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,11 +245,11 @@ impl<'a> Codegen<'a> {
|
|||||||
|
|
||||||
// Skip terms that are enum variants or that have external
|
// Skip terms that are enum variants or that have external
|
||||||
// constructors/extractors.
|
// constructors/extractors.
|
||||||
if !termdata.is_constructor() || termdata.is_external() {
|
if !termdata.has_constructor() || termdata.has_external_constructor() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sig = termdata.to_sig(self.typeenv).unwrap();
|
let sig = termdata.constructor_sig(self.typeenv).unwrap();
|
||||||
|
|
||||||
let args = sig
|
let args = sig
|
||||||
.param_tys
|
.param_tys
|
||||||
@@ -393,7 +397,7 @@ impl<'a> Codegen<'a> {
|
|||||||
};
|
};
|
||||||
let outputname = self.value_name(&output);
|
let outputname = self.value_name(&output);
|
||||||
let termdata = &self.termenv.terms[term.index()];
|
let termdata = &self.termenv.terms[term.index()];
|
||||||
let sig = termdata.to_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 { "?" };
|
let fallible_try = if infallible { "" } else { "?" };
|
||||||
writeln!(
|
writeln!(
|
||||||
@@ -529,7 +533,7 @@ impl<'a> Codegen<'a> {
|
|||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let termdata = &self.termenv.terms[term.index()];
|
let termdata = &self.termenv.terms[term.index()];
|
||||||
let sig = termdata.to_sig(self.typeenv).unwrap();
|
let sig = termdata.extractor_sig(self.typeenv).unwrap();
|
||||||
|
|
||||||
let input_values = inputs
|
let input_values = inputs
|
||||||
.iter()
|
.iter()
|
||||||
@@ -671,7 +675,9 @@ impl<'a> Codegen<'a> {
|
|||||||
// variants in order to create a `match` rather than a
|
// variants in order to create a `match` rather than a
|
||||||
// chain of if-lets.
|
// chain of if-lets.
|
||||||
let mut edges = edges.clone();
|
let mut edges = edges.clone();
|
||||||
edges.sort_by(|e1, e2| (-e1.range.min, &e1.symbol).cmp(&(-e2.range.min, &e2.symbol)));
|
edges.sort_by(|e1, e2| {
|
||||||
|
(-e1.range.min, &e1.symbol).cmp(&(-e2.range.min, &e2.symbol))
|
||||||
|
});
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < edges.len() {
|
while i < edges.len() {
|
||||||
|
|||||||
@@ -400,12 +400,9 @@ impl PatternSequence {
|
|||||||
let termdata = &termenv.terms[term.index()];
|
let termdata = &termenv.terms[term.index()];
|
||||||
let arg_tys = &termdata.arg_tys[..];
|
let arg_tys = &termdata.arg_tys[..];
|
||||||
match &termdata.kind {
|
match &termdata.kind {
|
||||||
&TermKind::Declared => {
|
TermKind::EnumVariant { variant } => {
|
||||||
panic!("Pattern invocation of undefined term body");
|
|
||||||
}
|
|
||||||
&TermKind::EnumVariant { variant } => {
|
|
||||||
let arg_values =
|
let arg_values =
|
||||||
self.add_match_variant(input, ty, arg_tys, variant);
|
self.add_match_variant(input, ty, arg_tys, *variant);
|
||||||
for (subpat, value) in args.iter().zip(arg_values.into_iter()) {
|
for (subpat, value) in args.iter().zip(arg_values.into_iter()) {
|
||||||
let subpat = match subpat {
|
let subpat = match subpat {
|
||||||
&TermArgPattern::Pattern(ref pat) => pat,
|
&TermArgPattern::Pattern(ref pat) => pat,
|
||||||
@@ -420,16 +417,25 @@ impl PatternSequence {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&TermKind::InternalConstructor
|
TermKind::Decl {
|
||||||
| &TermKind::ExternalConstructor { .. } => {
|
extractor_kind: None,
|
||||||
panic!("Should not invoke constructor in pattern");
|
..
|
||||||
|
} => {
|
||||||
|
panic!("Pattern invocation of undefined term body")
|
||||||
}
|
}
|
||||||
&TermKind::InternalExtractor { .. } => {
|
TermKind::Decl {
|
||||||
panic!("Should have been expanded away");
|
extractor_kind: Some(ExtractorKind::InternalExtractor { .. }),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
panic!("Should have been expanded away")
|
||||||
}
|
}
|
||||||
&TermKind::ExternalExtractor {
|
TermKind::Decl {
|
||||||
ref arg_polarity,
|
extractor_kind:
|
||||||
infallible,
|
Some(ExtractorKind::ExternalExtractor {
|
||||||
|
ref arg_polarity,
|
||||||
|
infallible,
|
||||||
|
..
|
||||||
|
}),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// Evaluate all `input` args.
|
// Evaluate all `input` args.
|
||||||
@@ -469,8 +475,13 @@ impl PatternSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the extractor.
|
// Invoke the extractor.
|
||||||
let arg_values = self
|
let arg_values = self.add_extract(
|
||||||
.add_extract(inputs, input_tys, output_tys, term, infallible);
|
inputs,
|
||||||
|
input_tys,
|
||||||
|
output_tys,
|
||||||
|
term,
|
||||||
|
*infallible,
|
||||||
|
);
|
||||||
|
|
||||||
for (pat, &val) in output_pats.iter().zip(arg_values.iter()) {
|
for (pat, &val) in output_pats.iter().zip(arg_values.iter()) {
|
||||||
self.gen_pattern(
|
self.gen_pattern(
|
||||||
@@ -594,10 +605,13 @@ impl ExprSequence {
|
|||||||
.push((self.gen_expr(typeenv, termenv, &*arg_expr, &vars), arg_ty));
|
.push((self.gen_expr(typeenv, termenv, &*arg_expr, &vars), arg_ty));
|
||||||
}
|
}
|
||||||
match &termdata.kind {
|
match &termdata.kind {
|
||||||
&TermKind::EnumVariant { variant } => {
|
TermKind::EnumVariant { variant } => {
|
||||||
self.add_create_variant(&arg_values_tys[..], ty, variant)
|
self.add_create_variant(&arg_values_tys[..], ty, *variant)
|
||||||
}
|
}
|
||||||
&TermKind::InternalConstructor => {
|
TermKind::Decl {
|
||||||
|
constructor_kind: Some(ConstructorKind::InternalConstructor),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
self.add_construct(
|
self.add_construct(
|
||||||
&arg_values_tys[..],
|
&arg_values_tys[..],
|
||||||
ty,
|
ty,
|
||||||
@@ -605,7 +619,10 @@ impl ExprSequence {
|
|||||||
/* infallible = */ false,
|
/* infallible = */ false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
&TermKind::ExternalConstructor { .. } => {
|
TermKind::Decl {
|
||||||
|
constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
self.add_construct(
|
self.add_construct(
|
||||||
&arg_values_tys[..],
|
&arg_values_tys[..],
|
||||||
ty,
|
ty,
|
||||||
@@ -613,7 +630,10 @@ impl ExprSequence {
|
|||||||
/* infallible = */ true,
|
/* infallible = */ true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
otherwise => panic!("Should have been caught by typechecking: {:?}", otherwise),
|
TermKind::Decl {
|
||||||
|
constructor_kind: None,
|
||||||
|
..
|
||||||
|
} => panic!("Should have been caught by typechecking"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,9 +210,31 @@ pub enum TermKind {
|
|||||||
/// `(A.A1 ...)` then the variant ID corresponds to `A1`.
|
/// `(A.A1 ...)` then the variant ID corresponds to `A1`.
|
||||||
variant: VariantId,
|
variant: VariantId,
|
||||||
},
|
},
|
||||||
|
/// A term declared via a `(decl ...)` form.
|
||||||
|
Decl {
|
||||||
|
/// The kind of this term's constructor, if any.
|
||||||
|
constructor_kind: Option<ConstructorKind>,
|
||||||
|
/// The kind of this term's extractor, if any.
|
||||||
|
extractor_kind: Option<ExtractorKind>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of a constructor for a term.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ConstructorKind {
|
||||||
/// A term with "internal" rules that work in the forward direction. Becomes
|
/// A term with "internal" rules that work in the forward direction. Becomes
|
||||||
/// a compiled Rust function in the generated code.
|
/// a compiled Rust function in the generated code.
|
||||||
InternalConstructor,
|
InternalConstructor,
|
||||||
|
/// A term defined solely by an external constructor function.
|
||||||
|
ExternalConstructor {
|
||||||
|
/// The external name of the constructor function.
|
||||||
|
name: Sym,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of an extractor for a term.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ExtractorKind {
|
||||||
/// A term that defines an "extractor macro" in the LHS of a pattern. Its
|
/// A term that defines an "extractor macro" in the LHS of a pattern. Its
|
||||||
/// arguments take patterns and are simply substituted with the given
|
/// arguments take patterns and are simply substituted with the given
|
||||||
/// patterns when used.
|
/// patterns when used.
|
||||||
@@ -228,14 +250,9 @@ pub enum TermKind {
|
|||||||
arg_polarity: Vec<ArgPolarity>,
|
arg_polarity: Vec<ArgPolarity>,
|
||||||
/// Is the external extractor infallible?
|
/// Is the external extractor infallible?
|
||||||
infallible: bool,
|
infallible: bool,
|
||||||
|
/// The position where this external extractor was declared.
|
||||||
|
pos: Pos,
|
||||||
},
|
},
|
||||||
/// A term defined solely by an external constructor function.
|
|
||||||
ExternalConstructor {
|
|
||||||
/// The external name of the constructor function.
|
|
||||||
name: Sym,
|
|
||||||
},
|
|
||||||
/// Declared but no body or externs associated (yet).
|
|
||||||
Declared,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::ast::ArgPolarity;
|
pub use crate::ast::ArgPolarity;
|
||||||
@@ -261,40 +278,69 @@ impl Term {
|
|||||||
self.ret_ty
|
self.ret_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this term a constructor?
|
/// Is this term an enum variant?
|
||||||
pub fn is_constructor(&self) -> bool {
|
pub fn is_enum_variant(&self) -> bool {
|
||||||
match &self.kind {
|
matches!(self.kind, TermKind::EnumVariant { .. })
|
||||||
&TermKind::InternalConstructor { .. } | &TermKind::ExternalConstructor { .. } => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_declared(&self) -> bool {
|
/// Does this term have a constructor?
|
||||||
matches!(self.kind, TermKind::Declared)
|
pub fn has_constructor(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self.kind,
|
||||||
|
TermKind::EnumVariant { .. }
|
||||||
|
| TermKind::Decl {
|
||||||
|
constructor_kind: Some(_),
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this term external?
|
/// Does this term have an extractor?
|
||||||
pub fn is_external(&self) -> bool {
|
pub fn has_extractor(&self) -> bool {
|
||||||
match &self.kind {
|
matches!(
|
||||||
&TermKind::ExternalExtractor { .. } | &TermKind::ExternalConstructor { .. } => true,
|
self.kind,
|
||||||
_ => false,
|
TermKind::EnumVariant { .. }
|
||||||
}
|
| TermKind::Decl {
|
||||||
|
extractor_kind: Some(_),
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get this term's external function signature, if any.
|
/// Is this term's extractor external?
|
||||||
pub fn to_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
|
pub fn has_external_extractor(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self.kind,
|
||||||
|
TermKind::Decl {
|
||||||
|
extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this term's constructor external?
|
||||||
|
pub fn has_external_constructor(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self.kind,
|
||||||
|
TermKind::Decl {
|
||||||
|
constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }),
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get this term's extractor's external function signature, if any.
|
||||||
|
pub fn extractor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
&TermKind::ExternalConstructor { name } => Some(ExternalSig {
|
TermKind::Decl {
|
||||||
func_name: tyenv.syms[name.index()].clone(),
|
extractor_kind:
|
||||||
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
Some(ExtractorKind::ExternalExtractor {
|
||||||
param_tys: self.arg_tys.clone(),
|
name,
|
||||||
ret_tys: vec![self.ret_ty],
|
ref arg_polarity,
|
||||||
infallible: true,
|
infallible,
|
||||||
}),
|
..
|
||||||
&TermKind::ExternalExtractor {
|
}),
|
||||||
name,
|
..
|
||||||
ref arg_polarity,
|
|
||||||
infallible,
|
|
||||||
} => {
|
} => {
|
||||||
let mut arg_tys = vec![];
|
let mut arg_tys = vec![];
|
||||||
let mut ret_tys = vec![];
|
let mut ret_tys = vec![];
|
||||||
@@ -314,10 +360,30 @@ impl Term {
|
|||||||
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
||||||
param_tys: arg_tys,
|
param_tys: arg_tys,
|
||||||
ret_tys,
|
ret_tys,
|
||||||
infallible,
|
infallible: *infallible,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
&TermKind::InternalConstructor { .. } => {
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get this term's constructor's external function signature, if any.
|
||||||
|
pub fn constructor_sig(&self, tyenv: &TypeEnv) -> Option<ExternalSig> {
|
||||||
|
match &self.kind {
|
||||||
|
TermKind::Decl {
|
||||||
|
constructor_kind: Some(ConstructorKind::ExternalConstructor { name }),
|
||||||
|
..
|
||||||
|
} => Some(ExternalSig {
|
||||||
|
func_name: tyenv.syms[name.index()].clone(),
|
||||||
|
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
||||||
|
param_tys: self.arg_tys.clone(),
|
||||||
|
ret_tys: vec![self.ret_ty],
|
||||||
|
infallible: true,
|
||||||
|
}),
|
||||||
|
TermKind::Decl {
|
||||||
|
constructor_kind: Some(ConstructorKind::InternalConstructor { .. }),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let name = format!("constructor_{}", tyenv.syms[self.name.index()]);
|
let name = format!("constructor_{}", tyenv.syms[self.name.index()]);
|
||||||
Some(ExternalSig {
|
Some(ExternalSig {
|
||||||
func_name: name.clone(),
|
func_name: name.clone(),
|
||||||
@@ -740,7 +806,10 @@ impl TermEnv {
|
|||||||
name,
|
name,
|
||||||
arg_tys,
|
arg_tys,
|
||||||
ret_ty,
|
ret_ty,
|
||||||
kind: TermKind::Declared,
|
kind: TermKind::Decl {
|
||||||
|
constructor_kind: None,
|
||||||
|
extractor_kind: None,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -813,15 +882,35 @@ impl TermEnv {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let termdata = &mut self.terms[term.index()];
|
let termdata = &mut self.terms[term.index()];
|
||||||
match &termdata.kind {
|
match &mut termdata.kind {
|
||||||
&TermKind::Declared => {
|
TermKind::Decl {
|
||||||
termdata.kind = TermKind::InternalConstructor;
|
constructor_kind, ..
|
||||||
|
} => {
|
||||||
|
match constructor_kind {
|
||||||
|
None => {
|
||||||
|
*constructor_kind = Some(ConstructorKind::InternalConstructor);
|
||||||
|
}
|
||||||
|
Some(ConstructorKind::InternalConstructor) => {
|
||||||
|
// OK, no error; multiple rules can apply to
|
||||||
|
// one internal constructor term.
|
||||||
|
}
|
||||||
|
Some(ConstructorKind::ExternalConstructor { .. }) => {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
"Rule LHS root term is incorrect kind; cannot \
|
||||||
|
be external constructor"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&TermKind::InternalConstructor => {
|
TermKind::EnumVariant { .. } => {
|
||||||
// OK, no error; multiple rules can apply to one internal constructor term.
|
tyenv.report_error(
|
||||||
}
|
pos,
|
||||||
_ => {
|
"Rule LHS root term is incorrect kind; cannot be enum variant"
|
||||||
tyenv.report_error(pos, "Rule LHS root term is incorrect kind; cannot be internal constructor".to_string());
|
.to_string(),
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -870,17 +959,36 @@ impl TermEnv {
|
|||||||
extractor_call_graph.insert(sym, callees);
|
extractor_call_graph.insert(sym, callees);
|
||||||
|
|
||||||
let termdata = &mut self.terms[term.index()];
|
let termdata = &mut self.terms[term.index()];
|
||||||
match &termdata.kind {
|
match &mut termdata.kind {
|
||||||
&TermKind::Declared => {
|
TermKind::EnumVariant { .. } => {
|
||||||
termdata.kind = TermKind::InternalExtractor { template };
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
tyenv.report_error(
|
tyenv.report_error(
|
||||||
ext.pos,
|
ext.pos,
|
||||||
"Extractor macro body defined on term of incorrect kind".to_string(),
|
"Extractor macro body defined on term of incorrect kind; cannot be an \
|
||||||
|
enum variant"
|
||||||
|
.into(),
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
TermKind::Decl { extractor_kind, .. } => match extractor_kind {
|
||||||
|
None => {
|
||||||
|
*extractor_kind = Some(ExtractorKind::InternalExtractor { template });
|
||||||
|
}
|
||||||
|
Some(ext_kind) => {
|
||||||
|
tyenv.report_error(
|
||||||
|
ext.pos,
|
||||||
|
"Duplicate extractor definition".to_string(),
|
||||||
|
);
|
||||||
|
let pos = match ext_kind {
|
||||||
|
ExtractorKind::InternalExtractor { template } => template.pos(),
|
||||||
|
ExtractorKind::ExternalExtractor { pos, .. } => *pos,
|
||||||
|
};
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
"Extractor was already defined here".to_string(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -914,8 +1022,16 @@ impl TermEnv {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let pos = match &self.terms[term.index()].kind {
|
let pos = match &self.terms[term.index()].kind {
|
||||||
TermKind::InternalExtractor { template } => template.pos(),
|
TermKind::Decl {
|
||||||
_ => unreachable!(),
|
extractor_kind: Some(ExtractorKind::InternalExtractor { template }),
|
||||||
|
..
|
||||||
|
} => template.pos(),
|
||||||
|
_ => {
|
||||||
|
// Again, there must have already been errors
|
||||||
|
// recorded.
|
||||||
|
assert!(!tyenv.errors.is_empty());
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let path: Vec<_> = path
|
let path: Vec<_> = path
|
||||||
@@ -944,11 +1060,37 @@ impl TermEnv {
|
|||||||
vars: vec![],
|
vars: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let rule_term = match rule.pattern.root_term() {
|
||||||
|
Some(name) => {
|
||||||
|
let sym = tyenv.intern_mut(name);
|
||||||
|
match self.term_map.get(&sym) {
|
||||||
|
Some(term) => *term,
|
||||||
|
None => {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
"Cannot define a rule for an unknown term".to_string(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
"Rule does not have a term at the root of its left-hand side"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (lhs, ty) = unwrap_or_continue!(self.translate_pattern(
|
let (lhs, ty) = unwrap_or_continue!(self.translate_pattern(
|
||||||
tyenv,
|
tyenv,
|
||||||
|
rule_term,
|
||||||
&rule.pattern,
|
&rule.pattern,
|
||||||
None,
|
None,
|
||||||
&mut bindings
|
&mut bindings,
|
||||||
|
/* is_root = */ true,
|
||||||
));
|
));
|
||||||
let rhs = unwrap_or_continue!(self.translate_expr(
|
let rhs = unwrap_or_continue!(self.translate_expr(
|
||||||
tyenv,
|
tyenv,
|
||||||
@@ -984,15 +1126,35 @@ impl TermEnv {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let termdata = &mut self.terms[term_id.index()];
|
let termdata = &mut self.terms[term_id.index()];
|
||||||
match &termdata.kind {
|
match &mut termdata.kind {
|
||||||
&TermKind::Declared => {
|
TermKind::Decl {
|
||||||
termdata.kind = TermKind::ExternalConstructor { name: func_sym };
|
constructor_kind, ..
|
||||||
}
|
} => match constructor_kind {
|
||||||
_ => {
|
None => {
|
||||||
|
*constructor_kind =
|
||||||
|
Some(ConstructorKind::ExternalConstructor { name: func_sym });
|
||||||
|
}
|
||||||
|
Some(ConstructorKind::InternalConstructor) => {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
format!(
|
||||||
|
"External constructor declared on term that already has rules: {}",
|
||||||
|
term.0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Some(ConstructorKind::ExternalConstructor { .. }) => {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
"Duplicate external constructor definition".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TermKind::EnumVariant { .. } => {
|
||||||
tyenv.report_error(
|
tyenv.report_error(
|
||||||
pos,
|
pos,
|
||||||
format!(
|
format!(
|
||||||
"Constructor defined on term of improper type '{}'",
|
"External constructor cannot be defined on enum variant: {}",
|
||||||
term.0,
|
term.0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -1031,18 +1193,45 @@ impl TermEnv {
|
|||||||
vec![ArgPolarity::Output; termdata.arg_tys.len()]
|
vec![ArgPolarity::Output; termdata.arg_tys.len()]
|
||||||
};
|
};
|
||||||
|
|
||||||
match &termdata.kind {
|
match &mut termdata.kind {
|
||||||
&TermKind::Declared => {
|
TermKind::Decl { extractor_kind, .. } => match extractor_kind {
|
||||||
termdata.kind = TermKind::ExternalExtractor {
|
None => {
|
||||||
name: func_sym,
|
*extractor_kind = Some(ExtractorKind::ExternalExtractor {
|
||||||
arg_polarity,
|
name: func_sym,
|
||||||
infallible,
|
arg_polarity,
|
||||||
};
|
infallible,
|
||||||
}
|
pos,
|
||||||
_ => {
|
});
|
||||||
|
}
|
||||||
|
Some(ExtractorKind::ExternalExtractor { pos: pos2, .. }) => {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
"Duplicate external extractor definition".to_string(),
|
||||||
|
);
|
||||||
|
tyenv.report_error(
|
||||||
|
*pos2,
|
||||||
|
"External extractor already defined".to_string(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Some(ExtractorKind::InternalExtractor { template }) => {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
"Cannot define external extractor for term that already has an \
|
||||||
|
internal extractor macro body defined"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
tyenv.report_error(
|
||||||
|
template.pos(),
|
||||||
|
"Internal extractor macro body already defined".to_string(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TermKind::EnumVariant { .. } => {
|
||||||
tyenv.report_error(
|
tyenv.report_error(
|
||||||
pos,
|
pos,
|
||||||
format!("Extractor defined on term of improper type '{}'", term.0),
|
format!("Cannot define extractor for enum variant '{}'", term.0),
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1058,7 +1247,8 @@ impl TermEnv {
|
|||||||
if let ast::Def::Decl(decl) = def {
|
if let ast::Def::Decl(decl) = def {
|
||||||
let sym = tyenv.intern_mut(&decl.term);
|
let sym = tyenv.intern_mut(&decl.term);
|
||||||
let term = self.term_map[&sym];
|
let term = self.term_map[&sym];
|
||||||
if self.terms[term.index()].is_declared() {
|
let term = &self.terms[term.index()];
|
||||||
|
if !term.has_constructor() && !term.has_extractor() {
|
||||||
tyenv.report_error(
|
tyenv.report_error(
|
||||||
decl.pos,
|
decl.pos,
|
||||||
format!(
|
format!(
|
||||||
@@ -1074,9 +1264,11 @@ impl TermEnv {
|
|||||||
fn translate_pattern(
|
fn translate_pattern(
|
||||||
&self,
|
&self,
|
||||||
tyenv: &mut TypeEnv,
|
tyenv: &mut TypeEnv,
|
||||||
|
rule_term: TermId,
|
||||||
pat: &ast::Pattern,
|
pat: &ast::Pattern,
|
||||||
expected_ty: Option<TypeId>,
|
expected_ty: Option<TypeId>,
|
||||||
bindings: &mut Bindings,
|
bindings: &mut Bindings,
|
||||||
|
is_root: bool,
|
||||||
) -> Option<(Pattern, TypeId)> {
|
) -> Option<(Pattern, TypeId)> {
|
||||||
log::trace!("translate_pattern: {:?}", pat);
|
log::trace!("translate_pattern: {:?}", pat);
|
||||||
log::trace!("translate_pattern: bindings = {:?}", bindings);
|
log::trace!("translate_pattern: bindings = {:?}", bindings);
|
||||||
@@ -1135,9 +1327,11 @@ impl TermEnv {
|
|||||||
for subpat in subpats {
|
for subpat in subpats {
|
||||||
let (subpat, ty) = unwrap_or_continue!(self.translate_pattern(
|
let (subpat, ty) = unwrap_or_continue!(self.translate_pattern(
|
||||||
tyenv,
|
tyenv,
|
||||||
|
rule_term,
|
||||||
&*subpat,
|
&*subpat,
|
||||||
expected_ty,
|
expected_ty,
|
||||||
bindings
|
bindings,
|
||||||
|
/* is_root = */ false,
|
||||||
));
|
));
|
||||||
expected_ty = expected_ty.or(Some(ty));
|
expected_ty = expected_ty.or(Some(ty));
|
||||||
children.push(subpat);
|
children.push(subpat);
|
||||||
@@ -1155,8 +1349,14 @@ impl TermEnv {
|
|||||||
pos,
|
pos,
|
||||||
} => {
|
} => {
|
||||||
// Do the subpattern first so we can resolve the type for sure.
|
// Do the subpattern first so we can resolve the type for sure.
|
||||||
let (subpat, ty) =
|
let (subpat, ty) = self.translate_pattern(
|
||||||
self.translate_pattern(tyenv, &*subpat, expected_ty, bindings)?;
|
tyenv,
|
||||||
|
rule_term,
|
||||||
|
&*subpat,
|
||||||
|
expected_ty,
|
||||||
|
bindings,
|
||||||
|
/* is_root = */ false,
|
||||||
|
)?;
|
||||||
|
|
||||||
let name = tyenv.intern_mut(var);
|
let name = tyenv.intern_mut(var);
|
||||||
if bindings.vars.iter().any(|bv| bv.name == name) {
|
if bindings.vars.iter().any(|bv| bv.name == name) {
|
||||||
@@ -1254,15 +1454,43 @@ impl TermEnv {
|
|||||||
let termdata = &self.terms[tid.index()];
|
let termdata = &self.terms[tid.index()];
|
||||||
|
|
||||||
match &termdata.kind {
|
match &termdata.kind {
|
||||||
&TermKind::EnumVariant { .. } => {
|
TermKind::Decl {
|
||||||
|
constructor_kind: Some(ConstructorKind::InternalConstructor),
|
||||||
|
..
|
||||||
|
} if is_root && *tid == rule_term => {
|
||||||
|
// This is just the `(foo ...)` pseudo-pattern inside a
|
||||||
|
// `(rule (foo ...) ...)` form. Just keep checking the
|
||||||
|
// sub-patterns.
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if let &ast::TermArgPattern::Expr(_) = arg {
|
if let ast::TermArgPattern::Expr(e) = arg {
|
||||||
tyenv.report_error(pos, format!("Term in pattern '{}' cannot have an injected expr, because it is an enum variant", sym.0));
|
tyenv.report_error(
|
||||||
|
e.pos(),
|
||||||
|
"cannot use output-polarity expression with top-level rules"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&TermKind::ExternalExtractor {
|
TermKind::EnumVariant { .. } => {
|
||||||
ref arg_polarity, ..
|
for arg in args {
|
||||||
|
if let &ast::TermArgPattern::Expr(_) = arg {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
format!(
|
||||||
|
"Term in pattern '{}' cannot have an injected expr, because \
|
||||||
|
it is an enum variant",
|
||||||
|
sym.0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TermKind::Decl {
|
||||||
|
extractor_kind:
|
||||||
|
Some(ExtractorKind::ExternalExtractor {
|
||||||
|
ref arg_polarity, ..
|
||||||
|
}),
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
for (arg, pol) in args.iter().zip(arg_polarity.iter()) {
|
for (arg, pol) in args.iter().zip(arg_polarity.iter()) {
|
||||||
match (arg, pol) {
|
match (arg, pol) {
|
||||||
@@ -1276,12 +1504,20 @@ impl TermEnv {
|
|||||||
}
|
}
|
||||||
(_, &ArgPolarity::Output) => {}
|
(_, &ArgPolarity::Output) => {}
|
||||||
(&ast::TermArgPattern::Pattern(ref p), &ArgPolarity::Input) => {
|
(&ast::TermArgPattern::Pattern(ref p), &ArgPolarity::Input) => {
|
||||||
tyenv.report_error(p.pos(), "Non-expression used in pattern but expression required for input-polarity extractor arg".to_string());
|
tyenv.report_error(
|
||||||
|
p.pos(),
|
||||||
|
"Non-expression used in pattern but expression required for \
|
||||||
|
input-polarity extractor arg"
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&TermKind::InternalExtractor { ref template } => {
|
TermKind::Decl {
|
||||||
|
extractor_kind: Some(ExtractorKind::InternalExtractor { ref template }),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
// Expand the extractor macro! We create a map
|
// Expand the extractor macro! We create a map
|
||||||
// from macro args to AST pattern trees and
|
// from macro args to AST pattern trees and
|
||||||
// then evaluate the template with these
|
// then evaluate the template with these
|
||||||
@@ -1291,7 +1527,12 @@ impl TermEnv {
|
|||||||
let sub_ast = match template_arg {
|
let sub_ast = match template_arg {
|
||||||
&ast::TermArgPattern::Pattern(ref pat) => pat.clone(),
|
&ast::TermArgPattern::Pattern(ref pat) => pat.clone(),
|
||||||
&ast::TermArgPattern::Expr(_) => {
|
&ast::TermArgPattern::Expr(_) => {
|
||||||
tyenv.report_error(pos, "Cannot expand an extractor macro with an expression in a macro argument".to_string());
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
"Cannot expand an extractor macro with an expression in a \
|
||||||
|
macro argument"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1299,15 +1540,26 @@ impl TermEnv {
|
|||||||
}
|
}
|
||||||
log::trace!("internal extractor macro args = {:?}", args);
|
log::trace!("internal extractor macro args = {:?}", args);
|
||||||
let pat = template.subst_macro_args(¯o_args[..])?;
|
let pat = template.subst_macro_args(¯o_args[..])?;
|
||||||
return self.translate_pattern(tyenv, &pat, expected_ty, bindings);
|
return self.translate_pattern(
|
||||||
|
tyenv,
|
||||||
|
rule_term,
|
||||||
|
&pat,
|
||||||
|
expected_ty,
|
||||||
|
bindings,
|
||||||
|
/* is_root = */ false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
&TermKind::ExternalConstructor { .. } | &TermKind::InternalConstructor => {
|
TermKind::Decl {
|
||||||
// OK.
|
extractor_kind: None,
|
||||||
}
|
..
|
||||||
&TermKind::Declared => {
|
} => {
|
||||||
tyenv.report_error(
|
tyenv.report_error(
|
||||||
pos,
|
pos,
|
||||||
format!("Declared but undefined term '{}' used", sym.0),
|
format!(
|
||||||
|
"Cannot use term '{}' that does not have a defined extractor in a \
|
||||||
|
left-hand side pattern",
|
||||||
|
sym.0
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1319,6 +1571,7 @@ impl TermEnv {
|
|||||||
let arg_ty = unwrap_or_continue!(term.arg_tys.get(i).copied());
|
let arg_ty = unwrap_or_continue!(term.arg_tys.get(i).copied());
|
||||||
let (subpat, _) = unwrap_or_continue!(self.translate_pattern_term_arg(
|
let (subpat, _) = unwrap_or_continue!(self.translate_pattern_term_arg(
|
||||||
tyenv,
|
tyenv,
|
||||||
|
rule_term,
|
||||||
pos,
|
pos,
|
||||||
arg,
|
arg,
|
||||||
Some(arg_ty),
|
Some(arg_ty),
|
||||||
@@ -1336,6 +1589,7 @@ impl TermEnv {
|
|||||||
fn translate_pattern_term_arg(
|
fn translate_pattern_term_arg(
|
||||||
&self,
|
&self,
|
||||||
tyenv: &mut TypeEnv,
|
tyenv: &mut TypeEnv,
|
||||||
|
rule_term: TermId,
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
pat: &ast::TermArgPattern,
|
pat: &ast::TermArgPattern,
|
||||||
expected_ty: Option<TypeId>,
|
expected_ty: Option<TypeId>,
|
||||||
@@ -1343,7 +1597,14 @@ impl TermEnv {
|
|||||||
) -> Option<(TermArgPattern, TypeId)> {
|
) -> Option<(TermArgPattern, TypeId)> {
|
||||||
match pat {
|
match pat {
|
||||||
&ast::TermArgPattern::Pattern(ref pat) => {
|
&ast::TermArgPattern::Pattern(ref pat) => {
|
||||||
let (subpat, ty) = self.translate_pattern(tyenv, pat, expected_ty, bindings)?;
|
let (subpat, ty) = self.translate_pattern(
|
||||||
|
tyenv,
|
||||||
|
rule_term,
|
||||||
|
pat,
|
||||||
|
expected_ty,
|
||||||
|
bindings,
|
||||||
|
/* is_root = */ false,
|
||||||
|
)?;
|
||||||
Some((TermArgPattern::Pattern(subpat), ty))
|
Some((TermArgPattern::Pattern(subpat), ty))
|
||||||
}
|
}
|
||||||
&ast::TermArgPattern::Expr(ref expr) => {
|
&ast::TermArgPattern::Expr(ref expr) => {
|
||||||
|
|||||||
17
cranelift/isle/isle_examples/construct-and-extract.isle
Normal file
17
cranelift/isle/isle_examples/construct-and-extract.isle
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
(type i32 (primitive i32))
|
||||||
|
|
||||||
|
(type B (enum (B (x i32) (y i32))))
|
||||||
|
|
||||||
|
;; `isub` has a constructor and extractor.
|
||||||
|
(decl isub (i32 i32) B)
|
||||||
|
(rule (isub x y)
|
||||||
|
(B.B x y))
|
||||||
|
(extractor (isub x y)
|
||||||
|
(B.B x y))
|
||||||
|
|
||||||
|
;; `value_array_2` has both an external extractor and an external constructor.
|
||||||
|
(type Value (primitive Value))
|
||||||
|
(type ValueArray2 extern (enum))
|
||||||
|
(decl value_array_2 (Value Value) ValueArray2)
|
||||||
|
(extern extractor infallible value_array_2 unpack_value_array_2)
|
||||||
|
(extern constructor value_array_2 pack_value_array_2)
|
||||||
Reference in New Issue
Block a user