Current section

Files

Jump to
gladvent src cmd@run.erl
Raw

src/cmd@run.erl

-module(cmd@run).
-compile(no_auto_import).
-export([run_command/1, run_all_command/1]).
-export_type([solve_err/0, err/0, direction/0, gleam_err/0]).
-type solve_err() :: undef | {run_failed, binary()}.
-type err() :: {failed_to_read_input, binary()} |
{unregistered, integer()} |
{other, binary()}.
-type direction() :: both.
-type gleam_err() :: {gleam_err,
gleam@erlang@atom:atom_(),
binary(),
binary(),
integer(),
binary(),
gleam@option:option(gleam@dynamic:dynamic())}.
-spec err_to_snag(err()) -> snag:snag().
err_to_snag(Err) ->
_pipe = case Err of
{unregistered, Day} ->
<<<<<<<<"day"/utf8, " "/utf8>>/binary,
(gleam@int:to_string(Day))/binary>>/binary,
" "/utf8>>/binary,
"unregistered"/utf8>>;
{failed_to_read_input, Input_path} ->
<<"failed to read input file: "/utf8, Input_path/binary>>;
{other, S} ->
S
end,
snag:new(_pipe).
-spec string_trim(binary(), direction(), binary()) -> binary().
string_trim(S, Dir, Sub) ->
string:trim(S, Dir, erlang:binary_to_list(Sub)).
-spec do(
integer(),
gleam@map:map_(integer(), {fun((binary()) -> gleam@dynamic:dynamic()),
fun((binary()) -> gleam@dynamic:dynamic())}),
boolean()
) -> {ok,
{{ok, gleam@dynamic:dynamic()} | {error, solve_err()},
{ok, gleam@dynamic:dynamic()} | {error, solve_err()}}} |
{error, err()}.
do(Day, Runners, Allow_crash) ->
case begin
_pipe = gleam@map:get(Runners, Day),
gleam@result:replace_error(_pipe, {unregistered, Day})
end of
{error, _try} -> {error, _try};
{ok, {Pt_1, Pt_2}} ->
Input_path = gleam@string:join(
[<<"input/day_"/utf8>>,
gleam@int:to_string(Day),
<<".txt"/utf8>>],
<<""/utf8>>
),
case begin
_pipe@1 = Input_path,
_pipe@2 = gleam@erlang@file:read(_pipe@1),
_pipe@3 = gleam@result:map(
_pipe@2,
fun(_capture) ->
string_trim(_capture, both, <<"\n"/utf8>>)
end
),
gleam@result:replace_error(
_pipe@3,
{failed_to_read_input, Input_path}
)
end of
{error, _try@1} -> {error, _try@1};
{ok, Input} ->
case Allow_crash of
true ->
{ok, {{ok, Pt_1(Input)}, {ok, Pt_2(Input)}}};
false ->
Pt_1@1 = begin
_pipe@4 = fun() -> Pt_1(Input) end,
_pipe@5 = gleam_erlang_ffi:rescue(_pipe@4),
gleam@result:map_error(
_pipe@5,
fun run_err_to_string/1
)
end,
Pt_2@1 = begin
_pipe@6 = fun() -> Pt_2(Input) end,
_pipe@7 = gleam_erlang_ffi:rescue(_pipe@6),
gleam@result:map_error(
_pipe@7,
fun run_err_to_string/1
)
end,
{ok, {Pt_1@1, Pt_2@1}}
end
end
end.
-spec crash_to_dyn(gleam@erlang:crash()) -> gleam@dynamic:dynamic().
crash_to_dyn(Err) ->
case Err of
{errored, Dyn} ->
Dyn;
{exited, Dyn} ->
Dyn;
{thrown, Dyn} ->
Dyn
end.
-spec decode_gleam_err() -> fun((gleam@dynamic:dynamic()) -> {ok, gleam_err()} |
{error, list(gleam@dynamic:decode_error())}).
decode_gleam_err() ->
gleam@dynamic:decode6(
fun(Field@0, Field@1, Field@2, Field@3, Field@4, Field@5) -> {gleam_err, Field@0, Field@1, Field@2, Field@3, Field@4, Field@5} end,
gleam@dynamic:field(
erlang:binary_to_atom(<<"gleam_error"/utf8>>),
fun gleam@erlang@atom:from_dynamic/1
),
gleam@dynamic:field(
erlang:binary_to_atom(<<"module"/utf8>>),
fun gleam@dynamic:string/1
),
gleam@dynamic:field(
erlang:binary_to_atom(<<"function"/utf8>>),
fun gleam@dynamic:string/1
),
gleam@dynamic:field(
erlang:binary_to_atom(<<"line"/utf8>>),
fun gleam@dynamic:int/1
),
gleam@dynamic:field(
erlang:binary_to_atom(<<"message"/utf8>>),
fun gleam@dynamic:string/1
),
gleam@dynamic:any(
[gleam@dynamic:field(
erlang:binary_to_atom(<<"value"/utf8>>),
gleam@dynamic:optional(fun gleam@dynamic:dynamic/1)
),
fun(_) -> {ok, none} end]
)
).
-spec gleam_err_to_string(gleam_err()) -> binary().
gleam_err_to_string(G) ->
gleam@string:join(
[<<"error:"/utf8>>,
erlang:atom_to_binary(erlang:element(2, G)),
<<"-"/utf8>>,
erlang:element(6, G),
<<"in module"/utf8>>,
erlang:element(3, G),
<<"in function"/utf8>>,
erlang:element(4, G),
<<"at line"/utf8>>,
gleam@int:to_string(erlang:element(5, G)),
begin
_pipe = erlang:element(7, G),
_pipe@1 = gleam@option:map(
_pipe,
fun(Val) ->
<<"with value "/utf8,
(gleam@string:inspect(Val))/binary>>
end
),
gleam@option:unwrap(_pipe@1, <<""/utf8>>)
end],
<<" "/utf8>>
).
-spec run_err_to_string(gleam@erlang:crash()) -> solve_err().
run_err_to_string(Err) ->
Dyn = crash_to_dyn(Err),
_pipe = (decode_gleam_err())(Dyn),
_pipe@1 = gleam@result:map(_pipe, fun gleam_err_to_string/1),
_pipe@2 = gleam@result:lazy_unwrap(
_pipe@1,
fun() ->
<<"run failed for some reason: "/utf8,
(gleam@string:inspect(Err))/binary>>
end
),
{run_failed, _pipe@2}.
-spec run_res_to_string({ok, gleam@dynamic:dynamic()} | {error, solve_err()}) -> binary().
run_res_to_string(Res) ->
case Res of
{ok, Res@1} ->
gleam@string:inspect(Res@1);
{error, Err} ->
case Err of
undef ->
<<"function undefined"/utf8>>;
{run_failed, S} ->
S
end
end.
-spec collect(
{integer(),
{ok,
{{ok, gleam@dynamic:dynamic()} | {error, solve_err()},
{ok, gleam@dynamic:dynamic()} | {error, solve_err()}}} |
{error, err()}}
) -> binary().
collect(X) ->
Day = gleam@int:to_string(erlang:element(1, X)),
case erlang:element(2, X) of
{ok, {Res_1, Res_2}} ->
<<<<<<<<<<<<<<"Ran day "/utf8, Day/binary>>/binary, ":\n"/utf8>>/binary,
" Part 1: "/utf8>>/binary,
(run_res_to_string(Res_1))/binary>>/binary,
"\n"/utf8>>/binary,
" Part 2: "/utf8>>/binary,
(run_res_to_string(Res_2))/binary>>;
{error, Err} ->
_pipe = Err,
_pipe@1 = err_to_snag(_pipe),
_pipe@2 = snag:layer(
_pipe@1,
gleam@string:append(<<"failed to run day "/utf8>>, Day)
),
snag:pretty_print(_pipe@2)
end.
-spec timeout_flag() -> {binary(), glint@flag:contents()}.
timeout_flag() ->
glint@flag:int(<<"timeout"/utf8>>, 0, <<"Run with specified timeout"/utf8>>).
-spec allow_crash_flag() -> {binary(), glint@flag:contents()}.
allow_crash_flag() ->
glint@flag:bool(
<<"allow-crash"/utf8>>,
false,
<<"Don't catch exceptions thrown by runners"/utf8>>
).
-spec run_command(
gleam@map:map_(integer(), {fun((binary()) -> gleam@dynamic:dynamic()),
fun((binary()) -> gleam@dynamic:dynamic())})
) -> glint:stub({ok, list(binary())} | {error, snag:snag()}).
run_command(Runners) ->
{stub,
[<<"run"/utf8>>],
fun(_capture) -> run(_capture, Runners, false) end,
[timeout_flag(), allow_crash_flag()],
<<"Run the specified days"/utf8>>}.
-spec run_all_command(
gleam@map:map_(integer(), {fun((binary()) -> gleam@dynamic:dynamic()),
fun((binary()) -> gleam@dynamic:dynamic())})
) -> glint:stub({ok, list(binary())} | {error, snag:snag()}).
run_all_command(Runners) ->
{stub,
[<<"run"/utf8>>, <<"all"/utf8>>],
fun(_capture) -> run(_capture, Runners, true) end,
[timeout_flag(), allow_crash_flag()],
<<"Run all registered days"/utf8>>}.
-spec run(
glint:command_input(),
gleam@map:map_(integer(), {fun((binary()) -> gleam@dynamic:dynamic()),
fun((binary()) -> gleam@dynamic:dynamic())}),
boolean()
) -> {ok, list(binary())} | {error, snag:snag()}.
run(Input, Runners, Run_all) ->
{ok, {i, Timeout@1}} = case glint@flag:get(
erlang:element(3, Input),
erlang:element(1, timeout_flag())
) of
{ok, {i, Timeout}} -> {ok, {i, Timeout}};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"cmd/run"/utf8>>,
function => <<"run"/utf8>>,
line => 216})
end,
{ok, {b, Allow_crash@1}} = case glint@flag:get(
erlang:element(3, Input),
erlang:element(1, allow_crash_flag())
) of
{ok, {b, Allow_crash}} -> {ok, {b, Allow_crash}};
_try@1 ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try@1,
module => <<"cmd/run"/utf8>>,
function => <<"run"/utf8>>,
line => 217})
end,
case case Timeout@1 of
0 ->
{ok, endless};
_@1 when Timeout@1 < 0 ->
invalid_timeout_err(Timeout@1);
_@2 ->
{ok, {ending, Timeout@1}}
end of
{error, _try@2} -> {error, _try@2};
{ok, Timing} ->
case case Run_all of
true ->
_pipe = Runners,
_pipe@1 = gleam@map:keys(_pipe),
_pipe@2 = gleam@list:sort(_pipe@1, fun gleam@int:compare/2),
{ok, _pipe@2};
false ->
_pipe@3 = erlang:element(2, Input),
_pipe@4 = parse:days(_pipe@3),
wrap_failed_to_parse_err(_pipe@4, erlang:element(2, Input))
end of
{error, _try@3} -> {error, _try@3};
{ok, Days} ->
_pipe@5 = Days,
_pipe@6 = cmd:exec(
_pipe@5,
Timing,
fun(_capture) ->
do(_capture, Runners, Allow_crash@1)
end,
fun(Field@0) -> {other, Field@0} end,
fun collect/1
),
{ok, _pipe@6}
end
end.
-spec invalid_timeout_err(integer()) -> {ok, any()} | {error, snag:snag()}.
invalid_timeout_err(Timeout) ->
_pipe = [<<"invalid timeout value "/utf8>>,
<<"'"/utf8>>,
gleam@int:to_string(Timeout),
<<"'"/utf8>>],
_pipe@1 = gleam@string:concat(_pipe),
_pipe@2 = snag:error(_pipe@1),
snag:context(
_pipe@2,
<<"timeout must be greater than or equal to 1 ms"/utf8>>
).
-spec wrap_failed_to_parse_err({ok, HDX} | {error, snag:snag()}, list(binary())) -> {ok,
HDX} |
{error, snag:snag()}.
wrap_failed_to_parse_err(Res, Args) ->
snag:context(
Res,
gleam@string:join(
[<<"failed to parse arguments:"/utf8>> | Args],
<<" "/utf8>>
)
).