github.com/lheiskan/zebrapack@v4.1.1-0.20181107023619-e955d028f9bf+incompatible/parse/directives.go (about)

     1  package parse
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/glycerine/zebrapack/gen"
     6  	"go/ast"
     7  	"strings"
     8  )
     9  
    10  const linePrefix = "//msgp:"
    11  
    12  // func(args, fileset)
    13  type directive func([]string, *FileSet) error
    14  
    15  // func(passName, args, printer)
    16  type passDirective func(gen.Method, []string, *gen.Printer) error
    17  
    18  // map of all recognized directives
    19  //
    20  // to add a directive, define a func([]string, *FileSet) error
    21  // and then add it to this list.
    22  var directives = map[string]directive{
    23  	"shim":   applyShim,
    24  	"ignore": ignore,
    25  	"tuple":  astuple,
    26  }
    27  
    28  var passDirectives = map[string]passDirective{
    29  	"ignore": passignore,
    30  }
    31  
    32  func passignore(m gen.Method, text []string, p *gen.Printer) error {
    33  	pushstate(m.String())
    34  	for _, a := range text {
    35  		p.ApplyDirective(m, gen.IgnoreTypename(a))
    36  		infof("ignoring %s\n", a)
    37  	}
    38  	popstate()
    39  	return nil
    40  }
    41  
    42  // find all comment lines that begin with //msgp:
    43  func yieldComments(c []*ast.CommentGroup) []string {
    44  	var out []string
    45  	for _, cg := range c {
    46  		for _, line := range cg.List {
    47  			if strings.HasPrefix(line.Text, linePrefix) {
    48  				out = append(out, strings.TrimPrefix(line.Text, linePrefix))
    49  			}
    50  		}
    51  	}
    52  	return out
    53  }
    54  
    55  //msgp:shim {Type} as:{Newtype} using:{toFunc/fromFunc}
    56  func applyShim(text []string, f *FileSet) error {
    57  	if len(text) != 4 {
    58  		return fmt.Errorf("shim directive should have 3 arguments; found %d", len(text)-1)
    59  	}
    60  
    61  	name := text[1]
    62  	be := gen.Ident(strings.TrimPrefix(strings.TrimSpace(text[2]), "as:"), false) // parse as::{base}
    63  	if name[0] == '*' {
    64  		name = name[1:]
    65  		be.Needsref(true)
    66  	}
    67  	be.Alias(name)
    68  
    69  	usestr := strings.TrimPrefix(strings.TrimSpace(text[3]), "using:") // parse using::{method/method}
    70  
    71  	methods := strings.Split(usestr, "/")
    72  	if len(methods) != 2 {
    73  		return fmt.Errorf("expected 2 using::{} methods; found %d (%q)", len(methods), text[3])
    74  	}
    75  
    76  	be.ShimToBase = methods[0]
    77  	be.ShimFromBase = methods[1]
    78  
    79  	infof("%s -> %s\n", name, be.Value.String())
    80  	f.findShim(name, be)
    81  
    82  	return nil
    83  }
    84  
    85  //msgp:ignore {TypeA} {TypeB}...
    86  func ignore(text []string, f *FileSet) error {
    87  	if len(text) < 2 {
    88  		return nil
    89  	}
    90  	for _, item := range text[1:] {
    91  		name := strings.TrimSpace(item)
    92  		if _, ok := f.Identities[name]; ok {
    93  			delete(f.Identities, name)
    94  			infof("ignoring %s\n", name)
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  //msgp:tuple {TypeA} {TypeB}...
   101  func astuple(text []string, f *FileSet) error {
   102  	if len(text) < 2 {
   103  		return nil
   104  	}
   105  	for _, item := range text[1:] {
   106  		name := strings.TrimSpace(item)
   107  		if el, ok := f.Identities[name]; ok {
   108  			if st, ok := el.(*gen.Struct); ok {
   109  				st.AsTuple = true
   110  				infoln(name)
   111  			} else {
   112  				warnf("%s: only structs can be tuples\n", name)
   113  			}
   114  		}
   115  	}
   116  	return nil
   117  }