Make sure that infallible match operations come after fallible ones

Eventually we will probably want to sort by a partial ordering based on pattern
subsumption to break ties between rules with the same priority. This local
heuristic of making sure infallibilty comes last is good enough for now and
handles the cases we care about thus far.

Fixes #10
This commit is contained in:
Nick Fitzgerald
2021-10-26 14:32:22 -07:00
committed by Chris Fallin
parent 6c6b7a2b78
commit 037db8aab6
2 changed files with 43 additions and 25 deletions

View File

@@ -651,7 +651,7 @@ impl<'a> Codegen<'a> {
indent: &str,
ctx: &mut BodyContext,
) -> bool {
log::trace!("generate_body: trie {:?}", trie);
log::trace!("generate_body:\n{}", trie.pretty());
let mut returned = false;
match trie {
&TrieNode::Empty => {}
@@ -692,10 +692,16 @@ impl<'a> Codegen<'a> {
let mut i = 0;
while i < edges.len() {
// Gather adjacent match variants so that we can turn these
// into a `match` rather than a sequence of `if let`s.
let mut last = i;
let mut adjacent_variants = BTreeSet::new();
let mut adjacent_variant_input = None;
log::trace!("edge: {:?}", edges[i]);
log::trace!(
"edge: range = {:?}, symbol = {:?}",
edges[i].range,
edges[i].symbol
);
while last < edges.len() {
match &edges[last].symbol {
&TrieSymbol::Match {
@@ -719,11 +725,11 @@ impl<'a> Codegen<'a> {
}
}
// edges[i..last] is a run of adjacent
// MatchVariants (possibly an empty one). Only use
// a `match` form if there are at least two
// adjacent options.
// Now `edges[i..last]` is a run of adjacent `MatchVariants`
// (possibly an empty one). Only use a `match` form if there
// are at least two adjacent options.
if last - i > 1 {
eprintln!("FITZGEN: generating body matches");
self.generate_body_matches(code, depth, &edges[i..last], indent, ctx);
i = last;
continue;
@@ -738,8 +744,13 @@ impl<'a> Codegen<'a> {
match symbol {
&TrieSymbol::EndOfMatch => {
returned = self.generate_body(code, depth + 1, node, indent, ctx);
eprintln!(
"FITZGEN: generated end-of-match; returned = {:?}",
returned
);
}
&TrieSymbol::Match { ref op } => {
eprintln!("FITZGEN: generating [if] let");
let id = InstId(depth);
let infallible =
self.generate_pattern_inst(code, id, op, indent, ctx);

View File

@@ -31,15 +31,6 @@ pub enum Value {
/// A single Pattern instruction.
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum PatternInst {
/// Get the Nth input argument, which corresponds to the Nth field
/// of the root term.
Arg {
/// The index of the argument to get.
index: usize,
/// The type of the argument.
ty: TypeId,
},
/// Match a value as equal to another value. Produces no values.
MatchEqual {
/// The first value.
@@ -83,6 +74,21 @@ pub enum PatternInst {
variant: VariantId,
},
/// Evaluate an expression and provide the given value as the result of this
/// match instruction. The expression has access to the pattern-values up to
/// this point in the sequence.
Expr {
/// The expression to evaluate.
seq: ExprSequence,
/// The value produced by the expression.
output: Value,
/// The type of the output value.
output_ty: TypeId,
},
// NB: this has to come second-to-last, because it might be infallible, for
// the same reasons that `Arg` has to be last.
//
/// Invoke an extractor, taking the given values as input (the first is the
/// value to extract, the other are the `Input`-polarity extractor args) and
/// producing an output value for each `Output`-polarity extractor arg.
@@ -99,16 +105,17 @@ pub enum PatternInst {
infallible: bool,
},
/// Evaluate an expression and provide the given value as the result of this
/// match instruction. The expression has access to the pattern-values up to
/// this point in the sequence.
Expr {
/// The expression to evaluate.
seq: ExprSequence,
/// The value produced by the expression.
output: Value,
/// The type of the output value.
output_ty: TypeId,
// NB: This has to go last, since it is infallible, so that when we sort
// edges in the trie, we visit infallible edges after first having tried the
// more-specific fallible options.
//
/// Get the Nth input argument, which corresponds to the Nth field
/// of the root term.
Arg {
/// The index of the argument to get.
index: usize,
/// The type of the argument.
ty: TypeId,
},
}