-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, <<""/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 ).