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

View File

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

View File

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

View File

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