shelly-shell 0.5.0

A Rust based Unix style shell with a typed and structured language syntax.
# Builtin widget callbacks use the ordinary named function and array contracts.
fn widget_case($source: String, $stdout: String, $diagnostic: String)
{
    let $fixture = $args[0]
    let $reply = run_process [`$shelly, "-m", "-c", $source] [
        "cwd": $fixture, "env": ["HOME": $fixture, "PATH": "/usr/bin:/bin",
            "SHELLY_STD_PATH": "${fixture}/std", "TERM": "dumb", "LANG": "C.UTF-8"],
        "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 $status = if $diagnostic == "" { 0 } else { 1 }
    if ($out != $stdout) || ($reply["exit_code"] != $status) ||
        ($reply["error"] != ()) || ($reply["signal"] != ()) || $reply["timed_out"] ||
        (($diagnostic == "") && ($err != "")) ||
        (($diagnostic != "") && (!($err.contains $diagnostic)))
    { echo $source $reply $out $err; fail "widget callback mismatch" }
}

widget_case 'echo $widgets.count; let $copy: [WidgetFn] = $widgets; echo $copy.count' "0\n0\n" ""
widget_case 'echo ($widget_color.type == String) ($widget_color == "\x1b[38;2;49;216;224m"); $widget_color = "yellow"; echo $widget_color' "true true\nyellow\n" ""
widget_case '$widget_color = 7' "" "Expected String"
widget_case 'fn label(): String { "named" }; $widgets = [`label, fn (): String { "closure" }]; for $widget in $widgets { echo ($widget) ($widget.type == WidgetFn) }' "named true\nclosure true\n" ""
widget_case 'let $text = "before"; $widgets = [fn (): String { $text }]; $text = "after"; echo ($widgets[0])' "after\n" ""
widget_case '$widgets = [fn (): String { "first" }]; $widgets = [$widgets..., fn (): String { "second" }]; $widgets[0] = fn (): String { "changed" }; for $widget in $widgets { echo ($widget) }; $widgets = []; echo $widgets.count' "changed\nsecond\n0\n" ""
widget_case 'let $widget: WidgetFn = fn (): String { "typed" }; echo ($widget)' "typed\n" ""
widget_case '$widgets = [7]' "" "requires a bound function"
widget_case '$widgets = [fn ($n: Integer): String { String($n) }]' "" "arity is incompatible"
widget_case '$widgets = [fn (): Integer { 7 }]' "" "return type is incompatible"
widget_case '$widgets = [fn (): any { 7 }]; $widgets[0]' "" "Return value: Expected String"
widget_case '$widgets = [fn (): String { "good" }]; $widgets[0] = fn (): Integer { 7 }' "" "return type is incompatible"
widget_case '$widgets = [fn (): String { "good" }]; for $widget in $widgets { let $bad: Integer = ($widget) }' "" "Expected Integer, got String"

let $fixture = $args[0]
printf "%s" 'echo $widgets.count; pub let $callback: WidgetFn = fn (): String { "module" }; $widgets = [$callback]; pub fn widget_count(): Integer { $widgets.count }' -> "${fixture}/widget_module.shy"
widget_case 'import widget_module; echo (widget_module::widget_count) $widgets.count; echo ($widget_module::callback.type == WidgetFn)' "0\n1 0\ntrue\n" ""