-module(molt@internal@path).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/path.gleam").
-export([parse/1, to_string/1, with_segment_key_name/3, split_last_segment/1, split_at_last_index/1, drop_last_segment/1, path_to_table_header/1, contains_index/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/path.gleam", 119).
?DOC(false).
-spec validate_segments(list(molt@types:path_segment())) -> {ok,
list(molt@types:path_segment())} |
{error, molt@error:molt_error()}.
validate_segments(Segments) ->
case Segments of
[{index_segment, _} | _] ->
{error,
{invalid_path,
<<"index segments must follow a key segment"/utf8>>}};
_ ->
{ok, Segments}
end.
-file("src/molt/internal/path.gleam", 237).
?DOC(false).
-spec parse_path_bracket_index(list(binary()), binary()) -> {ok,
{integer(), list(binary())}} |
{error, molt@error:molt_error()}.
parse_path_bracket_index(Chars, Acc) ->
case Chars of
[] ->
{error, {invalid_path, <<"unterminated bracket"/utf8>>}};
[<<"]"/utf8>> | Rest] ->
case gleam_stdlib:parse_int(Acc) of
{ok, N} ->
{ok, {N, Rest}};
{error, _} ->
{error,
{invalid_path,
<<"non-integer in brackets: "/utf8, Acc/binary>>}}
end;
[Ch | Rest@1] ->
parse_path_bracket_index(Rest@1, <<Acc/binary, Ch/binary>>)
end.
-file("src/molt/internal/path.gleam", 270).
?DOC(false).
-spec parse_path_double_quoted(
list(binary()),
list(molt@types:path_segment()),
binary()
) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}.
parse_path_double_quoted(Chars, Segments, Acc) ->
case Chars of
[] ->
{error, {invalid_path, <<"unterminated double quote"/utf8>>}};
[<<"\\"/utf8>> | Chars@1] ->
case Chars@1 of
[] ->
{error,
{invalid_path, <<"unterminated double quote"/utf8>>}};
[Escaped | Chars@2] ->
Ch = case Escaped of
<<"n"/utf8>> ->
<<"\n"/utf8>>;
<<"t"/utf8>> ->
<<"\t"/utf8>>;
<<"r"/utf8>> ->
<<"\r"/utf8>>;
<<"\\"/utf8>> ->
<<"\\"/utf8>>;
<<"\""/utf8>> ->
<<"\""/utf8>>;
_ ->
<<"\\"/utf8, Escaped/binary>>
end,
parse_path_double_quoted(
Chars@2,
Segments,
<<Acc/binary, Ch/binary>>
)
end;
[<<"\""/utf8>> | Chars@3] ->
parse_path_segments(
Chars@3,
[{key_segment, Acc} | Segments],
<<""/utf8>>,
false
);
[Ch@1 | Chars@4] ->
parse_path_double_quoted(
Chars@4,
Segments,
<<Acc/binary, Ch@1/binary>>
)
end.
-file("src/molt/internal/path.gleam", 252).
?DOC(false).
-spec parse_path_single_quoted(
list(binary()),
list(molt@types:path_segment()),
binary()
) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}.
parse_path_single_quoted(Chars, Segments, Acc) ->
case Chars of
[] ->
{error, {invalid_path, <<"unterminated single quote"/utf8>>}};
[<<"'"/utf8>> | Chars@1] ->
parse_path_segments(
Chars@1,
[{key_segment, Acc} | Segments],
<<""/utf8>>,
false
);
[Ch | Chars@2] ->
parse_path_single_quoted(
Chars@2,
Segments,
<<Acc/binary, Ch/binary>>
)
end.
-file("src/molt/internal/path.gleam", 216).
?DOC(false).
-spec parse_path_after_bracket(list(binary()), list(molt@types:path_segment())) -> {ok,
list(molt@types:path_segment())} |
{error, molt@error:molt_error()}.
parse_path_after_bracket(Chars, Segments) ->
case Chars of
[] ->
{ok, lists:reverse(Segments)};
[<<"."/utf8>> | Rest] ->
parse_path_segments(Rest, Segments, <<""/utf8>>, true);
[<<"["/utf8>> | Rest@1] ->
case parse_path_bracket_index(Rest@1, <<""/utf8>>) of
{ok, {Index, Remaining}} ->
parse_path_after_bracket(
Remaining,
[{index_segment, Index} | Segments]
);
{error, Error} ->
{error, Error}
end;
_ ->
{error,
{invalid_path, <<"expected dot or bracket after index"/utf8>>}}
end.
-file("src/molt/internal/path.gleam", 127).
?DOC(false).
-spec parse_path_segments(
list(binary()),
list(molt@types:path_segment()),
binary(),
boolean()
) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}.
parse_path_segments(Chars, Segments, Current, Need_segment) ->
case Chars of
[] ->
case {Current, Need_segment} of
{<<""/utf8>>, true} ->
{error, {invalid_path, <<"trailing dot"/utf8>>}};
{<<""/utf8>>, false} ->
{ok, lists:reverse(Segments)};
{_, _} ->
{ok, lists:reverse([{key_segment, Current} | Segments])}
end;
[<<"."/utf8>> | Rest] ->
case {Current, Need_segment orelse (Segments =:= [])} of
{<<""/utf8>>, true} ->
{error, {invalid_path, <<"empty segment"/utf8>>}};
{<<""/utf8>>, false} ->
parse_path_segments(Rest, Segments, <<""/utf8>>, true);
{_, _} ->
parse_path_segments(
Rest,
[{key_segment, Current} | Segments],
<<""/utf8>>,
true
)
end;
[<<"["/utf8>> | Rest@1] ->
gleam@bool:guard(
Need_segment andalso (Current =:= <<""/utf8>>),
{error, {invalid_path, <<"empty segment before bracket"/utf8>>}},
fun() ->
Segments@1 = case Current of
<<""/utf8>> ->
Segments;
_ ->
[{key_segment, Current} | Segments]
end,
case parse_path_bracket_index(Rest@1, <<""/utf8>>) of
{ok, {Index, Remaining}} ->
parse_path_after_bracket(
Remaining,
[{index_segment, Index} | Segments@1]
);
{error, Error} ->
{error, Error}
end
end
);
[<<"'"/utf8>> | Chars@1] ->
gleam@bool:guard(
Current /= <<""/utf8>>,
{error, {invalid_path, <<"unexpected quote in bare key"/utf8>>}},
fun() ->
parse_path_single_quoted(Chars@1, Segments, <<""/utf8>>)
end
);
[<<"\""/utf8>> | Chars@2] ->
gleam@bool:guard(
Current /= <<""/utf8>>,
{error, {invalid_path, <<"unexpected quote in bare key"/utf8>>}},
fun() ->
parse_path_double_quoted(Chars@2, Segments, <<""/utf8>>)
end
);
[Ch | Chars@3] ->
gleam@bool:guard(
not molt@internal@utils:is_bare_key(Ch),
{error,
{invalid_path,
<<<<"invalid character '"/utf8, Ch/binary>>/binary,
"' in bare key segment; quote the segment with ' or \""/utf8>>}},
fun() ->
parse_path_segments(
Chars@3,
Segments,
<<Current/binary, Ch/binary>>,
false
)
end
)
end.
-file("src/molt/internal/path.gleam", 19).
?DOC(false).
-spec parse(binary()) -> {ok, list(molt@types:path_segment())} |
{error, molt@error:molt_error()}.
parse(Input) ->
case Input of
<<""/utf8>> ->
{ok, []};
_ ->
case parse_path_segments(
gleam@string:to_graphemes(Input),
[],
<<""/utf8>>,
false
) of
{ok, Segments} ->
validate_segments(Segments);
{error, Error} ->
{error, Error}
end
end.
-file("src/molt/internal/path.gleam", 37).
?DOC(false).
-spec to_string(list(molt@types:path_segment())) -> binary().
to_string(Segments) ->
molt@internal@utils:path_to_string(Segments).
-file("src/molt/internal/path.gleam", 41).
?DOC(false).
-spec with_segment_key_name(
molt@types:path_segment(),
IHN,
fun((binary()) -> IHN)
) -> IHN.
with_segment_key_name(Segment, Return, Do) ->
case Segment of
{key_segment, Name} ->
Do(Name);
{index_segment, _} ->
Return
end.
-file("src/molt/internal/path.gleam", 52).
?DOC(false).
-spec split_last_segment(list(molt@types:path_segment())) -> {list(molt@types:path_segment()),
molt@types:path_segment()}.
split_last_segment(Segments) ->
gleam@bool:guard(
Segments =:= [],
{[], {key_segment, <<""/utf8>>}},
fun() -> case lists:reverse(Segments) of
[Last | Rest] ->
{lists:reverse(Rest), Last};
[] ->
{[], {key_segment, <<""/utf8>>}}
end end
).
-file("src/molt/internal/path.gleam", 71).
?DOC(false).
-spec do_split_at_last_index(
list(molt@types:path_segment()),
list(molt@types:path_segment())
) -> {ok, {list(molt@types:path_segment()), list(molt@types:path_segment())}} |
{error, nil}.
do_split_at_last_index(Rev_remaining, After) ->
case Rev_remaining of
[] ->
{error, nil};
[{index_segment, I} | Rest] ->
{ok, {lists:reverse([{index_segment, I} | Rest]), After}};
[Segment | Rest@1] ->
do_split_at_last_index(Rest@1, [Segment | After])
end.
-file("src/molt/internal/path.gleam", 67).
?DOC(false).
-spec split_at_last_index(list(molt@types:path_segment())) -> {ok,
{list(molt@types:path_segment()), list(molt@types:path_segment())}} |
{error, nil}.
split_at_last_index(Segments) ->
do_split_at_last_index(lists:reverse(Segments), []).
-file("src/molt/internal/path.gleam", 83).
?DOC(false).
-spec drop_last_segment(list(molt@types:path_segment())) -> list(molt@types:path_segment()).
drop_last_segment(Path) ->
{Path@1, _} = split_last_segment(Path),
Path@1.
-file("src/molt/internal/path.gleam", 94).
?DOC(false).
-spec path_to_table_header(list(molt@types:path_segment())) -> list(binary()).
path_to_table_header(Segments) ->
gleam@list:filter_map(Segments, fun(Seg) -> case Seg of
{key_segment, K} ->
{ok, K};
{index_segment, _} ->
{error, nil}
end end).
-file("src/molt/internal/path.gleam", 112).
?DOC(false).
-spec is_index_segment(molt@types:path_segment()) -> boolean().
is_index_segment(Seg) ->
case Seg of
{index_segment, _} ->
true;
{key_segment, _} ->
false
end.
-file("src/molt/internal/path.gleam", 108).
?DOC(false).
-spec contains_index(list(molt@types:path_segment())) -> boolean().
contains_index(Segments) ->
gleam@list:any(Segments, fun is_index_segment/1).