-module(gleeth@ethereum@abi@type_parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gleeth/ethereum/abi/type_parser.gleam"). -export([parse/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. -file("src/gleeth/ethereum/abi/type_parser.gleam", 133). ?DOC( " Find the matching ')' accounting for nested parens.\n" " Returns (content_inside_parens, rest_after_closing_paren).\n" ). -spec find_matching_paren(binary(), integer(), binary()) -> {ok, {binary(), binary()}} | {error, gleeth@ethereum@abi@types:abi_error()}. find_matching_paren(S, Depth, Acc) -> case gleam_stdlib:string_pop_grapheme(S) of {error, _} -> {error, {type_parse_error, <<"Unmatched opening parenthesis"/utf8>>}}; {ok, {<<")"/utf8>>, Rest}} -> case Depth of 0 -> {ok, {Acc, Rest}}; _ -> find_matching_paren( Rest, Depth - 1, <> ) end; {ok, {<<"("/utf8>>, Rest@1}} -> find_matching_paren(Rest@1, Depth + 1, <>); {ok, {Ch, Rest@2}} -> find_matching_paren(Rest@2, Depth, <>) end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 156). -spec split_commas_impl(binary(), integer(), binary(), list(binary())) -> {ok, list(binary())} | {error, gleeth@ethereum@abi@types:abi_error()}. split_commas_impl(S, Depth, Current, Acc) -> case gleam_stdlib:string_pop_grapheme(S) of {error, _} -> {ok, lists:reverse([Current | Acc])}; {ok, {<<","/utf8>>, Rest}} -> case Depth of 0 -> split_commas_impl(Rest, 0, <<""/utf8>>, [Current | Acc]); _ -> split_commas_impl( Rest, Depth, <>, Acc ) end; {ok, {<<"("/utf8>>, Rest@1}} -> split_commas_impl( Rest@1, Depth + 1, <>, Acc ); {ok, {<<")"/utf8>>, Rest@2}} -> split_commas_impl( Rest@2, Depth - 1, <>, Acc ); {ok, {Ch, Rest@3}} -> split_commas_impl(Rest@3, Depth, <>, Acc) end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 152). ?DOC(" Split a string by commas, but only at parenthesis depth 0.\n"). -spec split_at_top_level_commas(binary()) -> {ok, list(binary())} | {error, gleeth@ethereum@abi@types:abi_error()}. split_at_top_level_commas(S) -> split_commas_impl(S, 0, <<""/utf8>>, []). -file("src/gleeth/ethereum/abi/type_parser.gleam", 215). -spec take_until_close_bracket(binary(), binary()) -> {ok, {binary(), binary()}} | {error, gleeth@ethereum@abi@types:abi_error()}. take_until_close_bracket(S, Acc) -> case gleam_stdlib:string_pop_grapheme(S) of {error, _} -> {error, {type_parse_error, <<"Unmatched '[' in type"/utf8>>}}; {ok, {<<"]"/utf8>>, Rest}} -> {ok, {Acc, Rest}}; {ok, {Ch, Rest@1}} -> take_until_close_bracket(Rest@1, <>) end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 177). ?DOC(" Apply trailing array suffixes: [] or [N]\n"). -spec apply_array_suffixes(gleeth@ethereum@abi@types:abi_type(), binary()) -> {ok, gleeth@ethereum@abi@types:abi_type()} | {error, gleeth@ethereum@abi@types:abi_error()}. apply_array_suffixes(Base, Rest) -> case gleam_stdlib:string_starts_with(Rest, <<"["/utf8>>) of false -> case Rest of <<""/utf8>> -> {ok, Base}; _ -> {error, {type_parse_error, <<"Unexpected trailing characters: "/utf8, Rest/binary>>}} end; true -> After_bracket = gleam@string:drop_start(Rest, 1), gleam@result:'try'( take_until_close_bracket(After_bracket, <<""/utf8>>), fun(_use0) -> {Size_str, After_close} = _use0, case Size_str of <<""/utf8>> -> apply_array_suffixes({array, Base}, After_close); _ -> gleam@result:'try'( begin _pipe = gleam_stdlib:parse_int(Size_str), gleam@result:map_error( _pipe, fun(_) -> {type_parse_error, <<"Invalid array size: "/utf8, Size_str/binary>>} end ) end, fun(Size) -> apply_array_suffixes( {fixed_array, Base, Size}, After_close ) end ) end end ) end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 243). -spec is_digit(binary()) -> boolean(). is_digit(Ch) -> case Ch 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/gleeth/ethereum/abi/type_parser.gleam", 231). -spec take_digits_impl(binary(), binary()) -> {binary(), binary()}. take_digits_impl(S, Acc) -> case gleam_stdlib:string_pop_grapheme(S) of {error, _} -> {Acc, <<""/utf8>>}; {ok, {Ch, Rest}} -> case is_digit(Ch) of true -> take_digits_impl(Rest, <>); false -> {Acc, <>} end end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 227). ?DOC(" Take leading digits from a string, return (digits, rest).\n"). -spec take_digits(binary()) -> {binary(), binary()}. take_digits(S) -> take_digits_impl(S, <<""/utf8>>). -file("src/gleeth/ethereum/abi/type_parser.gleam", 48). ?DOC(" Parse uint or int. The prefix \"uint\"/\"int\" has already been consumed.\n"). -spec parse_int_type(binary(), boolean()) -> {ok, {gleeth@ethereum@abi@types:abi_type(), binary()}} | {error, gleeth@ethereum@abi@types:abi_error()}. parse_int_type(Rest, Unsigned) -> {Digits, Remaining} = take_digits(Rest), case Digits of <<""/utf8>> -> T = case Unsigned of true -> {uint, 256}; false -> {int, 256} end, {ok, {T, Remaining}}; _ -> gleam@result:'try'( begin _pipe = gleam_stdlib:parse_int(Digits), gleam@result:map_error( _pipe, fun(_) -> {type_parse_error, <<"Invalid integer size: "/utf8, Digits/binary>>} end ) end, fun(Size) -> case ((Size >= 8) andalso (Size =< 256)) andalso ((Size rem 8) =:= 0) of true -> T@1 = case Unsigned of true -> {uint, Size}; false -> {int, Size} end, {ok, {T@1, Remaining}}; false -> {error, {type_parse_error, <<"Integer size must be 8-256 in steps of 8, got: "/utf8, (erlang:integer_to_binary(Size))/binary>>}} end end ) end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 88). ?DOC(" Parse bytes or bytes. The prefix \"bytes\" has already been consumed.\n"). -spec parse_bytes_type(binary()) -> {ok, {gleeth@ethereum@abi@types:abi_type(), binary()}} | {error, gleeth@ethereum@abi@types:abi_error()}. parse_bytes_type(Rest) -> {Digits, Remaining} = take_digits(Rest), case Digits of <<""/utf8>> -> {ok, {bytes, Remaining}}; _ -> gleam@result:'try'( begin _pipe = gleam_stdlib:parse_int(Digits), gleam@result:map_error( _pipe, fun(_) -> {type_parse_error, <<"Invalid bytes size: "/utf8, Digits/binary>>} end ) end, fun(Size) -> case (Size >= 1) andalso (Size =< 32) of true -> {ok, {{fixed_bytes, Size}, Remaining}}; false -> {error, {type_parse_error, <<"Fixed bytes size must be 1-32, got: "/utf8, (erlang:integer_to_binary(Size))/binary>>}} end end ) end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 111). ?DOC(" Parse a tuple type: (T1,T2,...). Handles nested parentheses.\n"). -spec parse_tuple(binary()) -> {ok, {gleeth@ethereum@abi@types:abi_type(), binary()}} | {error, gleeth@ethereum@abi@types:abi_error()}. parse_tuple(S) -> Inner_and_rest = gleam@string:drop_start(S, 1), gleam@result:'try'( find_matching_paren(Inner_and_rest, 0, <<""/utf8>>), fun(_use0) -> {Inner, After_paren} = _use0, gleam@result:'try'( split_at_top_level_commas(Inner), fun(Element_strings) -> case Element_strings of [<<""/utf8>>] -> {ok, {{tuple, []}, After_paren}}; _ -> gleam@result:'try'( gleam@list:try_map(Element_strings, fun parse/1), fun(Elements) -> {ok, {{tuple, Elements}, After_paren}} end ) end end ) end ). -file("src/gleeth/ethereum/abi/type_parser.gleam", 10). ?DOC( " Parse a Solidity type string into an AbiType.\n" " Handles: uint, int, address, bool, bytes, bytes, string,\n" " [], [N], (,,...).\n" ). -spec parse(binary()) -> {ok, gleeth@ethereum@abi@types:abi_type()} | {error, gleeth@ethereum@abi@types:abi_error()}. parse(Type_string) -> Trimmed = gleam@string:trim(Type_string), case Trimmed of <<""/utf8>> -> {error, {type_parse_error, <<"Empty type string"/utf8>>}}; _ -> parse_type(Trimmed) end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 18). -spec parse_type(binary()) -> {ok, gleeth@ethereum@abi@types:abi_type()} | {error, gleeth@ethereum@abi@types:abi_error()}. parse_type(S) -> case gleam_stdlib:string_starts_with(S, <<"("/utf8>>) of true -> parse_with_array_suffix(S); false -> parse_with_array_suffix(S) end. -file("src/gleeth/ethereum/abi/type_parser.gleam", 27). ?DOC(" Parse a type, then consume any trailing [] or [N] suffixes.\n"). -spec parse_with_array_suffix(binary()) -> {ok, gleeth@ethereum@abi@types:abi_type()} | {error, gleeth@ethereum@abi@types:abi_error()}. parse_with_array_suffix(S) -> gleam@result:'try'( parse_base_type(S), fun(_use0) -> {Base, Rest} = _use0, apply_array_suffixes(Base, Rest) end ). -file("src/gleeth/ethereum/abi/type_parser.gleam", 34). ?DOC( " Parse the base type (before any array suffixes).\n" " Returns the parsed type and any remaining unparsed string.\n" ). -spec parse_base_type(binary()) -> {ok, {gleeth@ethereum@abi@types:abi_type(), binary()}} | {error, gleeth@ethereum@abi@types:abi_error()}. parse_base_type(S) -> case S of <<"("/utf8, _/binary>> -> parse_tuple(S); <<"uint"/utf8, Rest/binary>> -> parse_int_type(Rest, true); <<"int"/utf8, Rest@1/binary>> -> parse_int_type(Rest@1, false); <<"address"/utf8, Rest@2/binary>> -> {ok, {address, Rest@2}}; <<"bool"/utf8, Rest@3/binary>> -> {ok, {bool, Rest@3}}; <<"bytes"/utf8, Rest@4/binary>> -> parse_bytes_type(Rest@4); <<"string"/utf8, Rest@5/binary>> -> {ok, {string, Rest@5}}; _ -> {error, {type_parse_error, <<"Unknown type: "/utf8, S/binary>>}} end.