Current section
Files
Jump to
Current section
Files
src/automata@ical@parser.erl
-module(automata@ical@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/ical/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() :: {unexpected_end, integer()} |
{mismatched_block, binary(), binary(), integer()} |
{malformed_property, integer(), binary()} |
{malformed_parameter, integer(), binary()} |
empty_input_error.
-file("src/automata/ical/parser.gleam", 26).
-spec lex_error_to_parse_error(automata@ical@lexer:lex_error()) -> parse_error().
lex_error_to_parse_error(Err) ->
case Err of
empty_input ->
empty_input_error;
{malformed_line, Ln, Raw} ->
{malformed_property, Ln, Raw};
{malformed_parameter, Ln@1, Raw@1} ->
{malformed_parameter, Ln@1, Raw@1}
end.
-file("src/automata/ical/parser.gleam", 36).
-spec tokenize_all(
list(automata@ical@lexer:logical_line()),
list(automata@ical@ast:raw_property())
) -> {ok, list(automata@ical@ast:raw_property())} | {error, parse_error()}.
tokenize_all(Lines, Acc) ->
case Lines of
[] ->
{ok, lists:reverse(Acc)};
[First | Rest] ->
case automata@ical@lexer:tokenize_line(First) of
{error, Err} ->
{error, lex_error_to_parse_error(Err)};
{ok, Prop} ->
tokenize_all(Rest, [Prop | Acc])
end
end.
-file("src/automata/ical/parser.gleam", 79).
?DOC(" BEGIN:kind の中を読み進めて、END:kind を見つけたらそこで切り上げる。\n").
-spec consume_component(
binary(),
integer(),
list(automata@ical@ast:raw_property()),
list(automata@ical@ast:raw_property()),
list(automata@ical@ast:raw_component())
) -> {ok,
{automata@ical@ast:raw_component(),
list(automata@ical@ast:raw_property())}} |
{error, parse_error()}.
consume_component(Kind, Begin_line, Properties, Acc_props, Acc_children) ->
case Properties of
[] ->
{error, {mismatched_block, Kind, <<"<eof>"/utf8>>, Begin_line}};
[First | Rest] ->
{raw_property, Name, _, Raw_value, Ln} = First,
case Name of
<<"END"/utf8>> ->
End_kind = string:uppercase(Raw_value),
case End_kind =:= Kind of
true ->
Component = {raw_component,
Kind,
lists:reverse(Acc_props),
lists:reverse(Acc_children),
Begin_line},
{ok, {Component, Rest}};
false ->
{error, {mismatched_block, Kind, End_kind, Ln}}
end;
<<"BEGIN"/utf8>> ->
Child_kind = string:uppercase(Raw_value),
gleam@result:'try'(
consume_component(Child_kind, Ln, Rest, [], []),
fun(_use0) ->
{Child, After} = _use0,
consume_component(
Kind,
Begin_line,
After,
Acc_props,
[Child | Acc_children]
)
end
);
_ ->
consume_component(
Kind,
Begin_line,
Rest,
[First | Acc_props],
Acc_children
)
end
end.
-file("src/automata/ical/parser.gleam", 50).
-spec build_calendar(list(automata@ical@ast:raw_property())) -> {ok,
automata@ical@ast:raw_calendar()} |
{error, parse_error()}.
build_calendar(Properties) ->
case Properties of
[] ->
{error, empty_input_error};
[{raw_property, Name, _, Raw_value, Ln} | Rest] ->
Normalized_name = Name,
Normalized_value = string:uppercase(Raw_value),
case {Normalized_name, Normalized_value} of
{<<"BEGIN"/utf8>>, <<"VCALENDAR"/utf8>>} ->
gleam@result:'try'(
consume_component(
<<"VCALENDAR"/utf8>>,
Ln,
Rest,
[],
[]
),
fun(_use0) ->
{Vcal, Leftover} = _use0,
case Leftover of
[] ->
{raw_component, _, Props, Children, _} = Vcal,
{ok, {raw_calendar, Props, Children}};
[{raw_property, _, _, _, Leftover_ln} | _] ->
{error, {unexpected_end, Leftover_ln}}
end
end
);
{_, _} ->
{error, {unexpected_end, Ln}}
end
end.
-file("src/automata/ical/parser.gleam", 18).
-spec parse(binary()) -> {ok, automata@ical@ast:raw_calendar()} |
{error, parse_error()}.
parse(Input) ->
gleam@result:'try'(
begin
_pipe = automata@ical@lexer:unfold(Input),
gleam@result:map_error(_pipe, fun lex_error_to_parse_error/1)
end,
fun(Logical_lines) ->
gleam@result:'try'(
tokenize_all(Logical_lines, []),
fun(Properties) -> build_calendar(Properties) end
)
end
).