-module(diced). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([parse/1]). -export_type([modifier/0, dice/0, dice_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type modifier() :: {keep_highest, integer()} | {keep_lowest, integer()} | {drop_highest, integer()} | {drop_lowest, integer()} | {reroll, integer()} | {recursive_reroll, integer()} | {explode, integer()} | {minimum, integer()} | {maximum, integer()}. -type dice() :: {basic, integer(), integer(), list(modifier())} | {fate, integer(), list(modifier())} | {number, integer(), list(modifier())}. -type dice_error() :: invalid_amount | invalid_string | invalid_value | invalid_modifier. -file("src/diced.gleam", 96). -spec parse_amount(binary()) -> {ok, integer()} | {error, dice_error()}. parse_amount(Amount) -> _pipe = gleam_stdlib:parse_int(Amount), gleam@result:replace_error(_pipe, invalid_amount). -file("src/diced.gleam", 148). -spec do_with_modifier_value(binary(), integer()) -> {binary(), integer()}. do_with_modifier_value(String, Value) -> case String of <<"0"/utf8, Rest/binary>> -> do_with_modifier_value(Rest, Value * 10); <<"1"/utf8, Rest@1/binary>> -> do_with_modifier_value(Rest@1, (Value * 10) + 1); <<"2"/utf8, Rest@2/binary>> -> do_with_modifier_value(Rest@2, (Value * 10) + 2); <<"3"/utf8, Rest@3/binary>> -> do_with_modifier_value(Rest@3, (Value * 10) + 3); <<"4"/utf8, Rest@4/binary>> -> do_with_modifier_value(Rest@4, (Value * 10) + 4); <<"5"/utf8, Rest@5/binary>> -> do_with_modifier_value(Rest@5, (Value * 10) + 5); <<"6"/utf8, Rest@6/binary>> -> do_with_modifier_value(Rest@6, (Value * 10) + 6); <<"7"/utf8, Rest@7/binary>> -> do_with_modifier_value(Rest@7, (Value * 10) + 7); <<"8"/utf8, Rest@8/binary>> -> do_with_modifier_value(Rest@8, (Value * 10) + 8); <<"9"/utf8, Rest@9/binary>> -> do_with_modifier_value(Rest@9, (Value * 10) + 9); _ -> {String, Value} end. -file("src/diced.gleam", 141). -spec with_modifier_value(binary()) -> {binary(), integer()}. with_modifier_value(String) -> case do_with_modifier_value(String, 0) of {A, V} when V =:= 0 -> {A, 1}; {A@1, V@1} -> {A@1, V@1} end. -file("src/diced.gleam", 101). -spec parse_value(binary()) -> {ok, {integer(), binary()}} | {error, dice_error()}. parse_value(Value) -> Modifier_splitter = splitter:new( [<<"kh"/utf8>>, <<"kl"/utf8>>, <<"dh"/utf8>>, <<"dl"/utf8>>, <<"r"/utf8>>, <<"R"/utf8>>, <<"!"/utf8>>, <<"m"/utf8>>, <<"M"/utf8>>] ), {Value@1, A, B} = splitter_ffi:split(Modifier_splitter, Value), gleam@result:'try'( gleam@result:replace_error( gleam_stdlib:parse_int(Value@1), invalid_value ), fun(Value@2) -> {ok, {Value@2, <>}} end ). -file("src/diced.gleam", 112). -spec do_parse_modifiers( binary(), {ok, list(modifier())} | {error, dice_error()} ) -> {ok, list(modifier())} | {error, dice_error()}. do_parse_modifiers(Modifiers, Found) -> gleam@result:'try'( Found, fun(Found@1) -> Splitter = splitter:new( [<<"kh"/utf8>>, <<"kl"/utf8>>, <<"dh"/utf8>>, <<"dl"/utf8>>, <<"r"/utf8>>, <<"R"/utf8>>, <<"!"/utf8>>, <<"m"/utf8>>, <<"M"/utf8>>] ), case splitter_ffi:split(Splitter, Modifiers) of {<<""/utf8>>, <<""/utf8>>, <<""/utf8>>} -> {ok, lists:reverse(Found@1)}; {<<""/utf8>>, Mod, Rest} -> {Rest@1, Value} = with_modifier_value(Rest), Modifier = case Mod of <<"kh"/utf8>> -> {keep_highest, Value}; <<"kl"/utf8>> -> {keep_lowest, Value}; <<"dh"/utf8>> -> {drop_highest, Value}; <<"dl"/utf8>> -> {drop_lowest, Value}; <<"r"/utf8>> -> {reroll, Value}; <<"R"/utf8>> -> {recursive_reroll, Value}; <<"!"/utf8>> -> {explode, Value}; <<"m"/utf8>> -> {minimum, Value}; <<"M"/utf8>> -> {maximum, Value}; _ -> erlang:error(#{gleam_error => panic, message => <<"unreachable"/utf8>>, module => <<"diced"/utf8>>, function => <<"do_parse_modifiers"/utf8>>, line => 133}) end, do_parse_modifiers(Rest@1, {ok, [Modifier | Found@1]}); _ -> {error, invalid_modifier} end end ). -file("src/diced.gleam", 108). -spec parse_modifiers(binary()) -> {ok, list(modifier())} | {error, dice_error()}. parse_modifiers(Modifiers) -> do_parse_modifiers(Modifiers, {ok, []}). -file("src/diced.gleam", 62). ?DOC( " Convert a string containing algebraic dice notation into a type describing how the dice should behave when rolled.\n" "\n" " ```gleam\n" " diced.parse(\"2d20kh\")\n" " // Ok(diced.Basic(2, 20, [KeepHighest(1)]))\n" " ```\n" ). -spec parse(binary()) -> {ok, dice()} | {error, dice_error()}. parse(String) -> Dice_splitter = splitter:new([<<"d"/utf8>>, <<"dF"/utf8>>]), case splitter_ffi:split(Dice_splitter, String) of {Value, <<""/utf8>>, Mods} -> gleam@result:'try'( begin _pipe = gleam_stdlib:parse_int(Value), gleam@result:replace_error(_pipe, invalid_value) end, fun(Value@1) -> gleam@result:'try'( parse_modifiers(Mods), fun(Modifiers) -> {ok, {number, Value@1, Modifiers}} end ) end ); {Amount, <<"d"/utf8>>, <<""/utf8>>} -> gleam@result:'try'( parse_amount(Amount), fun(Amount@1) -> {ok, {basic, Amount@1, 6, []}} end ); {<<""/utf8>>, <<"d"/utf8>>, Mods@1} -> gleam@result:'try'( parse_value(Mods@1), fun(_use0) -> {Value@2, Rest} = _use0, gleam@result:'try'( parse_modifiers(Rest), fun(Modifiers@1) -> {ok, {basic, 1, Value@2, Modifiers@1}} end ) end ); {Amount@2, <<"d"/utf8>>, Mods@2} -> gleam@result:'try'( parse_amount(Amount@2), fun(Amount@3) -> gleam@result:'try'( parse_value(Mods@2), fun(_use0@1) -> {Value@3, Rest@1} = _use0@1, gleam@result:'try'( parse_modifiers(Rest@1), fun(Modifiers@2) -> {ok, {basic, Amount@3, Value@3, Modifiers@2}} end ) end ) end ); {Amount@4, <<"dF"/utf8>>, Mods@3} -> gleam@result:'try'( parse_amount(Amount@4), fun(Amount@5) -> gleam@result:'try'( parse_modifiers(Mods@3), fun(Modifiers@3) -> {ok, {fate, Amount@5, Modifiers@3}} end ) end ); {_, _, _} -> {error, invalid_string} end.