-module(tomlet@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/tomlet/parser.gleam"). -export([date_repr_is_valid/1, time_repr_is_valid/1, datetime_repr_is_valid/1, parse/1]). -export_type([parse_error/0, expected_token_kind/0, span_state/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. ?MODULEDOC(false). -type parse_error() :: {unexpected, binary(), expected_token_kind(), integer()} | {key_already_in_use, list(binary()), integer()}. -type expected_token_kind() :: expected_value | expected_key | expected_table_header | expected_syntax. -type span_state() :: span_outside | span_basic | span_literal | span_multi_basic | span_multi_literal | span_comment. -file("src/tomlet/parser.gleam", 1366). ?DOC(false). -spec strip_inline_comment_loop(list(binary()), boolean(), boolean(), binary()) -> binary(). strip_inline_comment_loop(Chars, In_basic, In_literal, Acc) -> case Chars of [] -> Acc; [<<"\\"/utf8>>, Escaped | Rest] -> case In_basic of true -> strip_inline_comment_loop( Rest, In_basic, In_literal, <<<>/binary, Escaped/binary>> ); false -> strip_inline_comment_loop( [Escaped | Rest], In_basic, In_literal, <> ) end; [<<"#"/utf8>> | Rest@1] -> case In_basic orelse In_literal of true -> strip_inline_comment_loop( Rest@1, In_basic, In_literal, <> ); false -> Acc end; [<<"\""/utf8>> | Rest@2] -> case In_literal of true -> strip_inline_comment_loop( Rest@2, In_basic, In_literal, <> ); false -> strip_inline_comment_loop( Rest@2, not In_basic, In_literal, <> ) end; [<<"'"/utf8>> | Rest@3] -> case In_basic of true -> strip_inline_comment_loop( Rest@3, In_basic, In_literal, <> ); false -> strip_inline_comment_loop( Rest@3, In_basic, not In_literal, <> ) end; [Char | Rest@4] -> strip_inline_comment_loop( Rest@4, In_basic, In_literal, <> ) end. -file("src/tomlet/parser.gleam", 1345). ?DOC(false). -spec strip_inline_comment(binary()) -> binary(). strip_inline_comment(Text) -> strip_inline_comment_loop( gleam@string:to_graphemes(Text), false, false, <<""/utf8>> ). -file("src/tomlet/parser.gleam", 1349). ?DOC(false). -spec strip_inline_comments_by_line(binary()) -> binary(). strip_inline_comments_by_line(Text) -> _pipe = Text, _pipe@1 = gleam@string:split(_pipe, <<"\n"/utf8>>), _pipe@2 = gleam@list:map(_pipe@1, fun strip_inline_comment/1), gleam@string:join(_pipe@2, <<"\n"/utf8>>). -file("src/tomlet/parser.gleam", 1115). ?DOC(false). -spec bracket_depth(list(binary()), integer(), boolean(), boolean()) -> integer(). bracket_depth(Chars, Depth, In_basic, In_literal) -> case Chars of [] -> Depth; [Char | Rest] -> case {Char, In_basic, In_literal} of {<<"\\"/utf8>>, true, false} -> case Rest of [] -> bracket_depth(Rest, Depth, In_basic, In_literal); [_ | After_escape] -> bracket_depth( After_escape, Depth, In_basic, In_literal ) end; {<<"\""/utf8>>, _, false} -> bracket_depth(Rest, Depth, not In_basic, In_literal); {<<"'"/utf8>>, false, _} -> bracket_depth(Rest, Depth, In_basic, not In_literal); {<<"["/utf8>>, false, false} -> bracket_depth(Rest, Depth + 1, In_basic, In_literal); {<<"{"/utf8>>, false, false} -> bracket_depth(Rest, Depth + 1, In_basic, In_literal); {<<"]"/utf8>>, false, false} -> bracket_depth(Rest, Depth - 1, In_basic, In_literal); {<<"}"/utf8>>, false, false} -> bracket_depth(Rest, Depth - 1, In_basic, In_literal); {_, _, _} -> bracket_depth(Rest, Depth, In_basic, In_literal) end end. -file("src/tomlet/parser.gleam", 1111). ?DOC(false). -spec brackets_are_balanced(binary()) -> boolean(). brackets_are_balanced(Text) -> bracket_depth(gleam@string:to_graphemes(Text), 0, false, false) =:= 0. -file("src/tomlet/parser.gleam", 98). ?DOC(false). -spec line_value_text(binary()) -> binary(). line_value_text(Line) -> case gleam@string:split_once(Line, <<"="/utf8>>) of {ok, {_, Raw_value}} -> gleam@string:trim(Raw_value); {error, nil} -> <<""/utf8>> end. -file("src/tomlet/parser.gleam", 92). ?DOC(false). -spec multiline_is_closed(binary()) -> boolean(). multiline_is_closed(Text) -> Triples = gleam@string:split(Text, <<"\"\"\""/utf8>>), Literal_triples = gleam@string:split(Text, <<"'''"/utf8>>), (erlang:length(Triples) > 2) orelse (erlang:length(Literal_triples) > 2). -file("src/tomlet/parser.gleam", 72). ?DOC(false). -spec starts_multiline_value(binary()) -> boolean(). starts_multiline_value(Line) -> gleam_stdlib:contains_string(Line, <<"\"\"\""/utf8>>) orelse gleam_stdlib:contains_string( Line, <<"'''"/utf8>> ). -file("src/tomlet/parser.gleam", 60). ?DOC(false). -spec line_needs_more_lines(binary()) -> boolean(). line_needs_more_lines(Line) -> gleam@bool:guard( starts_multiline_value(Line) andalso not multiline_is_closed(Line), true, fun() -> Value = line_value_text(Line), case Value of <<""/utf8>> -> false; _ -> not brackets_are_balanced( strip_inline_comments_by_line(Value) ) end end ). -file("src/tomlet/parser.gleam", 76). ?DOC(false). -spec collect_until_complete_value(list(binary()), binary()) -> {binary(), list(binary())}. collect_until_complete_value(Lines, Current) -> case Lines of [] -> {Current, []}; [Line | Rest] -> Next = <<<>/binary, Line/binary>>, case not line_needs_more_lines(Next) of true -> {Next, Rest}; false -> collect_until_complete_value(Rest, Next) end end. -file("src/tomlet/parser.gleam", 42). ?DOC(false). -spec merge_multiline_lines(list(binary()), list(binary())) -> list(binary()). merge_multiline_lines(Lines, Acc) -> case Lines of [] -> lists:reverse(Acc); [Line | Rest] -> case line_needs_more_lines(Line) of true -> {Merged, Remaining} = collect_until_complete_value( Rest, Line ), merge_multiline_lines(Remaining, [Merged | Acc]); false -> merge_multiline_lines(Rest, [Line | Acc]) end end. -file("src/tomlet/parser.gleam", 896). ?DOC(false). -spec dotted_table_paths_loop( list(binary()), list(binary()), list(binary()), list(list(binary())) ) -> list(list(binary())). dotted_table_paths_loop(Key, Prefix, Active_table, Acc) -> case Key of [] -> Acc; [_] -> Acc; [Segment | Rest] -> Next_prefix = lists:append(Prefix, [Segment]), Next_acc = case erlang:length(Next_prefix) > erlang:length( Active_table ) of true -> [Next_prefix | Acc]; false -> Acc end, dotted_table_paths_loop(Rest, Next_prefix, Active_table, Next_acc) end. -file("src/tomlet/parser.gleam", 889). ?DOC(false). -spec dotted_table_paths(list(binary()), list(binary())) -> list(list(binary())). dotted_table_paths(Active_table, Key) -> dotted_table_paths_loop(Key, [], Active_table, []). -file("src/tomlet/parser.gleam", 916). ?DOC(false). -spec add_paths(list(list(binary())), list(list(binary()))) -> list(list(binary())). add_paths(Paths, Existing) -> case Paths of [] -> Existing; [Path | Rest] -> case gleam@list:contains(Existing, Path) of true -> add_paths(Rest, Existing); false -> add_paths(Rest, [Path | Existing]) end end. -file("src/tomlet/parser.gleam", 881). ?DOC(false). -spec add_dotted_table_paths( list(list(binary())), list(binary()), list(binary()) ) -> list(list(binary())). add_dotted_table_paths(Existing, Active_table, Key) -> add_paths(dotted_table_paths(Active_table, Key), Existing). -file("src/tomlet/parser.gleam", 865). ?DOC(false). -spec dotted_key_extends_table( list(list(binary())), list(binary()), list(binary()) ) -> boolean(). dotted_key_extends_table(Table_paths, Active_table, Key) -> case Table_paths of [] -> false; [Table | Rest] -> (tomlet@key:starts_with(Key, Table) andalso not tomlet@key:starts_with( Active_table, Table )) orelse dotted_key_extends_table(Rest, Active_table, Key) end. -file("src/tomlet/parser.gleam", 855). ?DOC(false). -spec dotted_key_extends_defined_table( list(list(binary())), list(list(binary())), list(binary()), list(binary()) ) -> boolean(). dotted_key_extends_defined_table( Explicit_tables, Array_tables, Active_table, Key ) -> dotted_key_extends_table(Explicit_tables, Active_table, Key) orelse dotted_key_extends_table( Array_tables, Active_table, Key ). -file("src/tomlet/parser.gleam", 793). ?DOC(false). -spec key_path_conflicts(list(list(binary())), list(binary())) -> boolean(). key_path_conflicts(Seen, Key) -> case Seen of [] -> false; [Existing | Rest] -> (tomlet@key:starts_with(Existing, Key) orelse tomlet@key:starts_with( Key, Existing )) orelse key_path_conflicts(Rest, Key) end. -file("src/tomlet/parser.gleam", 786). ?DOC(false). -spec remove_keys_under_table(list(list(binary())), list(binary())) -> list(list(binary())). remove_keys_under_table(Seen, Table_key) -> gleam@list:filter( Seen, fun(Key) -> not tomlet@key:starts_with(Key, Table_key) end ). -file("src/tomlet/parser.gleam", 841). ?DOC(false). -spec array_table_parent_already_implied( tomlet@ast:header(), list(list(binary())), list(list(binary())), list(binary()) ) -> boolean(). array_table_parent_already_implied( Header, Array_tables, Array_table_parents, Key ) -> case Header of {header, _, array_of_tables_header, _} -> gleam@list:contains(Array_table_parents, Key) andalso not gleam@list:contains( Array_tables, Key ); _ -> false end. -file("src/tomlet/parser.gleam", 828). ?DOC(false). -spec table_kind_already_defined( tomlet@ast:header(), list(list(binary())), list(list(binary())), list(binary()) ) -> boolean(). table_kind_already_defined(Header, Explicit_tables, Array_tables, Key) -> case Header of {header, _, standard_table, _} -> gleam@list:contains(Array_tables, Key); {header, _, array_of_tables_header, _} -> gleam@list:contains(Explicit_tables, Key) end. -file("src/tomlet/parser.gleam", 816). ?DOC(false). -spec standard_table_already_defined( tomlet@ast:header(), list(list(binary())), list(binary()) ) -> boolean(). standard_table_already_defined(Header, Explicit_tables, Key) -> case Header of {header, _, standard_table, _} -> gleam@list:contains(Explicit_tables, Key); _ -> false end. -file("src/tomlet/parser.gleam", 803). ?DOC(false). -spec key_path_conflicts_for_table_header(list(list(binary())), list(binary())) -> boolean(). key_path_conflicts_for_table_header(Seen, Key) -> case Seen of [] -> false; [Existing | Rest] -> ((Existing =:= Key) orelse tomlet@key:starts_with(Key, Existing)) orelse key_path_conflicts_for_table_header(Rest, Key) end. -file("src/tomlet/parser.gleam", 781). ?DOC(false). -spec header_key(tomlet@ast:header()) -> list(binary()). header_key(Header) -> {header, Key, _, _} = Header, tomlet@key:to_strings(Key). -file("src/tomlet/parser.gleam", 1721). ?DOC(false). -spec based_int_result({ok, integer()} | {error, nil}, binary(), integer()) -> {ok, tomlet@ast:value()} | {error, parse_error()}. based_int_result(Result, Source_text, Offset) -> case Result of {ok, Value} -> {ok, {int, Value, Source_text}}; {error, nil} -> {error, {unexpected, Source_text, expected_value, Offset}} end. -file("src/tomlet/parser.gleam", 1759). ?DOC(false). -spec based_digit_value(binary()) -> {ok, integer()} | {error, nil}. based_digit_value(Char) -> case Char of <<"0"/utf8>> -> {ok, 0}; <<"1"/utf8>> -> {ok, 1}; <<"2"/utf8>> -> {ok, 2}; <<"3"/utf8>> -> {ok, 3}; <<"4"/utf8>> -> {ok, 4}; <<"5"/utf8>> -> {ok, 5}; <<"6"/utf8>> -> {ok, 6}; <<"7"/utf8>> -> {ok, 7}; <<"8"/utf8>> -> {ok, 8}; <<"9"/utf8>> -> {ok, 9}; <<"a"/utf8>> -> {ok, 10}; <<"A"/utf8>> -> {ok, 10}; <<"b"/utf8>> -> {ok, 11}; <<"B"/utf8>> -> {ok, 11}; <<"c"/utf8>> -> {ok, 12}; <<"C"/utf8>> -> {ok, 12}; <<"d"/utf8>> -> {ok, 13}; <<"D"/utf8>> -> {ok, 13}; <<"e"/utf8>> -> {ok, 14}; <<"E"/utf8>> -> {ok, 14}; <<"f"/utf8>> -> {ok, 15}; <<"F"/utf8>> -> {ok, 15}; _ -> {error, nil} end. -file("src/tomlet/parser.gleam", 1740). ?DOC(false). -spec parse_based_int_digits_loop(list(binary()), integer(), integer()) -> {ok, integer()} | {error, nil}. parse_based_int_digits_loop(Chars, Base, Acc) -> case Chars of [] -> {ok, Acc}; [Char | Rest] -> case based_digit_value(Char) of {ok, Value} -> case Value < Base of true -> parse_based_int_digits_loop( Rest, Base, (Acc * Base) + Value ); false -> {error, nil} end; {error, nil} -> {error, nil} end end. -file("src/tomlet/parser.gleam", 1732). ?DOC(false). -spec parse_based_int_digits(binary(), integer(), integer()) -> {ok, integer()} | {error, nil}. parse_based_int_digits(Text, Base, Acc) -> parse_based_int_digits_loop(gleam@string:to_graphemes(Text), Base, Acc). -file("src/tomlet/parser.gleam", 1696). ?DOC(false). -spec parse_based_int_value(binary(), binary(), integer()) -> {ok, tomlet@ast:value()} | {error, parse_error()}. parse_based_int_value(Normalized, Source_text, Offset) -> case gleam_stdlib:string_starts_with(Normalized, <<"0x"/utf8>>) of true -> _pipe = parse_based_int_digits( gleam@string:drop_start(Normalized, 2), 16, 0 ), based_int_result(_pipe, Source_text, Offset); false -> case gleam_stdlib:string_starts_with(Normalized, <<"0o"/utf8>>) of true -> _pipe@1 = parse_based_int_digits( gleam@string:drop_start(Normalized, 2), 8, 0 ), based_int_result(_pipe@1, Source_text, Offset); false -> case gleam_stdlib:string_starts_with( Normalized, <<"0b"/utf8>> ) of true -> _pipe@2 = parse_based_int_digits( gleam@string:drop_start(Normalized, 2), 2, 0 ), based_int_result(_pipe@2, Source_text, Offset); false -> {error, {unexpected, Source_text, expected_value, Offset}} end end end. -file("src/tomlet/parser.gleam", 2107). ?DOC(false). -spec char_is_digit(binary()) -> boolean(). char_is_digit(Char) -> case Char of <<"0"/utf8>> -> true; <<"1"/utf8>> -> true; <<"2"/utf8>> -> true; <<"3"/utf8>> -> true; <<"4"/utf8>> -> true; <<"5"/utf8>> -> true; <<"6"/utf8>> -> true; <<"7"/utf8>> -> true; <<"8"/utf8>> -> true; <<"9"/utf8>> -> true; _ -> false end. -file("src/tomlet/parser.gleam", 1900). ?DOC(false). -spec separated_digits_loop( list(binary()), fun((binary()) -> boolean()), boolean(), boolean() ) -> boolean(). separated_digits_loop( Chars, Is_valid_digit, Seen_digit, Previous_was_underscore ) -> case Chars of [] -> Seen_digit andalso not Previous_was_underscore; [<<"_"/utf8>> | Rest] -> case Seen_digit andalso not Previous_was_underscore of true -> separated_digits_loop( Rest, Is_valid_digit, Seen_digit, true ); false -> false end; [Char | Rest@1] -> case Is_valid_digit(Char) of true -> separated_digits_loop(Rest@1, Is_valid_digit, true, false); false -> false end end. -file("src/tomlet/parser.gleam", 1893). ?DOC(false). -spec separated_digits_are_valid(list(binary()), fun((binary()) -> boolean())) -> boolean(). separated_digits_are_valid(Chars, Is_valid_digit) -> separated_digits_loop(Chars, Is_valid_digit, false, false). -file("src/tomlet/parser.gleam", 1868). ?DOC(false). -spec decimal_digits_are_valid(binary()) -> boolean(). decimal_digits_are_valid(Text) -> gleam@bool:guard( not separated_digits_are_valid( gleam@string:to_graphemes(Text), fun char_is_digit/1 ), false, fun() -> case gleam@string:replace(Text, <<"_"/utf8>>, <<""/utf8>>) of <<""/utf8>> -> false; Digits -> Has_leading_zero = (string:length(Digits) > 1) andalso gleam_stdlib:string_starts_with( Digits, <<"0"/utf8>> ), not Has_leading_zero end end ). -file("src/tomlet/parser.gleam", 2136). ?DOC(false). -spec is_bin_digit_string(binary()) -> boolean(). is_bin_digit_string(Char) -> (Char =:= <<"0"/utf8>>) orelse (Char =:= <<"1"/utf8>>). -file("src/tomlet/parser.gleam", 1883). ?DOC(false). -spec based_digits_are_valid(binary(), fun((binary()) -> boolean())) -> boolean(). based_digits_are_valid(Text, Is_valid_digit) -> case gleam@string:replace(Text, <<"_"/utf8>>, <<""/utf8>>) of <<""/utf8>> -> false; _ -> separated_digits_are_valid( gleam@string:to_graphemes(Text), Is_valid_digit ) end. -file("src/tomlet/parser.gleam", 2129). ?DOC(false). -spec is_oct_digit_string(binary()) -> boolean(). is_oct_digit_string(Char) -> case Char of <<"0"/utf8>> -> true; <<"1"/utf8>> -> true; <<"2"/utf8>> -> true; <<"3"/utf8>> -> true; <<"4"/utf8>> -> true; <<"5"/utf8>> -> true; <<"6"/utf8>> -> true; <<"7"/utf8>> -> true; _ -> false end. -file("src/tomlet/parser.gleam", 2114). ?DOC(false). -spec char_is_hex_digit(binary()) -> boolean(). char_is_hex_digit(Char) -> char_is_digit(Char) orelse (case Char of <<"a"/utf8>> -> true; <<"b"/utf8>> -> true; <<"c"/utf8>> -> true; <<"d"/utf8>> -> true; <<"e"/utf8>> -> true; <<"f"/utf8>> -> true; <<"A"/utf8>> -> true; <<"B"/utf8>> -> true; <<"C"/utf8>> -> true; <<"D"/utf8>> -> true; <<"E"/utf8>> -> true; <<"F"/utf8>> -> true; _ -> false end). -file("src/tomlet/parser.gleam", 2125). ?DOC(false). -spec is_hex_digit_string(binary()) -> boolean(). is_hex_digit_string(Char) -> char_is_hex_digit(Char). -file("src/tomlet/parser.gleam", 2101). ?DOC(false). -spec drop_sign(binary()) -> binary(). drop_sign(Text) -> Has_sign = gleam_stdlib:string_starts_with(Text, <<"+"/utf8>>) orelse gleam_stdlib:string_starts_with( Text, <<"-"/utf8>> ), gleam@bool:guard( not Has_sign, Text, fun() -> gleam@string:drop_start(Text, 1) end ). -file("src/tomlet/parser.gleam", 1836). ?DOC(false). -spec int_repr_is_valid(binary()) -> boolean(). int_repr_is_valid(Text) -> Has_sign = gleam_stdlib:string_starts_with(Text, <<"+"/utf8>>) orelse gleam_stdlib:string_starts_with( Text, <<"-"/utf8>> ), Unsigned = drop_sign(Text), case gleam_stdlib:string_starts_with(Unsigned, <<"0x"/utf8>>) of true -> not Has_sign andalso based_digits_are_valid( gleam@string:drop_start(Unsigned, 2), fun is_hex_digit_string/1 ); false -> case gleam_stdlib:string_starts_with(Unsigned, <<"0o"/utf8>>) of true -> not Has_sign andalso based_digits_are_valid( gleam@string:drop_start(Unsigned, 2), fun is_oct_digit_string/1 ); false -> case gleam_stdlib:string_starts_with( Unsigned, <<"0b"/utf8>> ) of true -> not Has_sign andalso based_digits_are_valid( gleam@string:drop_start(Unsigned, 2), fun is_bin_digit_string/1 ); false -> decimal_digits_are_valid(Unsigned) end end end. -file("src/tomlet/parser.gleam", 1684). ?DOC(false). -spec parse_int_value(binary(), integer()) -> {ok, tomlet@ast:value()} | {error, parse_error()}. parse_int_value(Text, Offset) -> Normalized = gleam@string:replace(Text, <<"_"/utf8>>, <<""/utf8>>), case int_repr_is_valid(Text) of true -> case gleam_stdlib:parse_int(Normalized) of {ok, Value} -> {ok, {int, Value, Text}}; {error, nil} -> parse_based_int_value(Normalized, Text, Offset) end; false -> {error, {unexpected, Text, expected_value, Offset}} end. -file("src/tomlet/parser.gleam", 2086). ?DOC(false). -spec is_leap_year(integer()) -> boolean(). is_leap_year(Year) -> ((Year rem 4) =:= 0) andalso (((Year rem 100) /= 0) orelse ((Year rem 400) =:= 0)). -file("src/tomlet/parser.gleam", 2073). ?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(Year) of true -> 29; false -> 28 end; _ -> 0 end. -file("src/tomlet/parser.gleam", 2090). ?DOC(false). -spec two_digits_in_range(binary(), integer(), integer()) -> boolean(). two_digits_in_range(Text, Minimum, Maximum) -> Has_two_digits = (string:length(Text) =:= 2) andalso separated_digits_are_valid( gleam@string:to_graphemes(Text), fun char_is_digit/1 ), gleam@bool:guard( not Has_two_digits, false, fun() -> case gleam_stdlib:parse_int(Text) of {ok, Value} -> (Value >= Minimum) andalso (Value =< Maximum); {error, nil} -> false end end ). -file("src/tomlet/parser.gleam", 2054). ?DOC(false). -spec date_parts_are_valid(binary()) -> boolean(). date_parts_are_valid(Text) -> Year = gleam@string:slice(Text, 0, 4), Month = gleam@string:slice(Text, 5, 2), Day = gleam@string:slice(Text, 8, 2), case (separated_digits_are_valid( gleam@string:to_graphemes(Year), fun char_is_digit/1 ) andalso two_digits_in_range(Month, 1, 12)) andalso two_digits_in_range(Day, 1, 31) of true -> case {gleam_stdlib:parse_int(Year), gleam_stdlib:parse_int(Month), gleam_stdlib:parse_int(Day)} of {{ok, Year_number}, {ok, Month_number}, {ok, Day_number}} -> Day_number =< days_in_month(Year_number, Month_number); {_, _, _} -> false end; false -> false end. -file("src/tomlet/parser.gleam", 1960). ?DOC(false). -spec date_repr_is_valid(binary()) -> boolean(). date_repr_is_valid(Text) -> Has_date_shape = ((string:length(Text) =:= 10) andalso (gleam@string:slice( Text, 4, 1 ) =:= <<"-"/utf8>>)) andalso (gleam@string:slice(Text, 7, 1) =:= <<"-"/utf8>>), gleam@bool:guard( not Has_date_shape, false, fun() -> date_parts_are_valid(Text) end ). -file("src/tomlet/parser.gleam", 2040). ?DOC(false). -spec fraction_is_valid(binary()) -> boolean(). fraction_is_valid(Text) -> case Text of <<""/utf8>> -> true; _ -> case gleam_stdlib:string_starts_with(Text, <<"."/utf8>>) of true -> Digits = gleam@string:drop_start(Text, 1), separated_digits_are_valid( gleam@string:to_graphemes(Digits), fun char_is_digit/1 ); false -> false end end. -file("src/tomlet/parser.gleam", 2024). ?DOC(false). -spec time_repr_is_valid(binary()) -> boolean(). time_repr_is_valid(Text) -> Has_time_shape = ((string:length(Text) >= 8) andalso (gleam@string:slice( Text, 2, 1 ) =:= <<":"/utf8>>)) andalso (gleam@string:slice(Text, 5, 1) =:= <<":"/utf8>>), gleam@bool:guard( not Has_time_shape, false, fun() -> Hour = gleam@string:slice(Text, 0, 2), Minute = gleam@string:slice(Text, 3, 2), Seconds = gleam@string:slice(Text, 6, 2), Fraction = gleam@string:drop_start(Text, 8), ((two_digits_in_range(Hour, 0, 23) andalso two_digits_in_range( Minute, 0, 59 )) andalso two_digits_in_range(Seconds, 0, 59)) andalso fraction_is_valid(Fraction) end ). -file("src/tomlet/parser.gleam", 2013). ?DOC(false). -spec offset_repr_is_valid(binary()) -> boolean(). offset_repr_is_valid(Text) -> Has_offset_shape = ((string:length(Text) =:= 6) andalso (gleam_stdlib:string_starts_with( Text, <<"+"/utf8>> ) orelse gleam_stdlib:string_starts_with(Text, <<"-"/utf8>>))) andalso (gleam@string:slice(Text, 3, 1) =:= <<":"/utf8>>), gleam@bool:guard( not Has_offset_shape, false, fun() -> Hour = gleam@string:slice(Text, 1, 2), Minute = gleam@string:slice(Text, 4, 2), two_digits_in_range(Hour, 0, 23) andalso two_digits_in_range( Minute, 0, 59 ) end ). -file("src/tomlet/parser.gleam", 1999). ?DOC(false). -spec find_offset_separator(list(binary()), binary()) -> {ok, {binary(), binary()}} | {error, nil}. find_offset_separator(Chars, Before) -> case Chars of [] -> {error, nil}; [Char | Rest] -> case (Char =:= <<"+"/utf8>>) orelse (Char =:= <<"-"/utf8>>) of true -> {ok, {Before, <>))/binary>>}}; false -> find_offset_separator(Rest, <>) end end. -file("src/tomlet/parser.gleam", 1987). ?DOC(false). -spec time_offset_repr_is_valid(binary()) -> boolean(). time_offset_repr_is_valid(Text) -> case gleam_stdlib:string_ends_with(Text, <<"Z"/utf8>>) orelse gleam_stdlib:string_ends_with( Text, <<"z"/utf8>> ) of true -> time_repr_is_valid(gleam@string:drop_end(Text, 1)); false -> case find_offset_separator( gleam@string:to_graphemes(Text), <<""/utf8>> ) of {ok, {Time, Offset}} -> time_repr_is_valid(Time) andalso offset_repr_is_valid( Offset ); {error, nil} -> time_repr_is_valid(Text) end end. -file("src/tomlet/parser.gleam", 1969). ?DOC(false). -spec datetime_repr_is_valid(binary()) -> boolean(). datetime_repr_is_valid(Text) -> case gleam@string:split_once(Text, <<"T"/utf8>>) of {ok, {Date, Time_offset}} -> date_repr_is_valid(Date) andalso time_offset_repr_is_valid( Time_offset ); {error, nil} -> case gleam@string:split_once(Text, <<"t"/utf8>>) of {ok, {Date@1, Time_offset@1}} -> date_repr_is_valid(Date@1) andalso time_offset_repr_is_valid( Time_offset@1 ); {error, nil} -> case gleam@string:split_once(Text, <<" "/utf8>>) of {ok, {Date@2, Time_offset@2}} -> date_repr_is_valid(Date@2) andalso time_offset_repr_is_valid( Time_offset@2 ); {error, nil} -> false end end end. -file("src/tomlet/parser.gleam", 1674). ?DOC(false). -spec parse_date_like_value(binary()) -> {ok, tomlet@ast:value()} | {error, nil}. parse_date_like_value(Text) -> gleam@bool:guard( datetime_repr_is_valid(Text), {ok, {date_time, Text}}, fun() -> gleam@bool:guard( time_repr_is_valid(Text), {ok, {time, Text}}, fun() -> gleam@bool:guard( date_repr_is_valid(Text), {ok, {date, Text}}, fun() -> {error, nil} end ) end ) end ). -file("src/tomlet/parser.gleam", 1666). ?DOC(false). -spec parse_signed_exponent(binary()) -> {ok, integer()} | {error, nil}. parse_signed_exponent(Text) -> Without_plus = case gleam_stdlib:string_starts_with(Text, <<"+"/utf8>>) of true -> gleam@string:drop_start(Text, 1); false -> Text end, gleam_stdlib:parse_int(Without_plus). -file("src/tomlet/parser.gleam", 1655). ?DOC(false). -spec parse_number_part_as_float(binary()) -> {ok, float()} | {error, nil}. parse_number_part_as_float(Text) -> case gleam_stdlib:parse_float(Text) of {ok, Value} -> {ok, Value}; {error, nil} -> case gleam_stdlib:parse_int(Text) of {ok, Value@1} -> {ok, erlang:float(Value@1)}; {error, nil} -> {error, nil} end end. -file("src/tomlet/parser.gleam", 1643). ?DOC(false). -spec parse_exponent_float_parts({binary(), binary()}) -> {ok, float()} | {error, nil}. parse_exponent_float_parts(Parts) -> {Mantissa, Exponent} = Parts, case {parse_number_part_as_float(Mantissa), parse_signed_exponent(Exponent)} of {{ok, Mantissa_value}, {ok, Exponent_value}} -> case gleam@float:power(10.0, erlang:float(Exponent_value)) of {ok, Scale} -> {ok, Mantissa_value * Scale}; {error, nil} -> {error, nil} end; {_, _} -> {error, nil} end. -file("src/tomlet/parser.gleam", 1632). ?DOC(false). -spec parse_exponent_float(binary()) -> {ok, float()} | {error, nil}. parse_exponent_float(Text) -> case gleam@string:split_once(Text, <<"e"/utf8>>) of {ok, Parts} -> parse_exponent_float_parts(Parts); {error, nil} -> case gleam@string:split_once(Text, <<"E"/utf8>>) of {ok, Parts@1} -> parse_exponent_float_parts(Parts@1); {error, nil} -> {error, nil} end end. -file("src/tomlet/parser.gleam", 1625). ?DOC(false). -spec parse_toml_float(binary()) -> {ok, float()} | {error, nil}. parse_toml_float(Text) -> case gleam_stdlib:parse_float(Text) of {ok, Value} -> {ok, Value}; {error, nil} -> parse_exponent_float(Text) end. -file("src/tomlet/parser.gleam", 1610). ?DOC(false). -spec parse_special_float_value(binary(), binary()) -> {ok, tomlet@ast:value()} | {error, nil}. parse_special_float_value(Normalized, Source_text) -> case Normalized of <<"inf"/utf8>> -> {ok, {special_float, positive_infinity, Source_text}}; <<"+inf"/utf8>> -> {ok, {special_float, positive_infinity, Source_text}}; <<"-inf"/utf8>> -> {ok, {special_float, negative_infinity, Source_text}}; <<"nan"/utf8>> -> {ok, {special_float, not_a_number, Source_text}}; <<"+nan"/utf8>> -> {ok, {special_float, not_a_number, Source_text}}; <<"-nan"/utf8>> -> {ok, {special_float, not_a_number, Source_text}}; _ -> {error, nil} end. -file("src/tomlet/parser.gleam", 1941). ?DOC(false). -spec mantissa_repr_is_valid(binary()) -> boolean(). mantissa_repr_is_valid(Text) -> case gleam@string:split_once(Text, <<"."/utf8>>) of {ok, {Whole, Fraction}} -> decimal_digits_are_valid(Whole) andalso separated_digits_are_valid( gleam@string:to_graphemes(Fraction), fun char_is_digit/1 ); {error, nil} -> decimal_digits_are_valid(Text) end. -file("src/tomlet/parser.gleam", 1953). ?DOC(false). -spec exponent_repr_is_valid(binary()) -> boolean(). exponent_repr_is_valid(Text) -> separated_digits_are_valid( gleam@string:to_graphemes(drop_sign(Text)), fun char_is_digit/1 ). -file("src/tomlet/parser.gleam", 1921). ?DOC(false). -spec float_repr_is_valid(binary()) -> boolean(). float_repr_is_valid(Text) -> case Text of <<"inf"/utf8>> -> true; <<"+inf"/utf8>> -> true; <<"-inf"/utf8>> -> true; <<"nan"/utf8>> -> true; <<"+nan"/utf8>> -> true; <<"-nan"/utf8>> -> true; _ -> Unsigned = drop_sign(Text), case gleam@string:split_once(Unsigned, <<"e"/utf8>>) of {ok, {Mantissa, Exponent}} -> mantissa_repr_is_valid(Mantissa) andalso exponent_repr_is_valid( Exponent ); {error, nil} -> case gleam@string:split_once(Unsigned, <<"E"/utf8>>) of {ok, {Mantissa@1, Exponent@1}} -> mantissa_repr_is_valid(Mantissa@1) andalso exponent_repr_is_valid( Exponent@1 ); {error, nil} -> mantissa_repr_is_valid(Unsigned) end end end. -file("src/tomlet/parser.gleam", 1581). ?DOC(false). -spec parse_float_value(binary()) -> {ok, tomlet@ast:value()} | {error, nil}. parse_float_value(Text) -> Normalized = gleam@string:replace(Text, <<"_"/utf8>>, <<""/utf8>>), case float_repr_is_valid(Text) andalso ((((((((gleam_stdlib:contains_string( Normalized, <<"."/utf8>> ) orelse gleam_stdlib:contains_string(Normalized, <<"e"/utf8>>)) orelse gleam_stdlib:contains_string(Normalized, <<"E"/utf8>>)) orelse (Normalized =:= <<"inf"/utf8>>)) orelse (Normalized =:= <<"+inf"/utf8>>)) orelse (Normalized =:= <<"-inf"/utf8>>)) orelse (Normalized =:= <<"nan"/utf8>>)) orelse (Normalized =:= <<"+nan"/utf8>>)) orelse (Normalized =:= <<"-nan"/utf8>>)) of true -> case parse_special_float_value(Normalized, Text) of {ok, Value} -> {ok, Value}; {error, nil} -> case parse_toml_float(Normalized) of {ok, Value@1} -> {ok, {float, Value@1, Text}}; {error, _} -> {error, nil} end end; false -> {error, nil} end. -file("src/tomlet/parser.gleam", 1573). ?DOC(false). -spec parse_bool_value(binary()) -> {ok, tomlet@ast:value()} | {error, nil}. parse_bool_value(Text) -> case Text of <<"true"/utf8>> -> {ok, {bool, true, Text}}; <<"false"/utf8>> -> {ok, {bool, false, Text}}; _ -> {error, nil} end. -file("src/tomlet/parser.gleam", 2140). ?DOC(false). -spec char_is_disallowed_control(binary()) -> boolean(). char_is_disallowed_control(Char) -> case Char of <<"\x{0000}"/utf8>> -> true; <<"\x{0001}"/utf8>> -> true; <<"\x{0002}"/utf8>> -> true; <<"\x{0003}"/utf8>> -> true; <<"\x{0004}"/utf8>> -> true; <<"\x{0005}"/utf8>> -> true; <<"\x{0006}"/utf8>> -> true; <<"\x{0007}"/utf8>> -> true; <<"\x{0008}"/utf8>> -> true; <<"\x{000B}"/utf8>> -> true; <<"\x{000C}"/utf8>> -> true; <<"\r"/utf8>> -> true; <<"\x{000E}"/utf8>> -> true; <<"\x{000F}"/utf8>> -> true; <<"\x{0010}"/utf8>> -> true; <<"\x{0011}"/utf8>> -> true; <<"\x{0012}"/utf8>> -> true; <<"\x{0013}"/utf8>> -> true; <<"\x{0014}"/utf8>> -> true; <<"\x{0015}"/utf8>> -> true; <<"\x{0016}"/utf8>> -> true; <<"\x{0017}"/utf8>> -> true; <<"\x{0018}"/utf8>> -> true; <<"\x{0019}"/utf8>> -> true; <<"\x{001A}"/utf8>> -> true; <<"\x{001B}"/utf8>> -> true; <<"\x{001C}"/utf8>> -> true; <<"\x{001D}"/utf8>> -> true; <<"\x{001E}"/utf8>> -> true; <<"\x{001F}"/utf8>> -> true; <<"\x{007F}"/utf8>> -> true; _ -> false end. -file("src/tomlet/parser.gleam", 1482). ?DOC(false). -spec literal_string_chars_are_valid(list(binary())) -> boolean(). literal_string_chars_are_valid(Chars) -> case Chars of [] -> true; [<<"'"/utf8>> | _] -> false; [<<"\n"/utf8>> | _] -> false; [Char | Rest] -> case char_is_disallowed_control(Char) of true -> false; false -> literal_string_chars_are_valid(Rest) end end. -file("src/tomlet/parser.gleam", 1478). ?DOC(false). -spec literal_string_content_is_valid(binary()) -> boolean(). literal_string_content_is_valid(Text) -> literal_string_chars_are_valid(gleam@string:to_graphemes(Text)). -file("src/tomlet/parser.gleam", 1462). ?DOC(false). -spec parse_literal_string(binary()) -> {ok, tomlet@ast:value()} | {error, nil}. parse_literal_string(Text) -> Is_delimited = gleam_stdlib:string_starts_with(Text, <<"'"/utf8>>) andalso gleam_stdlib:string_ends_with( Text, <<"'"/utf8>> ), gleam@bool:guard( not Is_delimited, {error, nil}, fun() -> Inner = begin _pipe = Text, _pipe@1 = gleam@string:drop_start(_pipe, 1), gleam@string:drop_end(_pipe@1, 1) end, gleam@bool:guard( not literal_string_content_is_valid(Inner), {error, nil}, fun() -> {ok, {string, Inner, literal_string, Text}} end ) end ). -file("src/tomlet/parser.gleam", 2293). ?DOC(false). -spec hex_to_int(list(binary()), integer()) -> {ok, integer()} | {error, nil}. hex_to_int(Chars, Acc) -> case Chars of [] -> {ok, Acc}; [Char | Rest] -> case based_digit_value(Char) of {ok, Value} -> hex_to_int(Rest, (Acc * 16) + Value); {error, nil} -> {error, nil} end end. -file("src/tomlet/parser.gleam", 1825). ?DOC(false). -spec unicode_escape_scalar_is_valid(binary()) -> boolean(). unicode_escape_scalar_is_valid(Escape) -> case hex_to_int(gleam@string:to_graphemes(Escape), 0) of {ok, Value} -> case gleam@string:utf_codepoint(Value) of {ok, _} -> true; {error, nil} -> false end; {error, nil} -> false end. -file("src/tomlet/parser.gleam", 2304). ?DOC(false). -spec take_chars(list(binary()), integer(), binary()) -> {binary(), list(binary())}. take_chars(Chars, Count, Acc) -> case {Count, Chars} of {0, _} -> {Acc, Chars}; {_, [Char | Rest]} -> take_chars(Rest, Count - 1, <>); {_, []} -> {Acc, []} end. -file("src/tomlet/parser.gleam", 1811). ?DOC(false). -spec unicode_escape_is_valid_for( fun((list(binary())) -> boolean()), list(binary()), integer() ) -> boolean(). unicode_escape_is_valid_for(Validate_remaining, Chars, Count) -> {Escape, Remaining} = take_chars(Chars, Count, <<""/utf8>>), case (string:length(Escape) =:= Count) andalso unicode_escape_scalar_is_valid( Escape ) of true -> Validate_remaining(Remaining); false -> false end. -file("src/tomlet/parser.gleam", 1807). ?DOC(false). -spec unicode_escape_is_valid(list(binary()), integer()) -> boolean(). unicode_escape_is_valid(Chars, Count) -> unicode_escape_is_valid_for( fun basic_string_chars_are_valid/1, Chars, Count ). -file("src/tomlet/parser.gleam", 1785). ?DOC(false). -spec basic_string_chars_are_valid(list(binary())) -> boolean(). basic_string_chars_are_valid(Chars) -> case Chars of [] -> true; [<<"\\"/utf8>>] -> false; [<<"\\"/utf8>>, Escaped | Rest] -> case Escaped of <<"b"/utf8>> -> basic_string_chars_are_valid(Rest); <<"t"/utf8>> -> basic_string_chars_are_valid(Rest); <<"n"/utf8>> -> basic_string_chars_are_valid(Rest); <<"f"/utf8>> -> basic_string_chars_are_valid(Rest); <<"r"/utf8>> -> basic_string_chars_are_valid(Rest); <<"\""/utf8>> -> basic_string_chars_are_valid(Rest); <<"\\"/utf8>> -> basic_string_chars_are_valid(Rest); <<"u"/utf8>> -> unicode_escape_is_valid(Rest, 4); <<"U"/utf8>> -> unicode_escape_is_valid(Rest, 8); _ -> false end; [<<"\n"/utf8>> | _] -> false; [<<"\""/utf8>> | _] -> false; [Char | Rest@1] -> case char_is_disallowed_control(Char) of true -> false; false -> basic_string_chars_are_valid(Rest@1) end end. -file("src/tomlet/parser.gleam", 1781). ?DOC(false). -spec basic_string_content_is_valid(binary()) -> boolean(). basic_string_content_is_valid(Text) -> basic_string_chars_are_valid(gleam@string:to_graphemes(Text)). -file("src/tomlet/parser.gleam", 1446). ?DOC(false). -spec parse_basic_string(binary()) -> {ok, tomlet@ast:value()} | {error, nil}. parse_basic_string(Text) -> Is_delimited = gleam_stdlib:string_starts_with(Text, <<"\""/utf8>>) andalso gleam_stdlib:string_ends_with( Text, <<"\""/utf8>> ), gleam@bool:guard( not Is_delimited, {error, nil}, fun() -> Inner = begin _pipe = Text, _pipe@1 = gleam@string:drop_start(_pipe, 1), gleam@string:drop_end(_pipe@1, 1) end, gleam@bool:guard( not basic_string_content_is_valid(Inner), {error, nil}, fun() -> {ok, {string, Inner, basic_string, Text}} end ) end ). -file("src/tomlet/parser.gleam", 1561). ?DOC(false). -spec multiline_literal_string_chars_are_valid(list(binary())) -> boolean(). multiline_literal_string_chars_are_valid(Chars) -> case Chars of [] -> true; [<<"'"/utf8>>, <<"'"/utf8>>, <<"'"/utf8>> | _] -> false; [Char | Rest] -> case char_is_disallowed_control(Char) of true -> false; false -> multiline_literal_string_chars_are_valid(Rest) end end. -file("src/tomlet/parser.gleam", 1557). ?DOC(false). -spec multiline_literal_string_content_is_valid(binary()) -> boolean(). multiline_literal_string_content_is_valid(Text) -> multiline_literal_string_chars_are_valid(gleam@string:to_graphemes(Text)). -file("src/tomlet/parser.gleam", 1431). ?DOC(false). -spec parse_multiline_literal_string(binary()) -> {ok, tomlet@ast:value()} | {error, nil}. parse_multiline_literal_string(Text) -> Is_delimited = gleam_stdlib:string_starts_with(Text, <<"'''"/utf8>>) andalso gleam_stdlib:string_ends_with( Text, <<"'''"/utf8>> ), gleam@bool:guard( not Is_delimited, {error, nil}, fun() -> Inner = begin _pipe = Text, _pipe@1 = gleam@string:drop_start(_pipe, 3), gleam@string:drop_end(_pipe@1, 3) end, Content_valid = (Text /= <<"'''"/utf8>>) andalso multiline_literal_string_content_is_valid( Inner ), gleam@bool:guard( not Content_valid, {error, nil}, fun() -> {ok, {string, Inner, multi_literal_string, Text}} end ) end ). -file("src/tomlet/parser.gleam", 1546). ?DOC(false). -spec multiline_basic_line_ending_escape_is_valid(list(binary())) -> boolean(). multiline_basic_line_ending_escape_is_valid(Chars) -> case Chars of [] -> false; [<<" "/utf8>> | Rest] -> multiline_basic_line_ending_escape_is_valid(Rest); [<<"\t"/utf8>> | Rest@1] -> multiline_basic_line_ending_escape_is_valid(Rest@1); [<<"\n"/utf8>> | Rest@2] -> multiline_basic_string_chars_are_valid(Rest@2); [<<"\r"/utf8>>, <<"\n"/utf8>> | Rest@3] -> multiline_basic_string_chars_are_valid(Rest@3); _ -> false end. -file("src/tomlet/parser.gleam", 1518). ?DOC(false). -spec multiline_basic_escape_is_valid(list(binary())) -> boolean(). multiline_basic_escape_is_valid(Chars) -> case Chars of [] -> false; [<<"\n"/utf8>> | Rest] -> multiline_basic_string_chars_are_valid(Rest); [<<"\r"/utf8>>, <<"\n"/utf8>> | Rest@1] -> multiline_basic_string_chars_are_valid(Rest@1); [<<" "/utf8>> | Rest@2] -> multiline_basic_line_ending_escape_is_valid(Rest@2); [<<"\t"/utf8>> | Rest@3] -> multiline_basic_line_ending_escape_is_valid(Rest@3); [Escaped | Rest@4] -> case Escaped of <<"b"/utf8>> -> multiline_basic_string_chars_are_valid(Rest@4); <<"t"/utf8>> -> multiline_basic_string_chars_are_valid(Rest@4); <<"n"/utf8>> -> multiline_basic_string_chars_are_valid(Rest@4); <<"f"/utf8>> -> multiline_basic_string_chars_are_valid(Rest@4); <<"r"/utf8>> -> multiline_basic_string_chars_are_valid(Rest@4); <<"\""/utf8>> -> multiline_basic_string_chars_are_valid(Rest@4); <<"\\"/utf8>> -> multiline_basic_string_chars_are_valid(Rest@4); <<"u"/utf8>> -> unicode_escape_is_valid_for( fun multiline_basic_string_chars_are_valid/1, Rest@4, 4 ); <<"U"/utf8>> -> unicode_escape_is_valid_for( fun multiline_basic_string_chars_are_valid/1, Rest@4, 8 ); _ -> false end end. -file("src/tomlet/parser.gleam", 1504). ?DOC(false). -spec multiline_basic_string_chars_are_valid(list(binary())) -> boolean(). multiline_basic_string_chars_are_valid(Chars) -> case Chars of [] -> true; [<<"\\"/utf8>>] -> false; [<<"\\"/utf8>> | Rest] -> multiline_basic_escape_is_valid(Rest); [<<"\""/utf8>>, <<"\""/utf8>>, <<"\""/utf8>> | _] -> false; [Char | Rest@1] -> case char_is_disallowed_control(Char) of true -> false; false -> multiline_basic_string_chars_are_valid(Rest@1) end end. -file("src/tomlet/parser.gleam", 1500). ?DOC(false). -spec multiline_basic_string_content_is_valid(binary()) -> boolean(). multiline_basic_string_content_is_valid(Text) -> multiline_basic_string_chars_are_valid(gleam@string:to_graphemes(Text)). -file("src/tomlet/parser.gleam", 1416). ?DOC(false). -spec parse_multiline_basic_string(binary()) -> {ok, tomlet@ast:value()} | {error, nil}. parse_multiline_basic_string(Text) -> Is_delimited = gleam_stdlib:string_starts_with(Text, <<"\"\"\""/utf8>>) andalso gleam_stdlib:string_ends_with(Text, <<"\"\"\""/utf8>>), gleam@bool:guard( not Is_delimited, {error, nil}, fun() -> Inner = begin _pipe = Text, _pipe@1 = gleam@string:drop_start(_pipe, 3), gleam@string:drop_end(_pipe@1, 3) end, Content_valid = (Text /= <<"\"\"\""/utf8>>) andalso multiline_basic_string_content_is_valid( Inner ), gleam@bool:guard( not Content_valid, {error, nil}, fun() -> {ok, {string, Inner, multi_basic_string, Text}} end ) end ). -file("src/tomlet/parser.gleam", 941). ?DOC(false). -spec parse_scalar_value(binary(), integer()) -> {ok, tomlet@ast:value()} | {error, parse_error()}. parse_scalar_value(Text, Offset) -> Parsers = [fun parse_multiline_basic_string/1, fun parse_multiline_literal_string/1, fun parse_basic_string/1, fun parse_literal_string/1, fun parse_bool_value/1, fun parse_float_value/1, fun parse_date_like_value/1], case gleam@list:find_map(Parsers, fun(Parse) -> Parse(Text) end) of {ok, Value} -> {ok, Value}; {error, nil} -> parse_int_value(Text, Offset) end. -file("src/tomlet/parser.gleam", 1107). ?DOC(false). -spec trim_start_byte_offset(binary()) -> integer(). trim_start_byte_offset(Text) -> erlang:byte_size(Text) - erlang:byte_size(gleam@string:trim_start(Text)). -file("src/tomlet/parser.gleam", 972). ?DOC(false). -spec split_top_level_commas_loop( list(binary()), integer(), boolean(), boolean(), binary(), integer(), list({binary(), integer()}) ) -> list({binary(), integer()}). split_top_level_commas_loop( Chars, Depth, In_basic, In_literal, Current, Current_start, Parts ) -> case Chars of [] -> lists:reverse( [{gleam@string:trim(Current), Current_start + trim_start_byte_offset(Current)} | Parts] ); [Char | Rest] -> case {Char, Depth, In_basic, In_literal} of {<<"\\"/utf8>>, _, true, false} -> case Rest of [] -> split_top_level_commas_loop( Rest, Depth, In_basic, In_literal, <>, Current_start, Parts ); [Escaped | After_escape] -> split_top_level_commas_loop( After_escape, Depth, In_basic, In_literal, <<<>/binary, Escaped/binary>>, Current_start, Parts ) end; {<<","/utf8>>, 0, false, false} -> split_top_level_commas_loop( Rest, Depth, In_basic, In_literal, <<""/utf8>>, (Current_start + erlang:byte_size(Current)) + 1, [{gleam@string:trim(Current), Current_start + trim_start_byte_offset(Current)} | Parts] ); {<<"\""/utf8>>, _, _, false} -> split_top_level_commas_loop( Rest, Depth, not In_basic, In_literal, <>, Current_start, Parts ); {<<"'"/utf8>>, _, false, _} -> split_top_level_commas_loop( Rest, Depth, In_basic, not In_literal, <>, Current_start, Parts ); {<<"["/utf8>>, _, false, false} -> split_top_level_commas_loop( Rest, Depth + 1, In_basic, In_literal, <>, Current_start, Parts ); {<<"{"/utf8>>, _, false, false} -> split_top_level_commas_loop( Rest, Depth + 1, In_basic, In_literal, <>, Current_start, Parts ); {<<"]"/utf8>>, _, false, false} -> split_top_level_commas_loop( Rest, Depth - 1, In_basic, In_literal, <>, Current_start, Parts ); {<<"}"/utf8>>, _, false, false} -> split_top_level_commas_loop( Rest, Depth - 1, In_basic, In_literal, <>, Current_start, Parts ); {_, _, _, _} -> split_top_level_commas_loop( Rest, Depth, In_basic, In_literal, <>, Current_start, Parts ) end end. -file("src/tomlet/parser.gleam", 960). ?DOC(false). -spec split_top_level_commas(binary()) -> list({binary(), integer()}). split_top_level_commas(Text) -> split_top_level_commas_loop( gleam@string:to_graphemes(Text), 0, false, false, <<""/utf8>>, 0, [] ). -file("src/tomlet/parser.gleam", 2282). ?DOC(false). -spec unicode_escape_to_string(binary()) -> binary(). unicode_escape_to_string(Escape) -> case hex_to_int(gleam@string:to_graphemes(Escape), 0) of {ok, Value} -> case gleam@string:utf_codepoint(Value) of {ok, Codepoint} -> gleam_stdlib:utf_codepoint_list_to_string([Codepoint]); {error, nil} -> <<<<"\\u{"/utf8, Escape/binary>>/binary, "}"/utf8>> end; {error, nil} -> <<<<"\\u{"/utf8, Escape/binary>>/binary, "}"/utf8>> end. -file("src/tomlet/parser.gleam", 2250). ?DOC(false). -spec basic_key_value_loop(list(binary()), binary()) -> binary(). basic_key_value_loop(Chars, Acc) -> case Chars of [] -> Acc; [<<"\\"/utf8>>, Escaped | Rest] -> case Escaped of <<"b"/utf8>> -> basic_key_value_loop(Rest, <>); <<"t"/utf8>> -> basic_key_value_loop(Rest, <>); <<"n"/utf8>> -> basic_key_value_loop(Rest, <>); <<"f"/utf8>> -> basic_key_value_loop(Rest, <>); <<"r"/utf8>> -> basic_key_value_loop(Rest, <>); <<"\""/utf8>> -> basic_key_value_loop(Rest, <>); <<"\\"/utf8>> -> basic_key_value_loop(Rest, <>); <<"u"/utf8>> -> {Escape, Remaining} = take_chars(Rest, 4, <<""/utf8>>), basic_key_value_loop( Remaining, <> ); <<"U"/utf8>> -> {Escape@1, Remaining@1} = take_chars(Rest, 8, <<""/utf8>>), basic_key_value_loop( Remaining@1, <> ); _ -> basic_key_value_loop( Rest, <<<>/binary, Escaped/binary>> ) end; [Char | Rest@1] -> basic_key_value_loop(Rest@1, <>) end. -file("src/tomlet/parser.gleam", 2246). ?DOC(false). -spec basic_key_value(binary()) -> binary(). basic_key_value(Text) -> basic_key_value_loop(gleam@string:to_graphemes(Text), <<""/utf8>>). -file("src/tomlet/parser.gleam", 1495). ?DOC(false). -spec string_is_multiline_delimited(binary()) -> boolean(). string_is_multiline_delimited(Text) -> (gleam_stdlib:string_starts_with(Text, <<"\"\"\""/utf8>>) andalso gleam_stdlib:string_ends_with( Text, <<"\"\"\""/utf8>> )) orelse (gleam_stdlib:string_starts_with(Text, <<"'''"/utf8>>) andalso gleam_stdlib:string_ends_with( Text, <<"'''"/utf8>> )). -file("src/tomlet/parser.gleam", 731). ?DOC(false). -spec parse_key_segment(binary()) -> {ok, tomlet@ast:key_segment()} | {error, nil}. parse_key_segment(Segment) -> Trimmed = gleam@string:trim(Segment), gleam@bool:guard( Trimmed =:= <<""/utf8>>, {error, nil}, fun() -> gleam@bool:guard( string_is_multiline_delimited(Trimmed), {error, nil}, fun() -> case (gleam_stdlib:string_starts_with( Trimmed, <<"\""/utf8>> ) andalso gleam_stdlib:string_ends_with( Trimmed, <<"\""/utf8>> )) andalso (string:length(Trimmed) > 1) of true -> Inner = begin _pipe = Trimmed, _pipe@1 = gleam@string:drop_start(_pipe, 1), gleam@string:drop_end(_pipe@1, 1) end, case basic_string_content_is_valid(Inner) of true -> {ok, {quoted_key_segment, basic_key_value(Inner), Trimmed}}; false -> {error, nil} end; false -> case (gleam_stdlib:string_starts_with( Trimmed, <<"'"/utf8>> ) andalso gleam_stdlib:string_ends_with( Trimmed, <<"'"/utf8>> )) andalso (string:length(Trimmed) > 1) of true -> {ok, {quoted_key_segment, begin _pipe@2 = Trimmed, _pipe@3 = gleam@string:drop_start( _pipe@2, 1 ), gleam@string:drop_end( _pipe@3, 1 ) end, Trimmed}}; false -> case (((gleam_stdlib:string_starts_with( Trimmed, <<"\""/utf8>> ) orelse gleam_stdlib:string_ends_with( Trimmed, <<"\""/utf8>> )) orelse gleam_stdlib:string_starts_with( Trimmed, <<"'"/utf8>> )) orelse gleam_stdlib:string_ends_with( Trimmed, <<"'"/utf8>> )) orelse not tomlet@key:is_bare_key(Trimmed) of true -> {error, nil}; false -> {ok, {bare_key_segment, Trimmed}} end end end end ) end ). -file("src/tomlet/parser.gleam", 550). ?DOC(false). -spec split_key_segments_loop( list(binary()), binary(), list(binary()), boolean(), boolean() ) -> list(binary()). split_key_segments_loop(Chars, Current, Segments, In_basic, In_literal) -> case Chars of [] -> lists:reverse([Current | Segments]); [<<"\\"/utf8>>, Escaped | Rest] -> case In_basic of true -> split_key_segments_loop( Rest, <<<>/binary, Escaped/binary>>, Segments, In_basic, In_literal ); false -> split_key_segments_loop( Rest, <>, Segments, In_basic, In_literal ) end; [<<"."/utf8>> | Rest@1] -> case In_basic orelse In_literal of true -> split_key_segments_loop( Rest@1, <>, Segments, In_basic, In_literal ); false -> split_key_segments_loop( Rest@1, <<""/utf8>>, [Current | Segments], In_basic, In_literal ) end; [<<"\""/utf8>> | Rest@2] -> case In_literal of true -> split_key_segments_loop( Rest@2, <>, Segments, In_basic, In_literal ); false -> split_key_segments_loop( Rest@2, <>, Segments, not In_basic, In_literal ) end; [<<"'"/utf8>> | Rest@3] -> case In_basic of true -> split_key_segments_loop( Rest@3, <>, Segments, In_basic, In_literal ); false -> split_key_segments_loop( Rest@3, <>, Segments, In_basic, not In_literal ) end; [Char | Rest@4] -> split_key_segments_loop( Rest@4, <>, Segments, In_basic, In_literal ) end. -file("src/tomlet/parser.gleam", 546). ?DOC(false). -spec split_key_segments_text(binary()) -> list(binary()). split_key_segments_text(Text) -> split_key_segments_loop( gleam@string:to_graphemes(Text), <<""/utf8>>, [], false, false ). -file("src/tomlet/parser.gleam", 536). ?DOC(false). -spec parse_key(binary()) -> {ok, tomlet@ast:key()} | {error, nil}. parse_key(Text) -> _pipe = split_key_segments_text(Text), _pipe@1 = gleam@list:try_map(_pipe, fun parse_key_segment/1), gleam@result:map(_pipe@1, fun(Field@0) -> {key, Field@0} end). -file("src/tomlet/parser.gleam", 726). ?DOC(false). -spec bool_pick(boolean(), binary(), binary()) -> binary(). bool_pick(Condition, Yes, No) -> gleam@bool:guard(Condition, Yes, fun() -> No end). -file("src/tomlet/parser.gleam", 646). ?DOC(false). -spec split_key_value_loop( list(binary()), binary(), binary(), boolean(), boolean(), boolean() ) -> {ok, {binary(), binary()}} | {error, nil}. split_key_value_loop(Chars, Key, Value, In_basic, In_literal, Found) -> case Chars of [] -> case Found of true -> {ok, {Key, Value}}; false -> {error, nil} end; [Char | Rest] -> case {Char, Found, In_basic, In_literal} of {<<"\\"/utf8>>, _, true, false} -> case Rest of [] -> split_key_value_loop( Rest, Key, Value, In_basic, In_literal, Found ); [Escaped | After_escape] -> split_key_value_loop( After_escape, <>, <<""/utf8>> ))/binary>>, <>, <<""/utf8>> ))/binary>>, In_basic, In_literal, Found ) end; {<<"="/utf8>>, false, false, false} -> split_key_value_loop( Rest, Key, Value, In_basic, In_literal, true ); {<<"\""/utf8>>, _, _, false} -> split_key_value_loop( Rest, <>, <<""/utf8>>))/binary>>, <>, <<""/utf8>>))/binary>>, not In_basic, In_literal, Found ); {<<"'"/utf8>>, _, false, _} -> split_key_value_loop( Rest, <>, <<""/utf8>>))/binary>>, <>, <<""/utf8>>))/binary>>, In_basic, not In_literal, Found ); {_, false, _, _} -> split_key_value_loop( Rest, <>, Value, In_basic, In_literal, Found ); {_, true, _, _} -> split_key_value_loop( Rest, Key, <>, In_basic, In_literal, Found ) end end. -file("src/tomlet/parser.gleam", 542). ?DOC(false). -spec split_key_value(binary()) -> {ok, {binary(), binary()}} | {error, nil}. split_key_value(Line) -> split_key_value_loop( gleam@string:to_graphemes(Line), <<""/utf8>>, <<""/utf8>>, false, false, false ). -file("src/tomlet/parser.gleam", 1243). ?DOC(false). -spec inline_table_newlines_are_valid_loop( list(binary()), integer(), boolean(), boolean() ) -> boolean(). inline_table_newlines_are_valid_loop(Chars, Depth, In_basic, In_literal) -> case Chars of [] -> true; [<<"\\"/utf8>>, _ | Rest] when In_basic -> inline_table_newlines_are_valid_loop( Rest, Depth, In_basic, In_literal ); [<<"\n"/utf8>> | Rest@1] -> case ((Depth > 0) orelse In_basic) orelse In_literal of true -> inline_table_newlines_are_valid_loop( Rest@1, Depth, In_basic, In_literal ); false -> false end; [<<"\""/utf8>> | Rest@2] when not In_literal -> inline_table_newlines_are_valid_loop( Rest@2, Depth, not In_basic, In_literal ); [<<"'"/utf8>> | Rest@3] when not In_basic -> inline_table_newlines_are_valid_loop( Rest@3, Depth, In_basic, not In_literal ); [<<"["/utf8>> | Rest@4] when not In_basic andalso not In_literal -> inline_table_newlines_are_valid_loop( Rest@4, Depth + 1, In_basic, In_literal ); [<<"{"/utf8>> | Rest@5] when not In_basic andalso not In_literal -> inline_table_newlines_are_valid_loop( Rest@5, Depth + 1, In_basic, In_literal ); [<<"]"/utf8>> | Rest@6] when not In_basic andalso not In_literal -> inline_table_newlines_are_valid_loop( Rest@6, Depth - 1, In_basic, In_literal ); [<<"}"/utf8>> | Rest@7] when not In_basic andalso not In_literal -> inline_table_newlines_are_valid_loop( Rest@7, Depth - 1, In_basic, In_literal ); [_ | Rest@8] -> inline_table_newlines_are_valid_loop( Rest@8, Depth, In_basic, In_literal ) end. -file("src/tomlet/parser.gleam", 1234). ?DOC(false). -spec inline_table_newlines_are_valid(binary()) -> boolean(). inline_table_newlines_are_valid(Text) -> inline_table_newlines_are_valid_loop( gleam@string:to_graphemes(Text), 0, false, false ). -file("src/tomlet/parser.gleam", 1301). ?DOC(false). -spec parse_inline_entries( list({binary(), integer()}), integer(), list(list(binary())) ) -> {ok, list(tomlet@ast:inline_table_entry())} | {error, parse_error()}. parse_inline_entries(Parts, Body_offset, Seen) -> case Parts of [] -> {ok, []}; [{Part, Part_offset} | Rest] -> Entry_offset = Body_offset + Part_offset, gleam@bool:guard( gleam@string:trim(Part) =:= <<""/utf8>>, {error, {unexpected, <<""/utf8>>, expected_syntax, Entry_offset}}, fun() -> gleam@result:'try'( gleam@result:replace_error( split_key_value(Part), {unexpected, Part, expected_syntax, Entry_offset} ), fun(_use0) -> {Raw_key, Raw_value} = _use0, gleam@result:'try'( gleam@result:replace_error( parse_key(gleam@string:trim(Raw_key)), {unexpected, Part, expected_key, Entry_offset} ), fun(Key) -> Key_path = tomlet@key:to_strings(Key), gleam@bool:guard( key_path_conflicts(Seen, Key_path), {error, {unexpected, Part, expected_syntax, Entry_offset}}, fun() -> gleam@result:'try'( parse_value( gleam@string:trim( strip_inline_comments_by_line( Raw_value ) ), ((Entry_offset + erlang:byte_size( Raw_key )) + 1) + trim_start_byte_offset( Raw_value ) ), fun(Value) -> gleam@result:'try'( parse_inline_entries( Rest, Body_offset, [Key_path | Seen] ), fun(Entries) -> {ok, [{inline_table_entry, {trivia, <<""/utf8>>}, Key, Value, {trivia, <<""/utf8>>}} | Entries]} end ) end ) end ) end ) end ) end ) end. -file("src/tomlet/parser.gleam", 1202). ?DOC(false). -spec parse_inline_table_value(binary(), integer()) -> {ok, tomlet@ast:value()} | {error, parse_error()}. parse_inline_table_value(Text, Offset) -> Is_inline_table = gleam_stdlib:string_starts_with(Text, <<"{"/utf8>>) andalso gleam_stdlib:string_ends_with(Text, <<"}"/utf8>>), gleam@bool:guard( not Is_inline_table, {error, {unexpected, Text, expected_syntax, Offset}}, fun() -> Body = begin _pipe = Text, _pipe@1 = gleam@string:drop_start(_pipe, 1), gleam@string:drop_end(_pipe@1, 1) end, Clean_body = strip_inline_comments_by_line(Body), gleam@bool:guard( not inline_table_newlines_are_valid(Body), {error, {unexpected, Text, expected_syntax, Offset}}, fun() -> case gleam@string:trim(Clean_body) of <<""/utf8>> -> {ok, {inline_table, [], Text}}; _ -> case parse_inline_entries( split_top_level_commas(Clean_body), Offset + 1, [] ) of {ok, Entries} -> {ok, {inline_table, Entries, Text}}; {error, Error} -> {error, Error} end end end ) end ). -file("src/tomlet/parser.gleam", 1172). ?DOC(false). -spec parse_array_items(list({binary(), integer()}), integer()) -> {ok, list(tomlet@ast:array_item())} | {error, parse_error()}. parse_array_items(Parts, Body_offset) -> case Parts of [] -> {ok, []}; [{Part, Part_offset} | Rest] -> case gleam@string:trim(strip_inline_comments_by_line(Part)) of <<""/utf8>> -> case Rest of [] -> {ok, []}; _ -> {error, {unexpected, <<""/utf8>>, expected_value, Body_offset + Part_offset}} end; Clean_part -> case parse_value(Clean_part, Body_offset + Part_offset) of {ok, Value} -> case parse_array_items(Rest, Body_offset) of {ok, Items} -> {ok, [{array_item, {trivia, <<""/utf8>>}, Value, {trivia, <<""/utf8>>}} | Items]}; {error, Error} -> {error, Error} end; {error, Error@1} -> {error, Error@1} end end end. -file("src/tomlet/parser.gleam", 1147). ?DOC(false). -spec parse_array_value(binary(), integer()) -> {ok, tomlet@ast:value()} | {error, parse_error()}. parse_array_value(Text, Offset) -> Is_array = gleam_stdlib:string_starts_with(Text, <<"["/utf8>>) andalso gleam_stdlib:string_ends_with( Text, <<"]"/utf8>> ), gleam@bool:guard( not Is_array, {error, {unexpected, Text, expected_syntax, Offset}}, fun() -> Body = begin _pipe = Text, _pipe@1 = gleam@string:drop_start(_pipe, 1), gleam@string:drop_end(_pipe@1, 1) end, Clean_body = strip_inline_comments_by_line(Body), case gleam@string:trim(Clean_body) of <<""/utf8>> -> {ok, {array, [], Text}}; _ -> case parse_array_items( split_top_level_commas(Clean_body), Offset + 1 ) of {ok, Items} -> {ok, {array, Items, Text}}; {error, Error} -> {error, Error} end end end ). -file("src/tomlet/parser.gleam", 930). ?DOC(false). -spec parse_value(binary(), integer()) -> {ok, tomlet@ast:value()} | {error, parse_error()}. parse_value(Text, Offset) -> case gleam_stdlib:string_starts_with(Text, <<"["/utf8>>) of true -> parse_array_value(Text, Offset); false -> case gleam_stdlib:string_starts_with(Text, <<"{"/utf8>>) of true -> parse_inline_table_value(Text, Offset); false -> parse_scalar_value(Text, Offset) end end. -file("src/tomlet/parser.gleam", 1356). ?DOC(false). -spec strip_value_comments(binary()) -> binary(). strip_value_comments(Text) -> Trimmed = gleam@string:trim_start(Text), case gleam_stdlib:string_starts_with(Trimmed, <<"\"\"\""/utf8>>) orelse gleam_stdlib:string_starts_with( Trimmed, <<"'''"/utf8>> ) of true -> strip_inline_comment(Text); false -> strip_inline_comments_by_line(Text) end. -file("src/tomlet/parser.gleam", 444). ?DOC(false). -spec scalar_split(binary()) -> {binary(), binary()}. scalar_split(Trimmed_start) -> Value_text = gleam@string:trim(strip_value_comments(Trimmed_start)), Trailing = gleam@string:drop_start(Trimmed_start, string:length(Value_text)), {Value_text, Trailing}. -file("src/tomlet/parser.gleam", 450). ?DOC(false). -spec trailing_is_trivia(binary()) -> boolean(). trailing_is_trivia(Text) -> case gleam@string:trim(Text) of <<""/utf8>> -> true; Rest -> gleam_stdlib:string_starts_with(Rest, <<"#"/utf8>>) end. -file("src/tomlet/parser.gleam", 476). ?DOC(false). -spec scan_value_span(list(binary()), span_state(), integer(), integer()) -> integer(). scan_value_span(Chars, State, Depth, Count) -> gleam@bool:guard( ((Count > 0) andalso (State =:= span_outside)) andalso (Depth =:= 0), Count, fun() -> case {State, Chars} of {_, []} -> Count; {span_outside, [<<"\""/utf8>>, <<"\""/utf8>>, <<"\""/utf8>> | Rest]} -> scan_value_span(Rest, span_multi_basic, Depth, Count + 3); {span_outside, [<<"'"/utf8>>, <<"'"/utf8>>, <<"'"/utf8>> | Rest@1]} -> scan_value_span( Rest@1, span_multi_literal, Depth, Count + 3 ); {span_outside, [<<"\""/utf8>> | Rest@2]} -> scan_value_span(Rest@2, span_basic, Depth, Count + 1); {span_outside, [<<"'"/utf8>> | Rest@3]} -> scan_value_span(Rest@3, span_literal, Depth, Count + 1); {span_outside, [<<"#"/utf8>> | Rest@4]} -> scan_value_span(Rest@4, span_comment, Depth, Count + 1); {span_outside, [<<"["/utf8>> | Rest@5]} -> scan_value_span(Rest@5, span_outside, Depth + 1, Count + 1); {span_outside, [<<"{"/utf8>> | Rest@5]} -> scan_value_span(Rest@5, span_outside, Depth + 1, Count + 1); {span_outside, [<<"]"/utf8>> | Rest@6]} -> scan_value_span(Rest@6, span_outside, Depth - 1, Count + 1); {span_outside, [<<"}"/utf8>> | Rest@6]} -> scan_value_span(Rest@6, span_outside, Depth - 1, Count + 1); {span_outside, [_ | Rest@7]} -> scan_value_span(Rest@7, span_outside, Depth, Count + 1); {span_comment, [<<"\n"/utf8>> | Rest@8]} -> scan_value_span(Rest@8, span_outside, Depth, Count + 1); {span_comment, [_ | Rest@9]} -> scan_value_span(Rest@9, span_comment, Depth, Count + 1); {span_basic, [<<"\\"/utf8>>, _ | Rest@10]} -> scan_value_span(Rest@10, span_basic, Depth, Count + 2); {span_basic, [<<"\""/utf8>> | Rest@11]} -> scan_value_span(Rest@11, span_outside, Depth, Count + 1); {span_basic, [_ | Rest@12]} -> scan_value_span(Rest@12, span_basic, Depth, Count + 1); {span_literal, [<<"'"/utf8>> | Rest@13]} -> scan_value_span(Rest@13, span_outside, Depth, Count + 1); {span_literal, [_ | Rest@14]} -> scan_value_span(Rest@14, span_literal, Depth, Count + 1); {span_multi_basic, [<<"\\"/utf8>>, _ | Rest@15]} -> scan_value_span(Rest@15, span_multi_basic, Depth, Count + 2); {span_multi_basic, [<<"\""/utf8>>, <<"\""/utf8>>, <<"\""/utf8>> | Rest@16]} -> scan_value_span(Rest@16, span_outside, Depth, Count + 3); {span_multi_basic, [_ | Rest@17]} -> scan_value_span(Rest@17, span_multi_basic, Depth, Count + 1); {span_multi_literal, [<<"'"/utf8>>, <<"'"/utf8>>, <<"'"/utf8>> | Rest@18]} -> scan_value_span(Rest@18, span_outside, Depth, Count + 3); {span_multi_literal, [_ | Rest@19]} -> scan_value_span( Rest@19, span_multi_literal, Depth, Count + 1 ) end end ). -file("src/tomlet/parser.gleam", 472). ?DOC(false). -spec value_span_length(binary()) -> integer(). value_span_length(Text) -> scan_value_span(gleam@string:to_graphemes(Text), span_outside, 0, 0). -file("src/tomlet/parser.gleam", 457). ?DOC(false). -spec value_starts_span(binary()) -> boolean(). value_starts_span(Text) -> gleam_stdlib:string_starts_with(Text, <<"["/utf8>>) orelse gleam_stdlib:string_starts_with( Text, <<"{"/utf8>> ). -file("src/tomlet/parser.gleam", 1103). ?DOC(false). -spec trim_start_offset(binary()) -> integer(). trim_start_offset(Text) -> string:length(Text) - string:length(gleam@string:trim_start(Text)). -file("src/tomlet/parser.gleam", 424). ?DOC(false). -spec split_value_and_trailing(binary()) -> {binary(), binary()}. split_value_and_trailing(Raw_value) -> Trimmed_start = gleam@string:drop_start( Raw_value, trim_start_offset(Raw_value) ), case value_starts_span(Trimmed_start) of true -> Value_source = gleam@string:slice( Trimmed_start, 0, value_span_length(Trimmed_start) ), Trailing = gleam@string:drop_start( Trimmed_start, string:length(Value_source) ), case trailing_is_trivia(Trailing) of true -> {Value_source, Trailing}; false -> scalar_split(Trimmed_start) end; false -> scalar_split(Trimmed_start) end. -file("src/tomlet/parser.gleam", 382). ?DOC(false). -spec parse_key_value(binary(), integer()) -> {ok, gleam@option:option(tomlet@ast:entry())} | {error, parse_error()}. parse_key_value(Line, Offset) -> case split_key_value(Line) of {ok, {Raw_key, Raw_value}} -> Key_text = gleam@string:trim(Raw_key), {Value_text, Trailing} = split_value_and_trailing(Raw_value), Value_offset = ((Offset + erlang:byte_size(Raw_key)) + 1) + trim_start_byte_offset( Raw_value ), case parse_key(Key_text) of {ok, Key} -> case parse_value(Value_text, Value_offset) of {ok, Value} -> {ok, {some, {key_value, {trivia, <<""/utf8>>}, Key, Value, {trivia, <>}}}}; {error, Error} -> {error, Error} end; {error, nil} -> {error, {unexpected, Key_text, expected_key, Offset}} end; {error, nil} -> {error, {unexpected, Line, expected_syntax, Offset}} end. -file("src/tomlet/parser.gleam", 355). ?DOC(false). -spec parse_header(binary(), integer(), tomlet@ast:header_kind(), integer()) -> {ok, gleam@option:option(tomlet@ast:entry())} | {error, parse_error()}. parse_header(Trimmed, Delimiter_width, Kind, Offset) -> Name = begin _pipe = Trimmed, _pipe@1 = gleam@string:drop_start(_pipe, Delimiter_width), _pipe@2 = gleam@string:drop_end(_pipe@1, Delimiter_width), gleam@string:trim(_pipe@2) end, case parse_key(Name) of {ok, Key} -> {ok, {some, {table_header, {header, Key, Kind, {trivia, <<""/utf8>>}}}}}; {error, nil} -> {error, {unexpected, Name, expected_key, Offset + Delimiter_width}} end. -file("src/tomlet/parser.gleam", 341). ?DOC(false). -spec parse_table_header(binary(), integer()) -> {ok, gleam@option:option(tomlet@ast:entry())} | {error, parse_error()}. parse_table_header(Trimmed, Offset) -> parse_header(Trimmed, 1, standard_table, Offset). -file("src/tomlet/parser.gleam", 348). ?DOC(false). -spec parse_array_of_tables_header(binary(), integer()) -> {ok, gleam@option:option(tomlet@ast:entry())} | {error, parse_error()}. parse_array_of_tables_header(Trimmed, Offset) -> parse_header(Trimmed, 2, array_of_tables_header, Offset). -file("src/tomlet/parser.gleam", 317). ?DOC(false). -spec classify_content_line(binary(), binary(), binary(), integer()) -> {ok, gleam@option:option(tomlet@ast:entry())} | {error, parse_error()}. classify_content_line(Line, Trimmed_line, Trimmed, Offset) -> gleam@bool:guard( gleam_stdlib:string_starts_with(Trimmed_line, <<"#"/utf8>>), {ok, {some, {comment, Line}}}, fun() -> case gleam_stdlib:string_starts_with(Trimmed, <<"[["/utf8>>) andalso gleam_stdlib:string_ends_with( Trimmed, <<"]]"/utf8>> ) of true -> parse_array_of_tables_header(Trimmed, Offset); false -> case gleam_stdlib:string_starts_with(Trimmed, <<"["/utf8>>) andalso gleam_stdlib:string_ends_with(Trimmed, <<"]"/utf8>>) of true -> parse_table_header(Trimmed, Offset); false -> case gleam_stdlib:string_starts_with( Trimmed, <<"["/utf8>> ) of true -> {error, {unexpected, Trimmed, expected_table_header, Offset}}; false -> parse_key_value(Line, Offset) end end end end ). -file("src/tomlet/parser.gleam", 2199). ?DOC(false). -spec string_contains_disallowed_unquoted_unicode_loop( list(binary()), boolean(), boolean(), boolean() ) -> boolean(). string_contains_disallowed_unquoted_unicode_loop( Chars, In_basic_string, In_literal_string, Escaped ) -> case Chars of [] -> false; [<<"#"/utf8>> | _] when not In_basic_string andalso not In_literal_string -> false; [<<"\\"/utf8>> | Rest] when In_basic_string andalso not Escaped -> string_contains_disallowed_unquoted_unicode_loop( Rest, In_basic_string, In_literal_string, true ); [<<"\""/utf8>> | Rest@1] when not In_literal_string andalso not Escaped -> string_contains_disallowed_unquoted_unicode_loop( Rest@1, not In_basic_string, In_literal_string, false ); [<<"'"/utf8>> | Rest@2] when not In_basic_string -> string_contains_disallowed_unquoted_unicode_loop( Rest@2, In_basic_string, not In_literal_string, false ); [Char | Rest@3] -> Disallowed = (not In_basic_string andalso not In_literal_string) andalso ((Char =:= <<"\x{3000}"/utf8>>) orelse (Char =:= <<"\x{FEFF}"/utf8>>)), Disallowed orelse string_contains_disallowed_unquoted_unicode_loop( Rest@3, In_basic_string, In_literal_string, false ) end. -file("src/tomlet/parser.gleam", 2190). ?DOC(false). -spec string_contains_disallowed_unquoted_unicode(binary()) -> boolean(). string_contains_disallowed_unquoted_unicode(Text) -> string_contains_disallowed_unquoted_unicode_loop( gleam@string:to_graphemes(Text), false, false, false ). -file("src/tomlet/parser.gleam", 2181). ?DOC(false). -spec string_contains_disallowed_control_loop(list(binary())) -> boolean(). string_contains_disallowed_control_loop(Chars) -> case Chars of [] -> false; [Char | Rest] -> char_is_disallowed_control(Char) orelse string_contains_disallowed_control_loop( Rest ) end. -file("src/tomlet/parser.gleam", 2177). ?DOC(false). -spec string_contains_disallowed_control(binary()) -> boolean(). string_contains_disallowed_control(Text) -> string_contains_disallowed_control_loop(gleam@string:to_graphemes(Text)). -file("src/tomlet/parser.gleam", 296). ?DOC(false). -spec parse_line(binary(), integer()) -> {ok, gleam@option:option(tomlet@ast:entry())} | {error, parse_error()}. parse_line(Line, Offset) -> gleam@bool:guard( string_contains_disallowed_control(Line) orelse string_contains_disallowed_unquoted_unicode( Line ), {error, {unexpected, Line, expected_syntax, Offset}}, fun() -> Trimmed_line = gleam@string:trim(Line), Trimmed = gleam@string:trim(strip_inline_comment(Line)), case Trimmed of <<""/utf8>> -> case gleam_stdlib:string_starts_with( Trimmed_line, <<"#"/utf8>> ) of true -> {ok, {some, {comment, Line}}}; false -> {ok, {some, blank_line}} end; _ -> classify_content_line(Line, Trimmed_line, Trimmed, Offset) end end ). -file("src/tomlet/parser.gleam", 256). ?DOC(false). -spec apply_key_value( tomlet@ast:key(), tomlet@ast:entry(), list(binary()), integer(), integer(), list(binary()), list(list(binary())), list(list(binary())), list(list(binary())), list(list(binary())), list(list(binary())), list(tomlet@ast:entry()) ) -> {ok, tomlet@ast:table()} | {error, parse_error()}. apply_key_value( Key, Entry, Rest, Offset, Line_len, Active_table, Seen, Explicit_tables, Array_tables, Array_table_parents, Dotted_tables, Entries ) -> Full_key = lists:append(Active_table, tomlet@key:to_strings(Key)), gleam@bool:guard( key_path_conflicts(Seen, Full_key) orelse dotted_key_extends_defined_table( Explicit_tables, Array_tables, Active_table, Full_key ), {error, {key_already_in_use, Full_key, Offset}}, fun() -> Next_dotted_tables = add_dotted_table_paths( Dotted_tables, Active_table, Full_key ), parse_lines( Rest, Offset + Line_len, Active_table, [Full_key | Seen], Explicit_tables, Array_tables, Array_table_parents, Next_dotted_tables, [Entry | Entries] ) end ). -file("src/tomlet/parser.gleam", 187). ?DOC(false). -spec apply_table_header( tomlet@ast:header(), tomlet@ast:entry(), list(binary()), integer(), integer(), list(list(binary())), list(list(binary())), list(list(binary())), list(list(binary())), list(list(binary())), list(tomlet@ast:entry()) ) -> {ok, tomlet@ast:table()} | {error, parse_error()}. apply_table_header( Header, Entry, Rest, Offset, Line_len, Seen, Explicit_tables, Array_tables, Array_table_parents, Dotted_tables, Entries ) -> Table_key = header_key(Header), gleam@bool:guard( (((key_path_conflicts_for_table_header(Seen, Table_key) orelse gleam@list:contains( Dotted_tables, Table_key )) orelse standard_table_already_defined( Header, Explicit_tables, Table_key )) orelse table_kind_already_defined( Header, Explicit_tables, Array_tables, Table_key )) orelse array_table_parent_already_implied( Header, Array_tables, Array_table_parents, Table_key ), {error, {key_already_in_use, Table_key, Offset}}, fun() -> Next_seen = case Header of {header, _, array_of_tables_header, _} -> remove_keys_under_table(Seen, Table_key); _ -> Seen end, Next_explicit_tables = case Header of {header, _, standard_table, _} -> [Table_key | Explicit_tables]; {header, _, array_of_tables_header, _} -> remove_keys_under_table(Explicit_tables, Table_key) end, Next_dotted_tables_after_header = case Header of {header, _, array_of_tables_header, _} -> remove_keys_under_table(Dotted_tables, Table_key); _ -> Dotted_tables end, Next_array_tables = case Header of {header, _, array_of_tables_header, _} -> [Table_key | Array_tables]; _ -> Array_tables end, Next_array_table_parents = case Header of {header, _, array_of_tables_header, _} -> add_paths( dotted_table_paths([], Table_key), Array_table_parents ); _ -> Array_table_parents end, parse_lines( Rest, Offset + Line_len, Table_key, Next_seen, Next_explicit_tables, Next_array_tables, Next_array_table_parents, Next_dotted_tables_after_header, [Entry | Entries] ) end ). -file("src/tomlet/parser.gleam", 105). ?DOC(false). -spec parse_lines( list(binary()), integer(), list(binary()), list(list(binary())), list(list(binary())), list(list(binary())), list(list(binary())), list(list(binary())), list(tomlet@ast:entry()) ) -> {ok, tomlet@ast:table()} | {error, parse_error()}. parse_lines( Lines, Offset, Active_table, Seen, Explicit_tables, Array_tables, Array_table_parents, Dotted_tables, Entries ) -> case Lines of [] -> {ok, {table, lists:reverse(Entries), none}}; [Line | Rest] -> Line_len = erlang:byte_size(Line) + 1, gleam@bool:guard( (Line =:= <<""/utf8>>) andalso (Rest =:= []), {ok, {table, lists:reverse(Entries), none}}, fun() -> case parse_line(Line, Offset) of {ok, none} -> parse_lines( Rest, Offset + Line_len, Active_table, Seen, Explicit_tables, Array_tables, Array_table_parents, Dotted_tables, Entries ); {ok, {some, Entry}} -> case Entry of {table_header, Header} -> apply_table_header( Header, Entry, Rest, Offset, Line_len, Seen, Explicit_tables, Array_tables, Array_table_parents, Dotted_tables, Entries ); {key_value, _, Key, _, _} -> apply_key_value( Key, Entry, Rest, Offset, Line_len, Active_table, Seen, Explicit_tables, Array_tables, Array_table_parents, Dotted_tables, Entries ); _ -> parse_lines( Rest, Offset + Line_len, Active_table, Seen, Explicit_tables, Array_tables, Array_table_parents, Dotted_tables, [Entry | Entries] ) end; {error, Error} -> {error, Error} end end ) end. -file("src/tomlet/parser.gleam", 28). ?DOC(false). -spec parse(binary()) -> {ok, tomlet@ast:table()} | {error, parse_error()}. parse(Input) -> parse_lines( merge_multiline_lines(gleam@string:split(Input, <<"\n"/utf8>>), []), 0, [], [], [], [], [], [], [] ).