mirror of https://github.com/poanetwork/ex_abi.git
Create a formal lexer+parser for typespecs and function signatures
This commit is contained in:
parent
8d4b281b79
commit
7147b405aa
|
@ -18,3 +18,7 @@ erl_crash.dump
|
|||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
|
||||
# Ignore generated code from yecc and leex
|
||||
src/*_lexer.erl
|
||||
src/*_parser.erl
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
defmodule ABI.Parser do
|
||||
@moduledoc false
|
||||
|
||||
@doc false
|
||||
def parse!(str, opts \\ []) do
|
||||
{:ok, tokens, _} = str |> String.to_charlist |> :ethereum_abi_lexer.string
|
||||
|
||||
tokens = case opts[:as] do
|
||||
nil -> tokens
|
||||
:type -> [{:"expecting type", 1} | tokens]
|
||||
:selector -> [{:"expecting selector", 1} | tokens]
|
||||
end
|
||||
|
||||
{:ok, ast} = :ethereum_abi_parser.parse(tokens)
|
||||
|
||||
case ast do
|
||||
{:type, type} -> type
|
||||
{:selector, selector_parts} -> struct!(ABI.FunctionSelector, selector_parts)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
Definitions.
|
||||
|
||||
INT = [0-9]+
|
||||
LETTERS = [a-z_]+
|
||||
WHITESPACE = [\s\t\n\r]
|
||||
TYPES = uint|int|address|bool|fixed|uint|ufixed|bytes|function|string
|
||||
|
||||
Rules.
|
||||
|
||||
{TYPES} : {token, {atom, TokenLine, list_to_atom(TokenChars)}}.
|
||||
{INT} : {token, {int, TokenLine, list_to_integer(TokenChars)}}.
|
||||
{LETTERS} : {token, {binary, TokenLine, list_to_binary(TokenChars)}}.
|
||||
\[ : {token, {'[', TokenLine}}.
|
||||
\] : {token, {']', TokenLine}}.
|
||||
\( : {token, {'(', TokenLine}}.
|
||||
\) : {token, {')', TokenLine}}.
|
||||
, : {token, {',', TokenLine}}.
|
||||
-> : {token, {'->', TokenLine}}.
|
||||
{WHITESPACE}+ : skip_token.
|
||||
|
||||
Erlang code.
|
|
@ -0,0 +1,72 @@
|
|||
Terminals '(' ')' '[' ']' ',' '->' int atom binary 'expecting selector' 'expecting type'.
|
||||
Nonterminals dispatch selector nontrivial_selector comma_delimited_types type_with_subscripts array_subscripts tuple array_subscript identifier type typespec.
|
||||
Rootsymbol dispatch.
|
||||
|
||||
dispatch -> 'expecting type' type_with_subscripts : {type, '$2'}.
|
||||
dispatch -> 'expecting selector' selector : {selector, '$2'}.
|
||||
dispatch -> type_with_subscripts : {selector, #{function => nil, types => ['$1'], returns => nil}}.
|
||||
dispatch -> nontrivial_selector : {selector, '$1'}.
|
||||
|
||||
selector -> typespec : #{function => nil, types => '$1', returns => nil}.
|
||||
selector -> nontrivial_selector : '$1'.
|
||||
|
||||
nontrivial_selector -> typespec '->' type : #{function => nil, types => '$1', returns => '$3'}.
|
||||
nontrivial_selector -> identifier typespec : #{function => '$1', types => '$2', returns => nil}.
|
||||
nontrivial_selector -> identifier typespec '->' type : #{function => '$1', types => '$2', returns => '$4'}.
|
||||
|
||||
typespec -> '(' ')' : [].
|
||||
typespec -> '(' comma_delimited_types ')' : '$2'.
|
||||
|
||||
tuple -> '(' ')' : {tuple, []}.
|
||||
tuple -> '(' comma_delimited_types ')' : {tuple, '$2'}.
|
||||
|
||||
comma_delimited_types -> type_with_subscripts : ['$1'].
|
||||
comma_delimited_types -> type_with_subscripts ',' comma_delimited_types : ['$1' | '$3'].
|
||||
|
||||
identifier -> atom : atom_to_list(v('$1')).
|
||||
identifier -> binary : v('$1').
|
||||
|
||||
type_with_subscripts -> type : '$1'.
|
||||
type_with_subscripts -> type array_subscripts : with_subscripts('$1', '$2').
|
||||
|
||||
array_subscripts -> array_subscript : ['$1'].
|
||||
array_subscripts -> array_subscript array_subscripts : ['$1' | '$2'].
|
||||
|
||||
array_subscript -> '[' ']' : variable.
|
||||
array_subscript -> '[' int ']' : v('$2').
|
||||
|
||||
type -> atom :
|
||||
plain_type(v('$1')).
|
||||
type -> atom int :
|
||||
juxt_type(v('$1'), v('$2')).
|
||||
type -> atom int identifier int :
|
||||
double_juxt_type(v('$1'), v('$4'), v('$2'), v('$3')).
|
||||
type -> tuple : '$1'.
|
||||
|
||||
|
||||
Erlang code.
|
||||
|
||||
v({_Token, _Line, Value}) -> Value.
|
||||
|
||||
plain_type(address) -> address;
|
||||
plain_type(bool) -> bool;
|
||||
plain_type(function) -> function;
|
||||
plain_type(string) -> string;
|
||||
plain_type(bytes) -> bytes;
|
||||
plain_type(int) -> juxt_type(int, 256);
|
||||
plain_type(uint) -> juxt_type(uint, 256);
|
||||
plain_type(fixed) -> double_juxt_type(fixed, "x", 128, 19);
|
||||
plain_type(ufixed) -> double_juxt_type(ufixed, "x", 128, 19).
|
||||
|
||||
with_subscripts(Type, []) -> Type;
|
||||
with_subscripts(Type, [H | T]) -> with_subscripts(with_subscript(Type, H), T).
|
||||
|
||||
with_subscript(Type, variable) -> {array, Type};
|
||||
with_subscript(Type, N) when is_integer(N), N >= 0 -> {array, Type, N}.
|
||||
|
||||
juxt_type(int, M) when M > 0, M =< 256, (M rem 8) =:= 0 -> {int, M};
|
||||
juxt_type(uint, M) when M > 0, M =< 256, (M rem 8) =:= 0 -> {uint, M};
|
||||
juxt_type(bytes, M) when M > 0, M =< 32 -> {bytes, M}.
|
||||
|
||||
double_juxt_type(fixed, "x", M, N) when M >= 0, M =< 256, (M rem 8) =:= 0, N > 0, N =< 80 -> {fixed, M, N};
|
||||
double_juxt_type(ufixed, "x", M, N) when M >= 0, M =< 256, (M rem 8) =:= 0, N > 0, N =< 80 -> {ufixed, M, N}.
|
Loading…
Reference in New Issue