Below is my pyparsing grammar for parsing the method signature of a Solidity function, and an example signature to parse:
from pyparsing import Word, alphas, alphanums, oneOf, Group, Forward, ZeroOrMore, Optional, delimitedList
solidity_type = Forward()
primitive = oneOf("address uint uint8 uint16 uint32 uint64 uint128 uint256 int int8 int16 int32 int64 int128 int256 bool bytes bytes1 bytes4 bytes32")
array = solidity_type + "[]"
tuple_type = "(" + delimitedList(solidity_type) + ")"
solidity_type <<= (primitive | array | tuple_type)
function_name = Word(alphas, alphanums + "_")
arguments = Optional(delimitedList(solidity_type))
function_signature = function_name + "(" + arguments + ")"
sig = "diamondCut((address,uint8,bytes4[])[],address,bytes)"
parsed_sig = function_signature.parseString(sig)
print(parsed_sig.dump())
The error I get is {RecursionError}maximum recursion depth exceeded
. Narrowing it down, I realize that this statement produces the same error:
array.parseString("(bytes4)[]")
I tried surrounding some of the expressions with Group
, and re-ordering the options in the solidity_type
definition. I also tried defining array
as its own Forward
.
I don't understand how to change my code so that the example signature parses without error.
Your grammar is left recursive.
solidity_type
goes to array
in the alternationarray
goes directly to solidity_type
During the recursion, no tokens are consumed. That is why you get the recursion error.
Fortunately, pyparsing can handle that, but you have to enable that feature:
from pyparsing import ParserElement
ParserElement.enable_left_recursion()
# rest of your grammar here
You should also rewrite the solidity_type
by swapping array
and primitive
. array
should come first, because it is more specific.