github.com/lmittmann/w3@v0.20.0/internal/abi/parser.go (about)

     1  package abi
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"strconv"
     8  
     9  	"github.com/ethereum/go-ethereum/accounts/abi"
    10  )
    11  
    12  var ErrSyntax = errors.New("syntax error")
    13  
    14  // Parse parses the given Solidity args and returns its arguments.
    15  func Parse(s string, tuples ...any) (a Arguments, err error) {
    16  	l := newLexer(s)
    17  	p := newParser(l, tuples)
    18  
    19  	if err := p.parseArgs(); err != nil {
    20  		return nil, fmt.Errorf("%w: %v", ErrSyntax, err)
    21  	}
    22  	return (Arguments)(p.args), nil
    23  }
    24  
    25  // ParseWithName parses the given Solidity function/event signature and returns
    26  // its name and arguments.
    27  func ParseWithName(s string, tuples ...any) (name string, a Arguments, err error) {
    28  	l := newLexer(s)
    29  	p := newParser(l, tuples)
    30  
    31  	if err := p.parseArgsWithName(); err != nil {
    32  		return "", nil, fmt.Errorf("%w: %v", ErrSyntax, err)
    33  	}
    34  	return p.name, (Arguments)(p.args), nil
    35  }
    36  
    37  type parser struct {
    38  	lexer *lexer
    39  	items []*item
    40  	i     int
    41  
    42  	tuples   []any
    43  	tupleMap map[string]abi.Argument
    44  
    45  	name string
    46  	args abi.Arguments
    47  
    48  	err error
    49  }
    50  
    51  func newParser(lexer *lexer, tuples []any) *parser {
    52  	return &parser{
    53  		lexer:  lexer,
    54  		items:  make([]*item, 0),
    55  		i:      -1,
    56  		tuples: tuples,
    57  	}
    58  }
    59  
    60  func (p *parser) next() *item {
    61  	if p.i < len(p.items)-1 {
    62  		p.i += 1
    63  		return p.items[p.i]
    64  	}
    65  
    66  	next, err := p.lexer.nextItem()
    67  	if err != nil {
    68  		p.err = err
    69  		return nil
    70  	}
    71  
    72  	p.i += 1
    73  	p.items = append(p.items, next)
    74  	return next
    75  }
    76  
    77  func (p *parser) backup() {
    78  	p.i -= 1
    79  }
    80  
    81  func (p *parser) peek() *item {
    82  	next := p.next()
    83  	p.backup()
    84  	return next
    85  }
    86  
    87  func (p *parser) parseArgsWithName() error {
    88  	// parse name
    89  	if next := p.next(); p.err != nil {
    90  		return p.err
    91  	} else if next.Typ != itemTypeID {
    92  		return fmt.Errorf(`unexpected %s, expecting name`, next)
    93  	} else {
    94  		p.name = next.Val
    95  	}
    96  
    97  	// parse "("
    98  	if next := p.next(); p.err != nil {
    99  		return p.err
   100  	} else if next.Typ != itemTypePunct || next.Val != "(" {
   101  		return fmt.Errorf(`unexpected %s, expecting "("`, next)
   102  	}
   103  
   104  	if err := p.parseArgs(); err != nil {
   105  		return err
   106  	}
   107  
   108  	// parse ")"
   109  	if next := p.next(); p.err != nil {
   110  		return p.err
   111  	} else if next.Typ != itemTypePunct || next.Val != ")" {
   112  		return fmt.Errorf(`unexpected %s, expecting ")"`, next)
   113  	}
   114  
   115  	// parse EOF
   116  	if next := p.next(); p.err != nil {
   117  		return p.err
   118  	} else if next.Typ != itemTypeEOF {
   119  		return fmt.Errorf(`unexpected %s, expecting EOF`, next)
   120  	}
   121  	return nil
   122  }
   123  
   124  func (p *parser) parseArgs() error {
   125  	// parse tuples
   126  	tupleMap, err := buildTuples(p.tuples...)
   127  	if err != nil {
   128  		return err
   129  	}
   130  	p.tupleMap = tupleMap
   131  
   132  	if peek := p.peek(); p.err != nil {
   133  		return p.err
   134  	} else if (peek.Typ == itemTypeEOF && p.name == "") ||
   135  		(peek.Typ == itemTypePunct && peek.Val == ")" && p.name != "") {
   136  		return nil
   137  	}
   138  
   139  	for {
   140  		// parse type
   141  		typ, err := p.parseType()
   142  		if err != nil {
   143  			return err
   144  		}
   145  		arg := abi.Argument{Type: *typ}
   146  
   147  		// parse optional indexed and name
   148  		peek := p.peek()
   149  		if p.err != nil {
   150  			return p.err
   151  		} else if peek.Typ == itemTypeID {
   152  			if peek.Val == "indexed" {
   153  				arg.Indexed = true
   154  			} else {
   155  				arg.Name = peek.Val
   156  			}
   157  			p.next()
   158  
   159  			peek = p.peek()
   160  			if p.err != nil {
   161  				return p.err
   162  			} else if peek.Typ == itemTypeID && arg.Indexed {
   163  				arg.Name = peek.Val
   164  				p.next()
   165  			}
   166  		}
   167  
   168  		p.args = append(p.args, arg)
   169  
   170  		// parse ",", EOF, or ")"
   171  		if peek := p.peek(); p.err != nil {
   172  			return p.err
   173  		} else if peek.Typ == itemTypeEOF && p.name == "" {
   174  			break
   175  		} else if peek.Typ == itemTypePunct && peek.Val == ")" && p.name != "" {
   176  			break
   177  		} else if peek.Typ == itemTypePunct && peek.Val == "," {
   178  			p.next()
   179  		} else {
   180  			if p.name == "" {
   181  				return fmt.Errorf(`unexpected %s, want "," or EOF`, peek)
   182  			} else {
   183  				return fmt.Errorf(`unexpected %s, want "," or ")"`, peek)
   184  			}
   185  		}
   186  	}
   187  	return nil
   188  }
   189  
   190  // parseType parses a non-tuple type of form "type (indexed)? (name)?"
   191  func (p *parser) parseType() (*abi.Type, error) {
   192  	var (
   193  		typ *abi.Type
   194  		ok  bool
   195  		err error
   196  	)
   197  	if peek := p.peek(); p.err != nil {
   198  		return nil, p.err
   199  	} else if peek.Typ == itemTypeID {
   200  		// check built-in types first
   201  		typ, ok = peek.IsType()
   202  		if !ok {
   203  			// check named tuples
   204  			if tupleArg, exists := p.tupleMap[peek.Val]; exists {
   205  				typ = &tupleArg.Type
   206  				ok = true
   207  			}
   208  		}
   209  		if !ok {
   210  			return nil, fmt.Errorf(`unexpected %s, expecting type`, peek)
   211  		}
   212  		p.next()
   213  	} else if peek.Typ == itemTypePunct && peek.Val == "(" {
   214  		// tuple type
   215  		typ, err = p.parseTupleTypes()
   216  		if err != nil {
   217  			return nil, err
   218  		}
   219  	} else {
   220  		return nil, fmt.Errorf(`unexpected %s, expecting type`, peek)
   221  	}
   222  
   223  	// optional: parse slice or array
   224  	typ, err = p.parseSliceOrArray(typ)
   225  	if err != nil {
   226  		return nil, err
   227  	}
   228  
   229  	return typ, nil
   230  }
   231  
   232  func (p *parser) parseTupleType(i int) (*abi.Type, string, error) {
   233  	typ, err := p.parseType()
   234  	if err != nil {
   235  		return nil, "", err
   236  	}
   237  
   238  	// parse name
   239  	next := p.next()
   240  	if p.err != nil {
   241  		return nil, "", p.err
   242  	}
   243  	if next.Typ != itemTypeID {
   244  		// no name given; put the token back and make up a fake name
   245  		p.backup()
   246  		return typ, fmt.Sprintf("arg%d", i), nil
   247  	}
   248  
   249  	return typ, next.Val, nil
   250  }
   251  
   252  func (p *parser) parseTupleTypes() (*abi.Type, error) {
   253  	if next := p.next(); p.err != nil {
   254  		return nil, p.err
   255  	} else if next.Typ != itemTypePunct || next.Val != "(" {
   256  		return nil, fmt.Errorf(`unexpected %s, expecting "("`, next)
   257  	}
   258  
   259  	typ := &abi.Type{T: abi.TupleTy}
   260  	fields := make([]reflect.StructField, 0)
   261  	for i := 0; ; i++ {
   262  		// parse type
   263  		elemTyp, name, err := p.parseTupleType(i)
   264  		if err != nil {
   265  			return nil, err
   266  		}
   267  		typ.TupleElems = append(typ.TupleElems, elemTyp)
   268  		typ.TupleRawNames = append(typ.TupleRawNames, name)
   269  		fields = append(fields, reflect.StructField{
   270  			Name: abi.ToCamelCase(name),
   271  			Type: elemTyp.GetType(),
   272  			Tag:  reflect.StructTag(`abi:"` + name + `"`),
   273  		})
   274  
   275  		next := p.next()
   276  		if p.err != nil {
   277  			return nil, p.err
   278  		}
   279  		if next.Typ == itemTypePunct {
   280  			if next.Val == ")" {
   281  				break
   282  			} else if next.Val == "," {
   283  				continue
   284  			}
   285  		}
   286  		return nil, fmt.Errorf(`unexpected %s, expecting "," or ")"`, next)
   287  	}
   288  	typ.TupleType = reflect.StructOf(fields)
   289  	return typ, nil
   290  }
   291  
   292  func (p *parser) parseSliceOrArray(typ *abi.Type) (*abi.Type, error) {
   293  	parent := *typ
   294  	for peek := p.peek(); p.err == nil && peek.Typ == itemTypePunct && peek.Val == "["; peek = p.peek() {
   295  		// parse "["
   296  		p.next()
   297  
   298  		// nest type
   299  		parentCopy := parent
   300  		parent = abi.Type{
   301  			Elem: &parentCopy,
   302  		}
   303  
   304  		// parse optional number
   305  		next := p.next()
   306  		if p.err != nil {
   307  			return nil, p.err
   308  		}
   309  		if next.Typ == itemTypeNum {
   310  			parent.Size, _ = strconv.Atoi(next.Val)
   311  			parent.T = abi.ArrayTy
   312  			next = p.next()
   313  			if p.err != nil {
   314  				return nil, p.err
   315  			}
   316  		} else {
   317  			parent.T = abi.SliceTy
   318  		}
   319  
   320  		// parse "]"
   321  		if next.Typ != itemTypePunct || next.Val != "]" {
   322  			return nil, fmt.Errorf(`unexpected %s, expecting "]"`, next)
   323  		}
   324  	}
   325  	if p.err != nil {
   326  		return nil, p.err
   327  	}
   328  	return &parent, nil
   329  }