-module(molt@internal@classifier).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/classifier.gleam").
-export([match_datetime/1, match_type/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-file("src/molt/internal/classifier.gleam", 258).
?DOC(false).
-spec do_take_digits(binary(), list(binary()), fun((binary()) -> boolean())) -> {boolean(),
binary(),
binary()}.
do_take_digits(Text, Acc, Predicate) ->
gleam@bool:lazy_guard(
Text =:= <<""/utf8>>,
fun() ->
{true, molt@internal@utils:reverse_concat(Acc), <<""/utf8>>}
end,
fun() -> case molt@internal@utils:split_at(Text, 1) of
{<<"_"/utf8>>, <<""/utf8>>} ->
{false, <<""/utf8>>, <<""/utf8>>};
{<<"_"/utf8>>, <<"_"/utf8, _/binary>>} ->
{false, <<""/utf8>>, <<""/utf8>>};
{<<"_"/utf8>>, Rest} ->
gleam@bool:guard(
not Predicate(gleam@string:slice(Rest, 0, 1)),
{false, <<""/utf8>>, <<""/utf8>>},
fun() -> do_take_digits(Rest, Acc, Predicate) end
);
{First, Rest@1} ->
gleam@bool:guard(
Predicate(First),
do_take_digits(Rest@1, [First | Acc], Predicate),
fun() ->
{true,
molt@internal@utils:reverse_concat(Acc),
Text}
end
)
end end
).
-file("src/molt/internal/classifier.gleam", 245).
?DOC(false).
-spec take_digits(binary()) -> {boolean(), binary(), binary()}.
take_digits(Text) ->
gleam@bool:guard(
Text =:= <<""/utf8>>,
{false, <<""/utf8>>, <<""/utf8>>},
fun() ->
{First, Rest} = molt@internal@utils:split_at(Text, 1),
gleam@bool:guard(
begin
_pipe = casefold:is_decimal_grapheme(First),
gleam@bool:negate(_pipe)
end,
{false, <<""/utf8>>, <<""/utf8>>},
fun() ->
do_take_digits(
Rest,
[First],
fun casefold:is_decimal_grapheme/1
)
end
)
end
).
-file("src/molt/internal/classifier.gleam", 296).
?DOC(false).
-spec match_exponent(binary()) -> gleam@option:option(molt@types:toml_kind()).
match_exponent(Text) ->
Text@1 = case Text of
<<"+"/utf8, Rest/binary>> ->
Rest;
<<"-"/utf8, Rest/binary>> ->
Rest;
_ ->
Text
end,
gleam@bool:guard(
Text@1 =:= <<""/utf8>>,
none,
fun() ->
gleam@bool:guard(
begin
_pipe = gleam@string:slice(Text@1, 0, 1),
_pipe@1 = casefold:is_decimal_grapheme(_pipe),
gleam@bool:negate(_pipe@1)
end,
none,
fun() -> case take_digits(Text@1) of
{true, _, <<""/utf8>>} ->
{some, float};
_ ->
none
end end
)
end
).
-file("src/molt/internal/classifier.gleam", 288).
?DOC(false).
-spec has_invalid_leading_zero(binary()) -> boolean().
has_invalid_leading_zero(Text) ->
case Text of
<<"0"/utf8>> ->
false;
<<"0"/utf8, _/binary>> ->
true;
_ ->
false
end.
-file("src/molt/internal/classifier.gleam", 78).
?DOC(false).
-spec match_decimal(binary()) -> gleam@option:option(molt@types:toml_kind()).
match_decimal(Text) ->
Text@1 = case Text of
<<"+"/utf8, Rest/binary>> ->
Rest;
<<"-"/utf8, Rest/binary>> ->
Rest;
_ ->
Text
end,
gleam@bool:guard(
Text@1 =:= <<""/utf8>>,
none,
fun() ->
gleam@bool:guard(
begin
_pipe = gleam@string:slice(Text@1, 0, 1),
_pipe@1 = casefold:is_decimal_grapheme(_pipe),
gleam@bool:negate(_pipe@1)
end,
none,
fun() ->
{Valid, Integer, Decimal} = take_digits(Text@1),
gleam@bool:guard(
not Valid,
none,
fun() ->
gleam@bool:guard(
has_invalid_leading_zero(Integer),
none,
fun() -> case Decimal of
<<""/utf8>> ->
{some, integer};
<<"."/utf8>> ->
none;
<<"."/utf8, Fraction/binary>> ->
{Valid@1, Fraction@1, Exponent} = take_digits(
Fraction
),
gleam@bool:guard(
not Valid@1,
none,
fun() ->
gleam@bool:guard(
Fraction@1 =:= <<""/utf8>>,
none,
fun() ->
case Exponent of
<<""/utf8>> ->
{some,
float};
<<"e"/utf8, Exponent@1/binary>> ->
match_exponent(
Exponent@1
);
<<"E"/utf8, Exponent@1/binary>> ->
match_exponent(
Exponent@1
);
_ ->
none
end
end
)
end
);
<<"e"/utf8, Exponent@2/binary>> ->
match_exponent(Exponent@2);
<<"E"/utf8, Exponent@2/binary>> ->
match_exponent(Exponent@2);
_ ->
none
end end
)
end
)
end
)
end
).
-file("src/molt/internal/classifier.gleam", 233).
?DOC(false).
-spec do_match_digits(binary(), fun((binary()) -> boolean())) -> boolean().
do_match_digits(Text, Predicate) ->
gleam@bool:guard(
Text =:= <<""/utf8>>,
true,
fun() -> case molt@internal@utils:split_at(Text, 1) of
{<<"_"/utf8>>, <<""/utf8>>} ->
false;
{<<"_"/utf8>>, <<"_"/utf8, _/binary>>} ->
false;
{<<"_"/utf8>>, Rest} ->
do_match_digits(Rest, Predicate);
{First, Rest@1} ->
Predicate(First) andalso do_match_digits(Rest@1, Predicate)
end end
).
-file("src/molt/internal/classifier.gleam", 227).
?DOC(false).
-spec match_digits(binary(), fun((binary()) -> boolean())) -> boolean().
match_digits(Text, Predicate) ->
gleam@bool:guard(
Text =:= <<""/utf8>>,
false,
fun() ->
{First, Rest} = molt@internal@utils:split_at(Text, 1),
Predicate(First) andalso do_match_digits(Rest, Predicate)
end
).
-file("src/molt/internal/classifier.gleam", 51).
?DOC(false).
-spec match_number(binary()) -> gleam@option:option(molt@types:toml_kind()).
match_number(Text) ->
case Text of
<<"0x"/utf8, Rest/binary>> ->
case match_digits(Rest, fun casefold:is_hex_grapheme/1) of
true ->
{some, hex_integer};
false ->
none
end;
<<"0o"/utf8, Rest@1/binary>> ->
case match_digits(Rest@1, fun casefold:is_octal_grapheme/1) of
true ->
{some, octal_integer};
false ->
none
end;
<<"0b"/utf8, Rest@2/binary>> ->
case match_digits(Rest@2, fun casefold:is_binary_grapheme/1) of
true ->
{some, binary_integer};
false ->
none
end;
_ ->
match_decimal(Text)
end.
-file("src/molt/internal/classifier.gleam", 213).
?DOC(false).
-spec valid_time_fraction(binary()) -> boolean().
valid_time_fraction(Fraction) ->
case Fraction of
<<""/utf8>> ->
true;
<<"."/utf8>> ->
false;
<<"."/utf8, Fraction@1/binary>> ->
casefold:is_decimal(Fraction@1);
_ ->
false
end.
-file("src/molt/internal/classifier.gleam", 192).
?DOC(false).
-spec match_time_parts(binary(), binary(), binary(), binary()) -> boolean().
match_time_parts(Hour, Minute, Second, Fraction) ->
gleam@bool:guard(
string:length(Hour) /= 2,
false,
fun() ->
Hour@1 = begin
_pipe = gleam_stdlib:parse_int(Hour),
gleam@result:unwrap(_pipe, -1)
end,
gleam@bool:guard(
(Hour@1 < 0) orelse (Hour@1 > 23),
false,
fun() ->
gleam@bool:guard(
string:length(Minute) /= 2,
false,
fun() ->
Minute@1 = begin
_pipe@1 = gleam_stdlib:parse_int(Minute),
gleam@result:unwrap(_pipe@1, -1)
end,
gleam@bool:guard(
(Minute@1 < 0) orelse (Minute@1 > 59),
false,
fun() ->
gleam@bool:guard(
Second =:= <<""/utf8>>,
true,
fun() ->
gleam@bool:guard(
string:length(Second) /= 2,
false,
fun() ->
Second@1 = begin
_pipe@2 = gleam_stdlib:parse_int(
Second
),
gleam@result:unwrap(
_pipe@2,
-1
)
end,
((Second@1 >= 0) andalso (Second@1
=< 60))
andalso valid_time_fraction(
Fraction
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/molt/internal/classifier.gleam", 181).
?DOC(false).
-spec match_local_time(binary()) -> boolean().
match_local_time(Text) ->
case gleam@string:split(Text, <<":"/utf8>>) of
[Hour, Minute] ->
match_time_parts(Hour, Minute, <<""/utf8>>, <<""/utf8>>);
[Hour@1, Minute@1, Second] ->
{Second@1, Fraction} = molt@internal@utils:split_at(Second, 2),
match_time_parts(Hour@1, Minute@1, Second@1, Fraction);
_ ->
false
end.
-file("src/molt/internal/classifier.gleam", 360).
?DOC(false).
-spec is_leap(integer()) -> boolean().
is_leap(Year) ->
gleam@bool:guard(
(Year rem 4) /= 0,
false,
fun() ->
gleam@bool:guard(
(Year rem 100) /= 0,
true,
fun() -> (Year rem 400) =:= 0 end
)
end
).
-file("src/molt/internal/classifier.gleam", 347).
?DOC(false).
-spec days_in_month(integer(), integer()) -> integer().
days_in_month(Year, Month) ->
case Month of
1 ->
31;
3 ->
31;
5 ->
31;
7 ->
31;
8 ->
31;
10 ->
31;
12 ->
31;
4 ->
30;
6 ->
30;
9 ->
30;
11 ->
30;
2 ->
case is_leap(Year) of
true ->
29;
false ->
28
end;
_ ->
0
end.
-file("src/molt/internal/classifier.gleam", 159).
?DOC(false).
-spec valid_date_parts(binary(), binary(), binary()) -> boolean().
valid_date_parts(Year, Month, Day) ->
gleam@bool:guard(
string:length(Year) /= 4,
false,
fun() ->
gleam@bool:guard(
string:length(Month) /= 2,
false,
fun() ->
gleam@bool:guard(
string:length(Day) /= 2,
false,
fun() ->
Year@1 = begin
_pipe = gleam_stdlib:parse_int(Year),
gleam@result:unwrap(_pipe, -1)
end,
Month@1 = begin
_pipe@1 = gleam_stdlib:parse_int(Month),
gleam@result:unwrap(_pipe@1, 0)
end,
Day@1 = begin
_pipe@2 = gleam_stdlib:parse_int(Day),
gleam@result:unwrap(_pipe@2, 0)
end,
(((((Year@1 >= 0) andalso (Year@1 < 10000)) andalso (Month@1
>= 1))
andalso (Month@1 =< 12))
andalso (Day@1 >= 1))
andalso (Day@1 =< days_in_month(Year@1, Month@1))
end
)
end
)
end
).
-file("src/molt/internal/classifier.gleam", 152).
?DOC(false).
-spec match_local_date(binary()) -> boolean().
match_local_date(Text) ->
case gleam@string:split(Text, <<"-"/utf8>>) of
[Year, Month, Day] ->
valid_date_parts(Year, Month, Day);
_ ->
false
end.
-file("src/molt/internal/classifier.gleam", 137).
?DOC(false).
-spec match_local_datetime(binary()) -> boolean().
match_local_datetime(Text) ->
case molt@internal@utils:split_at(Text, 10) of
{_, <<""/utf8>>} ->
false;
{Date_part, Rest} ->
case {match_local_date(Date_part), Rest} of
{true, <<"T"/utf8, Time_part/binary>>} ->
match_local_time(Time_part);
{true, <<"t"/utf8, Time_part/binary>>} ->
match_local_time(Time_part);
{true, <<" "/utf8, Time_part/binary>>} ->
match_local_time(Time_part);
{_, _} ->
false
end
end.
-file("src/molt/internal/classifier.gleam", 340).
?DOC(false).
-spec match_offset_body(binary()) -> boolean().
match_offset_body(Text) ->
case gleam@string:split(Text, <<":"/utf8>>) of
[Hour, Minute] ->
match_time_parts(Hour, Minute, <<""/utf8>>, <<""/utf8>>);
_ ->
false
end.
-file("src/molt/internal/classifier.gleam", 321).
?DOC(false).
-spec do_match_time_offset(binary(), list(binary()), integer()) -> boolean().
do_match_time_offset(Input, Acc, Count) ->
case Input of
<<""/utf8>> ->
false;
<<"Z"/utf8, Input@1/binary>> ->
(Input@1 =:= <<""/utf8>>) andalso match_local_time(
molt@internal@utils:reverse_concat(Acc)
);
<<"z"/utf8, Input@1/binary>> ->
(Input@1 =:= <<""/utf8>>) andalso match_local_time(
molt@internal@utils:reverse_concat(Acc)
);
<<"+"/utf8, Input@2/binary>> when Count >= 5 ->
match_local_time(molt@internal@utils:reverse_concat(Acc)) andalso match_offset_body(
Input@2
);
<<"-"/utf8, Input@2/binary>> when Count >= 5 ->
match_local_time(molt@internal@utils:reverse_concat(Acc)) andalso match_offset_body(
Input@2
);
_ ->
{Ch, Input@3} = molt@internal@utils:split_at(Input, 1),
do_match_time_offset(Input@3, [Ch | Acc], Count + 1)
end.
-file("src/molt/internal/classifier.gleam", 317).
?DOC(false).
-spec match_time_offset(binary()) -> boolean().
match_time_offset(Input) ->
do_match_time_offset(Input, [], 0).
-file("src/molt/internal/classifier.gleam", 120).
?DOC(false).
-spec match_offset_datetime(binary()) -> boolean().
match_offset_datetime(Text) ->
case molt@internal@utils:split_at(Text, 10) of
{_, <<""/utf8>>} ->
false;
{Date_part, Rest} ->
case {match_local_date(Date_part), Rest} of
{true, <<"T"/utf8, Time_and_offset/binary>>} ->
match_time_offset(Time_and_offset);
{true, <<"t"/utf8, Time_and_offset/binary>>} ->
match_time_offset(Time_and_offset);
{true, <<" "/utf8, Time_and_offset/binary>>} ->
match_time_offset(Time_and_offset);
{_, _} ->
false
end
end.
-file("src/molt/internal/classifier.gleam", 34).
?DOC(false).
-spec match_datetime(binary()) -> gleam@option:option(molt@types:toml_kind()).
match_datetime(Text) ->
gleam@bool:guard(
match_offset_datetime(Text),
{some, offset_date_time},
fun() ->
gleam@bool:guard(
match_local_datetime(Text),
{some, local_date_time},
fun() ->
gleam@bool:guard(
match_local_date(Text),
{some, local_date},
fun() ->
gleam@bool:guard(
match_local_time(Text),
{some, local_time},
fun() -> none end
)
end
)
end
)
end
).
-file("src/molt/internal/classifier.gleam", 15).
?DOC(false).
-spec match_type(binary()) -> gleam@option:option(molt@types:toml_kind()).
match_type(Text) ->
case Text of
<<"true"/utf8>> ->
{some, bool_true};
<<"false"/utf8>> ->
{some, bool_false};
<<"inf"/utf8>> ->
{some, inf};
<<"+inf"/utf8>> ->
{some, pos_inf};
<<"-inf"/utf8>> ->
{some, neg_inf};
<<"nan"/utf8>> ->
{some, na_n};
<<"+nan"/utf8>> ->
{some, pos_na_n};
<<"-nan"/utf8>> ->
{some, neg_na_n};
_ ->
_pipe = match_datetime(Text),
gleam@option:lazy_or(_pipe, fun() -> match_number(Text) end)
end.