Add record patterns

This commit is contained in:
Folkert 2020-03-19 17:08:29 +01:00
parent 9745d86efb
commit 5fc96c09ee
2 changed files with 103 additions and 89 deletions

View file

@ -425,14 +425,35 @@ fn from_can<'a>(
// If it wasn't specifically an Identifier & Closure, proceed as normal.
let mono_pattern = from_can_pattern(env, &loc_pattern.value);
store_pattern(
env,
mono_pattern,
&loc_expr.value,
def.expr_var,
procs,
&mut stored,
);
let layout = Layout::from_var(env.arena, def.expr_var, env.subs, env.pointer_size)
.expect("invalid layout");
match &mono_pattern {
Pattern::Identifier(symbol) => {
stored.push((
*symbol,
layout.clone(),
from_can(env, loc_expr.value, procs, None),
));
}
_ => {
let symbol = env.fresh_symbol();
stored.push((
symbol,
layout.clone(),
from_can(env, loc_expr.value, procs, None),
));
match store_pattern(env, &mono_pattern, symbol, layout, &mut stored) {
Ok(()) => {}
Err(message) => todo!(
"generate runtime error, the pattern was invalid: {:?}",
message
),
}
}
}
// At this point, it's safe to assume we aren't assigning a Closure to a def.
// Extract Procs from the def body and the ret expression, and return the result!
@ -820,58 +841,9 @@ fn from_can<'a>(
}
fn store_pattern<'a>(
env: &mut Env<'a, '_>,
can_pat: Pattern,
can_expr: &roc_can::expr::Expr,
var: Variable,
procs: &mut Procs<'a>,
stored: &mut Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
) {
use Pattern::*;
let layout = match Layout::from_var(env.arena, var, env.subs, env.pointer_size) {
Ok(layout) => layout,
Err(()) => {
panic!("TODO gen a runtime error here");
}
};
// If we're defining a named closure, insert it into Procs and then
// remove the Let. When code gen later goes to look it up, it'll be in Procs!
//
// Before:
//
// identity = \a -> a
//
// identity 5
//
// After: (`identity` is now in Procs)
//
// identity 5
//
match can_pat {
Identifier(symbol) => {
stored.push((symbol, layout, from_can(env, can_expr.clone(), procs, None)))
}
Underscore => {
// Since _ is never read, it's safe to reassign it.
stored.push((
Symbol::UNDERSCORE,
layout,
from_can(env, can_expr.clone(), procs, None),
))
}
_ => {
panic!("TODO store_pattern for {:?}", can_pat);
}
}
}
fn store_pattern2<'a>(
env: &mut Env<'a, '_>,
can_pat: &Pattern<'a>,
outer_symbol: Symbol,
_index: usize,
layout: Layout<'a>,
stored: &mut Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
) -> Result<(), String> {
@ -879,22 +851,8 @@ fn store_pattern2<'a>(
match can_pat {
Identifier(symbol) => {
if true {
// stored.push((*symbol, layout, Expr::Load(outer_symbol)))
// let load = Expr::AccessAtIndex {
// index: index as u64,
// field_layouts: env.arena.alloc([
// Layout::Builtin(Builtin::Int64),
// Layout::Builtin(Builtin::Int64),
// ]),
// expr: env.arena.alloc(Expr::Load(outer_symbol)),
// };
let load = Expr::Load(outer_symbol);
stored.push((*symbol, layout, load))
} else {
todo!()
}
let load = Expr::Load(outer_symbol);
stored.push((*symbol, layout, load))
}
Underscore => {
// Since _ is never read, it's safe to reassign it.
@ -937,11 +895,16 @@ fn store_pattern2<'a>(
let symbol = env.fresh_symbol();
stored.push((symbol, layout.clone(), load));
store_pattern2(env, argument, symbol, 0, arg_layout.clone(), stored)?;
store_pattern(env, argument, symbol, arg_layout.clone(), stored)?;
}
}
}
}
RecordDestructure(destructs, layout) => {
for destruct in destructs {
store_record_destruct(env, destruct, outer_symbol, layout.clone(), stored)?;
}
}
Shadowed(region, ident) => {
return Err(format!(
@ -957,6 +920,40 @@ fn store_pattern2<'a>(
Ok(())
}
fn store_record_destruct<'a>(
env: &mut Env<'a, '_>,
destruct: &RecordDestruct<'a>,
outer_symbol: Symbol,
struct_layout: Layout<'a>,
stored: &mut Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
) -> Result<(), String> {
let record = env.arena.alloc(Expr::Load(outer_symbol));
let load = Expr::Access {
label: destruct.label.clone(),
field_layout: destruct.layout.clone(),
struct_layout,
record,
};
match &destruct.guard {
None => {
stored.push((destruct.symbol, destruct.layout.clone(), load));
}
Some(guard_pattern) => match &guard_pattern {
Pattern::Identifier(symbol) => {
stored.push((*symbol, destruct.layout.clone(), load));
}
_ => {
let symbol = env.fresh_symbol();
stored.push((symbol, destruct.layout.clone(), load));
store_pattern(env, guard_pattern, symbol, destruct.layout.clone(), stored)?;
}
},
}
Ok(())
}
fn from_can_when<'a>(
env: &mut Env<'a, '_>,
cond_var: Variable,
@ -991,14 +988,8 @@ fn from_can_when<'a>(
// NOTE this will still store shadowed names. I think that is fine because the branch
// will throw an error anyway.
let ret = match store_pattern2(
env,
&mono_pattern,
cond_symbol,
0,
cond_layout,
&mut stored,
) {
let ret = match store_pattern(env, &mono_pattern, cond_symbol, cond_layout, &mut stored)
{
Ok(_) => from_can(env, loc_branch.value, procs, None),
Err(message) => Expr::RuntimeError(env.arena.alloc(message)),
};
@ -1022,11 +1013,10 @@ fn from_can_when<'a>(
let mut stores = Vec::with_capacity_in(1, env.arena);
let mono_expr = match store_pattern2(
let mono_expr = match store_pattern(
env,
&mono_pattern,
cond_symbol,
0,
cond_layout.clone(),
&mut stores,
) {
@ -1229,6 +1219,7 @@ pub enum Pattern<'a> {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RecordDestruct<'a> {
pub label: Lowercase,
pub layout: Layout<'a>,
pub symbol: Symbol,
pub guard: Option<Pattern<'a>>,
}
@ -1327,15 +1318,22 @@ fn from_can_pattern<'a>(
destructs,
..
} => match Layout::from_var(env.arena, *whole_var, env.subs, env.pointer_size) {
Ok(layout) => {
Ok(Layout::Struct(field_layouts)) => {
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);
for loc_rec_des in destructs {
mono_destructs.push(from_can_record_destruct(env, &loc_rec_des.value));
for (loc_rec_des, (label, field_layout)) in
destructs.iter().zip(field_layouts.iter())
{
debug_assert!(&loc_rec_des.value.label == label);
mono_destructs.push(from_can_record_destruct(
env,
&loc_rec_des.value,
field_layout.clone(),
));
}
Pattern::RecordDestructure(mono_destructs, layout)
Pattern::RecordDestructure(mono_destructs, Layout::Struct(field_layouts))
}
Err(()) => panic!("Invalid layout"),
Ok(_) | Err(()) => panic!("Invalid layout"),
},
}
}
@ -1343,10 +1341,12 @@ fn from_can_pattern<'a>(
fn from_can_record_destruct<'a>(
env: &mut Env<'a, '_>,
can_rd: &roc_can::pattern::RecordDestruct,
field_layout: Layout<'a>,
) -> RecordDestruct<'a> {
RecordDestruct {
label: can_rd.label.clone(),
symbol: can_rd.symbol,
layout: field_layout,
guard: match &can_rd.guard {
None => None,
Some((_, loc_pattern)) => Some(from_can_pattern(env, &loc_pattern.value)),