This commit is contained in:
Chris Fallin
2021-09-04 17:20:55 -07:00
parent e5d76db97a
commit cd55dc9568
4 changed files with 50 additions and 17 deletions

View File

@@ -852,6 +852,8 @@ impl<'a> Codegen<'a> {
Ok(())
}
/// Returns a `bool` indicating whether this pattern inst is
/// infallible.
fn generate_pattern_inst(
&self,
code: &mut dyn Write,
@@ -859,27 +861,30 @@ impl<'a> Codegen<'a> {
inst: &PatternInst,
indent: &str,
ctx: &mut BodyContext,
) -> Result<(), Error> {
) -> Result<bool, Error> {
match inst {
&PatternInst::Arg { index, .. } => {
let output = Value::Expr {
let output = Value::Pattern {
inst: id,
output: 0,
};
let outputname = self.value_name(&output);
writeln!(code, "{}let {} = arg{};", indent, outputname, index)?;
writeln!(code, "{}{{", indent)?;
Ok(true)
}
&PatternInst::MatchEqual { ref a, ref b, .. } => {
let a = self.value_by_ref(a, ctx);
let b = self.value_by_ref(b, ctx);
writeln!(code, "{}if {} == {} {{", indent, a, b)?;
Ok(false)
}
&PatternInst::MatchInt {
ref input, int_val, ..
} => {
let input = self.value_by_val(input, ctx);
writeln!(code, "{}if {} == {} {{", indent, input, int_val)?;
Ok(false)
}
&PatternInst::MatchVariant {
ref input,
@@ -897,21 +902,23 @@ impl<'a> Codegen<'a> {
let variantname = &self.typeenv.syms[variant.name.index()];
let args = arg_tys
.iter()
.zip(variant.fields.iter())
.enumerate()
.map(|(i, ty)| {
.map(|(i, (ty, field))| {
let value = Value::Pattern {
inst: id,
output: i,
};
let valuename = self.value_name(&value);
let fieldname = &self.typeenv.syms[field.name.index()];
match &self.typeenv.types[ty.index()] {
&Type::Primitive(..) => {
self.define_val(&value, ctx, /* is_ref = */ false);
valuename
format!("{}: {}", fieldname, valuename)
}
&Type::Enum { .. } => {
self.define_val(&value, ctx, /* is_ref = */ true);
format!("ref {}", valuename)
format!("{}: ref {}", fieldname, valuename)
}
}
})
@@ -925,6 +932,7 @@ impl<'a> Codegen<'a> {
args.join(", "),
input
)?;
Ok(false)
}
&PatternInst::Extract {
ref input,
@@ -968,10 +976,9 @@ impl<'a> Codegen<'a> {
input
)?;
}
Ok(infallible)
}
}
Ok(())
}
fn generate_body(
@@ -981,15 +988,27 @@ impl<'a> Codegen<'a> {
trie: &TrieNode,
indent: &str,
ctx: &mut BodyContext,
) -> Result<(), Error> {
) -> Result<bool, Error> {
log::trace!("generate_body: trie {:?}", trie);
let mut returned = false;
match trie {
&TrieNode::Empty => {}
&TrieNode::Leaf { ref output, .. } => {
writeln!(
code,
"{}// Rule at {}.",
indent,
output.pos.pretty_print_line(&self.typeenv.filenames[..])
)?;
// If this is a leaf node, generate the ExprSequence and return.
for (id, inst) in output.insts.iter().enumerate() {
let id = InstId(id);
self.generate_expr_inst(code, id, inst, indent, ctx)?;
if let &ExprInst::Return { .. } = inst {
returned = true;
break;
}
}
}
@@ -1005,20 +1024,28 @@ impl<'a> Codegen<'a> {
{
match symbol {
&TrieSymbol::EndOfMatch => {
self.generate_body(code, depth + 1, node, &subindent, ctx)?;
returned = self.generate_body(code, depth + 1, node, indent, ctx)?;
}
&TrieSymbol::Match { ref op } => {
let id = InstId(depth);
self.generate_pattern_inst(code, id, op, &subindent, ctx)?;
self.generate_body(code, depth + 1, node, &subindent, ctx)?;
writeln!(code, "{}}}", subindent)?;
let infallible =
self.generate_pattern_inst(code, id, op, indent, ctx)?;
let sub_returned =
self.generate_body(code, depth + 1, node, &subindent, ctx)?;
writeln!(code, "{}}}", indent)?;
if infallible && sub_returned {
returned = true;
break;
}
}
}
}
}
}
writeln!(code, "{}return None;", indent)?;
Ok(())
if !returned {
writeln!(code, "{}return None;", indent)?;
}
Ok(returned)
}
}

View File

@@ -1,6 +1,7 @@
//! Lowered matching IR.
use crate::declare_id;
use crate::lexer::Pos;
use crate::sema::*;
use std::collections::HashMap;
@@ -110,6 +111,8 @@ pub struct ExprSequence {
/// Instruction sequence for expression. InstId indexes into this
/// sequence for `Value::Expr` values.
pub insts: Vec<ExprInst>,
/// Position at which the rule producing this sequence was located.
pub pos: Pos,
}
impl PatternSequence {
@@ -197,8 +200,7 @@ impl PatternSequence {
// Bind the appropriate variable and recurse.
assert!(!vars.contains_key(&var));
vars.insert(var, (None, input.unwrap())); // bind first, so subpat can use it
let root_term =
self.gen_pattern(input, typeenv, termenv, &*subpat, vars);
let root_term = self.gen_pattern(input, typeenv, termenv, &*subpat, vars);
vars.get_mut(&var).unwrap().0 = root_term;
root_term
}
@@ -352,6 +354,7 @@ pub fn lower_rule(
) {
let mut pattern_seq: PatternSequence = Default::default();
let mut expr_seq: ExprSequence = Default::default();
expr_seq.pos = termenv.rules[rule.index()].pos;
// Lower the pattern, starting from the root input value.
let ruledata = &termenv.rules[rule.index()];

View File

@@ -18,7 +18,7 @@ enum LexerInput<'a> {
File { content: String, filename: String },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Hash)]
pub struct Pos {
pub file: usize,
pub offset: usize,

View File

@@ -113,6 +113,7 @@ pub struct Rule {
pub lhs: Pattern,
pub rhs: Expr,
pub prio: Option<i64>,
pub pos: Pos,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -414,6 +415,7 @@ impl TermEnv {
for def in &defs.defs {
match def {
&ast::Def::Rule(ref rule) => {
let pos = rule.pos;
let mut bindings = Bindings {
next_var: 0,
vars: vec![],
@@ -434,6 +436,7 @@ impl TermEnv {
lhs,
rhs,
prio: rule.prio,
pos,
});
}
&ast::Def::Extern(ast::Extern::Constructor {