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  }