mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Add record patterns
This commit is contained in:
parent
9745d86efb
commit
5fc96c09ee
2 changed files with 103 additions and 89 deletions
|
@ -1333,6 +1333,20 @@ mod test_gen {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn when_on_record() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when { x: 0x2 } is
|
||||||
|
{ x } -> x + 3
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
5,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn when_on_just_just() {
|
// fn when_on_just_just() {
|
||||||
// assert_evals_to!(
|
// assert_evals_to!(
|
||||||
|
|
|
@ -425,14 +425,35 @@ fn from_can<'a>(
|
||||||
|
|
||||||
// If it wasn't specifically an Identifier & Closure, proceed as normal.
|
// If it wasn't specifically an Identifier & Closure, proceed as normal.
|
||||||
let mono_pattern = from_can_pattern(env, &loc_pattern.value);
|
let mono_pattern = from_can_pattern(env, &loc_pattern.value);
|
||||||
store_pattern(
|
|
||||||
env,
|
let layout = Layout::from_var(env.arena, def.expr_var, env.subs, env.pointer_size)
|
||||||
mono_pattern,
|
.expect("invalid layout");
|
||||||
&loc_expr.value,
|
|
||||||
def.expr_var,
|
match &mono_pattern {
|
||||||
procs,
|
Pattern::Identifier(symbol) => {
|
||||||
&mut stored,
|
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.
|
// 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!
|
// 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>(
|
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, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
can_pat: &Pattern<'a>,
|
can_pat: &Pattern<'a>,
|
||||||
outer_symbol: Symbol,
|
outer_symbol: Symbol,
|
||||||
_index: usize,
|
|
||||||
layout: Layout<'a>,
|
layout: Layout<'a>,
|
||||||
stored: &mut Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
stored: &mut Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
@ -879,22 +851,8 @@ fn store_pattern2<'a>(
|
||||||
|
|
||||||
match can_pat {
|
match can_pat {
|
||||||
Identifier(symbol) => {
|
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);
|
let load = Expr::Load(outer_symbol);
|
||||||
stored.push((*symbol, layout, load))
|
stored.push((*symbol, layout, load))
|
||||||
} else {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Underscore => {
|
Underscore => {
|
||||||
// Since _ is never read, it's safe to reassign it.
|
// Since _ is never read, it's safe to reassign it.
|
||||||
|
@ -937,11 +895,16 @@ fn store_pattern2<'a>(
|
||||||
let symbol = env.fresh_symbol();
|
let symbol = env.fresh_symbol();
|
||||||
stored.push((symbol, layout.clone(), load));
|
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) => {
|
Shadowed(region, ident) => {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
|
@ -957,6 +920,40 @@ fn store_pattern2<'a>(
|
||||||
Ok(())
|
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>(
|
fn from_can_when<'a>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
cond_var: Variable,
|
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
|
// NOTE this will still store shadowed names. I think that is fine because the branch
|
||||||
// will throw an error anyway.
|
// will throw an error anyway.
|
||||||
let ret = match store_pattern2(
|
let ret = match store_pattern(env, &mono_pattern, cond_symbol, cond_layout, &mut stored)
|
||||||
env,
|
{
|
||||||
&mono_pattern,
|
|
||||||
cond_symbol,
|
|
||||||
0,
|
|
||||||
cond_layout,
|
|
||||||
&mut stored,
|
|
||||||
) {
|
|
||||||
Ok(_) => from_can(env, loc_branch.value, procs, None),
|
Ok(_) => from_can(env, loc_branch.value, procs, None),
|
||||||
Err(message) => Expr::RuntimeError(env.arena.alloc(message)),
|
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 mut stores = Vec::with_capacity_in(1, env.arena);
|
||||||
|
|
||||||
let mono_expr = match store_pattern2(
|
let mono_expr = match store_pattern(
|
||||||
env,
|
env,
|
||||||
&mono_pattern,
|
&mono_pattern,
|
||||||
cond_symbol,
|
cond_symbol,
|
||||||
0,
|
|
||||||
cond_layout.clone(),
|
cond_layout.clone(),
|
||||||
&mut stores,
|
&mut stores,
|
||||||
) {
|
) {
|
||||||
|
@ -1229,6 +1219,7 @@ pub enum Pattern<'a> {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct RecordDestruct<'a> {
|
pub struct RecordDestruct<'a> {
|
||||||
pub label: Lowercase,
|
pub label: Lowercase,
|
||||||
|
pub layout: Layout<'a>,
|
||||||
pub symbol: Symbol,
|
pub symbol: Symbol,
|
||||||
pub guard: Option<Pattern<'a>>,
|
pub guard: Option<Pattern<'a>>,
|
||||||
}
|
}
|
||||||
|
@ -1327,15 +1318,22 @@ fn from_can_pattern<'a>(
|
||||||
destructs,
|
destructs,
|
||||||
..
|
..
|
||||||
} => match Layout::from_var(env.arena, *whole_var, env.subs, env.pointer_size) {
|
} => 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);
|
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);
|
||||||
for loc_rec_des in destructs {
|
for (loc_rec_des, (label, field_layout)) in
|
||||||
mono_destructs.push(from_can_record_destruct(env, &loc_rec_des.value));
|
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>(
|
fn from_can_record_destruct<'a>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
can_rd: &roc_can::pattern::RecordDestruct,
|
can_rd: &roc_can::pattern::RecordDestruct,
|
||||||
|
field_layout: Layout<'a>,
|
||||||
) -> RecordDestruct<'a> {
|
) -> RecordDestruct<'a> {
|
||||||
RecordDestruct {
|
RecordDestruct {
|
||||||
label: can_rd.label.clone(),
|
label: can_rd.label.clone(),
|
||||||
symbol: can_rd.symbol,
|
symbol: can_rd.symbol,
|
||||||
|
layout: field_layout,
|
||||||
guard: match &can_rd.guard {
|
guard: match &can_rd.guard {
|
||||||
None => None,
|
None => None,
|
||||||
Some((_, loc_pattern)) => Some(from_can_pattern(env, &loc_pattern.value)),
|
Some((_, loc_pattern)) => Some(from_can_pattern(env, &loc_pattern.value)),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue