Implement ? binop operator

This commit is contained in:
Sam Mohr 2025-01-16 02:44:32 -08:00
parent 9d37c906fe
commit b73e4387ae
No known key found for this signature in database
GPG key ID: EA41D161A3C1BC99
12 changed files with 291 additions and 55 deletions

View file

@ -972,10 +972,10 @@ mod test_can {
}
#[test]
fn try_desugar_double_question_suffix() {
fn try_desugar_double_question_binop() {
let src = indoc!(
r#"
Str.to_u64 "123" ?? Num.max_u64
Str.to_u64("123") ?? Num.max_u64
"#
);
let arena = Bump::new();
@ -985,33 +985,95 @@ mod test_can {
// Assert that we desugar to:
//
// when Str.to_u64 "123"
// Ok success_BRANCH1_0_9 -> success_BRANCH1_0_9
// Err _ -> Num.max_u64
// when Str.to_u64("123")
// Ok(double_question_ok_0_17) -> Ok(double_question_ok_0_17)
// Err(_) -> Num.max_u64
let (cond_expr, branches) = assert_when(&out.loc_expr.value);
let cond_args = assert_func_call(cond_expr, "to_u64", CalledVia::Space, &out.interns);
assert_eq!(cond_args.len(), 1);
assert_str_value(&cond_args[0].1.value, "123");
assert_eq!(branches.len(), 2);
assert_eq!(branches[0].patterns.len(), 1);
assert_eq!(branches[1].patterns.len(), 1);
assert_pattern_tag_apply_with_ident(
&branches[0].patterns[0].pattern.value,
"Ok",
"success_BRANCH1_0_16",
"double_question_ok_0_17",
&out.interns,
);
assert_var_usage(
&branches[0].value.value,
"success_BRANCH1_0_16",
"double_question_ok_0_17",
&out.interns,
);
assert_pattern_tag_apply_with_underscore(&branches[1].patterns[0].pattern.value, "Err");
assert_var_usage(&branches[1].value.value, "max_u64", &out.interns);
}
#[test]
fn try_desugar_single_question_binop() {
let src = indoc!(
r#"
Str.to_u64("123") ? FailedToConvert
"#
);
let arena = Bump::new();
let out = can_expr_with(&arena, test_home(), src);
assert_eq!(out.problems, Vec::new());
// Assert that we desugar to:
//
// when Str.to_u64("123")
// Ok(single_question_ok_0_17) -> single_question_ok_0_17
// Err(single_question_err_0_17) -> return Err(FailedToConvert(single_question_err_0_17))
let (cond_expr, branches) = assert_when(&out.loc_expr.value);
let cond_args = assert_func_call(cond_expr, "to_u64", CalledVia::Space, &out.interns);
assert_eq!(cond_args.len(), 1);
assert_str_value(&cond_args[0].1.value, "123");
assert_eq!(branches.len(), 2);
assert_eq!(branches[0].patterns.len(), 1);
assert_eq!(branches[1].patterns.len(), 1);
assert_pattern_tag_apply_with_ident(
&branches[0].patterns[0].pattern.value,
"Ok",
"single_question_ok_0_17",
&out.interns,
);
assert_var_usage(
&branches[0].value.value,
"single_question_ok_0_17",
&out.interns,
);
assert_pattern_tag_apply_with_ident(
&branches[1].patterns[0].pattern.value,
"Err",
"single_question_err_0_17",
&out.interns,
);
let err_expr = assert_return_expr(&branches[1].value.value);
let mapped_err = assert_tag_application(err_expr, "Err");
assert_eq!(mapped_err.len(), 1);
let inner_err = assert_tag_application(&mapped_err[0].1.value, "FailedToConvert");
assert_eq!(inner_err.len(), 1);
assert_var_usage(
&inner_err[0].1.value,
"single_question_err_0_17",
&out.interns,
);
}
#[test]
fn try_desugar_works_elsewhere() {
let src = indoc!(
@ -1192,6 +1254,13 @@ mod test_can {
}
}
fn assert_return_expr(expr: &Expr) -> &Expr {
match expr {
Expr::Return { return_value, .. } => &return_value.value,
_ => panic!("Expr was not a Return: {:?}", expr),
}
}
// TAIL CALLS
fn get_closure(expr: &Expr, i: usize) -> roc_can::expr::Recursive {
match expr {