Current section

Files

Jump to
automata src automata@cron@parser.erl
Raw

src/automata@cron@parser.erl

-module(automata@cron@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/cron/parser.gleam").
-export([parse/1]).
-export_type([parse_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 parse_error() :: {invalid_expression, binary()} |
{invalid_field_count, integer(), integer()} |
{empty_field, automata@cron@ast:field()} |
{unsupported_syntax, automata@cron@ast:field(), binary()} |
{reboot_not_supported, binary()}.
-file("src/automata/cron/parser.gleam", 60).
?DOC(
" Translate the Vixie cron nickname aliases (`@yearly`, `@annually`,\n"
" `@monthly`, `@weekly`, `@daily`, `@midnight`, `@hourly`) into their\n"
" canonical 5-field forms. Matching is case-insensitive, in line with\n"
" the spec and existing parsers (croniter, robfig/cron, node-cron).\n"
" `@reboot` is recognised but rejected with `RebootNotSupported`\n"
" (no 5-field equivalent — see the variant doc). Anything else\n"
" starting with `@` is `UnsupportedSyntax`.\n"
).
-spec parse_nickname(binary()) -> {ok, automata@cron@ast:raw_cron()} |
{error, parse_error()}.
parse_nickname(Value) ->
case string:lowercase(Value) of
<<"@yearly"/utf8>> ->
{ok,
{raw_cron,
<<"0"/utf8>>,
<<"0"/utf8>>,
<<"1"/utf8>>,
<<"1"/utf8>>,
<<"*"/utf8>>}};
<<"@annually"/utf8>> ->
{ok,
{raw_cron,
<<"0"/utf8>>,
<<"0"/utf8>>,
<<"1"/utf8>>,
<<"1"/utf8>>,
<<"*"/utf8>>}};
<<"@monthly"/utf8>> ->
{ok,
{raw_cron,
<<"0"/utf8>>,
<<"0"/utf8>>,
<<"1"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>}};
<<"@weekly"/utf8>> ->
{ok,
{raw_cron,
<<"0"/utf8>>,
<<"0"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>,
<<"0"/utf8>>}};
<<"@daily"/utf8>> ->
{ok,
{raw_cron,
<<"0"/utf8>>,
<<"0"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>}};
<<"@midnight"/utf8>> ->
{ok,
{raw_cron,
<<"0"/utf8>>,
<<"0"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>}};
<<"@hourly"/utf8>> ->
{ok,
{raw_cron,
<<"0"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>,
<<"*"/utf8>>}};
<<"@reboot"/utf8>> ->
{error, {reboot_not_supported, Value}};
_ ->
{error, {unsupported_syntax, expression, Value}}
end.
-file("src/automata/cron/parser.gleam", 107).
-spec first_empty_field(list(binary())) -> gleam@option:option(automata@cron@ast:field()).
first_empty_field(Fields) ->
case Fields of
[Minute, Hour, Day_of_month, Month, Day_of_week] ->
case Minute =:= <<""/utf8>> of
true ->
{some, minute};
false ->
case Hour =:= <<""/utf8>> of
true ->
{some, hour};
false ->
case Day_of_month =:= <<""/utf8>> of
true ->
{some, day_of_month};
false ->
case Month =:= <<""/utf8>> of
true ->
{some, month};
false ->
case Day_of_week =:= <<""/utf8>> of
true ->
{some, day_of_week};
false ->
none
end
end
end
end
end;
_ ->
none
end.
-file("src/automata/cron/parser.gleam", 151).
-spec flush_split_parts({list(binary()), binary()}) -> list(binary()).
flush_split_parts(Parts) ->
{Collected, Current} = Parts,
case Current =:= <<""/utf8>> of
true ->
lists:reverse(Collected);
false ->
lists:reverse([Current | Collected])
end.
-file("src/automata/cron/parser.gleam", 160).
-spec is_whitespace(binary()) -> boolean().
is_whitespace(Grapheme) ->
case Grapheme of
<<" "/utf8>> ->
true;
<<"\t"/utf8>> ->
true;
<<"\n"/utf8>> ->
true;
<<"\r"/utf8>> ->
true;
_ ->
false
end.
-file("src/automata/cron/parser.gleam", 134).
-spec split_whitespace(binary()) -> list(binary()).
split_whitespace(Input) ->
_pipe = Input,
_pipe@1 = gleam@string:to_graphemes(_pipe),
_pipe@2 = gleam@list:fold(
_pipe@1,
{[], <<""/utf8>>},
fun(Acc, Grapheme) ->
{Parts, Current} = Acc,
case is_whitespace(Grapheme) of
true ->
case Current =:= <<""/utf8>> of
true ->
{Parts, <<""/utf8>>};
false ->
{[Current | Parts], <<""/utf8>>}
end;
false ->
{Parts, <<Current/binary, Grapheme/binary>>}
end
end
),
flush_split_parts(_pipe@2).
-file("src/automata/cron/parser.gleam", 35).
-spec parse_five_field(binary()) -> {ok, automata@cron@ast:raw_cron()} |
{error, parse_error()}.
parse_five_field(Trimmed) ->
case split_whitespace(Trimmed) of
[Minute, Hour, Day_of_month, Month, Day_of_week] ->
case first_empty_field(
[Minute, Hour, Day_of_month, Month, Day_of_week]
) of
{some, Field} ->
{error, {empty_field, Field}};
none ->
{ok,
{raw_cron,
Minute,
Hour,
Day_of_month,
Month,
Day_of_week}}
end;
Fields ->
{error, {invalid_field_count, 5, erlang:length(Fields)}}
end.
-file("src/automata/cron/parser.gleam", 22).
-spec parse(binary()) -> {ok, automata@cron@ast:raw_cron()} |
{error, parse_error()}.
parse(Input) ->
Trimmed = gleam@string:trim(Input),
case Trimmed of
<<""/utf8>> ->
{error, {invalid_expression, Input}};
_ ->
case gleam_stdlib:string_starts_with(Trimmed, <<"@"/utf8>>) of
true ->
parse_nickname(Trimmed);
false ->
parse_five_field(Trimmed)
end
end.