//msgp:shim {Type} as:{Newtype} using:{toFunc/fromFunc} func applyShim(text []string, f *FileSet) error { if len(text) != 4 { return fmt.Errorf("shim directive should have 3 arguments; found %d", len(text)-1) } name := text[1] be := gen.Ident(strings.TrimPrefix(strings.TrimSpace(text[2]), "as:")) // parse as::{base} if name[0] == '*' { name = name[1:] be.Needsref(true) } be.Alias(name) usestr := strings.TrimPrefix(strings.TrimSpace(text[3]), "using:") // parse using::{method/method} methods := strings.Split(usestr, "/") if len(methods) != 2 { return fmt.Errorf("expected 2 using::{} methods; found %d (%q)", len(methods), text[3]) } be.ShimToBase = methods[0] be.ShimFromBase = methods[1] infof("%s -> %s\n", name, be.Value.String()) f.Identities[name] = be return nil }
// recursively translate ast.Expr to gen.Elem; nil means type not supported // expected input types: // - *ast.MapType (map[T]J) // - *ast.Ident (name) // - *ast.ArrayType ([(sz)]T) // - *ast.StarExpr (*T) // - *ast.StructType (struct {}) // - *ast.SelectorExpr (a.B) // - *ast.InterfaceType (interface {}) func (fs *FileSet) parseExpr(e ast.Expr) gen.Elem { switch e := e.(type) { case *ast.MapType: if k, ok := e.Key.(*ast.Ident); ok && k.Name == "string" { if in := fs.parseExpr(e.Value); in != nil { return &gen.Map{Value: in} } } return nil case *ast.Ident: b := gen.Ident(e.Name) // work to resove this expression // can be done later, once we've resolved // everything else. if b.Value == gen.IDENT { if _, ok := fs.Specs[e.Name]; !ok { warnf("non-local identifier: %s\n", e.Name) } } return b case *ast.ArrayType: // special case for []byte if e.Len == nil { if i, ok := e.Elt.(*ast.Ident); ok && i.Name == "byte" { return &gen.BaseElem{Value: gen.Bytes} } } // return early if we don't know // what the slice element type is els := fs.parseExpr(e.Elt) if els == nil { return nil } // array and not a slice if e.Len != nil { switch s := e.Len.(type) { case *ast.BasicLit: return &gen.Array{ Size: s.Value, Els: els, } case *ast.Ident: return &gen.Array{ Size: s.String(), Els: els, } case *ast.SelectorExpr: return &gen.Array{ Size: stringify(s), Els: els, } default: return nil } } return &gen.Slice{Els: els} case *ast.StarExpr: if v := fs.parseExpr(e.X); v != nil { return &gen.Ptr{Value: v} } return nil case *ast.StructType: if fields := fs.parseFieldList(e.Fields); len(fields) > 0 { return &gen.Struct{Fields: fields} } return nil case *ast.SelectorExpr: return gen.Ident(stringify(e)) case *ast.InterfaceType: // support `interface{}` if len(e.Methods.List) == 0 { return &gen.BaseElem{Value: gen.Intf} } return nil default: // other types not supported return nil } }