mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Add record patterns
This commit is contained in:
parent
9745d86efb
commit
5fc96c09ee
2 changed files with 103 additions and 89 deletions
|
@ -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)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue