-module(molt@internal@parser@scanners).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/parser/scanners.gleam").
-export([scan_basic_string/4, scan_literal_string/4, tokenize_header_line/3, consume_key_and_eq/3]).
-export_type([basic_scan_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.
?MODULEDOC(false).
-type basic_scan_error() :: unterminated_basic | bad_escape.
-file("src/molt/internal/parser/scanners.gleam", 203).
?DOC(false).
-spec take_n_hex(binary(), integer(), list(binary())) -> {ok,
{binary(), binary()}} |
{error, nil}.
take_n_hex(Input, N, Acc) ->
case N of
0 ->
{ok, {molt@internal@utils:reverse_concat(Acc), Input}};
_ ->
case Input of
<<"0"/utf8, Input@1/binary>> ->
take_n_hex(Input@1, N - 1, [<<"0"/utf8>> | Acc]);
<<"1"/utf8, Input@2/binary>> ->
take_n_hex(Input@2, N - 1, [<<"1"/utf8>> | Acc]);
<<"2"/utf8, Input@3/binary>> ->
take_n_hex(Input@3, N - 1, [<<"2"/utf8>> | Acc]);
<<"3"/utf8, Input@4/binary>> ->
take_n_hex(Input@4, N - 1, [<<"3"/utf8>> | Acc]);
<<"4"/utf8, Input@5/binary>> ->
take_n_hex(Input@5, N - 1, [<<"4"/utf8>> | Acc]);
<<"5"/utf8, Input@6/binary>> ->
take_n_hex(Input@6, N - 1, [<<"5"/utf8>> | Acc]);
<<"6"/utf8, Input@7/binary>> ->
take_n_hex(Input@7, N - 1, [<<"6"/utf8>> | Acc]);
<<"7"/utf8, Input@8/binary>> ->
take_n_hex(Input@8, N - 1, [<<"7"/utf8>> | Acc]);
<<"8"/utf8, Input@9/binary>> ->
take_n_hex(Input@9, N - 1, [<<"8"/utf8>> | Acc]);
<<"9"/utf8, Input@10/binary>> ->
take_n_hex(Input@10, N - 1, [<<"9"/utf8>> | Acc]);
<<"a"/utf8, Input@11/binary>> ->
take_n_hex(Input@11, N - 1, [<<"a"/utf8>> | Acc]);
<<"b"/utf8, Input@12/binary>> ->
take_n_hex(Input@12, N - 1, [<<"b"/utf8>> | Acc]);
<<"c"/utf8, Input@13/binary>> ->
take_n_hex(Input@13, N - 1, [<<"c"/utf8>> | Acc]);
<<"d"/utf8, Input@14/binary>> ->
take_n_hex(Input@14, N - 1, [<<"d"/utf8>> | Acc]);
<<"e"/utf8, Input@15/binary>> ->
take_n_hex(Input@15, N - 1, [<<"e"/utf8>> | Acc]);
<<"f"/utf8, Input@16/binary>> ->
take_n_hex(Input@16, N - 1, [<<"f"/utf8>> | Acc]);
<<"A"/utf8, Input@17/binary>> ->
take_n_hex(Input@17, N - 1, [<<"A"/utf8>> | Acc]);
<<"B"/utf8, Input@18/binary>> ->
take_n_hex(Input@18, N - 1, [<<"B"/utf8>> | Acc]);
<<"C"/utf8, Input@19/binary>> ->
take_n_hex(Input@19, N - 1, [<<"C"/utf8>> | Acc]);
<<"D"/utf8, Input@20/binary>> ->
take_n_hex(Input@20, N - 1, [<<"D"/utf8>> | Acc]);
<<"E"/utf8, Input@21/binary>> ->
take_n_hex(Input@21, N - 1, [<<"E"/utf8>> | Acc]);
<<"F"/utf8, Input@22/binary>> ->
take_n_hex(Input@22, N - 1, [<<"F"/utf8>> | Acc]);
_ ->
{error, nil}
end
end.
-file("src/molt/internal/parser/scanners.gleam", 241).
?DOC(false).
-spec parse_valid_scalar(binary()) -> {ok, integer()} | {error, nil}.
parse_valid_scalar(Hex) ->
case gleam@int:base_parse(Hex, 16) of
{ok, Cp} when ((Cp >= 0) andalso (Cp =< 16#10FFFF)) andalso ((Cp < 16#D800) orelse (Cp > 16#DFFF)) ->
{ok, Cp};
_ ->
{error, nil}
end.
-file("src/molt/internal/parser/scanners.gleam", 172).
?DOC(false).
-spec scan_basic_escape(binary()) -> {ok, {binary(), binary()}} | {error, nil}.
scan_basic_escape(Input) ->
case Input of
<<"\""/utf8, Input@1/binary>> ->
{ok, {<<"\\\""/utf8>>, Input@1}};
<<"\\"/utf8, Input@2/binary>> ->
{ok, {<<"\\\\"/utf8>>, Input@2}};
<<"b"/utf8, Input@3/binary>> ->
{ok, {<<"\\b"/utf8>>, Input@3}};
<<"t"/utf8, Input@4/binary>> ->
{ok, {<<"\\t"/utf8>>, Input@4}};
<<"n"/utf8, Input@5/binary>> ->
{ok, {<<"\\n"/utf8>>, Input@5}};
<<"f"/utf8, Input@6/binary>> ->
{ok, {<<"\\f"/utf8>>, Input@6}};
<<"r"/utf8, Input@7/binary>> ->
{ok, {<<"\\r"/utf8>>, Input@7}};
<<"e"/utf8, Input@8/binary>> ->
{ok, {<<"\\e"/utf8>>, Input@8}};
<<"u"/utf8, Input@9/binary>> ->
gleam@result:'try'(
take_n_hex(Input@9, 4, []),
fun(_use0) ->
{Hex, Input@10} = _use0,
gleam@result:'try'(
parse_valid_scalar(Hex),
fun(_) ->
{ok, {<<"\\u"/utf8, Hex/binary>>, Input@10}}
end
)
end
);
<<"U"/utf8, Input@11/binary>> ->
gleam@result:'try'(
take_n_hex(Input@11, 8, []),
fun(_use0@1) ->
{Hex@1, Input@12} = _use0@1,
gleam@result:'try'(
parse_valid_scalar(Hex@1),
fun(_) ->
{ok, {<<"\\U"/utf8, Hex@1/binary>>, Input@12}}
end
)
end
);
<<"x"/utf8, Input@13/binary>> ->
gleam@result:'try'(
take_n_hex(Input@13, 2, []),
fun(_use0@2) ->
{Hex@2, Input@14} = _use0@2,
{ok, {<<"\\x"/utf8, Hex@2/binary>>, Input@14}}
end
);
_ ->
{error, nil}
end.
-file("src/molt/internal/parser/scanners.gleam", 256).
?DOC(false).
-spec do_scan_basic(splitter:splitter(), binary(), list(binary())) -> {ok,
{list(binary()), binary()}} |
{error, basic_scan_error()}.
do_scan_basic(Split, Input, Acc) ->
{Prefix, Delim, Rest} = splitter_ffi:split(Split, Input),
Acc@1 = [Prefix | Acc],
case Delim of
<<""/utf8>> ->
{error, unterminated_basic};
<<"\""/utf8>> ->
{ok, {Acc@1, Rest}};
<<"\\"/utf8>> ->
case scan_basic_escape(Rest) of
{ok, {Fragment, Input@1}} ->
do_scan_basic(Split, Input@1, [Fragment | Acc@1]);
{error, nil} ->
{error, bad_escape}
end;
_ ->
{error, unterminated_basic}
end.
-file("src/molt/internal/parser/scanners.gleam", 143).
?DOC(false).
-spec absorb_trailing_basic(list(binary()), binary()) -> {list(binary()),
binary()}.
absorb_trailing_basic(Parts_rev, Rest) ->
case Rest of
<<"\"\""/utf8, After/binary>> ->
case gleam_stdlib:string_starts_with(After, <<"\""/utf8>>) of
true ->
{Parts_rev, Rest};
false ->
{[<<"\"\""/utf8>> | Parts_rev], After}
end;
<<"\""/utf8, After@1/binary>> ->
case gleam_stdlib:string_starts_with(After@1, <<"\""/utf8>>) of
true ->
{Parts_rev, Rest};
false ->
{[<<"\""/utf8>> | Parts_rev], After@1}
end;
_ ->
{Parts_rev, Rest}
end.
-file("src/molt/internal/parser/scanners.gleam", 590).
?DOC(false).
-spec maybe_emit_next_part(binary(), list(binary())) -> list(binary()).
maybe_emit_next_part(Pending_nl, Parts_rev) ->
gleam@bool:guard(
Pending_nl =:= <<""/utf8>>,
Parts_rev,
fun() -> [Pending_nl | Parts_rev] end
).
-file("src/molt/internal/parser/scanners.gleam", 276).
?DOC(false).
-spec scan_ml_basic(
molt@internal@parser@core:splitters(),
molt@types:toml_kind(),
binary(),
list(binary()),
binary(),
binary()
) -> {greenwood:token(molt@types:toml_kind()), binary(), binary(), binary()}.
scan_ml_basic(Sp, Kind, Input, Parts_rev, Pending_nl, Source_rest) ->
gleam@bool:guard(
(Input =:= <<""/utf8>>) andalso (Source_rest =:= <<""/utf8>>),
{{token,
invalid_multiline_basic_string,
molt@internal@utils:reverse_concat(Parts_rev)},
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>},
fun() ->
gleam@bool:lazy_guard(
Input =:= <<""/utf8>>,
fun() ->
Parts_rev@1 = maybe_emit_next_part(Pending_nl, Parts_rev),
{Input@1, Pending_nl@1, Source_rest@1} = splitter_ffi:split(
erlang:element(2, Sp),
Source_rest
),
scan_ml_basic(
Sp,
Kind,
Input@1,
Parts_rev@1,
Pending_nl@1,
Source_rest@1
)
end,
fun() ->
{Prefix, Delim, Input@2} = splitter_ffi:split(
erlang:element(7, Sp),
Input
),
Parts_rev@2 = maybe_emit_next_part(Prefix, Parts_rev),
gleam@bool:lazy_guard(
Delim =:= <<""/utf8>>,
fun() ->
scan_ml_basic(
Sp,
Kind,
<<""/utf8>>,
Parts_rev@2,
Pending_nl,
Source_rest
)
end,
fun() ->
gleam@bool:lazy_guard(
Delim =:= <<"\"\"\""/utf8>>,
fun() ->
{Parts_rev@3, Input@3} = absorb_trailing_basic(
Parts_rev@2,
Input@2
),
{greenwood:token(
Kind,
molt@internal@utils:reverse_concat(
Parts_rev@3
)
),
Input@3,
Pending_nl,
Source_rest}
end,
fun() ->
gleam@bool:lazy_guard(
Delim /= <<"\\"/utf8>>,
fun() ->
scan_ml_basic(
Sp,
Kind,
Input@2,
Parts_rev@2,
Pending_nl,
Source_rest
)
end,
fun() ->
case scan_basic_escape(Input@2) of
{ok, {Fragment, Input@4}} ->
scan_ml_basic(
Sp,
Kind,
Input@4,
[Fragment | Parts_rev@2],
Pending_nl,
Source_rest
);
{error, nil} ->
Parts_rev@4 = [<<"\\"/utf8,
Input@2/binary>> |
Parts_rev@2],
gleam@bool:guard(
not casefold:is_blank(
Input@2
),
{{token,
invalid_value,
molt@internal@utils:reverse_concat(
Parts_rev@4
)},
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>},
fun() ->
scan_ml_basic(
Sp,
Kind,
<<""/utf8>>,
Parts_rev@4,
Pending_nl,
Source_rest
)
end
)
end
end
)
end
)
end
)
end
)
end
).
-file("src/molt/internal/parser/scanners.gleam", 109).
?DOC(false).
-spec scan_multiline_basic(
molt@internal@parser@core:splitters(),
molt@types:toml_kind(),
binary(),
binary(),
binary()
) -> {greenwood:token(molt@types:toml_kind()), binary(), binary(), binary()}.
scan_multiline_basic(Sp, Kind, Input, Pending_nl, Source_rest) ->
case Kind of
multiline_basic_string_nl ->
{Input@1, Pending_nl@1, Source_rest@1} = splitter_ffi:split(
erlang:element(2, Sp),
Source_rest
),
scan_ml_basic(Sp, Kind, Input@1, [], Pending_nl@1, Source_rest@1);
_ ->
scan_ml_basic(Sp, Kind, Input, [], Pending_nl, Source_rest)
end.
-file("src/molt/internal/parser/scanners.gleam", 17).
?DOC(false).
-spec scan_basic_string(
molt@internal@parser@core:splitters(),
binary(),
binary(),
binary()
) -> {greenwood:token(molt@types:toml_kind()), binary(), binary(), binary()}.
scan_basic_string(Sp, Input, Pending_nl, Source_rest) ->
case Input of
<<"\"\""/utf8, After_triple/binary>> ->
Kind = case After_triple of
<<""/utf8>> ->
multiline_basic_string_nl;
_ ->
multiline_basic_string
end,
scan_multiline_basic(
Sp,
Kind,
After_triple,
Pending_nl,
Source_rest
);
_ ->
case do_scan_basic(erlang:element(5, Sp), Input, []) of
{ok, {Parts_rev, Rest}} ->
{greenwood:token(
basic_string,
molt@internal@utils:reverse_concat(Parts_rev)
),
Rest,
Pending_nl,
Source_rest};
{error, unterminated_basic} ->
{greenwood:token(
invalid_basic_string,
<<"\""/utf8, Input/binary>>
),
<<""/utf8>>,
Pending_nl,
Source_rest};
{error, bad_escape} ->
{greenwood:token(invalid_value, <<"\""/utf8, Input/binary>>),
<<""/utf8>>,
Pending_nl,
Source_rest}
end
end.
-file("src/molt/internal/parser/scanners.gleam", 411).
?DOC(false).
-spec absorb_trailing_literal(list(binary()), binary()) -> {list(binary()),
binary()}.
absorb_trailing_literal(Parts_rev, Rest) ->
case Rest of
<<"''"/utf8, After/binary>> ->
case gleam_stdlib:string_starts_with(After, <<"'"/utf8>>) of
true ->
{Parts_rev, Rest};
false ->
{[<<"''"/utf8>> | Parts_rev], After}
end;
<<"'"/utf8, After@1/binary>> ->
case gleam_stdlib:string_starts_with(After@1, <<"'"/utf8>>) of
true ->
{Parts_rev, Rest};
false ->
{[<<"'"/utf8>> | Parts_rev], After@1}
end;
_ ->
{Parts_rev, Rest}
end.
-file("src/molt/internal/parser/scanners.gleam", 356).
?DOC(false).
-spec do_scan_ml_literal(
molt@internal@parser@core:splitters(),
molt@types:toml_kind(),
binary(),
list(binary()),
binary(),
binary()
) -> {greenwood:token(molt@types:toml_kind()), binary(), binary(), binary()}.
do_scan_ml_literal(Sp, Kind, Input, Parts_rev, Pending_nl, Source_rest) ->
gleam@bool:guard(
(Input =:= <<""/utf8>>) andalso (Source_rest =:= <<""/utf8>>),
{{token,
invalid_multiline_literal_string,
molt@internal@utils:reverse_concat(Parts_rev)},
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>},
fun() ->
gleam@bool:lazy_guard(
Input =:= <<""/utf8>>,
fun() ->
Parts_rev@1 = maybe_emit_next_part(Pending_nl, Parts_rev),
{Input@1, Pending_nl@1, Source_rest@1} = splitter_ffi:split(
erlang:element(2, Sp),
Source_rest
),
do_scan_ml_literal(
Sp,
Kind,
Input@1,
Parts_rev@1,
Pending_nl@1,
Source_rest@1
)
end,
fun() ->
{Prefix, Delim, Input@2} = splitter_ffi:split(
erlang:element(8, Sp),
Input
),
Parts_rev@2 = maybe_emit_next_part(Prefix, Parts_rev),
gleam@bool:guard(
Delim =:= <<"'''"/utf8>>,
begin
{Parts_rev@3, Input@3} = absorb_trailing_literal(
Parts_rev@2,
Input@2
),
{greenwood:token(
Kind,
molt@internal@utils:reverse_concat(
Parts_rev@3
)
),
Input@3,
Pending_nl,
Source_rest}
end,
fun() ->
gleam@bool:lazy_guard(
Delim =:= <<""/utf8>>,
fun() ->
do_scan_ml_literal(
Sp,
Kind,
<<""/utf8>>,
Parts_rev@2,
Pending_nl,
Source_rest
)
end,
fun() ->
do_scan_ml_literal(
Sp,
Kind,
Input@2,
Parts_rev@2,
Pending_nl,
Source_rest
)
end
)
end
)
end
)
end
).
-file("src/molt/internal/parser/scanners.gleam", 432).
?DOC(false).
-spec scan_multiline_literal(
molt@internal@parser@core:splitters(),
molt@types:toml_kind(),
binary(),
binary(),
binary()
) -> {greenwood:token(molt@types:toml_kind()), binary(), binary(), binary()}.
scan_multiline_literal(Sp, Kind, Input, Pending_nl, Source_rest) ->
case Kind of
multiline_literal_string_nl ->
{Input@1, Pending_nl@1, Source_rest@1} = splitter_ffi:split(
erlang:element(2, Sp),
Source_rest
),
do_scan_ml_literal(
Sp,
Kind,
Input@1,
[],
Pending_nl@1,
Source_rest@1
);
_ ->
do_scan_ml_literal(Sp, Kind, Input, [], Pending_nl, Source_rest)
end.
-file("src/molt/internal/parser/scanners.gleam", 65).
?DOC(false).
-spec scan_literal_string(
molt@internal@parser@core:splitters(),
binary(),
binary(),
binary()
) -> {greenwood:token(molt@types:toml_kind()), binary(), binary(), binary()}.
scan_literal_string(Sp, Input, Pending_nl, Source_rest) ->
case Input of
<<"''"/utf8, After_triple/binary>> ->
Kind = case After_triple of
<<""/utf8>> ->
multiline_literal_string_nl;
_ ->
multiline_literal_string
end,
scan_multiline_literal(
Sp,
Kind,
After_triple,
Pending_nl,
Source_rest
);
_ ->
{Prefix, Delim, Rest} = splitter_ffi:split(
erlang:element(6, Sp),
Input
),
case Delim of
<<"'"/utf8>> ->
{greenwood:token(literal_string, Prefix),
Rest,
Pending_nl,
Source_rest};
_ ->
{greenwood:token(
invalid_literal_string,
<<"'"/utf8, Input/binary>>
),
<<""/utf8>>,
Pending_nl,
Source_rest}
end
end.
-file("src/molt/internal/parser/scanners.gleam", 466).
?DOC(false).
-spec tokenize_header_line(
molt@internal@parser@core:splitters(),
binary(),
list(greenwood:token(molt@types:toml_kind()))
) -> list(greenwood:token(molt@types:toml_kind())).
tokenize_header_line(Sp, Input, Acc) ->
case Input of
<<""/utf8>> ->
Acc;
_ ->
{Prefix, Delim, Rest} = splitter_ffi:split(
erlang:element(3, Sp),
Input
),
Acc@1 = case Prefix of
<<""/utf8>> ->
Acc;
_ ->
[greenwood:token(bare_key, Prefix) | Acc]
end,
case Delim of
<<""/utf8>> ->
Acc@1;
<<"["/utf8>> ->
tokenize_header_line(
Sp,
Rest,
[greenwood:token(left_bracket, <<""/utf8>>) | Acc@1]
);
<<"]"/utf8>> ->
tokenize_header_line(
Sp,
Rest,
[greenwood:token(right_bracket, <<""/utf8>>) | Acc@1]
);
<<"."/utf8>> ->
tokenize_header_line(
Sp,
Rest,
[greenwood:token(dot, <<""/utf8>>) | Acc@1]
);
<<"="/utf8>> ->
tokenize_header_line(
Sp,
Rest,
[greenwood:token(equals, <<""/utf8>>) | Acc@1]
);
<<" "/utf8>> ->
{Ws, Rest_after} = molt@internal@parser@core:scan_ws(
Delim,
Rest
),
tokenize_header_line(
Sp,
Rest_after,
[greenwood:token(whitespace, Ws) | Acc@1]
);
<<"\t"/utf8>> ->
{Ws, Rest_after} = molt@internal@parser@core:scan_ws(
Delim,
Rest
),
tokenize_header_line(
Sp,
Rest_after,
[greenwood:token(whitespace, Ws) | Acc@1]
);
<<"\""/utf8>> ->
{Str_tok, Rest_after@1, _, _} = scan_basic_string(
Sp,
Rest,
<<""/utf8>>,
<<""/utf8>>
),
tokenize_header_line(Sp, Rest_after@1, [Str_tok | Acc@1]);
<<"'"/utf8>> ->
{Str_tok@1, Rest_after@2, _, _} = scan_literal_string(
Sp,
Rest,
<<""/utf8>>,
<<""/utf8>>
),
tokenize_header_line(Sp, Rest_after@2, [Str_tok@1 | Acc@1]);
<<"#"/utf8>> ->
[greenwood:token(comment, <<"#"/utf8, Rest/binary>>) |
Acc@1];
_ ->
tokenize_header_line(Sp, Rest, Acc@1)
end
end.
-file("src/molt/internal/parser/scanners.gleam", 530).
?DOC(false).
-spec consume_key_and_eq(
molt@internal@parser@core:splitters(),
binary(),
list(greenwood:element(molt@types:toml_kind()))
) -> {list(greenwood:element(molt@types:toml_kind())), binary()}.
consume_key_and_eq(Sp, Input, Acc) ->
case Input of
<<""/utf8>> ->
{Acc, <<""/utf8>>};
_ ->
{Prefix, Delim, Rest} = splitter_ffi:split(
erlang:element(3, Sp),
Input
),
Acc@1 = case Prefix of
<<""/utf8>> ->
Acc;
_ ->
[{token_element, {token, bare_key, Prefix}} | Acc]
end,
case Delim of
<<""/utf8>> ->
{Acc@1, <<""/utf8>>};
<<"="/utf8>> ->
{[{token_element, {token, equals, <<""/utf8>>}} | Acc@1],
Rest};
<<"."/utf8>> ->
consume_key_and_eq(
Sp,
Rest,
[{token_element, {token, dot, <<""/utf8>>}} | Acc@1]
);
<<" "/utf8>> ->
{Ws, Rest_after} = molt@internal@parser@core:scan_ws(
Delim,
Rest
),
consume_key_and_eq(
Sp,
Rest_after,
[{token_element, {token, whitespace, Ws}} | Acc@1]
);
<<"\t"/utf8>> ->
{Ws, Rest_after} = molt@internal@parser@core:scan_ws(
Delim,
Rest
),
consume_key_and_eq(
Sp,
Rest_after,
[{token_element, {token, whitespace, Ws}} | Acc@1]
);
<<"\""/utf8>> ->
{Str_tok, Rest_after@1, _, _} = scan_basic_string(
Sp,
Rest,
<<""/utf8>>,
<<""/utf8>>
),
consume_key_and_eq(
Sp,
Rest_after@1,
[{token_element, Str_tok} | Acc@1]
);
<<"'"/utf8>> ->
{Str_tok@1, Rest_after@2, _, _} = scan_literal_string(
Sp,
Rest,
<<""/utf8>>,
<<""/utf8>>
),
consume_key_and_eq(
Sp,
Rest_after@2,
[{token_element, Str_tok@1} | Acc@1]
);
<<"["/utf8>> ->
consume_key_and_eq(
Sp,
Rest,
[{token_element, {token, left_bracket, <<""/utf8>>}} |
Acc@1]
);
<<"]"/utf8>> ->
consume_key_and_eq(
Sp,
Rest,
[{token_element, {token, right_bracket, <<""/utf8>>}} |
Acc@1]
);
<<"#"/utf8>> ->
{[{token_element,
{token, comment, <<"#"/utf8, Rest/binary>>}} |
Acc@1],
<<""/utf8>>};
_ ->
consume_key_and_eq(Sp, Rest, Acc@1)
end
end.