|
|
package parse
import ( "fmt" "go/ast" "strings"
"github.com/tinylib/msgp/gen" )
const linePrefix = "//msgp:"
// func(args, fileset)
type directive func([]string, *FileSet) error
// func(passName, args, printer)
type passDirective func(gen.Method, []string, *gen.Printer) error
// map of all recognized directives
//
// to add a directive, define a func([]string, *FileSet) error
// and then add it to this list.
var directives = map[string]directive{ "shim": applyShim, "ignore": ignore, "tuple": astuple, }
var passDirectives = map[string]passDirective{ "ignore": passignore, }
func passignore(m gen.Method, text []string, p *gen.Printer) error { pushstate(m.String()) for _, a := range text { p.ApplyDirective(m, gen.IgnoreTypename(a)) infof("ignoring %s\n", a) } popstate() return nil }
// find all comment lines that begin with //msgp:
func yieldComments(c []*ast.CommentGroup) []string { var out []string for _, cg := range c { for _, line := range cg.List { if strings.HasPrefix(line.Text, linePrefix) { out = append(out, strings.TrimPrefix(line.Text, linePrefix)) } } } return out }
//msgp:shim {Type} as:{Newtype} using:{toFunc/fromFunc} mode:{Mode}
func applyShim(text []string, f *FileSet) error { if len(text) < 4 || len(text) > 5 { return fmt.Errorf("shim directive should have 3 or 4 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]
if len(text) == 5 { modestr := strings.TrimPrefix(strings.TrimSpace(text[4]), "mode:") // parse mode::{mode}
switch modestr { case "cast": be.ShimMode = gen.Cast case "convert": be.ShimMode = gen.Convert default: return fmt.Errorf("invalid shim mode; found %s, expected 'cast' or 'convert", modestr) } }
infof("%s -> %s\n", name, be.Value.String()) f.findShim(name, be)
return nil }
//msgp:ignore {TypeA} {TypeB}...
func ignore(text []string, f *FileSet) error { if len(text) < 2 { return nil } for _, item := range text[1:] { name := strings.TrimSpace(item) if _, ok := f.Identities[name]; ok { delete(f.Identities, name) infof("ignoring %s\n", name) } } return nil }
//msgp:tuple {TypeA} {TypeB}...
func astuple(text []string, f *FileSet) error { if len(text) < 2 { return nil } for _, item := range text[1:] { name := strings.TrimSpace(item) if el, ok := f.Identities[name]; ok { if st, ok := el.(*gen.Struct); ok { st.AsTuple = true infoln(name) } else { warnf("%s: only structs can be tuples\n", name) } } } return nil }
|