mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
Add a deriver for encoding lists
This commit is contained in:
parent
0dfdcf5523
commit
e83175cf75
2 changed files with 203 additions and 1 deletions
|
@ -174,7 +174,7 @@ pub(crate) fn derive_to_encoder(
|
||||||
def_symbol: Symbol,
|
def_symbol: Symbol,
|
||||||
) -> DerivedBody {
|
) -> DerivedBody {
|
||||||
let (body, body_type) = match key {
|
let (body, body_type) = match key {
|
||||||
FlatEncodableKey::List() => todo!(),
|
FlatEncodableKey::List() => to_encoder_list(env, def_symbol),
|
||||||
FlatEncodableKey::Set() => todo!(),
|
FlatEncodableKey::Set() => todo!(),
|
||||||
FlatEncodableKey::Dict() => todo!(),
|
FlatEncodableKey::Dict() => todo!(),
|
||||||
FlatEncodableKey::Record(fields) => {
|
FlatEncodableKey::Record(fields) => {
|
||||||
|
@ -231,6 +231,190 @@ pub(crate) fn derive_to_encoder(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
||||||
|
// Build \lst -> Encode.list lst (\elem -> Encode.toEncoder elem)
|
||||||
|
//
|
||||||
|
// TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
use Expr::*;
|
||||||
|
|
||||||
|
let lst_sym = env.new_symbol("lst");
|
||||||
|
let elem_sym = env.new_symbol("elem");
|
||||||
|
|
||||||
|
// List elem
|
||||||
|
let elem_var = env.subs.fresh_unnamed_flex_var();
|
||||||
|
let elem_var_slice = SubsSlice::insert_into_subs(env.subs, [elem_var]);
|
||||||
|
let list_var = synth_var(
|
||||||
|
env.subs,
|
||||||
|
Content::Structure(FlatType::Apply(Symbol::LIST_LIST, elem_var_slice)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// build `toEncoder elem` type
|
||||||
|
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
let to_encoder_fn_var = env.import_encode_symbol(Symbol::ENCODE_TO_ENCODER);
|
||||||
|
|
||||||
|
// elem -[clos]-> t1
|
||||||
|
let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos
|
||||||
|
let elem_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1
|
||||||
|
let elem_to_encoder_fn_var = synth_var(
|
||||||
|
env.subs,
|
||||||
|
Content::Structure(FlatType::Func(
|
||||||
|
elem_var_slice,
|
||||||
|
to_encoder_clos_var,
|
||||||
|
elem_encoder_var,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// val -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
// ~ elem -[clos]-> t1
|
||||||
|
env.unify(to_encoder_fn_var, elem_to_encoder_fn_var);
|
||||||
|
|
||||||
|
// toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, elem_to_encoder_fn_var);
|
||||||
|
let to_encoder_fn = Box::new((
|
||||||
|
to_encoder_fn_var,
|
||||||
|
Loc::at_zero(to_encoder_var),
|
||||||
|
to_encoder_clos_var,
|
||||||
|
elem_encoder_var,
|
||||||
|
));
|
||||||
|
|
||||||
|
// toEncoder elem
|
||||||
|
let to_encoder_call = Call(
|
||||||
|
to_encoder_fn,
|
||||||
|
vec![(elem_var, Loc::at_zero(Var(elem_sym)))],
|
||||||
|
CalledVia::Space,
|
||||||
|
);
|
||||||
|
|
||||||
|
// elem -[to_elem_encoder]-> toEncoder elem
|
||||||
|
let to_elem_encoder_sym = env.new_symbol("to_elem_encoder");
|
||||||
|
|
||||||
|
// Create fn_var for ambient capture; we fix it up below.
|
||||||
|
let to_elem_encoder_fn_var = synth_var(env.subs, Content::Error);
|
||||||
|
|
||||||
|
// -[to_elem_encoder]->
|
||||||
|
let to_elem_encoder_labels =
|
||||||
|
UnionLambdas::insert_into_subs(env.subs, once((to_elem_encoder_sym, vec![])));
|
||||||
|
let to_elem_encoder_lset = synth_var(
|
||||||
|
env.subs,
|
||||||
|
Content::LambdaSet(LambdaSet {
|
||||||
|
solved: to_elem_encoder_labels,
|
||||||
|
recursion_var: OptVariable::NONE,
|
||||||
|
unspecialized: SubsSlice::default(),
|
||||||
|
ambient_function: to_elem_encoder_fn_var,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
// elem -[to_elem_encoder]-> toEncoder elem
|
||||||
|
env.subs.set_content(
|
||||||
|
to_elem_encoder_fn_var,
|
||||||
|
Content::Structure(FlatType::Func(
|
||||||
|
elem_var_slice,
|
||||||
|
to_elem_encoder_lset,
|
||||||
|
elem_encoder_var,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// \elem -> toEncoder elem
|
||||||
|
let to_elem_encoder = Closure(ClosureData {
|
||||||
|
function_type: to_elem_encoder_fn_var,
|
||||||
|
closure_type: to_elem_encoder_lset,
|
||||||
|
return_type: elem_encoder_var,
|
||||||
|
name: to_elem_encoder_sym,
|
||||||
|
captured_symbols: vec![],
|
||||||
|
recursive: Recursive::NotRecursive,
|
||||||
|
arguments: vec![(
|
||||||
|
elem_var,
|
||||||
|
AnnotatedMark::known_exhaustive(),
|
||||||
|
Loc::at_zero(Pattern::Identifier(elem_sym)),
|
||||||
|
)],
|
||||||
|
loc_body: Box::new(Loc::at_zero(to_encoder_call)),
|
||||||
|
});
|
||||||
|
|
||||||
|
// build `Encode.list lst (\elem -> Encode.toEncoder elem)` type
|
||||||
|
// List e, (e -> Encoder fmt) -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
let encode_list_fn_var = env.import_encode_symbol(Symbol::ENCODE_LIST);
|
||||||
|
|
||||||
|
// List elem, to_elem_encoder_fn_var -[clos]-> t1
|
||||||
|
let this_encode_list_args_slice =
|
||||||
|
VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_encoder_fn_var]);
|
||||||
|
let this_encode_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos
|
||||||
|
let this_list_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1
|
||||||
|
let this_encode_list_fn_var = synth_var(
|
||||||
|
env.subs,
|
||||||
|
Content::Structure(FlatType::Func(
|
||||||
|
this_encode_list_args_slice,
|
||||||
|
this_encode_list_clos_var,
|
||||||
|
this_list_encoder_var,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// List e, (e -> Encoder fmt) -[uls]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
// ~ List elem, to_elem_encoder_fn_var -[clos]-> t1
|
||||||
|
env.unify(encode_list_fn_var, this_encode_list_fn_var);
|
||||||
|
|
||||||
|
// Encode.list : List elem, to_elem_encoder_fn_var -[clos]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
let encode_list = AbilityMember(Symbol::ENCODE_LIST, None, this_encode_list_fn_var);
|
||||||
|
let encode_list_fn = Box::new((
|
||||||
|
this_encode_list_fn_var,
|
||||||
|
Loc::at_zero(encode_list),
|
||||||
|
this_encode_list_clos_var,
|
||||||
|
this_list_encoder_var,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Encode.list lst to_elem_encoder
|
||||||
|
let encode_list_call = Call(
|
||||||
|
encode_list_fn,
|
||||||
|
vec![
|
||||||
|
(list_var, Loc::at_zero(Var(lst_sym))),
|
||||||
|
(to_elem_encoder_fn_var, Loc::at_zero(to_elem_encoder)),
|
||||||
|
],
|
||||||
|
CalledVia::Space,
|
||||||
|
);
|
||||||
|
|
||||||
|
// \lst -> Encode.list lst (\elem -> Encode.toEncoder elem)
|
||||||
|
// Create fn_var for ambient capture; we fix it up below.
|
||||||
|
let fn_var = synth_var(env.subs, Content::Error);
|
||||||
|
|
||||||
|
// -[fn_name]->
|
||||||
|
let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![])));
|
||||||
|
let fn_clos_var = synth_var(
|
||||||
|
env.subs,
|
||||||
|
Content::LambdaSet(LambdaSet {
|
||||||
|
solved: fn_name_labels,
|
||||||
|
recursion_var: OptVariable::NONE,
|
||||||
|
unspecialized: SubsSlice::default(),
|
||||||
|
ambient_function: fn_var,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
// List elem -[fn_name]-> Encoder fmt
|
||||||
|
let list_var_slice = SubsSlice::insert_into_subs(env.subs, once(list_var));
|
||||||
|
env.subs.set_content(
|
||||||
|
fn_var,
|
||||||
|
Content::Structure(FlatType::Func(
|
||||||
|
list_var_slice,
|
||||||
|
fn_clos_var,
|
||||||
|
this_list_encoder_var,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// \lst -[fn_name]-> Encode.list lst (\elem -> Encode.toEncoder elem)
|
||||||
|
let clos = Closure(ClosureData {
|
||||||
|
function_type: fn_var,
|
||||||
|
closure_type: fn_clos_var,
|
||||||
|
return_type: this_list_encoder_var,
|
||||||
|
name: fn_name,
|
||||||
|
captured_symbols: vec![],
|
||||||
|
recursive: Recursive::NotRecursive,
|
||||||
|
arguments: vec![(
|
||||||
|
list_var,
|
||||||
|
AnnotatedMark::known_exhaustive(),
|
||||||
|
Loc::at_zero(Pattern::Identifier(lst_sym)),
|
||||||
|
)],
|
||||||
|
loc_body: Box::new(Loc::at_zero(encode_list_call)),
|
||||||
|
});
|
||||||
|
|
||||||
|
(clos, fn_var)
|
||||||
|
}
|
||||||
|
|
||||||
fn to_encoder_record(
|
fn to_encoder_record(
|
||||||
env: &mut Env<'_>,
|
env: &mut Env<'_>,
|
||||||
record_var: Variable,
|
record_var: Variable,
|
||||||
|
|
|
@ -712,4 +712,22 @@ fn recursive_tag_union() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list() {
|
||||||
|
derive_test(v!(Symbol::LIST_LIST v!(STR)), |golden| {
|
||||||
|
assert_snapshot!(golden, @r###"
|
||||||
|
# derived for List Str
|
||||||
|
# List val -[[toEncoder_list(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding
|
||||||
|
# List val -[[toEncoder_list(0)]]-> (List U8, fmt -[[] + fmt:Encode.list(19):4]-> List U8) | fmt has EncoderFormatting, val has Encoding
|
||||||
|
# Specialization lambda sets:
|
||||||
|
# @<1>: [[toEncoder_list(0)]]
|
||||||
|
# @<2>: [[] + fmt:Encode.list(19):4] | fmt has EncoderFormatting
|
||||||
|
#Derived.toEncoder_list =
|
||||||
|
\#Derived.lst ->
|
||||||
|
Encode.list #Derived.lst \#Derived.elem -> Encode.toEncoder #Derived.elem
|
||||||
|
"###
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// }}} deriver tests
|
// }}} deriver tests
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue