github.com/mavryk-network/mvgo@v1.19.9/internal/parse/parse.go (about) 1 package parse 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7 8 "github.com/mavryk-network/mvgo/contract/ast" 9 "github.com/mavryk-network/mvgo/micheline" 10 11 "github.com/pkg/errors" 12 ) 13 14 func Parse(raw []byte, name string) (*ast.Contract, []*ast.Struct, error) { 15 return newParser(raw).parse(name) 16 } 17 18 type parser struct { 19 script *micheline.Script 20 raw []byte 21 contract *ast.Contract 22 structs []*ast.Struct 23 cache *Cache 24 } 25 26 func newParser(raw []byte) *parser { 27 return &parser{ 28 script: micheline.NewScript(), 29 raw: raw, 30 contract: new(ast.Contract), 31 cache: NewCache(), 32 } 33 } 34 35 func (p *parser) parse(name string) (*ast.Contract, []*ast.Struct, error) { 36 err := json.Unmarshal(p.raw, &p.script) 37 if err != nil { 38 return nil, nil, errors.Wrap(err, "failed to unmarshal micheline code") 39 } 40 // Remove storage 41 p.script.Storage = micheline.Prim{} 42 p.raw, err = json.Marshal(p.script) 43 if err != nil { 44 return nil, nil, errors.Wrap(err, "failed to re-marshall script") 45 } 46 p.contract.Name = name 47 p.contract.Micheline = string(p.raw) 48 if err = p.parseStorage(); err != nil { 49 return nil, nil, errors.Wrap(err, "failed to parse storage") 50 } 51 if err = p.parseEntrypoints(); err != nil { 52 return nil, nil, errors.Wrap(err, "failed to parse entrypoints") 53 } 54 return p.contract, p.nameStructs(), nil 55 } 56 57 func (p *parser) parseStorage() (err error) { 58 p.contract.Storage, err = p.buildTypeStructs(p.script.StorageType().TypedefPtr("Storage")) 59 if err != nil { 60 return err 61 } 62 if p.contract.Storage.MichelineType == "struct" { 63 p.contract.Storage.Flat = true 64 } 65 return nil 66 } 67 68 func (p *parser) nameStructs() []*ast.Struct { 69 structs := []*ast.Struct{} 70 for i, s := range p.structs { 71 if s.Name == "" { 72 s.Name = fmt.Sprintf("%s_record_%d", p.contract.Name, i) 73 } else { 74 newName := fmt.Sprintf("%s_%s", p.contract.Name, s.Name) 75 if p.structNameExists(newName) { 76 newName += strconv.Itoa(i) 77 } 78 s.Name = newName 79 } 80 structs = append(structs, s) 81 } 82 83 return structs 84 } 85 86 func (p *parser) structNameExists(name string) bool { 87 for _, s := range p.structs { 88 if s.Name == name { 89 return true 90 } 91 } 92 return false 93 }