mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-14 18:21:40 +00:00
Finish building expressions for decoder_record
This commit is contained in:
parent
d3e96e9aa8
commit
6e008cf718
1 changed files with 376 additions and 36 deletions
|
|
@ -1,6 +1,5 @@
|
||||||
//! Derivers for the `Decoding` ability.
|
//! Derivers for the `Decoding` ability.
|
||||||
|
|
||||||
use bumpalo::collections::vec;
|
|
||||||
use roc_can::expr::{
|
use roc_can::expr::{
|
||||||
AnnotatedMark, ClosureData, Expr, Field, Recursive, WhenBranch, WhenBranchPattern,
|
AnnotatedMark, ClosureData, Expr, Field, Recursive, WhenBranch, WhenBranchPattern,
|
||||||
};
|
};
|
||||||
|
|
@ -41,19 +40,110 @@ pub(crate) fn derive_decoder(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decoder_record(env: &mut Env, def_symbol: Symbol, fields: Vec<Lowercase>) -> (Expr, Variable) {
|
fn decoder_record(env: &mut Env, _def_symbol: Symbol, fields: Vec<Lowercase>) -> (Expr, Variable) {
|
||||||
use Expr::*;
|
|
||||||
|
|
||||||
// Decode.custom \bytes, fmt -> Decode.decodeWith bytes (Decode.record initialState stepField finalizer) fmt
|
|
||||||
|
|
||||||
let initial_state = decoder_initial_state(&fields);
|
let initial_state = decoder_initial_state(&fields);
|
||||||
let finalizer = decoder_finalizer(env, fields);
|
let finalizer = decoder_finalizer(env, &fields);
|
||||||
let step_field = dbg!(decoder_step_field(env, fields));
|
let step_field = decoder_step_field(env, fields);
|
||||||
let expr_var = Variable::NULL; // TODO type of entire expression, namely something like this:
|
let expr_var = Variable::NULL; // TODO type of entire expression, namely something like this:
|
||||||
// Decoder {first: a, second: b} fmt | a has Decoding, b has Decoding, fmt has DecoderFormatting
|
// Decoder {first: a, second: b} fmt | a has Decoding, b has Decoding, fmt has DecoderFormatting
|
||||||
|
|
||||||
|
// Decode.record initialState stepField finalizer
|
||||||
|
let call_decode_record = Expr::Call(
|
||||||
|
Box::new((
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(Symbol::DECODE_RECORD)),
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
)),
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(initial_state),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(step_field),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(finalizer),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
CalledVia::Space,
|
||||||
|
);
|
||||||
|
|
||||||
// Decode.custom \bytes, fmt -> Decode.decodeWith bytes (Decode.record initialState stepField finalizer) fmt
|
// Decode.custom \bytes, fmt -> Decode.decodeWith bytes (Decode.record initialState stepField finalizer) fmt
|
||||||
(dbg!(initial_state), expr_var)
|
let call_decode_custom = {
|
||||||
|
let bytes_arg_symbol = env.new_symbol("bytes");
|
||||||
|
let fmt_arg_symbol = env.new_symbol("fmt");
|
||||||
|
|
||||||
|
// Decode.decodeWith bytes (Decode.record initialState stepField finalizer) fmt
|
||||||
|
let callback_body = Expr::Call(
|
||||||
|
Box::new((
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(Symbol::DECODE_DECODE_WITH)),
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
)),
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(bytes_arg_symbol)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(call_decode_record),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(fmt_arg_symbol)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
CalledVia::Space,
|
||||||
|
);
|
||||||
|
|
||||||
|
// \bytes, fmt -> Decode.decodeWith bytes (Decode.record initialState stepField finalizer) fmt
|
||||||
|
let custom_callback = {
|
||||||
|
Expr::Closure(ClosureData {
|
||||||
|
function_type: Variable::NULL, // TODO
|
||||||
|
closure_type: Variable::NULL, // TODO
|
||||||
|
return_type: Variable::NULL, // TODO
|
||||||
|
name: env.unique_symbol(),
|
||||||
|
captured_symbols: Vec::new(),
|
||||||
|
recursive: Recursive::NotRecursive,
|
||||||
|
arguments: vec![
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
AnnotatedMark::known_exhaustive(),
|
||||||
|
Loc::at_zero(Pattern::Identifier(bytes_arg_symbol)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
AnnotatedMark::known_exhaustive(),
|
||||||
|
Loc::at_zero(Pattern::Identifier(fmt_arg_symbol)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
loc_body: Box::new(Loc::at_zero(callback_body)),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decode.custom \bytes, fmt -> Decode.decodeWith bytes (Decode.record initialState stepField finalizer) fmt
|
||||||
|
Expr::Call(
|
||||||
|
Box::new((
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(Symbol::DECODE_CUSTOM)),
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
)),
|
||||||
|
vec![(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(custom_callback),
|
||||||
|
)],
|
||||||
|
CalledVia::Space,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
(call_decode_custom, expr_var)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Example:
|
/// Example:
|
||||||
|
|
@ -61,45 +151,272 @@ fn decoder_record(env: &mut Env, def_symbol: Symbol, fields: Vec<Lowercase>) ->
|
||||||
/// when field is
|
/// when field is
|
||||||
/// "first" ->
|
/// "first" ->
|
||||||
/// Keep (Decode.custom \bytes, fmt ->
|
/// Keep (Decode.custom \bytes, fmt ->
|
||||||
/// rec = Decode.decodeWith bytes Decode.decoder fmt
|
/// # Uses a single-branch `when` because `let` is more expensive to monomorphize
|
||||||
///
|
/// # due to checks for polymorphic expressions, and `rec` would be polymorphic.
|
||||||
|
/// when Decode.decodeWith bytes Decode.decoder fmt is
|
||||||
|
/// rec ->
|
||||||
/// {
|
/// {
|
||||||
/// rest: rec.rest,
|
/// rest: rec.rest,
|
||||||
/// result: when rec.result is
|
/// result: when rec.result is
|
||||||
/// Ok val -> Ok {state & f0: Ok val},
|
/// Ok val -> Ok {state & first: Ok val},
|
||||||
/// Err err -> Err err
|
/// Err err -> Err err
|
||||||
/// }
|
/// }
|
||||||
/// )
|
/// )
|
||||||
///
|
///
|
||||||
/// "second" ->
|
/// "second" -> # We actually use the first branch's structure, which is a desugared version of this
|
||||||
/// Keep (Decode.custom \bytes, fmt ->
|
/// Keep (Decode.custom \bytes, fmt ->
|
||||||
/// when Decode.decodeWith bytes Decode.decoder fmt is
|
/// when Decode.decodeWith bytes Decode.decoder fmt is
|
||||||
/// {result, rest} ->
|
/// {result, rest} ->
|
||||||
/// {result: Result.map result \val -> {state & f1: Ok val}, rest})
|
/// {result: Result.map result \val -> {state & second: Ok val}, rest})
|
||||||
/// _ -> Skip
|
/// _ -> Skip
|
||||||
fn decoder_step_field(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
fn decoder_step_field(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
||||||
let state_arg_symbol = env.new_symbol("stateRecord");
|
let state_arg_symbol = env.new_symbol("stateRecord");
|
||||||
let field_arg_symbol = env.new_symbol("field");
|
let field_arg_symbol = env.new_symbol("field");
|
||||||
|
|
||||||
// +1 because of the default branch.
|
// +1 because of the default branch.
|
||||||
let branches = Vec::with_capacity(fields.len() + 1);
|
let mut branches = Vec::with_capacity(fields.len() + 1);
|
||||||
|
|
||||||
for field in fields {
|
for field_name in fields {
|
||||||
// Example:
|
// Example:
|
||||||
// "first" ->
|
// "first" ->
|
||||||
// Keep (Decode.custom \bytes, fmt ->
|
// Keep (Decode.custom \bytes, fmt ->
|
||||||
|
// # Uses a single-branch `when` because `let` is more expensive to monomorphize
|
||||||
|
// # due to checks for polymorphic expressions, and `rec` would be polymorphic.
|
||||||
// when Decode.decodeWith bytes Decode.decoder fmt is
|
// when Decode.decodeWith bytes Decode.decoder fmt is
|
||||||
// {result, rest} ->
|
// rec ->
|
||||||
// {result: Result.map result \val -> {state & f0: Ok val}, rest})
|
// {
|
||||||
|
// rest: rec.rest,
|
||||||
|
// result: when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
|
||||||
let custom_callback = {
|
let custom_callback = {
|
||||||
// \bytes, fmt ->
|
// \bytes, fmt ->
|
||||||
|
// # Uses a single-branch `when` because `let` is more expensive to monomorphize
|
||||||
|
// # due to checks for polymorphic expressions, and `rec` would be polymorphic.
|
||||||
// when Decode.decodeWith bytes Decode.decoder fmt is
|
// when Decode.decodeWith bytes Decode.decoder fmt is
|
||||||
// {result, rest} ->
|
// rec ->
|
||||||
// {result: Result.map result \val -> {state & f0: Ok val}, rest})
|
// {
|
||||||
|
// rest: rec.rest,
|
||||||
|
// result: when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
// }
|
||||||
let bytes_arg_symbol = env.new_symbol("bytes");
|
let bytes_arg_symbol = env.new_symbol("bytes");
|
||||||
let fmt_arg_symbol = env.new_symbol("fmt");
|
let fmt_arg_symbol = env.new_symbol("fmt");
|
||||||
|
|
||||||
|
let custom_callback_body = {
|
||||||
|
let rec_symbol = env.new_symbol("rec");
|
||||||
|
|
||||||
|
// # Uses a single-branch `when` because `let` is more expensive to monomorphize
|
||||||
|
// # due to checks for polymorphic expressions, and `rec` would be polymorphic.
|
||||||
|
// when Decode.decodeWith bytes Decode.decoder fmt is
|
||||||
|
// rec ->
|
||||||
|
// {
|
||||||
|
// rest: rec.rest,
|
||||||
|
// result: when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
// }
|
||||||
|
let branch_body = {
|
||||||
|
// {
|
||||||
|
// rest: rec.rest,
|
||||||
|
// result: when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
// }
|
||||||
|
let mut fields_map = SendMap::default();
|
||||||
|
|
||||||
|
fields_map.insert(
|
||||||
|
"rest".into(),
|
||||||
|
Field {
|
||||||
|
var: Variable::NULL, // TODO
|
||||||
|
region: Region::zero(),
|
||||||
|
loc_expr: Box::new(Loc::at_zero(Expr::Access {
|
||||||
|
record_var: Variable::NULL, // TODO
|
||||||
|
ext_var: Variable::EMPTY_RECORD,
|
||||||
|
field_var: Variable::NULL, // TODO
|
||||||
|
loc_expr: Box::new(Loc::at_zero(Expr::Var(rec_symbol))),
|
||||||
|
field: "rest".into(),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let result_val = {
|
||||||
|
// result: when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
let ok_val_symbol = env.new_symbol("val");
|
||||||
|
let err_val_symbol = env.new_symbol("err");
|
||||||
|
|
||||||
|
let ok_branch_expr = {
|
||||||
|
// Ok {state & first: Ok val},
|
||||||
|
let mut updates = SendMap::default();
|
||||||
|
|
||||||
|
updates.insert(
|
||||||
|
field_name.clone(),
|
||||||
|
Field {
|
||||||
|
var: Variable::NULL, // TODO
|
||||||
|
region: Region::zero(),
|
||||||
|
loc_expr: Box::new(Loc::at_zero(Expr::Tag {
|
||||||
|
variant_var: Variable::NULL, // TODO
|
||||||
|
ext_var: Variable::NULL, // TODO
|
||||||
|
name: "Ok".into(),
|
||||||
|
arguments: vec![(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(ok_val_symbol)),
|
||||||
|
)],
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let updated_record = Expr::Update {
|
||||||
|
record_var: Variable::NULL, // TODO
|
||||||
|
ext_var: Variable::EMPTY_RECORD,
|
||||||
|
symbol: state_arg_symbol,
|
||||||
|
updates,
|
||||||
|
};
|
||||||
|
|
||||||
|
Expr::Tag {
|
||||||
|
variant_var: Variable::NULL, // TODO
|
||||||
|
ext_var: Variable::NULL, // TODO
|
||||||
|
name: "Ok".into(),
|
||||||
|
arguments: vec![(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(updated_record),
|
||||||
|
)],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let branches = vec![
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
WhenBranch {
|
||||||
|
patterns: vec![WhenBranchPattern {
|
||||||
|
pattern: Loc::at_zero(Pattern::AppliedTag {
|
||||||
|
whole_var: Variable::NULL, // TODO
|
||||||
|
ext_var: Variable::EMPTY_TAG_UNION,
|
||||||
|
tag_name: "Ok".into(),
|
||||||
|
arguments: vec![(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Pattern::Identifier(ok_val_symbol)),
|
||||||
|
)],
|
||||||
|
}),
|
||||||
|
degenerate: false,
|
||||||
|
}],
|
||||||
|
value: Loc::at_zero(ok_branch_expr),
|
||||||
|
guard: None,
|
||||||
|
redundant: RedundantMark::known_non_redundant(),
|
||||||
|
},
|
||||||
|
// Err err -> Err err
|
||||||
|
WhenBranch {
|
||||||
|
patterns: vec![WhenBranchPattern {
|
||||||
|
pattern: Loc::at_zero(Pattern::AppliedTag {
|
||||||
|
whole_var: Variable::NULL, // TODO
|
||||||
|
ext_var: Variable::EMPTY_TAG_UNION,
|
||||||
|
tag_name: "Err".into(),
|
||||||
|
arguments: vec![(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Pattern::Identifier(err_val_symbol)),
|
||||||
|
)],
|
||||||
|
}),
|
||||||
|
degenerate: false,
|
||||||
|
}],
|
||||||
|
value: Loc::at_zero(Expr::Tag {
|
||||||
|
variant_var: Variable::NULL, // TODO
|
||||||
|
ext_var: Variable::NULL, // TODO
|
||||||
|
name: "Err".into(),
|
||||||
|
arguments: vec![(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(err_val_symbol)),
|
||||||
|
)],
|
||||||
|
}),
|
||||||
|
guard: None,
|
||||||
|
redundant: RedundantMark::known_non_redundant(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
Expr::When {
|
||||||
|
loc_cond: Box::new(Loc::at_zero(Expr::Access {
|
||||||
|
record_var: Variable::NULL, // TODO
|
||||||
|
ext_var: Variable::EMPTY_RECORD,
|
||||||
|
field_var: Variable::NULL, // TODO
|
||||||
|
loc_expr: Box::new(Loc::at_zero(Expr::Var(rec_symbol))),
|
||||||
|
field: "result".into(),
|
||||||
|
})),
|
||||||
|
cond_var: Variable::NULL, // TODO
|
||||||
|
expr_var: Variable::NULL, // TODO
|
||||||
|
region: Region::zero(),
|
||||||
|
branches,
|
||||||
|
branches_cond_var: Variable::NULL, // TODO
|
||||||
|
exhaustive: ExhaustiveMark::known_exhaustive(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fields_map.insert(
|
||||||
|
"result".into(),
|
||||||
|
Field {
|
||||||
|
var: Variable::NULL, // TODO
|
||||||
|
region: Region::zero(),
|
||||||
|
loc_expr: Box::new(Loc::at_zero(result_val)),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Expr::Record {
|
||||||
|
record_var: Variable::NULL, // TODO this is the type of the entire record
|
||||||
|
fields: fields_map,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let branch = WhenBranch {
|
||||||
|
patterns: vec![WhenBranchPattern {
|
||||||
|
pattern: Loc::at_zero(Pattern::Identifier(rec_symbol)),
|
||||||
|
degenerate: false,
|
||||||
|
}],
|
||||||
|
value: Loc::at_zero(branch_body),
|
||||||
|
guard: None,
|
||||||
|
redundant: RedundantMark::known_non_redundant(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let condition_expr = Expr::Call(
|
||||||
|
Box::new((
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(Symbol::DECODE_DECODE_WITH)),
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
)),
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(bytes_arg_symbol)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(Symbol::DECODE_DECODER)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Variable::NULL, // TODO
|
||||||
|
Loc::at_zero(Expr::Var(fmt_arg_symbol)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
CalledVia::Space,
|
||||||
|
);
|
||||||
|
|
||||||
|
Expr::When {
|
||||||
|
loc_cond: Box::new(Loc::at_zero(condition_expr)),
|
||||||
|
cond_var: Variable::NULL, // TODO
|
||||||
|
expr_var: Variable::NULL, // TODO
|
||||||
|
region: Region::zero(),
|
||||||
|
branches: vec![branch],
|
||||||
|
branches_cond_var: Variable::NULL, // TODO
|
||||||
|
exhaustive: ExhaustiveMark::known_exhaustive(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Expr::Closure(ClosureData {
|
Expr::Closure(ClosureData {
|
||||||
function_type: Variable::NULL, // TODO
|
function_type: Variable::NULL, // TODO
|
||||||
closure_type: Variable::NULL, // TODO
|
closure_type: Variable::NULL, // TODO
|
||||||
|
|
@ -128,9 +445,16 @@ fn decoder_step_field(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
||||||
|
|
||||||
let decode_custom = {
|
let decode_custom = {
|
||||||
// Decode.custom \bytes, fmt ->
|
// Decode.custom \bytes, fmt ->
|
||||||
|
// # Uses a single-branch `when` because `let` is more expensive to monomorphize
|
||||||
|
// # due to checks for polymorphic expressions, and `rec` would be polymorphic.
|
||||||
// when Decode.decodeWith bytes Decode.decoder fmt is
|
// when Decode.decodeWith bytes Decode.decoder fmt is
|
||||||
// {result, rest} ->
|
// rec ->
|
||||||
// {result: Result.map result \val -> {state & f0: Ok val}, rest}
|
// {
|
||||||
|
// rest: rec.rest,
|
||||||
|
// result: when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
// }
|
||||||
Expr::Call(
|
Expr::Call(
|
||||||
Box::new((
|
Box::new((
|
||||||
Variable::NULL, // TODO
|
Variable::NULL, // TODO
|
||||||
|
|
@ -148,9 +472,17 @@ fn decoder_step_field(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
||||||
|
|
||||||
let keep = {
|
let keep = {
|
||||||
// Keep (Decode.custom \bytes, fmt ->
|
// Keep (Decode.custom \bytes, fmt ->
|
||||||
|
// # Uses a single-branch `when` because `let` is more expensive to monomorphize
|
||||||
|
// # due to checks for polymorphic expressions, and `rec` would be polymorphic.
|
||||||
// when Decode.decodeWith bytes Decode.decoder fmt is
|
// when Decode.decodeWith bytes Decode.decoder fmt is
|
||||||
// {result, rest} ->
|
// rec ->
|
||||||
// {result: Result.map result \val -> {state & f0: Ok val}, rest})
|
// {
|
||||||
|
// rest: rec.rest,
|
||||||
|
// result: when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
// }
|
||||||
|
// )
|
||||||
Expr::Tag {
|
Expr::Tag {
|
||||||
variant_var: Variable::NULL, // TODO
|
variant_var: Variable::NULL, // TODO
|
||||||
ext_var: Variable::EMPTY_TAG_UNION,
|
ext_var: Variable::EMPTY_TAG_UNION,
|
||||||
|
|
@ -165,12 +497,20 @@ fn decoder_step_field(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
||||||
let branch = {
|
let branch = {
|
||||||
// "first" ->
|
// "first" ->
|
||||||
// Keep (Decode.custom \bytes, fmt ->
|
// Keep (Decode.custom \bytes, fmt ->
|
||||||
|
// # Uses a single-branch `when` because `let` is more expensive to monomorphize
|
||||||
|
// # due to checks for polymorphic expressions, and `rec` would be polymorphic.
|
||||||
// when Decode.decodeWith bytes Decode.decoder fmt is
|
// when Decode.decodeWith bytes Decode.decoder fmt is
|
||||||
// {result, rest} ->
|
// rec ->
|
||||||
// {result: Result.map result \val -> {state & f0: Ok val}, rest})
|
// {
|
||||||
|
// rest: rec.rest,
|
||||||
|
// result: when rec.result is
|
||||||
|
// Ok val -> Ok {state & first: Ok val},
|
||||||
|
// Err err -> Err err
|
||||||
|
// }
|
||||||
|
// )
|
||||||
WhenBranch {
|
WhenBranch {
|
||||||
patterns: vec![WhenBranchPattern {
|
patterns: vec![WhenBranchPattern {
|
||||||
pattern: Loc::at_zero(Pattern::StrLiteral(field.into())),
|
pattern: Loc::at_zero(Pattern::StrLiteral(field_name.into())),
|
||||||
degenerate: false,
|
degenerate: false,
|
||||||
}],
|
}],
|
||||||
value: Loc::at_zero(keep),
|
value: Loc::at_zero(keep),
|
||||||
|
|
@ -241,7 +581,7 @@ fn decoder_step_field(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
||||||
/// Ok second -> Ok {first, second}
|
/// Ok second -> Ok {first, second}
|
||||||
/// Err NoField -> Err TooShort
|
/// Err NoField -> Err TooShort
|
||||||
/// Err NoField -> Err TooShort
|
/// Err NoField -> Err TooShort
|
||||||
fn decoder_finalizer(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
fn decoder_finalizer(env: &mut Env, fields: &[Lowercase]) -> Expr {
|
||||||
let state_arg_symbol = env.new_symbol("stateRecord");
|
let state_arg_symbol = env.new_symbol("stateRecord");
|
||||||
let mut fields_map = SendMap::default();
|
let mut fields_map = SendMap::default();
|
||||||
let mut pattern_symbols = Vec::with_capacity(fields.len());
|
let mut pattern_symbols = Vec::with_capacity(fields.len());
|
||||||
|
|
@ -284,7 +624,7 @@ fn decoder_finalizer(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
||||||
ext_var: Variable::EMPTY_RECORD,
|
ext_var: Variable::EMPTY_RECORD,
|
||||||
field_var: Variable::NULL, // TODO
|
field_var: Variable::NULL, // TODO
|
||||||
loc_expr: Box::new(Loc::at_zero(Expr::Var(state_arg_symbol))),
|
loc_expr: Box::new(Loc::at_zero(Expr::Var(state_arg_symbol))),
|
||||||
field: field_name,
|
field: field_name.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Example: `Ok x -> expr`
|
// Example: `Ok x -> expr`
|
||||||
|
|
@ -358,8 +698,8 @@ fn decoder_finalizer(env: &mut Env, fields: Vec<Lowercase>) -> Expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Example:
|
/// Example:
|
||||||
/// initialState : {f0: Result a [NoField], f1: Result b [NoField]}
|
/// initialState : {first: Result a [NoField], second: Result b [NoField]}
|
||||||
/// initialState = {f0: Err NoField, f1: Err NoField}
|
/// initialState = {first: Err NoField, second: Err NoField}
|
||||||
fn decoder_initial_state(fields: &[Lowercase]) -> Expr {
|
fn decoder_initial_state(fields: &[Lowercase]) -> Expr {
|
||||||
let mut initial_state_fields = SendMap::default();
|
let mut initial_state_fields = SendMap::default();
|
||||||
for field_name in fields {
|
for field_name in fields {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue