WIP.
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()];
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user