Current section
Files
Jump to
Current section
Files
src/gleeth@ethereum@abi@type_parser.erl
-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,
<<Acc/binary, ")"/utf8>>
)
end;
{ok, {<<"("/utf8>>, Rest@1}} ->
find_matching_paren(Rest@1, Depth + 1, <<Acc/binary, "("/utf8>>);
{ok, {Ch, Rest@2}} ->
find_matching_paren(Rest@2, Depth, <<Acc/binary, Ch/binary>>)
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,
<<Current/binary, ","/utf8>>,
Acc
)
end;
{ok, {<<"("/utf8>>, Rest@1}} ->
split_commas_impl(
Rest@1,
Depth + 1,
<<Current/binary, "("/utf8>>,
Acc
);
{ok, {<<")"/utf8>>, Rest@2}} ->
split_commas_impl(
Rest@2,
Depth - 1,
<<Current/binary, ")"/utf8>>,
Acc
);
{ok, {Ch, Rest@3}} ->
split_commas_impl(Rest@3, Depth, <<Current/binary, Ch/binary>>, 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, <<Acc/binary, Ch/binary>>)
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, <<Acc/binary, Ch/binary>>);
false ->
{Acc, <<Ch/binary, Rest/binary>>}
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<N> or int<N>. 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<N>. 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<N>, int<N>, address, bool, bytes<N>, bytes, string,\n"
" <type>[], <type>[N], (<type>,<type>,...).\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.