-module(jackson@internal@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([parse/1]). -spec unexpected_character(binary()) -> binary(). unexpected_character(String) -> First_char = gleam@string:slice(String, 0, 1), <<<<"Unexpected character: \""/utf8, First_char/binary>>/binary, "\""/utf8>>. -spec parse_bool(binary()) -> {ok, {jackson@internal@json:json(), binary()}} | {error, binary()}. parse_bool(Input) -> case Input of <<"true"/utf8, Rest/binary>> -> {ok, {{bool, true}, Rest}}; <<"false"/utf8, Rest@1/binary>> -> {ok, {{bool, false}, Rest@1}}; _ -> {error, <<"Expected one of: \"true\", \"false\""/utf8>>} end. -spec parse_null(binary()) -> {ok, {jackson@internal@json:json(), binary()}} | {error, binary()}. parse_null(Input) -> case Input of <<"null"/utf8, Rest/binary>> -> {ok, {null, Rest}}; _ -> {error, <<"Expected: \"null\""/utf8>>} end. -spec parse_exponent(binary(), binary()) -> {ok, jackson@internal@json:json()} | {error, nil}. parse_exponent(First, Second) -> First@1 = case {gleam@int:parse(First), gleam@float:parse(First)} of {_, {ok, Floatval}} -> {ok, Floatval}; {{ok, Intval}, _} -> {ok, gleam@int:to_float(Intval)}; {_, _} -> {error, nil} end, gleam@result:'try'( First@1, fun(First@2) -> Second@1 = case {gleam@int:parse(Second), gleam@float:parse(Second)} of {_, {ok, Floatval@1}} -> {ok, Floatval@1}; {{ok, Intval@1}, _} -> {ok, gleam@int:to_float(Intval@1)}; {_, _} -> {error, nil} end, gleam@result:'try'( Second@1, fun(Second@2) -> Multiplicand = gleam@float:power(10.0, Second@2), gleam@result:'try'( Multiplicand, fun(Mult) -> {ok, {float, First@2 * Mult}} end ) end ) end ). -spec parse_number(binary()) -> {ok, {jackson@internal@json:json(), binary()}} | {error, binary()}. parse_number(Input) -> _assert_subject = gleam@regex:from_string( <<"^-?[0-9]+(\\.[0-9]+)?((e|E)(\\+|-)?[0-9]+)?"/utf8>> ), {ok, Re} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"jackson/internal/parser"/utf8>>, function => <<"parse_number"/utf8>>, line => 124}) end, Res = gleam@regex:scan(Re, Input), case {Res, Input} of {_, <<""/utf8>>} -> {error, <<"Unexpected end of input"/utf8>>}; {[], _} -> {error, unexpected_character(Input)}; {[{match, Content, _} | _], _} -> Rest = gleam@string:slice( Input, gleam@string:length(Content), gleam@string:length(Input) ), case gleam@string:split( gleam@string:lowercase(Content), <<"e"/utf8>> ) of [] -> erlang:error(#{gleam_error => panic, message => <<"string cannot be empty"/utf8>>, module => <<"jackson/internal/parser"/utf8>>, function => <<"parse_number"/utf8>>, line => 140}); [First] -> case {gleam@int:parse(First), gleam@float:parse(First)} of {{ok, Intval}, _} -> {ok, {{integer, Intval}, Rest}}; {_, {ok, Floatval}} -> {ok, {{float, Floatval}, Rest}}; {_, _} -> {error, unexpected_character(Content)} end; [First@1, Second] -> case parse_exponent(First@1, Second) of {ok, Val} -> {ok, {Val, Rest}}; {error, _} -> {error, <<"Invalid number "/utf8, Content/binary>>} end; _ -> {error, <<"Invalid number "/utf8, Content/binary>>} end end. -spec parse_string(binary()) -> {ok, {jackson@internal@json:json(), binary()}} | {error, binary()}. parse_string(Input) -> _assert_subject = gleam@regex:from_string( <<"^\"([^\\\\\"\\\\u0000-\\\\u001F\\\\u007F-\\\\u009F\\\\u061C\\\\u200E\\\\u200F\\\\u202A-\\\\u202E\\\\u2066-\\\\u2069]|(\\\\(\"|\\\\|\\/|b|f|n|r|t|(u[0-9a-fA-F]{4}))))*?\""/utf8>> ), {ok, Re} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"jackson/internal/parser"/utf8>>, function => <<"parse_string"/utf8>>, line => 184}) end, Res = gleam@regex:scan(Re, Input), case Res of [] -> {error, unexpected_character(Input)}; [{match, _, _} = Match | _] -> Inner = gleam@string:slice( erlang:element(2, Match), 1, gleam@string:length(erlang:element(2, Match)) - 2 ), Rest = gleam@string:slice( Input, gleam@string:length(erlang:element(2, Match)), gleam@string:length(Input) ), {ok, {{string, jackson@internal@escaping:descape_string(Inner)}, Rest}} end. -spec parse_object_entry(binary()) -> {ok, {list({binary(), jackson@internal@json:json()}), binary()}} | {error, binary()}. parse_object_entry(Input) -> Input@1 = gleam@string:trim_left(Input), gleam@result:'try'( parse_loop(Input@1), fun(_use0) -> {Key, Rest} = _use0, Rest@1 = gleam@string:trim_left(Rest), case Key of {string, Key@1} -> gleam@bool:guard( not gleam@string:starts_with(Rest@1, <<":"/utf8>>), {error, unexpected_character(Rest@1)}, fun() -> gleam@result:'try'( parse_loop( gleam@string:slice( Rest@1, 1, gleam@string:length(Rest@1) ) ), fun(_use0@1) -> {Value, Rest@2} = _use0@1, Rest@3 = gleam@string:trim_left(Rest@2), case Rest@3 of <<","/utf8, Rest@4/binary>> -> gleam@result:'try'( parse_object_entry(Rest@4), fun(_use0@2) -> {_, Rest@5} = _use0@2, {ok, {[{Key@1, Value}], Rest@5}} end ); <<"}"/utf8, Rest@6/binary>> -> {ok, {[{Key@1, Value}], Rest@6}}; _ -> {error, unexpected_character(Rest@3)} end end ) end ); _ -> {error, <<"Only strings are valid keys in json"/utf8>>} end end ). -spec parse_loop(binary()) -> {ok, {jackson@internal@json:json(), binary()}} | {error, binary()}. parse_loop(Input) -> Input@1 = gleam@string:trim_left(Input), gleam@result:try_recover( parse_array(Input@1), fun(_) -> gleam@result:try_recover( parse_object(Input@1), fun(_) -> gleam@result:try_recover( parse_bool(Input@1), fun(_) -> gleam@result:try_recover( parse_null(Input@1), fun(_) -> gleam@result:try_recover( parse_number(Input@1), fun(_) -> gleam@result:try_recover( parse_string(Input@1), fun(Err) -> {error, Err} end ) end ) end ) end ) end ) end ). -spec parse_object(binary()) -> {ok, {jackson@internal@json:json(), binary()}} | {error, binary()}. parse_object(Input) -> Input@1 = gleam@string:trim_left(Input), case Input@1 of <<"{"/utf8, Rest/binary>> -> gleam@result:'try'( parse_object_entry(Rest), fun(_use0) -> {Entries, Rest@1} = _use0, {ok, {{object, Entries}, Rest@1}} end ); _ -> {error, unexpected_character(Input@1)} end. -spec parse(binary()) -> {ok, jackson@internal@json:json()} | {error, binary()}. parse(Input) -> Input@1 = gleam@string:trim(Input), case parse_loop(Input@1) of {error, Err} -> {error, Err}; {ok, {Val, <<""/utf8>>}} -> {ok, Val}; {ok, {_, Rest}} -> {error, unexpected_character(Rest)} end. -spec parse_array_value(binary()) -> {ok, {jackson@internal@json:json(), binary()}} | {error, binary()}. parse_array_value(Input) -> gleam@result:'try'( parse_loop(Input), fun(_use0) -> {Element, Rest} = _use0, Rest@1 = gleam@string:trim_left(Rest), case Rest@1 of <<","/utf8, Rest@2/binary>> -> case parse_array_value(Rest@2) of {ok, {{array, Inner}, Rest@3}} -> {ok, {{array, [Element | Inner]}, Rest@3}}; _ -> {error, unexpected_character(Rest@2)} end; <<"]"/utf8, Rest@4/binary>> -> {ok, {{array, [Element]}, Rest@4}}; _ -> {error, unexpected_character(Rest@1)} end end ). -spec parse_array(binary()) -> {ok, {jackson@internal@json:json(), binary()}} | {error, binary()}. parse_array(Input) -> Input@1 = gleam@string:trim_left(Input), case Input@1 of <<"["/utf8, Rest/binary>> -> parse_array_value(Rest); _ -> {error, unexpected_character(Input@1)} end.