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 }