let $failed = 0
fn destructure_case($source: String, $expected: String, $diagnostic: String)
{
let $fixture = $args[0]
let $result = run_process [`$shelly, "-m", "-c", $source] ["cwd": $fixture,
"env": ["HOME": $fixture, "PATH": "/usr/bin:/bin", "SHELLY_STD_PATH": ""],
"stdin_file": "/dev/null", "stdout_file": "${fixture}/out",
"stderr_file": "${fixture}/err", "timeout_ms": 3000]
let $out: String
let $err: String
"${fixture}/out" -> $out
"${fixture}/err" -> $err
let $exit = if $diagnostic == "" { 0 } else { 1 }
if ($result["exit_code"] != $exit) || ($result["signal"] != ())
|| ($result["error"] != ()) || $result["timed_out"] || ($out != $expected)
|| (($diagnostic == "") && ($err != ""))
|| (($diagnostic != "") && !($err.contains $diagnostic))
{ echo $source $result $out $err; $failed = $failed + 1 }
}
destructure_case 'let ($x, $y) = [22, 44]; echo $x $y' "22 44\n" ""
destructure_case 'let ($x, $y) = ([22, 44]); echo $x $y' "22 44\n" ""
destructure_case 'let ($x,) = [22]; echo $x; let (_) = [()]; let (_, _) = [(), ()]' "22\n" ""
destructure_case 'let $_ = "kept"; let (_, $y, _) = [1, 2, 3]; echo $_ $y; let ($_, $x) = [4,5]; echo $_ $x' "kept 2\n4 5\n" ""
destructure_case 'let (\n$x, # first\n_,\n$y,\n) = [1, 2, 3]; echo $x $y' "1 3\n" ""
destructure_case 'let $x = 1; let $y = 2; let ($x, $y) = [$y, $x]; echo $x $y' "2 1\n" ""
destructure_case 'let $calls = 0; fn pair(): [Integer, Integer] { $calls = $calls + 1; [22,44] }; let ($x, $y) = pair; echo $x $y $calls' "22 44 1\n" ""
destructure_case 'let $pair: [String, Integer] = ["hi", 7]; let ($text, $count) = $pair; let $s: String = $text; let $n: Integer = $count; echo $s $n' "hi 7\n" ""
destructure_case 'let ($a, $b) = ["hi", 2.5]; let $s: String = $a; let $f: Float = $b; echo $s $f' "hi 2.5\n" ""
destructure_case 'let $items = [1,2]; let ($x, $y) = [$items...]; echo $x $y; echo $items...' "1 2\n1 2\n" ""
destructure_case 'let $pair = [[1], [2]]; let ($a, $b) = $pair; $a[0] = 9; echo $a... $b... $pair[0]...' "9 2 1\n" ""
destructure_case 'let $x = 1; { let ($x, $y) = [2,3]; echo $x $y }; echo $x' "2 3\n1\n" ""
destructure_case 'fn make(): fn(): Integer { let ($x, $y) = [22,44]; fn(): Integer { $x + $y } }; let $f = make; echo ($f)' "66\n" ""
destructure_case 'let $x = 10; let $f = fn(): Integer { let ($x, $y) = [$x, 2]; $x + $y }; echo ($f) $x' "12 10\n" ""
destructure_case 'let ($x, $y) = [1,2]; let $f = fn(): Integer { $x + $y }; $x = 10; echo ($f)' "12\n" ""
destructure_case 'type Pair = [Integer, Integer]; let ($x, $y) = Pair([22,44]); echo $x $y' "22 44\n" ""
destructure_case '[when true] { let ($x, $y) = [22,44] }; echo $x $y' "22 44\n" ""
destructure_case 'try {} finally { let ($x, $y) = [22,44]; let $sum: Integer = $x + $y }; echo completed' "completed\n" ""
destructure_case 'let export ($LEFT, $RIGHT) = ["22","44"]; printenv LEFT; printenv RIGHT' "22\n44\n" ""
# Too few and too many items both fail before creating any bindings.
for $array in ['[]', '[22]', '[22,44,66]']
{ destructure_case ("let (\$x, \$y) = ${array}; echo wrong") "" "Array destructuring expected 2 elements" }
for $value in ['3', '"text"', '()', '["x": 1]']
{ destructure_case ("let (\$x, \$y) = ${value}; echo wrong") "" "Array destructuring requires an array" }
destructure_case 'let (_, _) = [1]' "" "Array destructuring expected 2 elements, got 1"
destructure_case 'let ($x,) = [1,2]' "" "Array destructuring expected 1 elements, got 2"
destructure_case 'let ($x, $x) = [1,2]' "" "Duplicate destructuring binding"
destructure_case 'let ($x, _, $x) = [1,2,3]' "" "Duplicate destructuring binding"
destructure_case 'let () = []' "" "Expected token: Identifier"
destructure_case 'let ($x, label) = [1,2]' "" "Expected token: Identifier"
destructure_case 'let ($x, ($y, $z)) = [1,[2,3]]' "" "Expected token: Identifier"
destructure_case 'let ($mod::x, $y) = [1,2]' "" "unqualified name"
destructure_case 'let ($x, $y)' "" "expected token: Assign"
destructure_case 'let ($x, $y) =' "" "Unexpected end of file"
destructure_case 'let ($x, $y) = [22,44]; let $bad: String = $x' "" "Expected String, got Integer"
destructure_case 'let ($items, $n) = [[Integer], 3]; $items = ["bad"]' "" "Expected Integer, got String"
destructure_case 'let $pair: [String, Integer] = ["hi",7]; let ($a, $b) = $pair; let $bad: String = $b' "" "Expected String, got Integer"
destructure_case 'fn bad(): String { let ($x, $y) = [22,44]; $x }' "" "Expected String, got Integer"
destructure_case '{ pub let ($x, $y) = [22,44] }' "" "pub is only allowed at module top level"
destructure_case '{ pub let (_, _) = [22,44] }' "" "pub is only allowed at module top level"
# Every public name from the pattern is exported, while private bindings stay private.
let $fixture = $args[0]
printf "%s" 'pub let ($x, $y) = [22,44]; let ($secret, $hidden) = [1,2]' -> "${fixture}/pairs.shy"
destructure_case 'import pairs::{ $x, $y }; echo $x $y' "22 44\n" ""
destructure_case 'import pairs; echo $pairs::x $pairs::y' "22 44\n" ""
destructure_case 'import pairs::{ $hidden }' "" "has no member"
require ($failed == 0) "let destructuring differs"