spiral¶

In [ ]:
open file_system_operators
open rust.rust_operators
open rust
open sm'_operators
In [ ]:
//// test

open testing

get_args¶

In [ ]:
inl get_args () =
    {
        fsharp = "fsharp", {
            spi_path = "spi-path", 's'
        }
        gleam = "gleam", {
            gleam_path = "gleam-path", 'g'
            target = "target", 't'
            deps = "deps", 'd'
        }
        cuda = "cuda", {
            py_path = "py-path", 'p'
            env = "env", 'e'
            deps = "deps", 'd'
        }
        fable = "fable", {
            fs_path = "fs-path", 'f'
            command = "command", 'c'
        }
        rust = "rust", {
            fs_path = "fs-path", 'f'
            deps = "deps", 'd'
            wasm = "wasm", 'w'
            contract = "contract", 'c'
            cleanup = "cleanup", 'l'
        }
        typescript = "typescript", {
            fs_path = "fs-path", 'f'
            deps = "deps", 'd'
        }
        python = "python", {
            fs_path = "fs-path", 'f'
            deps = "deps", 'd'
        }
        dib = "dib", {
            path = "path", 'p'
            retries = "retries", 'r'
            working_directory = "working-directory", 'w'
        }
    }

cuda_env¶

In [ ]:
union cuda_env =
    | Pip
    | Poetry

gleam_target¶

In [ ]:
union gleam_target =
    | Erlang
    | JavaScript

get_command¶

In [ ]:
let get_command () =
    ##"command"
    |> runtime.new_command
    |> runtime.command_subcommand_required true
    |> runtime.command_subcommand (
        ##(get_args () .fsharp |> fst)
        |> runtime.new_command
        |> runtime.command_init_arg ((get_args () .fsharp |> snd).spi_path) (
            runtime.arg_required true
        )
    )
    |> runtime.command_subcommand (
        ##(get_args () .gleam |> fst)
        |> runtime.new_command
        |> runtime.command_init_arg ((get_args () .gleam |> snd).gleam_path) (
            runtime.arg_required true
        )
        |> runtime.command_init_arg ((get_args () .gleam |> snd).target) (
            real runtime.arg_union `gleam_target ignore
        )
        |> runtime.command_init_arg ((get_args () .gleam |> snd).deps) (
            runtime.arg_value_names ;[ ##"NAME"; ##"VERSION" ]
            >> runtime.arg_num_args_range (
                runtime.new_value_range
                    false
                    (am'.Start (1i32 |> convert : unativeint))
                    (am'.End eval)
            )
            >> runtime.arg_action runtime.Append
        )
    )
    |> runtime.command_subcommand (
        ##(get_args () .cuda |> fst)
        |> runtime.new_command
        |> runtime.command_init_arg ((get_args () .cuda |> snd).py_path) (
            runtime.arg_required true
        )
        |> runtime.command_init_arg ((get_args () .cuda |> snd).env) (
            real runtime.arg_union `cuda_env ignore
        )
        |> runtime.command_init_arg ((get_args () .cuda |> snd).deps) (
            runtime.arg_value_names ;[ ##"NAME"; ##"VERSION" ]
            >> runtime.arg_num_args_range (
                runtime.new_value_range
                    false
                    (am'.Start (1i32 |> convert : unativeint))
                    (am'.End eval)
            )
            >> runtime.arg_action runtime.Append
        )
    )
    |> runtime.command_subcommand (
        ##(get_args () .fable |> fst)
        |> runtime.new_command
        |> runtime.command_init_arg ((get_args () .fable |> snd).fs_path) (
            runtime.arg_required true
        )
        |> runtime.command_init_arg ((get_args () .fable |> snd).command) (
            id
        )
    )
    |> runtime.command_subcommand (
        ##(get_args () .rust |> fst)
        |> runtime.new_command
        |> runtime.command_init_arg ((get_args () .rust |> snd).fs_path) (
            runtime.arg_required true
        )
        |> runtime.command_init_arg ((get_args () .rust |> snd).deps) (
            runtime.arg_value_names ;[ ##"NAME"; ##"VERSION" ]
            >> runtime.arg_num_args_range (
                runtime.new_value_range
                    false
                    (am'.Start (1i32 |> convert : unativeint))
                    (am'.End eval)
            )
            >> runtime.arg_action runtime.Append
        )
        |> runtime.command_init_arg ((get_args () .rust |> snd).wasm) (
            runtime.arg_num_args_range (
                runtime.new_value_range
                    true
                    (am'.End eval)
                    (am'.End fun _ => (1i32 |> convert : unativeint))
            )
            >> runtime.arg_require_equals true
            >> runtime.arg_default_missing_value ""
        )
        |> runtime.command_init_arg ((get_args () .rust |> snd).contract) (
            runtime.arg_num_args_range (
                runtime.new_value_range
                    true
                    (am'.End eval)
                    (am'.End fun _ => (1i32 |> convert : unativeint))
            )
            >> runtime.arg_require_equals true
            >> runtime.arg_default_missing_value ""
        )
        |> runtime.command_init_arg ((get_args () .rust |> snd).cleanup) (
            runtime.arg_default_value "true"
            >> runtime.arg_action runtime.SetFalse
        )
    )
    |> runtime.command_subcommand (
        ##(get_args () .typescript |> fst)
        |> runtime.new_command
        |> runtime.command_init_arg ((get_args () .typescript |> snd).fs_path) (
            runtime.arg_required true
        )
        |> runtime.command_init_arg ((get_args () .typescript |> snd).deps) (
            runtime.arg_value_names ;[ ##"NAME"; ##"VERSION" ]
            >> runtime.arg_num_args_range (
                runtime.new_value_range
                    false
                    (am'.Start (1i32 |> convert : unativeint))
                    (am'.End eval)
            )
            >> runtime.arg_action runtime.Append
        )
    )
    |> runtime.command_subcommand (
        ##(get_args () .python |> fst)
        |> runtime.new_command
        |> runtime.command_init_arg ((get_args () .python |> snd).fs_path) (
            runtime.arg_required true
        )
        |> runtime.command_init_arg ((get_args () .python |> snd).deps) (
            runtime.arg_value_names ;[ ##"NAME"; ##"VERSION" ]
            >> runtime.arg_num_args_range (
                runtime.new_value_range
                    false
                    (am'.Start (1i32 |> convert : unativeint))
                    (am'.End eval)
            )
            >> runtime.arg_action runtime.Append
        )
    )
    |> runtime.command_subcommand (
        ##(get_args () .dib |> fst)
        |> runtime.new_command
        |> runtime.command_init_arg ((get_args () .dib |> snd).path) (
            runtime.arg_required true
            // >> runtime.arg_value_parser (runtime.value_parser_path_buf ())
        )
        |> runtime.command_init_arg ((get_args () .dib |> snd).retries) (
            runtime.arg_value_parser (runtime.value_parser_expr "u8")
        )
        |> runtime.command_init_arg ((get_args () .dib |> snd).working_directory) (
            id
        )
    )

fable¶

fable_target¶

In [ ]:
union fable_target =
    | Rust
    | TypeScript
    | Python

fable_runtime¶

In [ ]:
union fable_runtime =
    | Wasm : string
    | Contract : string

execute_dotnet_fable¶

In [ ]:
let execute_dotnet_fable { workspace_root_external fsproj_path extension package_dir runtime } =
    open runtime
    execution_options fun x => { x with
        command =
            inl platform =
                if platform.is_windows ()
                then "_WINDOWS"
                else "_LINUX"
            inl platform : string = $'$" --define {!platform}"'
            inl runtime =
                match runtime with
                | Some (runtime : fable_runtime) =>
                    inl runtime = runtime |> reflection.union_to_string |> sm'.to_upper
                    $'$" --define {!runtime}"'
                | None => ""
            $'$"dotnet fable \\\"{!fsproj_path}\\\" --optimize --lang {!extension} --extension .{!extension} --outDir \\\"{!package_dir}\\\"{!platform}{!runtime}"'
        working_directory = workspace_root_external |> resultm.box |> resultm.ok'
    }
    |> execute_retry 3u8

get_package_dir¶

In [ ]:
let get_package_dir { workspace_root target name hash } =
    inl dir = workspace_root </> "target/spiral" </> name
    match hash, (target : option fable_target) with
    | Some hash, Some target => dir </> "packages" </> (target |> reflection.union_to_string) </> hash
    | _ => dir

persist_code_project¶

In [ ]:
let persist_code_project { workspace_root package_dir packages modules name code } =
    package_dir |> file_system.create_dir |> ignore

    inl fs_path = package_dir </> $'$"{!name}.fs"' |> file_system.normalize_path
    code |> file_system.write_all_text_exists fs_path

    inl modules_code =
        modules
        |> listm.map fun path =>
            inl path = workspace_root </> path
            $'$"<Compile Include=\\\"{!path}\\\" />"' : string
        |> listm'.box
        |> seq.of_list'
        |> sm'.concat "\\n        "

    inl packages_code =
        packages
        |> listm.map fun (package : string), (version : string) =>
            $'$"<PackageReference Include=\\\"{!package}\\\" Version=\\\"{!version}\\\" />"' : string
        |> listm'.box
        |> seq.of_list'
        |> sm'.concat "\\n        "

    inl fsproj_path = package_dir </> $'$"{!name}.fsproj"' |> file_system.normalize_path
    inl fsproj_code : string =
        $'$"<Project Sdk=\\\"Microsoft.NET.Sdk\\\">"'
        ++\# $'$"<PropertyGroup>"'
        ++\# $'$"    <TargetFramework>net9.0</TargetFramework>"'
        ++\# $'$"    <LangVersion>preview</LangVersion>"'
        ++\# $'$"    <RollForward>Major</RollForward>"'
        ++\# $'$"    <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>"'
        ++\# $'$"    <PublishAot>false</PublishAot>"'
        ++\# $'$"    <PublishTrimmed>false</PublishTrimmed>"'
        ++\# $'$"    <PublishSingleFile>true</PublishSingleFile>"'
        ++\# $'$"    <SelfContained>true</SelfContained>"'
        ++\# $'$"    <Version>0.0.1-alpha.1</Version>"'
        ++\# $'$"    <OutputType>Exe</OutputType>"'
        ++\# $'$"    <ServerGarbageCollection>true</ServerGarbageCollection>"'
        ++\# $'$"    <ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>"'
        ++\# $'$"</PropertyGroup>"'

        ++\# $'$"<PropertyGroup Condition=\\\"$([MSBuild]::IsOSPlatform(\'FreeBSD\'))\\\">"'
        ++\# $'$"    <DefineConstants>_FREEBSD</DefineConstants>"'
        ++\# $'$"</PropertyGroup>"'

        ++\# $'$"<PropertyGroup Condition=\\\"$([MSBuild]::IsOSPlatform(\'Linux\'))\\\">"'
        ++\# $'$"    <DefineConstants>_LINUX</DefineConstants>"'
        ++\# $'$"</PropertyGroup>"'

        ++\# $'$"<PropertyGroup Condition=\\\"$([MSBuild]::IsOSPlatform(\'OSX\'))\\\">"'
        ++\# $'$"    <DefineConstants>_OSX</DefineConstants>"'
        ++\# $'$"</PropertyGroup>"'

        ++\# $'$"<PropertyGroup Condition=\\\"$([MSBuild]::IsOSPlatform(\'Windows\'))\\\">"'
        ++\# $'$"    <DefineConstants>_WINDOWS</DefineConstants>"'
        ++\# $'$"</PropertyGroup>"'

        ++\# $'$"<ItemGroup>"'
        ++\# $'$"    {!modules_code}"'
        ++\# $'$"    <Compile Include=\\\"{!fs_path}\\\" />"'
        ++\# $'$"</ItemGroup>"'

        ++\# $'$"<ItemGroup>"'
        ++\# $'$"    {!packages_code}"'
        ++\# $'$"</ItemGroup>"'

        ++\# $'$"</Project>"'

    fsproj_code |> file_system.write_all_text_exists fsproj_path

    fsproj_path

publish_project¶

In [ ]:
inl publish_project runtime' output_dir path =
    inl full_path = path |> file_system.get_full_path
    inl file_dir = full_path |> file_system.directory_get_parent |> optionm'.default_value' ""
    inl extension = full_path |> file_system.get_extension

    trace Debug
        fun () => "publish_project"
        fun () => { full_path }

    match extension with
    | "fsproj" => ()
    | _ => failwith $'$"app.publish_project / Invalid project file / extension: {!extension}"'

    inl runtimes =
        runtime'
        |> optionm.map listm.singleton
        |> optionm'.default_value [ "linux-x64"; "win-x64" ]

    inl output_dir = output_dir |> optionm'.default_value "dist"

    runtimes
    |> listm.map fun runtime' =>
        runtime.execution_options fun x => { x with
            command = $'$@@"dotnet publish \"\"{!path}\"\" --configuration Release --output \"\"{!output_dir}\"\" --runtime {!runtime'}"'
            working_directory = file_dir |> Some |> optionm'.box
        }
        |> runtime.execute_with_options
        |> fst
    |> listm'.sum

publish_code¶

In [ ]:
inl publish_code { workspace_root runtime packages modules output_dir name code } =
    inl package_dir = get_package_dir { workspace_root name target = None; hash = None }
    inl fsproj_path = persist_code_project { workspace_root package_dir packages modules name code }
    inl exit_code = fsproj_path |> publish_project runtime output_dir
    if exit_code <>. 0 then
        trace Critical
            fun () => "publish_code"
            fun () => {
                code = code |> sm'.ellipsis_end 400
                fsproj_text = fsproj_path |> file_system.read_all_text
            }
    exit_code
In [ ]:
//// test
///! rust -d encoding_rs encoding_rs_io regex

publish_code {
    workspace_root = file_system.get_workspace_root ()
    runtime = None
    packages = []
    modules = []
    output_dir = None
    name = "test1"
    code = "1 + 1 |> ignore"
}
|> _assert_eq 0
00:00:00 v #1 file_system.create_dir / { dir = /home/runner/work/spiral/polyglot/target/spiral/test1 }
00:00:00 d #2 publish_project / { full_path = /home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj }
00:00:00 d #3 runtime.execute_with_options / { file_name = dotnet; arguments = ["publish", "/home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj", "--configuration", "Release", "--output", "dist", "--runtime", "win-x64"]; options = { command = dotnet publish "/home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj" --configuration Release --output "dist" --runtime win-x64; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = Some(
    "/home/runner/work/spiral/polyglot/target/spiral/test1",
); stderr = true } }
00:00:00 v #4 >   Determining projects to restore...
00:00:01 v #5 >   Restored /home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj (in 429 ms).
00:00:02 v #6 > /home/runner/work/spiral/polyglot/target/spiral/test1/test1.fs(1,16): warning FS0988: Main module of program is empty: nothing will happen when it is run [/home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj]
00:00:02 v #7 >   test1 -> /home/runner/work/spiral/polyglot/target/spiral/test1/bin/Release/net9.0/win-x64/test1.dll
00:00:03 v #8 >   test1 -> /home/runner/work/spiral/polyglot/target/spiral/test1/dist
00:00:03 v #9 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 523 }
00:00:03 d #10 runtime.execute_with_options / { file_name = dotnet; arguments = ["publish", "/home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj", "--configuration", "Release", "--output", "dist", "--runtime", "linux-x64"]; options = { command = dotnet publish "/home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj" --configuration Release --output "dist" --runtime linux-x64; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = Some(
    "/home/runner/work/spiral/polyglot/target/spiral/test1",
); stderr = true } }
00:00:03 v #11 >   Determining projects to restore...
00:00:04 v #12 >   Restored /home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj (in 238 ms).
00:00:05 v #13 > /home/runner/work/spiral/polyglot/target/spiral/test1/test1.fs(1,16): warning FS0988: Main module of program is empty: nothing will happen when it is run [/home/runner/work/spiral/polyglot/target/spiral/test1/test1.fsproj]
00:00:06 v #14 >   test1 -> /home/runner/work/spiral/polyglot/target/spiral/test1/bin/Release/net9.0/linux-x64/test1.dll
00:00:06 v #15 >   test1 -> /home/runner/work/spiral/polyglot/target/spiral/test1/dist
00:00:06 v #16 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 525 }
{ name = __assert_eq; actual = 0; expected = 0 }
In [ ]:
//// test
///! rust -d encoding_rs encoding_rs_io regex

publish_code {
    workspace_root = file_system.get_workspace_root ()
    runtime = None
    packages = []
    modules = []
    output_dir = None
    name = "test2"
    code = "1 + a |> ignore"
}
|> _assert_eq 2
00:00:00 v #1 file_system.create_dir / { dir = /home/runner/work/spiral/polyglot/target/spiral/test2 }
00:00:00 d #2 publish_project / { full_path = /home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj }
00:00:00 d #3 runtime.execute_with_options / { file_name = dotnet; arguments = ["publish", "/home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj", "--configuration", "Release", "--output", "dist", "--runtime", "win-x64"]; options = { command = dotnet publish "/home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj" --configuration Release --output "dist" --runtime win-x64; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = Some(
    "/home/runner/work/spiral/polyglot/target/spiral/test2",
); stderr = true } }
00:00:00 v #4 >   Determining projects to restore...
00:00:01 v #5 >   Restored /home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj (in 275 ms).
00:00:02 v #6 > /home/runner/work/spiral/polyglot/target/spiral/test2/test2.fs(1,5): error FS0039: The value or constructor 'a' is not defined. [/home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj]
00:00:02 v #7 runtime.execute_with_options / result / { exit_code = 1; std_trace_length = 324 }
00:00:02 d #8 runtime.execute_with_options / { file_name = dotnet; arguments = ["publish", "/home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj", "--configuration", "Release", "--output", "dist", "--runtime", "linux-x64"]; options = { command = dotnet publish "/home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj" --configuration Release --output "dist" --runtime linux-x64; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = Some(
    "/home/runner/work/spiral/polyglot/target/spiral/test2",
); stderr = true } }
00:00:02 v #9 >   Determining projects to restore...
00:00:03 v #10 >   Restored /home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj (in 260 ms).
00:00:04 v #11 > /home/runner/work/spiral/polyglot/target/spiral/test2/test2.fs(1,5): error FS0039: The value or constructor 'a' is not defined. [/home/runner/work/spiral/polyglot/target/spiral/test2/test2.fsproj]
00:00:04 v #12 runtime.execute_with_options / result / { exit_code = 1; std_trace_length = 324 }
00:00:04 c #13 publish_code / { code = 1 + a |> ignore; fsproj_text = <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <LangVersion>preview</LangVersion>
    <RollForward>Major</RollForward>
    <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
    <PublishAot>false</PublishAot>
    <PublishTrimmed>false</PublishTrimmed>
    <PublishSingleFile>true</PublishSingleFile>
    <SelfContained>true</SelfContained>
    <Version>0.0.1-alpha.1</Version>
    <OutputType>Exe</OutputType>
    <ServerGarbageCollection>true</ServerGarbageCollection>
    <ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('FreeBSD'))">
    <DefineConstants>_FREEBSD</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Linux'))">
    <DefineConstants>_LINUX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('OSX'))">
    <DefineConstants>_OSX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
    <DefineConstants>_WINDOWS</DefineConstants>
</PropertyGroup>
<ItemGroup>
    
    <Compile Include="/home/runner/work/spiral/polyglot/target/spiral/test2/test2.fs" />
</ItemGroup>
<ItemGroup>
    
</ItemGroup>
</Project> }
{ name = __assert_eq; actual = 2; expected = 2 }

read_file¶

In [ ]:
inl read_file path =
    inl code =
        path
        |> file_system.read_all_text
        |> sm'.replace_regex $'@@"(?P<a> *)(?P<b>let\\s+main\\s+.*?\\s*=)"' "$a[<EntryPoint>]\n$a$b"
    inl code_trim = code |> sm'.trim_end []
    if code_trim |> sm'.ends_with "\\n()"
    then code_trim |> sm'.slice 0i64 ((code_trim |> sm'.length) - 3)
    else code

persist_file¶

In [ ]:
inl persist_file { workspace_root package_dir packages modules path } =
    inl full_path = path |> file_system.get_full_path
    inl name = full_path |> file_system.get_file_name_without_extension
    inl code = full_path |> read_file
    persist_code_project { workspace_root package_dir packages modules name code }

publish_file¶

In [ ]:
inl publish_file { workspace_root runtime packages modules path } =
    inl full_path = path |> file_system.get_full_path
    inl dir = full_path |> file_system.directory_get_parent |> optionm'.default_value' ""
    publish_code {
        workspace_root
        runtime
        packages
        modules
        output_dir = dir </> "dist" |> Some
        name = full_path |> file_system.get_file_name_without_extension
        code = full_path |> read_file
    }

rust¶

get_workspace_cargo_toml_content¶

In [ ]:
inl get_workspace_cargo_toml_content { workspace_root } : string =
    inl workspace_root = workspace_root |> file_system.normalize_path
    $'$"cargo-features = [\\\"profile-rustflags\\\"]"'
    ++\# $'$""'
    ++\# $'$"[workspace]"'
    ++\# $'$"resolver = \\\"2\\\""'
    ++\# $'$"members = [\\\"packages/Rust/*\\\"]"'
    ++\# $'$""'
    ++\# $'$"[workspace.dependencies.fable_library_rust]"'
    ++\# $'$"path = \\\"{!workspace_root}/lib/rust/fable/fable_modules/fable-library-rust\\\""'
    ++\# $'$"default-features = false"'
    ++\# $'$"features = []"'
    ++\# $'$""'
    ++\# $'$"[workspace.dependencies]"'
    ++\# $'$"inline_colorization = \\\"~0.1\\\""'
    ++\# $'$""'
    ++\# $'$"[profile.release]"'
    ++\# $'$"codegen-units = 1"'
    ++\# $'$"opt-level = \\\"z\\\""'
    ++\# $'$"lto = true"'
    ++\# $'$"debug = false"'
    ++\# $'$"panic = \\\"abort\\\""'
    ++\# $'$"overflow-checks = true"'
    ++\# $'$"rustflags = [\\\"-C\\\", \\\"link-arg=-s\\\"]"'

get_cargo_toml_content¶

In [ ]:
inl get_cargo_toml_content { hash_hex runtime deps static_do_bindings } : string =
    $'$"cargo-features = [\\\"edition2024\\\"]"'
    ++\# $'$""'
    ++\# $'$"[package]"'
    ++\# $'$"name = \\\"spiral_{!hash_hex}\\\""'
    ++\# $'$"version = \\\"0.0.1\\\""'
    ++\# $'$"edition = \\\"2024\\\""'
    ++\# $'$""'
    ++\# $'$"[dependencies]"'
    ++\# (
        if runtime <>. None
        then $'$"fable_library_rust = {{ workspace = true }}"'
        else
            $'$"fable_library_rust = {{"'
            +. $'$" workspace = true,"'
            +. $'$" features = ["'
            +. (
                if static_do_bindings
                then $'$"\\\"static_do_bindings\\\", \\\"datetime\\\", \\\"guid\\\", \\\"threaded\\\""'
                else $'$"\\\"datetime\\\", \\\"guid\\\", \\\"threaded\\\""'
            )
            +. $'$"]"'
            +. $'$"}}"'
    )
    ++\# $'$"inline_colorization = {{ workspace = true }}"'
    ++\# $'$"{!deps}"'
    ++\# $'$""'
    ++\# (
        if runtime = None then
            $'$"[[bin]]"'
            ++\# $'$"name = \\\"spiral_{!hash_hex}\\\""'
        else
            $'$"[lib]"'
            ++\# $'$"crate-type = [\\\"cdylib\\\"]"'
    )
    ++\# $'$"path = \\\"spiral.rs\\\""'

get_empty_cargo_toml_content¶

In [ ]:
inl get_empty_cargo_toml_content () =
    inl guid = date_time.now () |> date_time.new_guid_from_date_time |> sm'.obj_to_string
    $'$"[package]"'
    ++\# $'$"name = \\\"spiral_{!guid}\\\""'
    ++\# $'$"version = \\\"0.0.1\\\""'
    ++\# $'$"edition = \\\"2021\\\""'
    ++\# $'$""'
    ++\# $'$"[[bin]]"'
    ++\# $'$"name = \\\"spiral_{!guid}\\\""'
    ++\# $'$"path = \\\"spiral.rs\\\""'

process_rust¶

In [ ]:
inl process_rust { fs_path deps trace_level runtime cleanup } =
    open runtime

    inl extension = "rs"
    inl code = fs_path |> file_system.read_all_text

    inl hash_hex = { extension code runtime } |> sm'.format |> crypto.hash_text

    inl workspace_name = "spiral"

    inl workspace_root_external = file_system.get_workspace_root_external ()
    inl workspace_root = workspace_root_external |> resultm.box |> resultm.unwrap_or_else id

    inl package_dir =
        get_package_dir { workspace_root name = workspace_name; target = Some Rust; hash = Some hash_hex }

    inl fsproj_path =
        persist_code_project {
            workspace_root
            package_dir
            packages = [ "Fable.Core", "4.3.0" ]
            modules = []
            name = workspace_name
            code
        }

    inl workspace_dir = package_dir </> "../../.."
    inl workspace_cargo_toml_path = workspace_dir </> "Cargo.toml"

    if workspace_cargo_toml_path |> file_system.file_exists |> not
    then get_empty_cargo_toml_content () |> file_system.write_all_text workspace_cargo_toml_path

    inl cargo_toml_path = package_dir </> "Cargo.toml"

    if cargo_toml_path |> file_system.file_exists |> not
    then get_empty_cargo_toml_content () |> file_system.write_all_text cargo_toml_path

    inl lib_link_target_path = workspace_root </> "lib/rust/fable/fable_modules/fable-library-rust"
    inl lib_link_path = package_dir </> "fable_modules/fable-library-rust"

    lib_link_path |> file_system.link_directory lib_link_target_path

    inl exit_code, dotnet_fable_result =
        execute_dotnet_fable { workspace_root_external fsproj_path extension package_dir runtime }

    inl result' = {
        extension = Some extension
        code = None
        code_path = None
        output = None
    }

    if exit_code <>. 0 then
        trace Critical
            fun () => "spiral.process_rust / dotnet fable error"
            fun () => { exit_code dotnet_fable_result }
        { result' with
            output = Some dotnet_fable_result
        }
    else
        inl deps =
            inl deps =
                if runtime = None
                then deps
                else
                    // TODO: simplify
                    inl has_near_sdk =
                        deps
                        |> am'.vec_filter (sm'.from_std_string >> sm'.contains "near-sdk")
                        |> am'.vec_len
                        |> i32
                        |> fun n => n > 0
                    // TODO: simplify with ++
                    if has_near_sdk
                    then deps
                    else deps |> am'.vec_extend (;[ "near-sdk" |> sm'.to_std_string ] |> am'.to_vec)
            deps
            |> am'.vec_map fun dep =>
                inl dep = dep |> sm'.from_std_string
                if dep |> sm'.contains "="
                then dep
                elif dep |> sm'.ends_with "]"
                then dep |> sm'.replace "[" $'$"={{version=\'*\',features=["' |> fun x => $'$"{!x}}}"'
                else $'$"{!dep}=\'*\'"'
            |> am'.from_vec
            |> fun x => x : _ i32 _
            |> seq.of_array'
            |> sm'.concat "\n"

        inl new_code_path = package_dir </> $'$"{!workspace_name}.{!extension}"'
        inl new_code = new_code_path |> file_system.read_all_text

        inl on_startup_text = "on_startup!" ++# (join "(")
        inl method0_fn_text = " method0" ++# (join "(")
        inl static_do_bindings =
            (new_code |> sm'.contains on_startup_text)
            && (new_code |> sm'.contains method0_fn_text |> not)
        inl cargo_toml_content =
            get_cargo_toml_content { hash_hex runtime deps static_do_bindings }
        inl workspace_cargo_toml_content = get_workspace_cargo_toml_content { workspace_root }

        cargo_toml_content |> file_system.write_all_text_exists cargo_toml_path
        workspace_cargo_toml_content |> file_system.write_all_text_exists workspace_cargo_toml_path

        inl range_rs_path = lib_link_path </> "src/Range.rs"
        if range_rs_path |> file_system.file_exists then
            inl text = range_rs_path |> file_system.read_all_text
            text
            |> sm'.replace "use crate::String_::fromCharCode;" "use crate::String_::fromChar;"
            |> sm'.replace "fromCharCode(c)" "std::char::from_u32(c).unwrap()"
            |> file_system.write_all_text_exists range_rs_path

        inl exit_code, cargo_fmt_result =
            fun () =>
                inl exit_code, result =
                    execution_options fun x => { x with
                        command = $'$"cargo fmt --manifest-path \\\"{!cargo_toml_path}\\\" --"'
                        working_directory = workspace_root_external |> resultm.box |> resultm.ok'
                    }
                    |> execute_with_options

                inl return () =
                    if exit_code = 0
                    then Ok (exit_code, result)
                    else Error (exit_code, result)

                if result |> sm'.contains "failed to load manifest for workspace member" |> not
                then return ()
                else
                    inl missing_toml_path =
                        "failed to read `(?<a>.*?Cargo.toml)`"
                        |> sm'.new_regex
                        |> resultm.unwrap'
                        |> sm'.regex_captures result
                        |> am'.from_vec
                        |> fun x => x : _ i32 _
                        |> am'.try_item 0
                        |> optionm.map (mapm.get "a" >> optionm'.unbox)
                        |> optionm'.flatten

                    match missing_toml_path with
                    | None => Error (exit_code, result)
                    | Some missing_toml_path =>
                        if missing_toml_path |> file_system.file_exists |> not then
                            missing_toml_path
                            |> file_system.directory_get_parent
                            |> optionm'.default_value' ""
                            |> file_system.create_dir
                            |> ignore

                            get_empty_cargo_toml_content ()
                            |> file_system.write_all_text missing_toml_path
                        return ()
            |> retry_fn' 3u8

        if exit_code <>. 0 then
            trace Critical
                fun () => "spiral.process_rust / cargo fmt error"
                fun () => { exit_code cargo_fmt_result }

        inl new_code = new_code_path |> file_system.read_all_text

        inl main_code_header =
            "pub fn main() -> Result<(), String> " ++# (join "{")

        inl main_code : string =
            if runtime = None
            then ""
            else
                $'$"\#[near_sdk::near_bindgen]"'
                ++\# $'$"\#[derive(near_sdk::PanicOnDefault)]"'
                ++\# $'$"pub struct MainState {{"'
                ++\# $'$"}}"'
                ++\# $'$""'
                ++\# $'$"\#[near_sdk::near_bindgen]"'
                ++\# $'$"impl MainState {{"'
                ++\# $'$"    pub fn state_main() {{"'
                ++\# $'$"        Spiral::method0();"'
                ++\# $'$"    }}"'
                ++\# $'$"}}"'
            ++\# (
                if runtime = None && (new_code |> sm'.contains (on_startup_text ++# "Spiral::method0()"))
                then $'$"{!main_code_header} Ok(Spiral::method0()) }}"'
                else $'$"{!main_code_header} Ok(()) }}"'
            )

        inl cached = new_code |> sm'.contains main_code_header

        inl new_code' = $'$"{!new_code}\\n\\n{!main_code}\\n"'
        inl new_code =
            if cached
            then new_code
            else
                inl runtime_contract =
                    match runtime with
                    | Some (Contract _) => true
                    | _ => false

                new_code'
                |> sm'.replace
                    ("),)" ++# !\($'"\\\";\\\".into()"'))
                    "));"
                |> sm'.replace
                    ("},)" ++# !\($'"\\\";\\\".into()"'))
                    "});"
                |> sm'.replace_regex
                    "\\s\\sdefaultOf\\(\\);"
                    " defaultOf::<()>();"
                |> sm'.replace_regex
                    "\\s\\sgetZero\\(\\);"
                    " getZero::<()>();"
                |> sm'.replace
                    ("(&e.get_Curren" ++# !\($'"\\\"t\\\".into()"'))
                    "(e.get_Current"
                |> sm'.replace
                    ("getNull" ++# !\($'"\\\"::<()>()\\\".into()"'))
                    "fable_library_rust::Native_::getZero()"


                |> sm'.replace
                    ("null::<()>(" ++# !\($'$"\\\")\\\".into()"'))
                    "fable_library_rust::Native_::getZero()"
                |> sm'.replace_regex
                    "null::<\\(\\)>\\(\\)"
                    "fable_library_rust::Native_::getZero()"

                |> sm'.replace_regex
                    "\\(null::<\\(\\)>\\(\\)"
                    "(null()"
                |> sm'.replace_regex
                    " null::<\\(\\)>\\(\\)"
                    " null()"
                |> sm'.replace_regex
                    "unbox::<bool>\\(null\\(\\)"
                    "false"
                |> sm'.replace_regex
                    "unbox::<string>\\(null\\(\\)"
                    "fable_library_rust::Native_::getZero()"
                |> sm'.replace_regex
                    "unbox::<i32>\\(null\\(\\)"
                    "0"
                |> sm'.replace_regex
                    "unbox::<i32>\\(null::<\\(\\)>\\(\\)\\)"
                    "0"
                |> sm'.replace_regex
                    "null\\(\\)"
                    "fable_library_rust::Native_::getZero()"

                |> sm'.replace_regex
                    "\\s\\sfable_library_rust::Native_::getZero\\(\\);"
                    " fable_library_rust::Native_::getZero::<()>();"

                |> sm'.replace
                    " gen:"
                    " f:"
                |> sm'.replace_regex
                    "\\(gen\\("
                    "(f("
                |> sm'.replace_regex
                    "\\(gen,"
                    "(f,"
                |> sm'.replace
                    " gen "
                    " f "

                |> sm'.replace
                    "::Slice'_"
                    "::Slice__"
                |> sm'.replace
                    " Slice'_"
                    " Slice__"
                |> sm'.replace
                    ("defaultOf()" ++# !\($'"\\\",\\\".into()"'))
                    "defaultOf::<std::sync::Arc<dyn IDisposable>>(),"
                |> sm'.replace
                    ("__self" ++# !\($'"\\\"__.\\\".into()"'))
                    "self."
                |> sm'.replace
                    ("_self" ++# !\($'"\\\"_.\\\".into()"'))
                    "self."
                |> sm'.replace
                    ("get_or_insert_wit" ++# !\($'"\\\"h\\\".into()"'))
                    "get_or_init"
                |> sm'.replace
                    ("use fable_library_rust::System::Collections::Concurrent::ConcurrentStack_1" ++# !\($'"\\\";\\\".into()"'))
                    "type ConcurrentStack_1<T> = T;"
                |> sm'.replace
                    ("use fable_library_rust::System::TimeZoneInfo" ++# !\($'"\\\";\\\".into()"'))
                    "type TimeZoneInfo = i64;"
                |> sm'.replace
                    ("use fable_library_rust::System::Threading::Tasks::TaskCanceledException" ++# !\($'"\\\";\\\".into()"'))
                    "type TaskCanceledException = ();"
                |> if static_do_bindings
                    then id
                    else sm'.replace
                            on_startup_text
                            ("// " ++# on_startup_text)
                |> if runtime_contract |> not
                    then id
                    else sm'.replace
                            ("use fable_library_rust::DateTime_::DateTime" ++# ";")
                            "type DateTime = ();"

        if not cached then
            new_code
            |> file_system.write_all_text_exists new_code_path

        inl command =
            if runtime <> None
            then $'$"cargo +nightly-2024-07-14 build --release --target wasm32-unknown-unknown --manifest-path \\\"{!cargo_toml_path}\\\""'
            else $'$"cargo run --manifest-path \\\"{!cargo_toml_path}\\\""'
        inl environment_variables =
            if runtime <> None
            then ;[]
            else
                inl fast = false
                ;[
                    "TRACE_LEVEL", "Verbose"
                    "RUSTC_WRAPPER", "sccache"
                    "RUST_BACKTRACE", "full"
                    "RUSTFLAGS",
                    if fast
                    then "-C prefer-dynamic -C strip=symbols -C link-arg=-s -C debuginfo=0"
                    else "-C prefer-dynamic"
                ]
        inl exit_code, cargo_result =
            execution_options fun x => { x with
                command
                environment_variables
                working_directory = workspace_root_external |> resultm.box |> resultm.ok'
            }
            |> execute_with_options

        inl result =
            if runtime = None then
                inl external_command =
                    inl vars =
                        a environment_variables
                        |> am.map fun k, v => $'$"$env:{!k}=\'\'{!v}\'\'"' : string
                        |> fun x => x : _ i32 _
                        |> seq.of_array
                        |> sm'.concat ";"
                    inl command =
                        a ;[
                            vars
                            command
                        ]
                        |> fun x => x : _ i32 _
                        |> seq.of_array
                        |> sm'.concat ";"
                    $'$"pwsh -c \'{!command}\'"' : string
                if exit_code <>. 0 then
                    trace Critical
                        fun () => "spiral.process_rust / error"
                        fun () => { exit_code new_code_path external_command cleanup cargo_result }
                    result'
                else
                    inl output =
                        try
                            fun () =>
                                cargo_result
                                |> sm'.split "\n"
                                |> fun x => a x : _ i32 _
                                |> am'.skip_while fun line =>
                                    (line |> sm'.contains "profile [optimized] target" |> not)
                                        && (line |> sm'.contains "profile [unoptimized] target" |> not)
                                        && (line |> sm'.contains "profile [unoptimized + debuginfo] target" |> not)
                                |> am'.skip 2
                                |> seq.of_array
                                |> sm'.concat "\n"
                            fun ex =>
                                trace Critical
                                    fun () => "spiral.process_rust / Exception"
                                    fun () => { ex new_code_path external_command cargo_result }
                                None
                        |> optionm'.box
                        |> optionm'.unwrap
                    { result' with
                        code = Some new_code
                        code_path = Some new_code_path
                        output = Some output
                    }
            else
                inl wasm_path : string =
                    $'$"target/spiral/{!workspace_name}/target/wasm32-unknown-unknown/release/spiral_{!hash_hex}.wasm"'

                inl command =
                    inl invoke_block_path = "scripts/invoke-block.ps1"
                    inl spiral_wasm_command : string =
                        inl runtime_cmd =
                            match runtime with
                            | Some (Wasm cmd) => cmd
                            | Some (Contract cmd) => cmd
                            | _ => ""
                        $'$"\'deps/spiral/workspace/target/release/spiral_wasm -w {!wasm_path} -t debug {!runtime_cmd}\'"'
                    inl automation = "AUTOMATION" |> env.get_environment_variable
                    $'$"pwsh -c \\\"pwsh {!invoke_block_path} {!spiral_wasm_command} -Linux -EnvironmentVariables AUTOMATION={!automation}\`nNEAR_RPC_TIMEOUT_SECS=100\\\""'

                if exit_code = 0 then
                    inl exit_code, spiral_wasm_result =
                        execution_options fun x => { x with
                            command
                            working_directory = workspace_root |> optionm'.some'
                        }
                        |> execute_with_options

                    if exit_code = 0 then
                        { result' with
                            code = Some new_code
                            code_path = Some new_code_path
                            output = Some spiral_wasm_result
                        }
                    else
                        trace Critical
                            fun () => "spiral.process_rust / wasm error"
                            fun () => {
                                exit_code new_code_path cargo_result cleanup
                                spiral_wasm_result = $'$"\\n{!spiral_wasm_result}"' : string
                            }
                        result'
                else
                    trace Critical
                        fun () => "spiral.process_rust / cargo error"
                        fun () => {
                            exit_code new_code_path wasm_path command cleanup
                            cargo_result = $'$"\\n{!cargo_result}"' : string
                        }
                    result'

        inl ci = "CI" |> env.get_environment_variable

        if cleanup || ci <> "" then
            package_dir |> file_system.directory_delete true

            inl cleanup =
                inl build_target =
                    if runtime <> None
                    then "wasm32-unknown-unknown/release"
                    else "debug"

                [ ".d"; ".exe"; ".pdb"; ".wasm"; "" ]
                |> listm.map fun ext =>
                    workspace_dir </> $'$"target/{!build_target}/spiral_{!hash_hex}{!ext}"'
                |> listm.map fun path => path, path |> file_system.file_exists

            trace Verbose
                fun () => "spiral.process_rust / cleanup"
                fun () => { new_code_path cleanup }

            cleanup
            |> listm'.filter snd
            |> listm.iter (fst >> file_system.file_delete)

        result

dib¶

process_dib¶

In [ ]:
inl process_dib { path retries working_directory } =
    inl exit_code, repl_result =
        let rec 루프 retry =
            inl exit_code, repl_result =
                runtime.execution_options fun x => { x with
                    command = $'$"dotnet repl --exit-after-run --run \\\"{!path}\\\" --output-path \\\"{!path}.ipynb\\\""'
                    environment_variables = ;[
                        "TRACE_LEVEL", "Verbose"
                        "AUTOMATION", "True"
                    ]
                    trace = false
                    working_directory = working_directory |> optionm'.box
                }
                |> runtime.execute_with_options

            if exit_code = 0 || retry >= retries
            then exit_code, repl_result
            else
                trace Debug
                    fun () => "spiral.run / repl error"
                    fun () => { exit_code repl_result retry = $'$"{!retry}/{!retries}"' : string }
                루프 (retry + 1)
        루프 1

    inl exit_code, result =
        if exit_code <>. 0
        then exit_code, repl_result
        else
            inl exit_code, jupyter_result =
                runtime.execution_options fun x => { x with
                    command = $'$"jupyter nbconvert \\\"{!path}.ipynb\\\" --to html --HTMLExporter.theme=dark"'
                }
                |> runtime.execute_with_options

            trace Debug
                fun () => "spiral.run / dib / jupyter nbconvert"
                fun () => { exit_code jupyter_result_length = jupyter_result |> sm'.length : i32 }

            if exit_code <>. 0
            then exit_code, $'$"repl_result: {!repl_result}\n\njupyter_result: {!jupyter_result}"'
            else
                inl exit_code, pwsh_replace_html_result =
                    inl path = path |> sm'.replace "'" "''"
                    runtime.execution_options fun x => { x with
                        command = $'$"pwsh -c \\\"$counter = 1; $path = \'{!path}.html\'; (Get-Content $path -Raw) -replace \'(id=\\\\\\"cell-id=)[a-fA-F0-9]{{8}}\', {{ $_.Groups[1].Value + $counter++ }} | Set-Content $path\\\""'
                    }
                    |> runtime.execute_with_options

                trace Debug
                    fun () => "spiral.run / dib / html cell ids"
                    fun () => { exit_code pwsh_replace_html_result_length = pwsh_replace_html_result |> sm'.length : i32 }

                $'$"{!path}.html"'
                |> file_system.read_all_text
                |> sm'.replace "\r\n" "\n"
                |> file_system.write_all_text $'$"{!path}.html"'

                $'$"{!path}.ipynb"'
                |> file_system.read_all_text
                |> sm'.replace "\r\n" "\n"
                |> sm'.replace "\\r\\n" "\\n"
                |> file_system.write_all_text $'$"{!path}.ipynb"'

                exit_code, $'$"repl_result: {!repl_result}\n\njupyter_result: {!jupyter_result}\n\npwsh_replace_html_result: {!pwsh_replace_html_result}"'

    trace Debug
        fun () => "spiral.run / dib"
        fun () => { exit_code result_length = result |> sm'.length : i32 }

    if exit_code <>. 0
    then failwith $'$"spiral.run / dib / exit_code: {!exit_code} / result: {!result}"'
    ;[
        "stdio",
        result
    ]

typescript¶

process_typescript¶

In [ ]:
inl process_typescript { fs_path deps trace_level } =
    inl extension = "ts"

    inl code = fs_path |> file_system.read_all_text

    inl hash_hex = (extension, code) |> sm'.format_debug |> crypto.hash_text

    inl workspace_name = "spiral"

    inl workspace_root_external = file_system.get_workspace_root_external ()
    inl workspace_root = workspace_root_external |> resultm.box |> resultm.unwrap_or_else id

    inl package_dir =
        get_package_dir
            { workspace_root name = workspace_name; target = Some TypeScript; hash = Some hash_hex }

    inl fsproj_path =
        persist_code_project {
            workspace_root
            package_dir
            packages = [ "Fable.Core", "4.3.0" ]
            modules = []
            name = workspace_name
            code
        }

    inl lib_path = workspace_root </> "lib/typescript/fable/fable_modules"
    inl lib_dir_prefix = $'$"fable-library-{!extension}"'
    inl lib_dir_prefix' = join lib_dir_prefix

    inl versions : _ (string * string) =
        lib_path
        |> file_system.new_walk_dir
        |> file_system.walk_dir_filter fun entry => async.new_future_move_send fun () =>
            entry
            |> file_system.dir_entry_file_type
            |> async.await_send
            |> resultm.map_error' sm'.format'
            |> resultm.unbox
            |> function
                | Ok file_type when file_type |> file_system.file_type_is_dir |> not => file_system.Ignore
                | _ =>
                    inl path =
                        entry
                        |> file_system.dir_entry_path
                        |> file_system.path_buf_display
                        |> sm'.format'
                        |> sm'.from_std_string
                    if path |> file_system.get_directory_name |> sm'.starts_with lib_dir_prefix |> not
                    then file_system.IgnoreDir
                    else
                        match path |> file_system.directory_get_parent |> optionm'.unbox with
                        | Some parent when parent |> sm'.contains lib_dir_prefix |> not =>
                            file_system.Continue
                        | _ => file_system.IgnoreDir
        |> async.stream_filter_map_futures fun (entry : _ _ file_system.async_walkdir_error) =>
            inl entry = entry |> resultm.map_error' sm'.format' |> resultm.unbox
            match entry with
            | Ok entry =>
                inl path =
                    entry
                    |> file_system.dir_entry_path
                    |> file_system.path_buf_display
                    |> sm'.format'
                    |> sm'.from_std_string
                inl version =
                    $'$"{!lib_dir_prefix'}\\.(?<a>[-\\d\\w.]+)$"'
                    |> sm'.new_regex
                    |> resultm.unwrap'
                    |> sm'.regex_captures path
                    |> am'.from_vec
                    |> fun x => x : _ int _
                    |> am'.try_item 0
                    |> optionm.map (mapm.get "a" >> optionm'.unbox)
                    |> optionm'.flatten
                version
                |> optionm.map fun version =>
                    path, version
            | Error error =>
                trace Critical
                    fun () => "spiral.process_typescript / stream_filter_map"
                    fun () => { error }
                None
            |> optionm'.box
        |> async.stream_collect_futures
        |> async.await
        |> async.into_par_iter
        |> async.par_map id
        |> async.par_collect

    inl version =
        versions
        |> am'.from_vec
        |> fun x => x : _ i32 _
        |> am'.try_item 0

    trace Debug
        fun () => "spiral.process_typescript"
        fun () => { version }


    let link_lib () =
        match version with
        | Some (_path, version) =>
            inl lib_link_target_path = lib_path </> $'$"fable-library-{!extension}.{!version}"'
            inl lib_link_path = package_dir </> $'$"fable_modules/fable-library-{!extension}.{!version}"'
            lib_link_path |> file_system.link_directory lib_link_target_path
            lib_link_target_path </> "fable_modules" |> file_system.directory_delete true
        | None => failwith $'$"spiral.process_typescript / fable library not found / lib_path: {!lib_path}"'

    link_lib ()

    inl exit_code, dotnet_fable_result =
        execute_dotnet_fable { workspace_root_external fsproj_path extension package_dir runtime = None }

    link_lib ()

    if exit_code <>. 0 then
        trace Critical
            fun () => "spiral.process_typescript"
            fun () => { exit_code dotnet_fable_result }
        { extension = Some extension; code = None; code_path = None; output = Some dotnet_fable_result }
    else
        inl deps =
            deps
            |> am'.vec_map fun dep =>
                inl dep = dep |> sm'.from_std_string
                if dep |> sm'.contains "="
                then dep
                else $'$"\\"{!dep}\\":\\"*\\""'
            |> am'.from_vec
            |> fun x => x : _ i32 _
            |> seq.of_array'
            |> sm'.concat ",\n"

        inl package_json_content =
            $'$"{{"'
            +. $'$"  \\\"name\\\": \\\"spiral_{!hash_hex}\\\","'
            +. $'$"  \\\"dependencies\\\": {{"'
            +. deps
            +. $'$"  }},"'
            +. $'$"    \\\"devDependencies\\\": {{"'
            +. $'$"  }},"'
            +. $'$"}}"'

        inl workspace_package_json_content =
            ""

        inl package_json_path = package_dir </> "package.json"

        inl workspace_dir = package_dir </> "../.."
        inl workspace_package_json_path = workspace_dir </> "package.json"

        package_json_content |> file_system.write_all_text_exists package_json_path

        workspace_package_json_content |> file_system.write_all_text_exists workspace_package_json_path

        inl new_code_path = package_dir </> $'$"{!workspace_name}.{!extension}"'
        trace Debug
            fun () => "spiral.process_typescript"
            fun () => { new_code_path }
        inl new_code = new_code_path |> file_system.read_all_text

        inl main_code_header =
            "// spiral.process_typescript"
        inl main_code = "// spiral.process_typescript"

        inl cached = new_code |> sm'.contains main_code_header

        inl new_code =
            if cached
            then new_code
            else
                new_code
                |> sm'.replace
                    $'$"\\\"./fable_modules/fable-library-ts.{!version}/"'
                    $'$"\\\"{!workspace_root}/lib/typescript/fable/fable_modules/fable-library-ts.{!version}/"'
                |> sm'.replace_regex
                    "\\s\\sdefaultOf\\(\\);"
                    " defaultOf::<()>();"

        if not cached then
            $'$"{!new_code}\\n\\n{!main_code}\\n"'
            |> file_system.write_all_text_exists new_code_path

        inl command = $'$"bun --bun run \\\"{!new_code_path}\\\""'
        inl environment_variables =
            match "~/.bun/bin" |> env.append_path with
            | Some path => [ "PATH", path ]
            | None => []
            ++ [
                "TRACE_LEVEL", "Verbose"
            ]
            |> listm'.box
            |> listm'.to_array'
        inl exit_code, run_result =
            runtime.execution_options fun x => { x with
                command
                environment_variables
                working_directory = workspace_root_external |> resultm.box |> resultm.ok'
            }
            |> runtime.execute_with_options

        inl external_command =
            inl vars =
                a environment_variables
                |> am.map fun k, v => $'$"$env:{!k}=\'\'{!v}\'\'"' : string
                |> fun x => x : _ i32 _
                |> seq.of_array
                |> sm'.concat ";"
            $'$"pwsh -c \'{!vars}; {!command}\'"' : string
        if exit_code = 0 then
            inl output =
                try
                    fun () =>
                        run_result
                        |> sm'.split "\n"
                        |> fun x => a x : _ i32 _
                        |> seq.of_array
                        |> sm'.concat "\n"
                    fun ex =>
                        trace Critical
                            fun () => "spiral.process_typescript / Exception"
                            fun () => { ex new_code_path external_command run_result }
                        None
                |> optionm'.box
                |> optionm'.unwrap

            {
                extension = Some extension
                code = Some new_code
                code_path = Some new_code_path
                output = Some output
            }
        else
            trace Critical
                fun () => "spiral.process_typescript / error"
                fun () => { exit_code run_result new_code_path external_command }
            { extension = Some extension; code = None; code_path = None; output = None }

python¶

process_python¶

In [ ]:
inl process_python { fs_path deps trace_level } =
    inl extension = "py"
    inl is_trace = trace_level = Verbose
    inl _trace (fn : () -> string) =
        if is_trace
        then trace Info (fun () => $'$"spiral.process_python / {!fn ()}"') id
        else fn () |> console.write_line

    inl code = fs_path |> file_system.read_all_text

    inl hash_hex = (extension, code) |> sm'.format_debug |> crypto.hash_text

    inl workspace_name = "spiral"

    inl workspace_root_external = file_system.get_workspace_root_external ()
    inl workspace_root = workspace_root_external |> resultm.box |> resultm.unwrap_or_else id

    inl package_dir =
        get_package_dir { workspace_root name = workspace_name; target = Some Python; hash = Some hash_hex }

    inl fsproj_path =
        persist_code_project {
            workspace_root
            package_dir
            packages = [ "Fable.Core", "4.3.0" ]
            modules = []
            name = workspace_name
            code
        }

    inl lib_path = workspace_root </> "lib/python/fable/fable_modules"

    inl lib_link_target_path = lib_path </> $'$"fable_library"'
    inl lib_link_path = package_dir </> $'$"fable_modules/fable_library"'

    lib_link_path |> file_system.link_directory lib_link_target_path

    inl exit_code, dotnet_fable_result =
        execute_dotnet_fable { workspace_root_external fsproj_path extension package_dir runtime = None }

    if exit_code <>. 0 then
        trace Critical
            fun () => "spiral.process_python"
            fun () => { exit_code dotnet_fable_result }
        { extension = Some extension; code = None; code_path = None; output = Some dotnet_fable_result }
    else
        inl deps =
            deps
            |> am'.vec_map fun dep =>
                inl dep = dep |> sm'.from_std_string
                if dep |> sm'.contains "="
                then dep
                else $'$"\\"{!dep}\\":\\"*\\""'
            |> am'.from_vec
            |> fun x => x : _ i32 _
            |> seq.of_array'
            |> sm'.concat ",\n"

        inl package_json_content =
            $'$"{{"'
            +. $'$"  \\\"name\\\": \\\"spiral_{!hash_hex}\\\","'
            +. $'$"  \\\"dependencies\\\": {{"'
            +. deps
            +. $'$"  }},"'
            +. $'$"    \\\"devDependencies\\\": {{"'
            +. $'$"  }},"'
            +. $'$"}}"'

        inl workspace_package_json_content =
            ""

        inl package_json_path = package_dir </> "package.json"

        inl workspace_dir = package_dir </> "../.."
        inl workspace_package_json_path = workspace_dir </> "package.json"

        package_json_content |> file_system.write_all_text_exists package_json_path

        workspace_package_json_content |> file_system.write_all_text_exists workspace_package_json_path

        inl new_code_path = package_dir </> $'$"{!workspace_name}.{!extension}"'
        trace Debug
            fun () => "spiral.process_python"
            fun () => { new_code_path }
        inl new_code = new_code_path |> file_system.read_all_text

        inl main_code_header =
            "# spiral.process_python"
        inl main_code = "# spiral.process_python"

        inl cached = new_code |> sm'.contains main_code_header

        inl new_code =
            if cached
            then new_code
            else
                new_code
                |> sm'.replace
                    ("),)" +. !\($'"\\\";\\\".into()"'))
                    "));"
                |> sm'.replace_regex
                    "\\s\\sdefaultOf\\(\\);"
                    " defaultOf::<()>();"

        if not cached
        then
            $'$"{!new_code}\\n\\n{!main_code}\\n"'
            |> file_system.write_all_text_exists new_code_path

        inl command = $'$"python \\\"{!new_code_path}\\\""'
        inl environment_variables =
            ;[
                "TRACE_LEVEL", "Verbose"
            ]
        inl exit_code, run_result =
            runtime.execution_options fun x => { x with
                command
                environment_variables
                working_directory = workspace_root_external |> resultm.box |> resultm.ok'
            }
            |> runtime.execute_with_options

        inl external_command =
            inl vars =
                a environment_variables
                |> am.map fun k, v => $'$"$env:{!k}=\'\'{!v}\'\'"' : string
                |> fun x => x : _ i32 _
                |> seq.of_array
                |> sm'.concat ";"
            $'$"pwsh -c \'{!vars}; {!command}\'"' : string
        if exit_code = 0 then
            inl output =
                try
                    fun () =>
                        run_result
                        |> sm'.split "\n"
                        |> fun x => a x : _ i32 _
                        |> seq.of_array
                        |> sm'.concat "\n"
                    fun ex =>
                        trace Critical
                            fun () => "spiral.process_python / Exception"
                            fun () => { ex new_code_path external_command run_result }
                        None
                |> optionm'.box
                |> optionm'.unwrap

            {
                extension = Some extension
                code = Some new_code
                code_path = Some new_code_path
                output = Some output
            }
        else
            trace Critical
                fun () => "spiral.process_python / error"
                fun () => { exit_code run_result new_code_path external_command }
            { extension = Some extension; code = None; code_path = None; output = None }

gleam¶

process_gleam¶

In [ ]:
inl process_gleam { gleam_path target deps } =
    inl extension = "gleam"

    inl new_code_path = gleam_path
    inl new_code = new_code_path |> file_system.read_all_text

    inl hash_hex = { extension new_code } |> sm'.format |> crypto.hash_text

    inl workspace_root_external = file_system.get_workspace_root_external ()
    inl workspace_root =
        workspace_root_external |> resultm.box |> resultm.unwrap_or_else id |> file_system.standardize_path

    inl src_dir =
        new_code_path
        |> file_system.directory_get_parent
        |> optionm'.default_value' ""
        |> file_system.standardize_path

    inl package_dir = src_dir </> ".." |> file_system.standardize_path

    inl manifest_path = package_dir </> "gleam.toml"

    inl deps =
        ;[
            "gleam_stdlib=\"0.57.0\""
            "gleam_time=\">=1.0.0 and <2.0.0\""
            "gleam_erlang=\">=0.34.0 and <1.0.0\""
            "envoy=\">=1.0.0 and <2.0.0\""
            "gary=\">=1.1.0 and <2.0.0\""
            "gtempo=\">=7.1.0 and <8.0.0\""
        ]
        |> am'.to_vec
        |> am'.vec_map sm'.to_std_string
        |> am'.vec_extend deps
        |> am'.vec_map fun dep =>
            inl dep = dep |> sm'.from_std_string
            if dep |> sm'.contains "="
            then dep
            elif dep |> sm'.ends_with "]"
            then dep |> sm'.replace "[" $'$"={{version=\'*\',features=["' |> fun x => $'$"{!x}}}"'
            else $'$"{!dep}=\'*\'"'
        |> am'.from_vec
        |> fun x => x : _ i32 _
        |> seq.of_array'
        |> sm'.concat "\n"

    inl target' = target |> reflection.union_to_string |> sm'.to_lower

    inl manifest =
        inl main =
            if new_code_path |> sm'.contains "_real"
            then "main_real"
            else "main"
        $'$"name = \\\"{!main}\\\""'
        ++\# $'$"target = \\\"{!target'}\\\""'
        ++\# $'$""'
        ++\# $'$"[dependencies]"'
        ++\# $'$"{!deps}"'

    manifest |> file_system.write_all_text_exists manifest_path

    inl exit_code, run_result =
        runtime.execution_options fun x => { x with
            command = $'$"gleam check"'
            working_directory = package_dir |> optionm'.some'
        }
        |> runtime.execute_with_options

    if exit_code <>. 0 then
        trace Critical
            fun () => "spiral.process_gleam / check error"
            fun () => { exit_code run_result new_code_path }
        { extension = Some extension; code = None; code_path = None; output = None }
    else
        inl command =
            if target = Erlang
            then $'$"gleam run --no-print-progress \\\"{!new_code_path}\\\""' : string
            else $'$"gleam build --no-print-progress"'
        inl environment_variables =
            ;[
                "TRACE_LEVEL", ""
                "GLEAM_LOG", ""
                "GLEAM_LOG_NOCOLOUR", ""
            ]
        inl exit_code, run_result =
            runtime.execution_options fun x => { x with
                command
                environment_variables
                working_directory = package_dir |> optionm'.some'
                stderr = false
            }
            |> runtime.execute_with_options

        inl external_command =
            inl vars =
                a environment_variables
                |> am.map fun k, v => $'$"$env:{!k}=\'\'{!v}\'\'"' : string
                |> fun x => x : _ i32 _
                |> seq.of_array
                |> sm'.concat ";"
            $'$"pwsh -c \'{!vars}; {!command}\'"' : string
        if exit_code <>. 0 then
            trace Critical
                fun () => "spiral.process_gleam / error"
                fun () => { exit_code run_result new_code_path external_command }
            { extension = Some extension; code = None; code_path = None; output = None }
        else
            inl run_result =
                if target = Erlang
                then run_result
                else
                    inl js_path = $'$"{!package_dir}/build/dev/javascript/main/main.mjs"'
                    inl js_text = js_path |> file_system.read_all_text
                    inl js_text = js_text |> sm'.replace $'$"\#app_"' $'$"\#app_{!hash_hex}"'
                    if js_text |> sm'.ends_with "main()" |> not then
                        $'$"{!js_text}\nmain()"'
                        |> file_system.write_all_text_exists js_path

                    inl exit_code, run_result =
                        runtime.execution_options fun x => { x with
                            command =
                                $'$"bunx --bun esbuild --bundle --minify --loader:.wasm=file --outdir={!src_dir} {!js_path}"'
                            environment_variables =
                                match "~/.bun/bin" |> env.append_path with
                                | Some path => ;[ "PATH", path ]
                                | None => ;[]
                            working_directory = package_dir |> optionm'.some'
                        }
                        |> runtime.execute_with_options

                    if exit_code <>. 0 then
                        trace Critical
                            fun () => "spiral.process_gleam / esbuild error"
                            fun () => { exit_code run_result new_code_path }
                        ""
                    else
                        inl html =
                            $'$"<\!DOCTYPE html>"'
                            ++\# $'$"<html lang=\\\"en\\\">"'
                            ++\# $'$"  <head>"'
                            ++\# $'$"    <meta charset=\\\"UTF-8\\\" />"'
                            ++\# $'$"    <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\" />"'
                            ++\# $'$"    <link"'
                            ++\# $'$"      data-trunk"'
                            ++\# $'$"      rel=\\\"inline\\\""'
                            ++\# $'$"      href=\\\"../build/packages/lustre_ui/priv/static/lustre_ui.css\\\""'
                            ++\# $'$"    />"'
                            ++\# $'$"    <link"'
                            ++\# $'$"      data-trunk"'
                            ++\# $'$"      rel=\\\"inline\\\""'
                            ++\# $'$"      type=\\\"module\\\""'
                            ++\# $'$"      href=\\\"main.js\\\""'
                            ++\# $'$"    />"'
                            ++\# $'$"  </head>"'
                            ++\# $'$"  <body>"'
                            ++\# $'$"    <div id=\\\"app_{!hash_hex}\\\"></div>"'
                            ++\# $'$"  </body>"'
                            ++\# $'$"</html>"'

                        inl html_path = $'$"{!src_dir}/index.html"'
                        html |> file_system.write_all_text_exists html_path

                        "" |> file_system.write_all_text_exists $'$"{!src_dir}/spiral_{!hash_hex}.rs"'

                        inl manifest =
                            $'$"[package]"'
                            ++\# $'$"name = \\\"spiral_{!hash_hex}\\\""'
                            ++\# $'$""'
                            ++\# $'$"[workspace]"'
                            ++\# $'$""'
                            ++\# $'$"[lib]"'
                            ++\# $'$"crate-type = [\\\"cdylib\\\", \\\"rlib\\\"]"'
                            ++\# $'$"path = \\\"spiral_{!hash_hex}.rs\\\""'
                            ++\# $'$""'
                            ++\# $'$"[dependencies]"'

                        manifest |> file_system.write_all_text_exists $'$"{!src_dir}/Cargo.toml"'

                        inl exit_code, run_result =
                            runtime.execution_options fun x => { x with
                                command = $'$"trunk build --release --minify --dist={!src_dir} --public-url=./ --no-sri"'
                                environment_variables =
                                    ;[
                                        "TRUNK_TOOLS_WASM_BINDGEN", "0.2.93"
                                    ]
                                working_directory = src_dir |> optionm'.some'
                            }
                            |> runtime.execute_with_options

                        if exit_code = 0
                        then html_path |> file_system.read_all_text
                        else
                            trace Critical
                                fun () => "spiral.process_gleam / trunk error"
                                fun () => { exit_code run_result new_code_path }
                            ""

            inl run_result' = run_result |> sm'.to_std_string

            inl output =
                try
                    fun () =>
                        run_result
                        |> sm'.split "\n"
                        |> am'.to_vec
                        |> am'.vec_filter fun x =>
                            (x |> sm'.starts_with "{compiling,\"" |> not)
                            && (x |> sm'.starts_with "{compiled,main" |> not)
                            && (x |> sm'.ends_with "main.beam\"}" |> not)
                            && (x |> sm'.ends_with "main_real.beam\"}" |> not)
                            && (x |> sm'.starts_with "src\\main.gleam:" |> not)
                            && (x |> sm'.starts_with "src\\main_real.gleam:" |> not)
                            && (x |> sm'.starts_with "src/main.gleam:" |> not)
                            && (x |> sm'.starts_with "src/main_real.gleam:" |> not)
                            && (x |> sm'.starts_with "% " |> not)
                        |> am'.from_vec
                        |> fun x => x : _ int _
                        |> seq.of_array
                        |> sm'.concat "\n"
                        |> sm'.trim
                    fun ex =>
                        trace Critical
                            fun () => "spiral.process_gleam / Exception"
                            fun () => { ex run_result' new_code_path external_command }
                        None
                |> optionm'.box
                |> optionm'.unwrap

            {
                extension = Some extension
                code = Some new_code
                code_path = Some new_code_path
                output = Some output
            }

cuda¶

process_cuda¶

In [ ]:
inl process_cuda { py_path env deps } =
    inl extension = "py"

    inl new_code_path = py_path
    inl new_code = new_code_path |> file_system.read_all_text

    inl workspace_root_external = file_system.get_workspace_root_external ()
    inl workspace_root = workspace_root_external |> resultm.box |> resultm.unwrap_or_else id

    inl package_dir = new_code_path |> file_system.directory_get_parent |> optionm'.default_value' ""

    inl manifest_path =
        match env with
        | Pip => package_dir </> "requirements.txt"
        | Poetry => package_dir </> "pyproject.toml"

    inl deps =
        deps
        |> am'.vec_map fun dep =>
            inl dep = dep |> sm'.from_std_string
            if dep |> sm'.contains "="
            then dep
            elif dep |> sm'.ends_with "]"
            then dep |> sm'.replace "[" $'$"={{version=\'*\',features=["' |> fun x => $'$"{!x}}}"'
            else $'$"{!dep}=\'*\'"'
        |> am'.from_vec
        |> fun x => x : _ i32 _
        |> seq.of_array'
        |> sm'.concat "\n"

    inl exit_code, run_result =
        if deps = ""
        then 0, ""
        else
            inl manifest =
                match env with
                | Pip =>
                    deps
                | Poetry =>
                    $'$"[tool.poetry]"'
                    ++\# $'$"name = \\\"test\\\""'
                    ++\# $'$"version = \\\"0.0.1\\\""'
                    ++\# $'$"description = \\\"\\\""'
                    ++\# $'$"authors = []"'
                    ++\# $'$""'
                    ++\# $'$"[tool.poetry.dependencies]"'
                    ++\# $'$"python=\\\"~3.12\\\""'
                    ++\# $'$"{!deps}"'
                    ++\# $'$""'
                    ++\# $'$"[build-system]"'
                    ++\# $'$"requires = [\\\"poetry-core\\\"]"'
                    ++\# $'$"build-backend = \\\"poetry.core.masonry.api\\\""'

            manifest |> file_system.write_all_text_exists manifest_path

            runtime.execution_options fun x => { x with
                command =
                    match env with
                    | Pip => $'$"pip install -r requirements.txt"'
                    | Poetry => $'$"poetry install"'
                working_directory = package_dir |> optionm'.some'
            }
            |> runtime.execute_with_options

    if exit_code <>. 0 then
        trace Critical
            fun () => "spiral.process_cuda / env install error"
            fun () => { env exit_code run_result new_code_path }
        { extension = Some extension; code = None; code_path = None; output = None }
    else
        inl command =
            match env with
            | Pip => $'$"python \\\"{!new_code_path}\\\""'
            | Poetry => $'$"poetry run python \\\"{!new_code_path}\\\""'
        inl environment_variables =
            ;[
                "TRACE_LEVEL", "Verbose"
            ]
        inl exit_code, run_result =
            runtime.execution_options fun x => { x with
                command
                environment_variables
                working_directory = package_dir |> optionm'.some'
            }
            |> runtime.execute_with_options

        inl external_command =
            inl vars =
                a environment_variables
                |> am.map fun k, v => $'$"$env:{!k}=\'\'{!v}\'\'"' : string
                |> fun x => x : _ i32 _
                |> seq.of_array
                |> sm'.concat ";"
            $'$"pwsh -c \'{!vars}; {!command}\'"' : string
        if exit_code = 0
            || (run_result |> sm'.contains "cupy_backends.cuda.api.runtime.CUDARuntimeError: cudaErrorInsufficientDriver") then
            inl output =
                try
                    fun () =>
                        run_result
                        |> sm'.split "\n"
                        |> fun x => a x : _ i32 _
                        |> seq.of_array
                        |> sm'.concat "\n"
                    fun ex =>
                        trace Critical
                            fun () => "spiral.process_cuda / Exception"
                            fun () => { ex run_result new_code_path external_command }
                        None
                |> optionm'.box
                |> optionm'.unwrap

            {
                extension = Some extension
                code = Some new_code
                code_path = Some new_code_path
                output = Some output
            }
        else
            trace Critical
                fun () => "spiral.process_cuda / error"
                fun () => { exit_code run_result new_code_path external_command }
            { extension = Some extension; code = None; code_path = None; output = None }

fsharp¶

process_fsharp¶

In [ ]:
inl process_fsharp { spi_path } =
    inl extension = "fsx"

    inl new_code_path = spi_path
    inl new_code = new_code_path |> file_system.read_all_text

    inl workspace_root_external = file_system.get_workspace_root_external ()
    inl workspace_root = workspace_root_external |> resultm.box |> resultm.unwrap_or_else id

    inl supervisor_path = workspace_root </> $"apps/spiral/dist/Supervisor!(platform.get_executable_suffix ())"
    inl code_dir = new_code_path |> file_system.directory_get_parent |> optionm'.default_value' ""
    inl file_name = new_code_path |> file_system.get_file_name_without_extension
    inl output_path = code_dir </> $'$"{!file_name}.{!extension}"'
    inl command = $'$"{!supervisor_path} --build-file \\\"{!new_code_path}\\\" \\\"{!output_path}\\\""'
    inl environment_variables =
        ;[
            "TRACE_LEVEL", "Verbose"
        ]
    inl exit_code, run_result =
        runtime.execution_options fun x => { x with
            command
            environment_variables
            working_directory = workspace_root_external |> resultm.box |> resultm.ok'
        }
        |> runtime.execute_with_options

    inl external_command =
        inl vars =
            a environment_variables
            |> am.map fun k, v => $'$"$env:{!k}=\'\'{!v}\'\'"' : string
            |> fun x => x : _ i32 _
            |> seq.of_array
            |> sm'.concat ";"
        $'$"pwsh -c \'{!vars}; {!command}\'"' : string
    if exit_code = 0 then
        inl output =
            try
                fun () =>
                    run_result
                    |> sm'.split "\n"
                    |> fun x => a x : _ i32 _
                    |> seq.of_array
                    |> sm'.concat "\n"
                fun ex =>
                    trace Critical
                        fun () => "spiral.process_fsharp / Exception"
                        fun () => { ex run_result new_code_path external_command }
                    None
            |> optionm'.box
            |> optionm'.unwrap

        {
            extension = Some extension
            code = Some new_code
            code_path = Some new_code_path
            output = Some output
        }
    else
        trace Critical
            fun () => "spiral.process_fsharp / error"
            fun () => { exit_code run_result new_code_path external_command }
        { extension = Some extension; code = None; code_path = None; output = None }

run¶

In [ ]:
let rec run trace_level (matches : runtime.arg_matches) : async.future_pin (resultm.result' string string) =
    fun () =>
        match matches |> runtime.matches_subcommand |> optionm'.unbox with
        | Some (subcommand, arg_matches)
                when (subcommand |> sm'.from_std_string) = (get_args () .gleam |> fst) =>

            inl gleam_path =
                arg_matches
                |> runtime.matches_get_one ((get_args () .gleam |> snd).gleam_path |> fst)
                |> optionm'.unbox
                |> optionm.value
                |> sm'.from_std_string

            inl target =
                arg_matches
                |> runtime.matches_get_one ((get_args () .gleam |> snd).target |> fst)
                |> optionm'.unbox
                |> optionm.map (
                    sm'.from_std_string
                    >> reflection.union_try_pick
                )
                |> optionm'.flatten
                |> optionm'.default_value Erlang

            inl deps : am'.vec sm'.std_string =
                arg_matches
                |> runtime.matches_get_many ((get_args () .gleam |> snd).deps |> fst)
                |> optionm'.unbox
                |> optionm'.default_value (;[] |> am'.to_vec)

            inl command_result =
                process_gleam { gleam_path target deps }
                |> fun { extension code output } =>
                    ;[
                        "extension", extension |> optionm'.default_value ""
                        "code", code |> optionm'.default_value ""
                        "output", output |> optionm'.default_value ""
                    ]

            ;[
                "command_result",
                command_result
                |> am'.to_vec
                |> am'.vec_map' fun k, v =>
                    new_pair (sm'.to_std_string k) (sm'.to_std_string v)
                |> mapm.b_tree_map_from_vec_pairs
                |> sm'.serialize
                |> resultm.unwrap'
                |> sm'.from_std_string
            ]

        | Some (subcommand, arg_matches)
                when (subcommand |> sm'.from_std_string) = (get_args () .cuda |> fst) =>

            inl py_path =
                arg_matches
                |> runtime.matches_get_one ((get_args () .cuda |> snd).py_path |> fst)
                |> optionm'.unbox
                |> optionm.value
                |> sm'.from_std_string

            inl env =
                arg_matches
                |> runtime.matches_get_one ((get_args () .cuda |> snd).env |> fst)
                |> optionm'.unbox
                |> optionm.map (
                    sm'.from_std_string
                    >> reflection.union_try_pick
                )
                |> optionm'.flatten
                |> optionm'.default_value Pip

            inl deps : am'.vec sm'.std_string =
                arg_matches
                |> runtime.matches_get_many ((get_args () .cuda |> snd).deps |> fst)
                |> optionm'.unbox
                |> optionm'.default_value (;[] |> am'.to_vec)

            inl command_result =
                process_cuda { py_path env deps }
                |> fun { extension code output } =>
                    ;[
                        "extension", extension |> optionm'.default_value ""
                        "code", code |> optionm'.default_value ""
                        "output", output |> optionm'.default_value ""
                    ]

            ;[
                "command_result",
                command_result
                |> am'.to_vec
                |> am'.vec_map' fun k, v =>
                    new_pair (sm'.to_std_string k) (sm'.to_std_string v)
                |> mapm.b_tree_map_from_vec_pairs
                |> sm'.serialize
                |> resultm.unwrap'
                |> sm'.from_std_string
            ]

        | Some (subcommand, arg_matches)
                when (subcommand |> sm'.from_std_string) = (get_args () .fable |> fst) =>

            inl fs_path =
                arg_matches
                |> runtime.matches_get_one ((get_args () .fable |> snd).fs_path |> fst)
                |> optionm'.unbox
                |> optionm.value
                |> sm'.from_std_string

            inl command =
                arg_matches
                |> runtime.matches_get_one ((get_args () .fable |> snd).command |> fst)
                |> optionm'.unbox
                |> optionm.map sm'.from_std_string

            inl command_result =
                match command with
                | Some command =>
                    get_command ()
                    |> runtime.command_get_matches_from (
                        $'$"_ {!command} --fs-path \\\"{!fs_path}\\\""' |> runtime.split_args |> resultm.get
                    )
                    |> run trace_level
                    |> async.await
                    |> resultm.unwrap'
                | None => "{}"

            ;[
                "command_result",
                command_result
            ]

        | Some (subcommand, arg_matches)
            when (subcommand |> sm'.from_std_string) = (get_args () .dib |> fst) =>

            inl path =
                arg_matches
                |> runtime.matches_get_one ((get_args () .dib |> snd).path |> fst)
                |> optionm'.map'' (
                    sm'.from_std_string
                    >> file_system.absolute_path
                )
                |> optionm'.unwrap

            inl retries =
                arg_matches
                |> runtime.matches_get_one ((get_args () .dib |> snd).retries |> fst)
                |> optionm'.default_value' 1u8

            inl working_directory =
                arg_matches
                |> runtime.matches_get_one ((get_args () .dib |> snd).working_directory |> fst)
                |> optionm'.unbox
                |> optionm.map sm'.from_std_string

            process_dib { path retries working_directory }

        | matches =>
            match matches with
            | Some (subcommand, arg_matches)
                    when (subcommand |> sm'.from_std_string) = (get_args () .rust |> fst) =>

                inl fs_path =
                    arg_matches
                    |> runtime.matches_get_one ((get_args () .rust |> snd).fs_path |> fst)
                    |> optionm'.unbox
                    |> optionm.value
                    |> sm'.from_std_string

                inl deps : am'.vec sm'.std_string =
                    arg_matches
                    |> runtime.matches_get_many ((get_args () .rust |> snd).deps |> fst)
                    |> optionm'.unbox
                    |> optionm'.default_value (;[] |> am'.to_vec)

                inl cleanup =
                    arg_matches
                    |> runtime.matches_get_flag ((get_args () .rust |> snd).cleanup |> fst)

                inl wasm =
                    arg_matches
                    |> runtime.matches_get_one ((get_args () .rust |> snd).wasm |> fst)
                    |> optionm'.unbox
                    |> optionm.map sm'.from_std_string

                inl contract =
                    arg_matches
                    |> runtime.matches_get_one ((get_args () .rust |> snd).contract |> fst)
                    |> optionm'.unbox
                    |> optionm.map sm'.from_std_string

                inl runtime =
                    match wasm, contract with
                    | Some wasm, _ => Wasm wasm |> Some
                    | _, Some contract => Contract contract |> Some
                    | _ => None

                process_rust { fs_path deps trace_level runtime cleanup }

            | Some (subcommand, arg_matches)
                    when (subcommand |> sm'.from_std_string) = (get_args () .typescript |> fst) =>

                inl fs_path =
                    arg_matches
                    |> runtime.matches_get_one ((get_args () .typescript |> snd).fs_path |> fst)
                    |> optionm'.unbox
                    |> optionm.value
                    |> sm'.from_std_string

                inl deps : am'.vec sm'.std_string =
                    arg_matches
                    |> runtime.matches_get_many ((get_args () .typescript |> snd).deps |> fst)
                    |> optionm'.unbox
                    |> optionm'.default_value (;[] |> am'.to_vec)

                process_typescript { fs_path deps trace_level }

            | Some (subcommand, arg_matches)
                    when (subcommand |> sm'.from_std_string) = (get_args () .python |> fst) =>
                inl fs_path =
                    arg_matches
                    |> runtime.matches_get_one ((get_args () .python |> snd).fs_path |> fst)
                    |> optionm'.unbox
                    |> optionm.value
                    |> sm'.from_std_string

                inl deps : am'.vec sm'.std_string =
                    arg_matches
                    |> runtime.matches_get_many ((get_args () .python |> snd).deps |> fst)
                    |> optionm'.unbox
                    |> optionm'.default_value (;[] |> am'.to_vec)

                process_python { fs_path deps trace_level }

            | Some (subcommand, arg_matches) =>
                trace Debug
                    fun () => "spiral.run / invalid subcommand"
                    fun () => { subcommand arg_matches }

                { extension = None; code = None; code_path = None; output = None }
            | _ =>
                { extension = None; code = None; code_path = None; output = None }
            |> fun { extension code code_path output } =>
                ;[
                    "extension", extension |> optionm'.default_value ""
                    "code", code |> optionm'.default_value ""
                    "code_path", code_path |> optionm'.default_value ""
                    "output", output |> optionm'.default_value ""
                ]
        |> am'.to_vec
        |> am'.vec_map' fun k, v =>
            new_pair (sm'.to_std_string k) (sm'.to_std_string v)
        |> mapm.b_tree_map_from_vec_pairs
        |> sm'.serialize
        |> resultm.map_error' (sm'.format' >> sm'.from_std_string)
        |> resultm.map' sm'.from_std_string
    |> async.new_future_move
In [ ]:
//// test
///! rust -d async-walkdir chrono clap encoding_rs encoding_rs_io futures rand rayon regex serde_json sha2

inl file_name = "main.fs"
inl code = "let method0 () =\n    3 - 6 |> System.Console.WriteLine\nmethod0 ()\n"

inl temp_dir, disposable =
    (file_name, code)
    |> sm'.format_debug
    |> crypto.hash_text
    |> file_system.create_temp_dir'
disposable |> use |> ignore
inl fs_path = temp_dir </> file_name

code |> file_system.write_all_text fs_path

get_command ()
|> runtime.command_get_matches_from ($'$"_ fable -f \\\"{!fs_path}\\\" -c \\\"rust -d regex=\'*\'\\\""' |> runtime.split_args |> resultm.get)
|> run Verbose
|> async.block_on_futures
|> resultm.unwrap'
|> sm'.deserialize
|> resultm.unwrap'
|> mapm.get ("command_result" |> sm'.to_std_string)
|> optionm'.unwrap
|> sm'.from_std_string
|> sm'.deserialize
|> resultm.unwrap'
|> fun result =>
    result
    |> mapm.get ("extension" |> sm'.to_std_string)
    |> optionm'.unwrap
    |> sm'.from_std_string
    |> _assert_eq "rs"
    result
    |> mapm.get ("output" |> sm'.to_std_string)
    |> optionm'.unwrap
    |> sm'.from_std_string
    |> _assert_eq "-3"
00:00:00 v #1 file_system.create_dir / { dir = /tmp/!create_temp_path_/spiral_75511ba09e49200b104f7e87e37f721026d9c1dd30babea1a14df44cf497e696/84b99b0b-d6d4-d4b8-7f79-3c480ce421da }
00:00:00 v #2 file_system.create_dir / { dir = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145 }
00:00:00 v #3 file_system.create_dir / { dir = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/fable_modules }
00:00:00 d #4 runtime.execute_with_options / { file_name = dotnet; arguments = ["fable", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/spiral.fsproj", "--optimize", "--lang", "rs", "--extension", ".rs", "--outDir", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145", "--define", "_LINUX"]; options = { command = dotnet fable "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/spiral.fsproj" --optimize --lang rs --extension .rs --outDir "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145" --define _LINUX; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:00 v #5 > Fable 5.0.0-alpha.9: F# to Rust compiler (status: alpha)
00:00:00 v #6 > 
00:00:00 v #7 > Thanks to the contributor! @do-wa
00:00:00 v #8 > Stand with Ukraine! https://standwithukraine.com.ua
00:00:00 v #9 >
00:00:00 v #10 > Parsing target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/spiral.fsproj...
00:00:02 v #11 > Project and references (1 source files) parsed in 2065ms
00:00:02 v #12 >
00:00:03 v #13 > Started Fable compilation...
00:00:04 v #14 > 
00:00:04 v #15 > Fable compilation finished in 1371ms
00:00:04 v #16 >
00:00:04 v #17 > ./target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/spiral.fs(3,0): (3,10) warning FABLE: For Rust, support for F# static and module do bindings is disabled by default. It can be enabled with the 'static_do_bindings' feature. Use at your own risk!
00:00:04 v #18 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 734 }
00:00:04 d #19 runtime.execute_with_options / { file_name = cargo; arguments = ["fmt", "--manifest-path", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/Cargo.toml", "--"]; options = { command = cargo fmt --manifest-path "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/Cargo.toml" --; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:04 v #20 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 0 }
00:00:04 d #21 runtime.execute_with_options / { file_name = cargo; arguments = ["run", "--manifest-path", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/Cargo.toml"]; options = { command = cargo run --manifest-path "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/Cargo.toml"; cancellation_token = None; environment_variables = Array(MutCell([("TRACE_LEVEL", "Verbose"), ("RUSTC_WRAPPER", "sccache"), ("RUST_BACKTRACE", "full"), ("RUSTFLAGS", "-C prefer-dynamic")])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:04 v #22 ! warning: /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/75511ba09e49200b104f7e87e37f721026d9c1dd30babea1a14df44cf497e696/Cargo.toml: the cargo feature `edition2024` has been stabilized in the 1.85 release and is no longer necessary to be listed in the manifest
00:00:04 v #23 !   See https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-edition-field for more information about using this feature.
00:00:04 v #24 ! warning: /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/Cargo.toml: the cargo feature `edition2024` has been stabilized in the 1.85 release and is no longer necessary to be listed in the manifest
00:00:04 v #25 !   See https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-edition-field for more information about using this feature.
00:00:04 v #26 !    Compiling fable_library_rust v0.1.0 (/home/runner/work/spiral/polyglot/lib/rust/fable/fable_modules/fable-library-rust)
00:00:04 v #27 !    Compiling spiral_2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145 v0.0.1 (/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145)
00:00:05 v #28 !     Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.28s
00:00:05 v #29 !      Running `target/spiral/spiral/target/debug/spiral_2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145`
00:00:05 v #30 > -3
00:00:05 v #31 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 1556 }
00:00:05 v #32 spiral.process_rust / cleanup / { new_code_path = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/spiral.rs; cleanup = UH5_1("/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/../../../target/debug/spiral_2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145.d", false, UH5_1("/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/../../../target/debug/spiral_2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145.exe", false, UH5_1("/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/../../../target/debug/spiral_2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145.pdb", false, UH5_1("/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/../../../target/debug/spiral_2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145.wasm", false, UH5_1("/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Rust/2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145/../../../target/debug/spiral_2ef8b15c945dbfbc67ff5bc26c9e9501a45a3263b540960ac7776259d199e145", false, UH5_0))))) }
{ name = __assert_eq; actual = rs; expected = rs }
{ name = __assert_eq; actual = -3; expected = -3 }
In [ ]:
//// test
///! rust -d async-walkdir chrono clap encoding_rs encoding_rs_io futures rand rayon regex serde_json sha2

inl file_name = "main.fs"
inl code = "3 - 6 |> System.Console.WriteLine\n"

inl temp_dir, disposable =
    (file_name, code)
    |> sm'.format_debug
    |> crypto.hash_text
    |> file_system.create_temp_dir'
disposable |> use |> ignore
inl fs_path = temp_dir </> file_name

code |> file_system.write_all_text fs_path

get_command ()
|> runtime.command_get_matches_from ($'$"_ fable -f \\\"{!fs_path}\\\" -c \\\"typescript\\\""' |> runtime.split_args |> resultm.get)
|> run Verbose
|> async.block_on_futures
|> resultm.unwrap'
|> sm'.deserialize
|> resultm.unwrap'
|> mapm.get ("command_result" |> sm'.to_std_string)
|> optionm'.unwrap
|> sm'.from_std_string
|> sm'.deserialize
|> resultm.unwrap'
|> fun result =>
    result
    |> mapm.get ("extension" |> sm'.to_std_string)
    |> optionm'.unwrap
    |> sm'.from_std_string
    |> _assert_eq "ts"
    result
    |> mapm.get ("output" |> sm'.to_std_string)
    |> optionm'.unwrap
    |> sm'.from_std_string
    |> _assert_eq "-3"
00:00:00 v #1 file_system.create_dir / { dir = /tmp/!create_temp_path_/spiral_b664424da5e63b3a534d023729799887b72de9c581f37b9d8ab29cd268636566/c6422374-71e4-07d4-0ba4-c3084b24fbba }
00:00:00 v #2 file_system.create_dir / { dir = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8 }
00:00:00 d #3 spiral.process_typescript / { version = US52_0("/home/runner/work/spiral/polyglot/lib/typescript/fable/fable_modules/fable-library-ts.5.0.0-alpha.9", "5.0.0-alpha.9") }
00:00:00 v #4 file_system.create_dir / { dir = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8/fable_modules }
00:00:00 d #5 runtime.execute_with_options / { file_name = dotnet; arguments = ["fable", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8/spiral.fsproj", "--optimize", "--lang", "ts", "--extension", ".ts", "--outDir", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8", "--define", "_LINUX"]; options = { command = dotnet fable "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8/spiral.fsproj" --optimize --lang ts --extension .ts --outDir "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8" --define _LINUX; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:00 v #6 > Fable 5.0.0-alpha.9: F# to TypeScript compiler
00:00:00 v #7 > Minimum @fable-org/fable-library-ts version (when installed from npm): 1.10.0
00:00:00 v #8 > 
00:00:00 v #9 > Thanks to the contributor! @markek
00:00:00 v #10 > Stand with Ukraine! https://standwithukraine.com.ua
00:00:00 v #11 >
00:00:00 v #12 > Parsing target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8/spiral.fsproj...
00:00:02 v #13 > Project and references (1 source files) parsed in 2077ms
00:00:02 v #14 >
00:00:03 v #15 > Started Fable compilation...
00:00:04 v #16 > 
00:00:04 v #17 > Fable compilation finished in 1245ms
00:00:04 v #18 >
00:00:04 v #19 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 511 }
00:00:04 d #20 spiral.process_typescript / { new_code_path = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8/spiral.ts }
00:00:04 d #21 runtime.execute_with_options / { file_name = bun; arguments = ["--bun", "run", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8/spiral.ts"]; options = { command = bun --bun run "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/TypeScript/702335b0756baa7db0d02dbbeaf9fc04cf2c3b7dbb45866c578c5109aaa8c4a8/spiral.ts"; cancellation_token = None; environment_variables = Array(MutCell([("PATH", "~/.bun/bin:/opt/microsoft/powershell/7:/opt/hostedtoolcache/Python/3.12.11/x64/bin:/opt/hostedtoolcache/Python/3.12.11/x64:/opt/hostedtoolcache/node/21.7.3/x64/bin:/usr/share/dotnet:/home/runner/work/_temp/.setup-beam/rebar3/bin:/home/runner/work/_temp/.setup-beam/gleam/bin:/home/runner/work/_temp/.setup-beam/otp/bin:/home/runner/.cargo/bin:/snap/bin:/home/runner/.local/bin:/opt/pipx_bin:/home/runner/.cargo/bin:/home/runner/.config/composer/vendor/bin:/usr/local/.ghcup/bin:/home/runner/.dotnet/tools:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/runner/.cargo/bin:/home/runner/.bun/bin:/home/runner/.cargo/bin:/home/runner/.bun/bin:/home/runner/.cargo/bin:/home/runner/.bun/bin"), ("TRACE_LEVEL", "Verbose")])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:04 v #22 > -3
00:00:04 v #23 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 2 }
{ name = __assert_eq; actual = ts; expected = ts }
{ name = __assert_eq; actual = -3; expected = -3 }
In [ ]:
//// test
///! rust -d async-walkdir chrono clap encoding_rs encoding_rs_io futures rand rayon regex serde_json sha2

inl file_name = "main.fs"
inl code = "3 - 6 |> System.Console.WriteLine\n"

inl temp_dir, disposable =
    (file_name, code)
    |> sm'.format_debug
    |> crypto.hash_text
    |> file_system.create_temp_dir'
disposable |> use |> ignore
inl fs_path = temp_dir </> file_name

code |> file_system.write_all_text fs_path

get_command ()
|> runtime.command_get_matches_from ($'$"_ fable -f \\\"{!fs_path}\\\" -c \\\"python\\\""' |> runtime.split_args |> resultm.get)
|> run Verbose
|> async.block_on_futures
|> resultm.unwrap'
|> sm'.deserialize
|> resultm.unwrap'
|> mapm.get ("command_result" |> sm'.to_std_string)
|> optionm'.unwrap
|> sm'.from_std_string
|> sm'.deserialize
|> resultm.unwrap'
|> fun result =>
    result
    |> mapm.get ("extension" |> sm'.to_std_string)
    |> optionm'.unwrap
    |> sm'.from_std_string
    |> _assert_eq "py"
    result
    |> mapm.get ("output" |> sm'.to_std_string)
    |> optionm'.unwrap
    |> sm'.from_std_string
    |> _assert_eq "-3"
00:00:00 v #1 file_system.create_dir / { dir = /tmp/!create_temp_path_/spiral_f8009b173951e5d5c44dded8853ecc0e996e2a0dc0696c652610990e3d62d860/c6422374-71e4-07d4-0ba4-c3084b24fbba }
00:00:00 v #2 file_system.create_dir / { dir = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce }
00:00:00 v #3 file_system.create_dir / { dir = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce/fable_modules }
00:00:00 d #4 runtime.execute_with_options / { file_name = dotnet; arguments = ["fable", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce/spiral.fsproj", "--optimize", "--lang", "py", "--extension", ".py", "--outDir", "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce", "--define", "_LINUX"]; options = { command = dotnet fable "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce/spiral.fsproj" --optimize --lang py --extension .py --outDir "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce" --define _LINUX; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:00 v #5 > Fable 5.0.0-alpha.9: F# to Python compiler (status: beta)
00:00:00 v #6 > 
00:00:00 v #7 > Thanks to the contributor! @simra
00:00:00 v #8 > Stand with Ukraine! https://standwithukraine.com.ua
00:00:00 v #9 >
00:00:00 v #10 > Parsing target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce/spiral.fsproj...
00:00:02 v #11 > Project and references (1 source files) parsed in 2022ms
00:00:02 v #12 >
00:00:03 v #13 > Started Fable compilation...
00:00:04 v #14 > 
00:00:04 v #15 > Fable compilation finished in 1231ms
00:00:04 v #16 >
00:00:04 v #17 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 434 }
00:00:04 d #18 spiral.process_python / { new_code_path = /home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce/spiral.py }
00:00:04 d #19 runtime.execute_with_options / { file_name = python; arguments = ["/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce/spiral.py"]; options = { command = python "/home/runner/work/spiral/polyglot/target/spiral/spiral/packages/Python/cb8f3dd33197bb0bc95f09b3f3057a6844a0b70d75477350491883d14d8680ce/spiral.py"; cancellation_token = None; environment_variables = Array(MutCell([("TRACE_LEVEL", "Verbose")])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:04 v #20 > -3
00:00:04 v #21 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 2 }
{ name = __assert_eq; actual = py; expected = py }
{ name = __assert_eq; actual = -3; expected = -3 }
In [ ]:
//// test
///! rust -d async-walkdir chrono clap encoding_rs encoding_rs_io futures rand rayon regex serde_json sha2

inl file_name = "test.dib"
inl code =
    "#!meta\n\n{\"kernelInfo\":{\"defaultKernelName\":\"fsharp\",\"items\":[]}}\n\n#!fsharp\n\n3 - 6\n"

inl temp_dir, disposable =
    (file_name, code)
    |> sm'.format_debug
    |> crypto.hash_text
    |> file_system.create_temp_dir'
disposable |> use |> ignore
inl path = temp_dir </> file_name |> file_system.normalize_path

code
|> file_system.write_all_text path

get_command ()
|> runtime.command_get_matches_from ($'$"_ dib -p {!path}"' |> runtime.split_args |> resultm.get)
|> run Verbose
|> async.block_on_futures
|> resultm.unwrap'
|> __assert sm'.contains Silent "<pre>-3"

$'$"{!path}.html"'
|> file_system.read_all_text
|> __assert sm'.contains Silent "\"cell-id=1\""
00:00:00 v #1 file_system.create_dir / { dir = /tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623 }
00:00:00 d #2 runtime.execute_with_options / { file_name = dotnet; arguments = ["repl", "--exit-after-run", "--run", "/tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib", "--output-path", "/tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib.ipynb"]; options = { command = dotnet repl --exit-after-run --run "/tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib" --output-path "/tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib.ipynb"; cancellation_token = None; environment_variables = Array(MutCell([("TRACE_LEVEL", "Verbose"), ("AUTOMATION", "True")])); on_line = None; stdin = None; trace = false; working_directory = None; stderr = true } }
> 
> ── fsharp ──────────────────────────────────────────────────────────────────────
> 3 - 6
> 
> ── [ 2.95s - return value ] ────────────────────────────────────────────────────
> │ <div class="dni-plaintext"><pre>-3
> │ </pre></div><style>
> │ .dni-code-hint {
> │     font-style: italic;
> │     overflow: hidden;
> │     white-space: nowrap;
> │ }
> │ .dni-treeview {
> │     white-space: nowrap;
> │ }
> │ .dni-treeview td {
> │     vertical-align: top;
> │     text-align: start;
> │ }
> │ details.dni-treeview {
> │     padding-left: 1em;
> │ }
> │ table td {
> │     text-align: start;
> │ }
> │ table tr { 
> │     vertical-align: top; 
> │     margin: 0em 0px;
> │ }
> │ table tr td pre 
> │ { 
> │     vertical-align: top !important; 
> │     margin: 0em 0px !important;
> │ } 
> │ table th {
> │     text-align: start;
> │ }
> │ </style>
00:00:04 v #3 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 1495 }
00:00:04 d #4 runtime.execute_with_options / { file_name = jupyter; arguments = ["nbconvert", "/tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib.ipynb", "--to", "html", "--HTMLExporter.theme=dark"]; options = { command = jupyter nbconvert "/tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib.ipynb" --to html --HTMLExporter.theme=dark; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:05 v #5 ! [NbConvertApp] Converting notebook /tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib.ipynb to html
00:00:05 v #6 ! /opt/hostedtoolcache/Python/3.12.11/x64/lib/python3.12/site-packages/nbformat/__init__.py:96: MissingIDFieldWarning: Cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.
00:00:05 v #7 !   validate(nb)
00:00:05 v #8 ! /opt/hostedtoolcache/Python/3.12.11/x64/lib/python3.12/site-packages/nbconvert/filters/highlight.py:71: UserWarning: IPython3 lexer unavailable, falling back on Python 3
00:00:05 v #9 !   return _pygments_highlight(
00:00:05 v #10 ! [NbConvertApp] Writing 271496 bytes to /tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib.html
00:00:05 v #11 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 1066 }
00:00:05 d #12 spiral.run / dib / jupyter nbconvert / { exit_code = 0; jupyter_result_length = 1066 }
00:00:05 d #13 runtime.execute_with_options / { file_name = pwsh; arguments = ["-c", "$counter = 1; $path = '/tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib.html'; (Get-Content $path -Raw) -replace '(id=\\\"cell-id=)[a-fA-F0-9]{8}', { $_.Groups[1].Value + $counter++ } | Set-Content $path"]; options = { command = pwsh -c "$counter = 1; $path = '/tmp/!create_temp_path_/spiral_a71d54d5341a1232148128b5c0da83f3d20ef3972adc819bc429a9fa7d0d4047/af524e22-8e9a-5d18-99ed-bd86e1b74623/test.dib.html'; (Get-Content $path -Raw) -replace '(id=\"cell-id=)[a-fA-F0-9]{8}', { $_.Groups[1].Value + $counter++ } | Set-Content $path"; cancellation_token = None; environment_variables = Array(MutCell([])); on_line = None; stdin = None; trace = true; working_directory = None; stderr = true } }
00:00:05 v #14 runtime.execute_with_options / result / { exit_code = 0; std_trace_length = 0 }
00:00:05 d #15 spiral.run / dib / html cell ids / { exit_code = 0; pwsh_replace_html_result_length = 0 }
00:00:05 d #16 spiral.run / dib / { exit_code = 0; result_length = 2620 }

tests¶

In [ ]:
inl tests () =
    testing.run_tests {
        verify_app = get_command >> runtime.command_debug_assert
    }

main¶

In [ ]:
///! _

inl main (args : array_base string) =
    inl trace_state = get_trace_state_or_init None

    trace Debug
        fun () => "spiral.main"
        fun () => { args }

    inl command = get_command ()
    inl arg_matches = command |> runtime.command_get_matches

    inl trace_state_level = trace_state.level

    inl result =
        arg_matches
        |> run *trace_state_level
        |> async.block_on_futures
        |> resultm.unwrap'

    if *trace_state_level = Info
    then result |> console.write_line

    0i32

inl main () =
    $'let tests () = !tests ()' : ()
    $'let main args = !main args' : ()