diff --git a/.github/actions/test/action.yaml b/.github/actions/test/action.yaml index 0a48221..fcdce3e 100644 --- a/.github/actions/test/action.yaml +++ b/.github/actions/test/action.yaml @@ -10,7 +10,7 @@ inputs: erlang-version: description: erlang-otp version required: false - default: 24.3.4 + default: 26.2.2 runs: using: composite diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 47e5cc1..0184db6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - erlang: ["24.2"] + erlang: ["26.2.2"] steps: - uses: actions/checkout@v2 - uses: ./.github/actions/test diff --git a/src/gladvent/internal/cmd/run.gleam b/src/gladvent/internal/cmd/run.gleam index 33d75ed..b8ced64 100644 --- a/src/gladvent/internal/cmd/run.gleam +++ b/src/gladvent/internal/cmd/run.gleam @@ -22,6 +22,7 @@ type AsyncResult = type RunErr { FailedToReadInput(String) + FailedToParseInput(String) Unregistered(Day) Other(String) } @@ -42,6 +43,7 @@ fn run_err_to_snag(err: RunErr) -> Snag { Unregistered(day) -> "day" <> " " <> int.to_string(day) <> " " <> "unregistered" FailedToReadInput(input_path) -> "failed to read input file: " <> input_path + FailedToParseInput(err) -> "failed to parse input: " <> err Other(s) -> s } |> snag.new @@ -61,7 +63,7 @@ fn string_trim(s: String, dir: Direction, sub: String) -> String { fn do_trim(a: String, b: Direction, c: Charlist) -> String fn do(year: Int, day: Day, runners: RunnerMap, allow_crash: Bool) -> RunResult { - use #(pt_1, pt_2) <- result.then( + use #(pt_1, pt_2, parse) <- result.try( runners |> map.get(day) |> result.replace_error(Unregistered(day)), @@ -70,24 +72,35 @@ fn do(year: Int, day: Day, runners: RunnerMap, allow_crash: Bool) -> RunResult { let input_path = "input/" <> int.to_string(year) <> "/" <> int.to_string(day) <> ".txt" - use input <- result.then( + use input <- result.try( input_path |> simplifile.read() |> result.map(string_trim(_, Both, "\n")) |> result.replace_error(FailedToReadInput(input_path)), ) + let parse = option.unwrap(parse, dynamic.from) + case allow_crash { - True -> Ok(#(Ok(pt_1(input)), Ok(pt_2(input)))) + True -> { + let input = parse(input) + Ok(#(Ok(pt_1(input)), Ok(pt_2(input)))) + } False -> { + use input <- result.try( + fn() { parse(input) } + |> erlang.rescue + |> result.map_error(crash_to_string) + |> result.map_error(FailedToParseInput), + ) let pt_1 = fn() { pt_1(input) } |> erlang.rescue - |> result.map_error(crash_to_string) + |> result.map_error(crash_to_solve_err) let pt_2 = fn() { pt_2(input) } |> erlang.rescue - |> result.map_error(crash_to_string) + |> result.map_error(crash_to_solve_err) Ok(#(pt_1, pt_2)) } } @@ -149,13 +162,18 @@ fn gleam_err_to_string(g: GleamErr) -> String { ) } -fn crash_to_string(err: erlang.Crash) -> SolveErr { +fn crash_to_string(err: erlang.Crash) -> String { crash_to_dyn(err) |> decode_gleam_err() |> result.map(gleam_err_to_string) |> result.lazy_unwrap(fn() { "run failed for some reason: " <> string.inspect(err) }) +} + +fn crash_to_solve_err(err: erlang.Crash) -> SolveErr { + err + |> crash_to_string |> RunFailed } diff --git a/src/gladvent/internal/runners.gleam b/src/gladvent/internal/runners.gleam index 6cc6784..debaecd 100644 --- a/src/gladvent/internal/runners.gleam +++ b/src/gladvent/internal/runners.gleam @@ -8,13 +8,13 @@ import gleam/result import gleam import gleam/dynamic.{type Dynamic} import gleam/int -import gleam/function +import gleam/option.{type Option} pub type PartRunner = - fn(String) -> Dynamic + fn(Dynamic) -> Dynamic pub type DayRunner = - #(PartRunner, PartRunner) + #(PartRunner, PartRunner, Option(fn(String) -> Dynamic)) pub type RunnerMap = Map(Day, DayRunner) @@ -80,15 +80,16 @@ fn get_runner(year: Int, filename: String) -> Result(#(Day, DayRunner)) { |> to_module_name |> atom.create_from_string - let p = case function_exists(year, filename, module, "parse") { - Ok(p) -> p - Error(_) -> function.identity - } - use pt_1 <- result.then(function_exists(year, filename, module, "pt_1")) use pt_2 <- result.then(function_exists(year, filename, module, "pt_2")) - Ok(#(day, #(function.compose(p, pt_1), function.compose(p, pt_2)))) + Ok( + #(day, #( + pt_1, + pt_2, + option.from_result(function_exists(year, filename, module, "parse")), + )), + ) } pub fn build_from_days_dir(year: Int) -> Result(Map(Day, DayRunner)) {