Authorize complete patterns as function args.

This is mainly a syntactic trick/sugar, but it's been pretty annoying
  to me for a while that we can't simply pattern-match/destructure
  single-variant constructors directly from the args list. A classic
  example is when writing property tests:

  ```ak
  test foo(params via both(bytearray(), int())) {
    let (bytes, ix) = params
    ...
  }
  ```

  Now can be replaced simply with:

  ```
  test foo((bytes, ix) via both(bytearray(), int())) {
    ...
  }
  ```

  If feels natural, especially coming from the JavaScript, Haskell or
  Rust worlds and is mostly convenient. Behind the scene, the compiler
  does nothing more than re-writing the AST as the first form, with
  pre-generated arg names. Then, we fully rely on the existing
  type-checking capabilities and thus, works in a seamless way as if we
  were just pattern matching inline.
This commit is contained in:
KtorZ
2024-06-07 15:23:33 +02:00
parent b6da42baf2
commit 858dfccc82
23 changed files with 944 additions and 68 deletions

View File

@@ -2539,3 +2539,37 @@ fn mutually_recursive_1() {
assert!(check(parse(source_code)).is_ok());
}
#[test]
fn fn_single_variant_pattern() {
let source_code = r#"
pub type Foo {
a: Int
}
pub fn foo(Foo { a }) {
a + 1
}
"#;
assert!(dbg!(check(parse(source_code))).is_ok());
}
#[test]
fn fn_multi_variant_pattern() {
let source_code = r#"
type Foo {
A { a: Int }
B { b: Int }
}
pub fn foo(A { a }) {
a + 1
}
"#;
assert!(matches!(
dbg!(check_validator(parse(source_code))),
Err((_, Error::NotExhaustivePatternMatch { .. }))
))
}

View File

@@ -883,3 +883,68 @@ fn format_pairs() {
}"#
);
}
#[test]
fn format_fn_pattern() {
assert_format!(
r#"
pub fn foo(Foo { a, b, .. }) {
todo
}
pub fn bar([Bar] : List<Bar>) {
todo
}
pub fn baz((Baz, Baz) as x) {
todo
}
pub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {
todo
}
test buz((a, b) via some_fuzzer()) {
todo
}
"#
);
}
#[test]
fn format_anon_fn_pattern() {
assert_format!(
r#"
pub fn main() {
let foo = fn (Foo { a, b, .. }) { todo }
let bar = fn ([Bar] : List<Bar>) { todo }
let baz = fn ((Baz, Baz) as x) { todo }
let fiz = fn (Pair(fst, snd) as x: Pair<Int, Int>) { todo }
todo
}
"#
);
}
#[test]
fn format_validator_pattern() {
assert_format!(
r#"
validator(Foo { a, b, .. }) {
fn foo() { todo }
}
validator([Bar] : List<Bar>) {
fn bar() { todo }
}
validator((Baz, Baz) as x) {
fn baz() { todo }
}
validator((fst, snd) as x: Pair<Int, Int>) {
fn fiz() { todo }
}
"#
);
}

View File

@@ -0,0 +1,23 @@
---
source: crates/aiken-lang/src/tests/format.rs
description: "Code:\n\npub fn main() {\n let foo = fn (Foo { a, b, .. }) { todo }\n let bar = fn ([Bar] : List<Bar>) { todo }\n let baz = fn ((Baz, Baz) as x) { todo }\n let fiz = fn (Pair(fst, snd) as x: Pair<Int, Int>) { todo }\n todo\n}\n"
---
pub fn main() {
let foo =
fn(Foo { a, b, .. }) {
todo
}
let bar =
fn([Bar]: List<Bar>) {
todo
}
let baz =
fn((Baz, Baz) as x) {
todo
}
let fiz =
fn(Pair(fst, snd) as x: Pair<Int, Int>) {
todo
}
todo
}

View File

@@ -0,0 +1,23 @@
---
source: crates/aiken-lang/src/tests/format.rs
description: "Code:\n\npub fn foo(Foo { a, b, .. }) {\n todo\n}\n\npub fn bar([Bar] : List<Bar>) {\n todo\n}\n\npub fn baz((Baz, Baz) as x) {\n todo\n}\n\npub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {\n todo\n}\n\ntest buz((a, b) via some_fuzzer()) {\n todo\n}\n"
---
pub fn foo(Foo { a, b, .. }) {
todo
}
pub fn bar([Bar]: List<Bar>) {
todo
}
pub fn baz((Baz, Baz) as x) {
todo
}
pub fn fiz(Pair(fst, snd) as x: Pair<Int, Int>) {
todo
}
test buz((a, b) via some_fuzzer()) {
todo
}

View File

@@ -0,0 +1,27 @@
---
source: crates/aiken-lang/src/tests/format.rs
description: "Code:\n\nvalidator(Foo { a, b, .. }) {\n fn foo() { todo }\n}\n\nvalidator([Bar] : List<Bar>) {\n fn bar() { todo }\n}\n\nvalidator((Baz, Baz) as x) {\n fn baz() { todo }\n}\n\nvalidator((fst, snd) as x: Pair<Int, Int>) {\n fn fiz() { todo }\n}\n"
---
validator(Foo { a, b, .. }) {
fn foo() {
todo
}
}
validator([Bar]: List<Bar>) {
fn bar() {
todo
}
}
validator((Baz, Baz) as x) {
fn baz() {
todo
}
}
validator((fst, snd) as x: Pair<Int, Int>) {
fn fiz() {
todo
}
}