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

     1  package parse
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/ast"
     7  	"path/filepath"
     8  	//"go/importer"
     9  	"go/format"
    10  	"go/parser"
    11  	"go/token"
    12  	"go/types"
    13  	"os"
    14  	"reflect"
    15  	"sort"
    16  	"strconv"
    17  	"strings"
    18  
    19  	"github.com/glycerine/zebrapack/cfg"
    20  	"github.com/glycerine/zebrapack/gen"
    21  	//	"github.com/shurcooL/go-goon"
    22  	"golang.org/x/tools/go/loader"
    23  )
    24  
    25  var StopOnError bool
    26  
    27  // A FileSet is the in-memory representation of a
    28  // parsed file.
    29  type FileSet struct {
    30  	Package    string              // package name
    31  	Specs      map[string]ast.Expr // type specs in file
    32  	Identities map[string]gen.Elem // processed from specs
    33  	Directives []string            // raw preprocessor directives
    34  	Imports    []*ast.ImportSpec   // imports
    35  	Cfg        *cfg.ZebraConfig
    36  
    37  	ZebraSchemaId int64
    38  	PackageInfo   *loader.PackageInfo
    39  	LoadedProg    *loader.Program
    40  	QuickPack     map[string]*loader.PackageInfo
    41  	Fset          *token.FileSet
    42  }
    43  
    44  // File parses a file at the relative path
    45  // provided and produces a new *FileSet.
    46  // If you pass in a path to a directory, the entire
    47  // directory will be parsed.
    48  // If unexport is false, only exported identifiers are included in the FileSet.
    49  // If the resulting FileSet would be empty, an error is returned.
    50  func File(c *cfg.ZebraConfig) (*FileSet, error) {
    51  	ok, isDir := fileOrDir(c.GoFile)
    52  	if !ok {
    53  		return nil, fmt.Errorf("error: path '%s' does not exist", c.GoFile)
    54  	}
    55  
    56  	name := c.GoFile
    57  	pushstate(name)
    58  	defer popstate()
    59  	fs := &FileSet{
    60  		Specs:      make(map[string]ast.Expr),
    61  		Identities: make(map[string]gen.Elem),
    62  		Cfg:        c,
    63  	}
    64  
    65  	var filenames []string
    66  	var err error
    67  	if isDir {
    68  		filenames, err = ListOfGoFilesInDir(name)
    69  		if err != nil {
    70  			return nil, err
    71  		}
    72  	} else {
    73  		filenames = []string{name}
    74  	}
    75  
    76  	packageName, err := getPackageNameFromGoFile(filenames[0])
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	fset := token.NewFileSet()
    82  	fs.Fset = fset
    83  
    84  	// loading/type checking is needed to get the constants involved
    85  	// in array definitions. For example, the constant
    86  	// `n` in the declaration `type S struct { arr [n]int }`;
    87  	// `n` might be a constant in another package.
    88  	// Hence we must load and thereby fully resolve
    89  	// constants; we can't get away with doing a shallow parse.
    90  
    91  	lc := loader.Config{
    92  		Fset:       fset,
    93  		CreatePkgs: []loader.PkgSpec{{Filenames: filenames}},
    94  		ParserMode: parser.ParseComments,
    95  	}
    96  	lprog, err := lc.Load()
    97  	if err != nil {
    98  		return nil, fmt.Errorf("error in getast.go: loader.Load() error: '%v'", err)
    99  	}
   100  	fs.LoadedProg = lprog
   101  	pkgInfo := lprog.Package(packageName)
   102  	if pkgInfo == nil {
   103  		panic(fmt.Errorf("load of '%s' for package name '%s' failed", name, packageName))
   104  	}
   105  	if !pkgInfo.TransitivelyErrorFree {
   106  		panic(fmt.Errorf("loader detected (possibly transitive) error during package load"))
   107  	}
   108  
   109  	// map from short package import name to the package
   110  	quickPack := make(map[string]*loader.PackageInfo)
   111  	for k, v := range lprog.AllPackages {
   112  		quickPack[k.Name()] = v
   113  	}
   114  	fs.QuickPack = quickPack
   115  
   116  	fs.Package = pkgInfo.Pkg.Name()
   117  	fs.PackageInfo = pkgInfo
   118  	gotZebraSchema := false
   119  	if isDir {
   120  		for _, fl := range pkgInfo.Files {
   121  			pushstate(fl.Name.Name)
   122  			fs.Directives = append(fs.Directives, yieldComments(fl.Comments)...)
   123  
   124  			if !gotZebraSchema {
   125  				// must get zebraSchemaId prior to FileExports(), as it dumps non-exports.
   126  				fs.getZebraSchemaId(fl)
   127  				gotZebraSchema = true
   128  			}
   129  			if !c.Unexported {
   130  				ast.FileExports(fl)
   131  			}
   132  			fs.getTypeSpecs(fl)
   133  			popstate()
   134  		}
   135  	} else {
   136  		if len(pkgInfo.Files) != 1 {
   137  			fmt.Printf("debug: expected single file, but got: len(pkgInfo.Files) = %v\n", len(pkgInfo.Files))
   138  			panic("huh?!? what to do with multiple or zero files here?")
   139  		}
   140  		f := pkgInfo.Files[0]
   141  		fs.Directives = yieldComments(f.Comments)
   142  		fs.getZebraSchemaId(f)
   143  
   144  		if !c.Unexported {
   145  			ast.FileExports(f)
   146  		}
   147  		fs.getTypeSpecs(f)
   148  	}
   149  
   150  	if len(fs.Specs) == 0 {
   151  		return nil, fmt.Errorf("no definitions in %s", name)
   152  	}
   153  
   154  	err = fs.process()
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	fs.applyDirectives()
   159  	fs.propInline()
   160  
   161  	return fs, nil
   162  }
   163  
   164  // applyDirectives applies all of the directives that
   165  // are known to the parser. additional method-specific
   166  // directives remain in f.Directives
   167  func (f *FileSet) applyDirectives() {
   168  	newdirs := make([]string, 0, len(f.Directives))
   169  	for _, d := range f.Directives {
   170  		chunks := strings.Split(d, " ")
   171  		if len(chunks) > 0 {
   172  			if fn, ok := directives[chunks[0]]; ok {
   173  				pushstate(chunks[0])
   174  				err := fn(chunks, f)
   175  				if err != nil {
   176  					warnln(err.Error())
   177  				}
   178  				popstate()
   179  			} else {
   180  				newdirs = append(newdirs, d)
   181  			}
   182  		}
   183  	}
   184  	f.Directives = newdirs
   185  }
   186  
   187  // A linkset is a graph of unresolved
   188  // identities.
   189  //
   190  // Since gen.Ident can only represent
   191  // one level of type indirection (e.g. Foo -> uint8),
   192  // type declarations like `type Foo Bar`
   193  // aren't resolve-able until we've processed
   194  // everything else.
   195  //
   196  // The goal of this dependency resolution
   197  // is to distill the type declaration
   198  // into just one level of indirection.
   199  // In other words, if we have:
   200  //
   201  //  type A uint64
   202  //  type B A
   203  //  type C B
   204  //  type D C
   205  //
   206  // ... then we want to end up
   207  // figuring out that D is just a uint64.
   208  type linkset map[string]*gen.BaseElem
   209  
   210  func (f *FileSet) resolve(ls linkset) {
   211  	progress := true
   212  	for progress && len(ls) > 0 {
   213  		progress = false
   214  		for name, elem := range ls {
   215  			real, ok := f.Identities[elem.TypeName()]
   216  			if ok {
   217  				// copy the old type descriptor,
   218  				// alias it to the new value,
   219  				// and insert it into the resolved
   220  				// identities list
   221  				progress = true
   222  				nt := real.Copy()
   223  				nt.Alias(name)
   224  				f.Identities[name] = nt
   225  				delete(ls, name)
   226  			}
   227  		}
   228  	}
   229  
   230  	// what's left can't be resolved
   231  	for name, elem := range ls {
   232  		warnf("couldn't resolve type %s (%s)\n", name, elem.TypeName())
   233  	}
   234  }
   235  
   236  // process takes the contents of f.Specs and
   237  // uses them to populate f.Identities
   238  func (f *FileSet) process() error {
   239  
   240  	deferred := make(linkset)
   241  parse:
   242  	for name, def := range f.Specs {
   243  		pushstate(name)
   244  		el, err := f.parseExpr(def, false)
   245  		if err != nil {
   246  			return err
   247  		}
   248  		if el == nil {
   249  			warnln("failed to parse")
   250  			popstate()
   251  			continue parse
   252  		}
   253  		// push unresolved identities into
   254  		// the graph of links and resolve after
   255  		// we've handled every possible named type.
   256  		if be, ok := el.(*gen.BaseElem); ok && be.Value == gen.IDENT {
   257  			deferred[name] = be
   258  			popstate()
   259  			continue parse
   260  		}
   261  		el.Alias(name)
   262  		f.Identities[name] = el
   263  		popstate()
   264  	}
   265  
   266  	if len(deferred) > 0 {
   267  		f.resolve(deferred)
   268  	}
   269  	return nil
   270  }
   271  
   272  func strToMethod(s string) gen.Method {
   273  	switch s {
   274  	case "encode":
   275  		return gen.Encode
   276  	case "decode":
   277  		return gen.Decode
   278  	case "test":
   279  		return gen.Test
   280  	case "size":
   281  		return gen.Size
   282  	case "marshal":
   283  		return gen.Marshal
   284  	case "unmarshal":
   285  		return gen.Unmarshal
   286  	default:
   287  		return 0
   288  	}
   289  }
   290  
   291  func (f *FileSet) applyDirs(p *gen.Printer) {
   292  	// apply directives of the form
   293  	//
   294  	// 	//msgp:encode ignore {{TypeName}}
   295  	//
   296  loop:
   297  	for _, d := range f.Directives {
   298  		chunks := strings.Split(d, " ")
   299  		if len(chunks) > 1 {
   300  			for i := range chunks {
   301  				chunks[i] = strings.TrimSpace(chunks[i])
   302  			}
   303  			m := strToMethod(chunks[0])
   304  			if m == 0 {
   305  				warnf("unknown pass name: %q\n", chunks[0])
   306  				continue loop
   307  			}
   308  			if fn, ok := passDirectives[chunks[1]]; ok {
   309  				pushstate(chunks[1])
   310  				err := fn(m, chunks[2:], p)
   311  				if err != nil {
   312  					warnf("error applying directive: %s\n", err)
   313  				}
   314  				popstate()
   315  			} else {
   316  				warnf("unrecognized directive %q\n", chunks[1])
   317  			}
   318  		} else {
   319  			warnf("empty directive: %q\n", d)
   320  		}
   321  	}
   322  }
   323  
   324  func (f *FileSet) PrintTo(p *gen.Printer) error {
   325  	f.applyDirs(p)
   326  	names := make([]string, 0, len(f.Identities))
   327  	for name := range f.Identities {
   328  		names = append(names, name)
   329  	}
   330  	sort.Strings(names)
   331  	for _, name := range names {
   332  		el := f.Identities[name]
   333  		if !el.SkipMe() {
   334  			el.SetVarname("z")
   335  			pushstate(el.TypeName())
   336  			err := p.Print(el)
   337  			popstate()
   338  			if err != nil {
   339  				return err
   340  			}
   341  		}
   342  	}
   343  	return nil
   344  }
   345  
   346  // getTypeSpecs extracts all of the *ast.TypeSpecs in the file
   347  // into fs.Identities, but does not set the actual element
   348  func (fs *FileSet) getTypeSpecs(f *ast.File) {
   349  
   350  	// collect all imports...
   351  	fs.Imports = append(fs.Imports, f.Imports...)
   352  
   353  	// check all declarations...
   354  	for i := range f.Decls {
   355  
   356  		switch g := f.Decls[i].(type) {
   357  		case *ast.GenDecl:
   358  			// and check the specs...
   359  			for _, s := range g.Specs {
   360  
   361  				// for ast.TypeSpecs....
   362  				switch ts := s.(type) {
   363  				case *ast.TypeSpec:
   364  					switch ts.Type.(type) {
   365  
   366  					// this is the list of parse-able
   367  					// type specs
   368  					case *ast.StructType,
   369  						*ast.ArrayType,
   370  						*ast.StarExpr,
   371  						*ast.MapType,
   372  						*ast.Ident:
   373  						fs.Specs[ts.Name.Name] = ts.Type
   374  
   375  					}
   376  
   377  				}
   378  			}
   379  		}
   380  	}
   381  }
   382  
   383  func fieldName(f *ast.Field) string {
   384  	switch len(f.Names) {
   385  	case 0:
   386  		return stringify(f.Type)
   387  	case 1:
   388  		return f.Names[0].Name
   389  	default:
   390  		return f.Names[0].Name + " (and others)"
   391  	}
   392  }
   393  
   394  type zid struct {
   395  	zid       int64
   396  	fieldName string
   397  }
   398  
   399  type zidSetSlice []zid
   400  
   401  func (p zidSetSlice) Len() int           { return len(p) }
   402  func (p zidSetSlice) Less(i, j int) bool { return p[i].zid < p[j].zid }
   403  func (p zidSetSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
   404  
   405  func (fs *FileSet) parseFieldList(fl *ast.FieldList) (out []gen.StructField, missingZid bool, err error) {
   406  	if fl == nil || fl.NumFields() == 0 {
   407  		return nil, false, nil
   408  	}
   409  	out = make([]gen.StructField, 0, fl.NumFields())
   410  	var zidSet []zid
   411  	for _, field := range fl.List {
   412  		pushstate(fieldName(field))
   413  		fds, err := fs.getField(field)
   414  		if err != nil {
   415  			fatalf(err.Error())
   416  			return nil, missingZid, err
   417  		}
   418  		for _, x := range fds {
   419  			//fmt.Printf("\n on field '%#v'\n", x)
   420  			if x.ZebraId >= 0 {
   421  				zidSet = append(zidSet, zid{zid: x.ZebraId, fieldName: x.FieldName})
   422  			} else {
   423  				// allows mixed zid:"0" and msg:"-" fields.
   424  				if x.ZebraId < -2 {
   425  					missingZid = true
   426  				}
   427  			}
   428  		}
   429  		if len(fds) > 0 {
   430  			out = append(out, fds...)
   431  		} else {
   432  			warnln(fmt.Sprintf("ignored. heh, on '%#v'", fs))
   433  		}
   434  		popstate()
   435  	}
   436  	// check zidSet sequential from 0, no gaps, no duplicates
   437  	if len(zidSet) > 0 {
   438  		sort.Sort(zidSetSlice(zidSet))
   439  		if zidSet[0].zid != 0 {
   440  			return nil, missingZid, fmt.Errorf("zid (zebra id tags on struct fields) must start at 0; lowest zid was '%v' at field '%v'", zidSet[0].zid, zidSet[0].fieldName)
   441  		}
   442  		for i := range zidSet {
   443  			if zidSet[i].zid != int64(i) {
   444  				return nil, missingZid, fmt.Errorf("zid sequence interrupted - commit conflict possible! gap or duplicate in zid sequence (saw %v; expected %v), near field '%v'", zidSet[i].zid, i, zidSet[i].fieldName)
   445  			}
   446  		}
   447  	}
   448  	return out, missingZid, nil
   449  }
   450  
   451  func anyMatches(haystack []string, needle string) bool {
   452  	needle = strings.TrimSpace(needle)
   453  	for _, v := range haystack {
   454  		tr := strings.TrimSpace(v)
   455  		if tr == needle {
   456  			return true
   457  		}
   458  	}
   459  	return false
   460  }
   461  
   462  // translate *ast.Field into []gen.StructField
   463  func (fs *FileSet) getField(f *ast.Field) ([]gen.StructField, error) {
   464  	sf := make([]gen.StructField, 1)
   465  	var extension bool
   466  	var omitempty bool
   467  
   468  	var skip bool
   469  	var deprecated bool
   470  	var showzero bool
   471  	var zebraId int64 = -3 // means NA. Use -1 for struct name if need be. -2 means msg:"-" deliberately.
   472  	var isIface bool
   473  
   474  	// parse tag; otherwise field name is field tag
   475  	if f.Tag != nil {
   476  		alltags := reflect.StructTag(strings.Trim(f.Tag.Value, "`"))
   477  		body := alltags.Get("msg")
   478  		tags := strings.Split(body, ",")
   479  		if len(tags) == 2 && tags[1] == "extension" {
   480  			extension = true
   481  		}
   482  		// must use msg:",omitempty" if no alt name, to
   483  		// mark a field omitempty. this avoids confusion
   484  		// with any alt name, which always comes first.
   485  		if len(tags) > 1 && anyMatches(tags[1:], "omitempty") {
   486  			omitempty = true
   487  		}
   488  		if len(tags) > 1 && anyMatches(tags[1:], "deprecated") {
   489  			deprecated = true
   490  		}
   491  		if len(tags) > 1 && anyMatches(tags[1:], "showzero") {
   492  			showzero = true
   493  		}
   494  		if len(tags) > 1 && anyMatches(tags[1:], "iface") {
   495  			isIface = true
   496  		}
   497  
   498  		// ignore "-" fields
   499  		if tags[0] == "-" {
   500  			skip = true
   501  			zebraId = -2
   502  			// can't return early, need to track deprecated zids.
   503  			//return nil, nil
   504  		}
   505  		if len(tags[0]) > 0 {
   506  			sf[0].FieldTag = tags[0]
   507  		}
   508  
   509  		// check deprecated
   510  		dep := alltags.Get("deprecated")
   511  		if dep == "true" {
   512  			deprecated = true
   513  			// ignore these too, but still need them to detect
   514  			// gaps in the zebra:id fields
   515  		}
   516  
   517  		// check zebra
   518  		zebra := alltags.Get("zid")
   519  		if zebra != "" {
   520  			// must be a non-negative number. "-" or negative
   521  			// are marked as skipped.
   522  			z := strings.Trim(zebra, " \t")
   523  			if len(z) > 0 && z[0] == '-' {
   524  				skip = true
   525  			} else {
   526  				id, err := strconv.Atoi(zebra)
   527  				if err != nil {
   528  					where := ""
   529  					if len(f.Names) > 0 {
   530  						where = " on '" + f.Names[0].Name + "'"
   531  					}
   532  					err2 := fmt.Errorf("bad `zid` tag%s, could not convert"+
   533  						" '%v' to non-zero integer: %v", where, zebra, err)
   534  					fatalf(err2.Error())
   535  					return nil, err2
   536  				}
   537  				if id < 0 {
   538  					skip = true
   539  				} else {
   540  					if !skip {
   541  						zebraId = int64(id)
   542  						//fmt.Printf("\n we see zebraId: %v\n", zebraId)
   543  					}
   544  				}
   545  			}
   546  			if len(f.Names) > 1 {
   547  				// we can't have one zid for two fields.
   548  				err2 := fmt.Errorf("error: problem with the `zid` tag '%v' on '%s' and '%s': only one zid per field allowed. Move each to its own line and give each its own zid tag.", zebra, f.Names[0].Name, f.Names[1].Name)
   549  				fatalf(err2.Error())
   550  				return nil, err2
   551  			}
   552  		}
   553  
   554  	}
   555  
   556  	ex, err := fs.parseExpr(f.Type, isIface)
   557  	if err != nil {
   558  		fatalf(err.Error())
   559  		return nil, err
   560  	}
   561  	if ex == nil {
   562  		skip = true
   563  		//fmt.Printf("\n we see nil field %#v\n", f.Names[0])
   564  		// struct{} type fields, must track for zid checking.
   565  		// so we can't return early here.
   566  	} else {
   567  		ex.SetZid(zebraId)
   568  	}
   569  
   570  	if !isIface && fs != nil && fs.PackageInfo != nil &&
   571  		len(fs.PackageInfo.Info.Types) > 0 {
   572  
   573  		if tv, ok := fs.PackageInfo.Info.Types[f.Type]; ok {
   574  			isIface = types.IsInterface(tv.Type)
   575  		}
   576  	}
   577  	sf[0].Deprecated = deprecated
   578  	sf[0].OmitEmpty = omitempty
   579  	sf[0].ZebraId = zebraId
   580  	sf[0].Skip = skip
   581  	sf[0].ShowZero = showzero
   582  	sf[0].IsIface = isIface
   583  
   584  	// parse field name
   585  	switch len(f.Names) {
   586  	case 0:
   587  		sf[0].FieldName = embedded(f.Type)
   588  	case 1:
   589  		sf[0].FieldName = f.Names[0].Name
   590  	default:
   591  		// this is for a multiple in-line declaration,
   592  		// e.g. type A struct { One, Two int }
   593  		sf = sf[0:0]
   594  		for _, nm := range f.Names {
   595  			sf = append(sf, gen.StructField{
   596  				FieldTag:   nm.Name,
   597  				FieldName:  nm.Name,
   598  				FieldElem:  ex.Copy(),
   599  				OmitEmpty:  omitempty,
   600  				Deprecated: deprecated,
   601  				ZebraId:    zebraId,
   602  				Skip:       skip,
   603  				IsIface:    isIface,
   604  			})
   605  		}
   606  		return sf, nil
   607  	}
   608  	sf[0].FieldElem = ex
   609  	if sf[0].FieldTag == "" {
   610  		sf[0].FieldTag = sf[0].FieldName
   611  	}
   612  
   613  	// validate extension
   614  	if extension {
   615  		switch ex := ex.(type) {
   616  		case *gen.Ptr:
   617  			if b, ok := ex.Value.(*gen.BaseElem); ok {
   618  				b.Value = gen.Ext
   619  			} else {
   620  				warnln("couldn't cast to extension.")
   621  				return nil, nil
   622  			}
   623  		case *gen.BaseElem:
   624  			ex.Value = gen.Ext
   625  		default:
   626  			warnln("couldn't cast to extension.")
   627  			return nil, nil
   628  		}
   629  	}
   630  	return sf, nil
   631  }
   632  
   633  // extract embedded field name
   634  //
   635  // so, for a struct like
   636  //
   637  //	type A struct {
   638  //		io.Writer
   639  //  }
   640  //
   641  // we want "Writer"
   642  func embedded(f ast.Expr) string {
   643  	switch f := f.(type) {
   644  	case *ast.Ident:
   645  		return f.Name
   646  	case *ast.StarExpr:
   647  		return embedded(f.X)
   648  	case *ast.SelectorExpr:
   649  		return f.Sel.Name
   650  	default:
   651  		// other possibilities are disallowed
   652  		return ""
   653  	}
   654  }
   655  
   656  // stringify a field type name
   657  func stringify(e ast.Expr) string {
   658  	switch e := e.(type) {
   659  	case *ast.Ident:
   660  		return e.Name
   661  	case *ast.StarExpr:
   662  		return "*" + stringify(e.X)
   663  	case *ast.SelectorExpr:
   664  		return stringify(e.X) + "." + e.Sel.Name
   665  	case *ast.ArrayType:
   666  		if e.Len == nil {
   667  			return "[]" + stringify(e.Elt)
   668  		}
   669  		return fmt.Sprintf("[%s]%s", stringify(e.Len), stringify(e.Elt))
   670  	case *ast.InterfaceType:
   671  		if e.Methods == nil || e.Methods.NumFields() == 0 {
   672  			return "interface{}"
   673  		}
   674  	}
   675  	return "<BAD>"
   676  }
   677  
   678  // recursively translate ast.Expr to gen.Elem; nil means type not supported
   679  // expected input types:
   680  // - *ast.MapType (map[T]J)
   681  // - *ast.Ident (name)
   682  // - *ast.ArrayType ([(sz)]T)
   683  // - *ast.StarExpr (*T)
   684  // - *ast.StructType (struct {})
   685  // - *ast.SelectorExpr (a.B)
   686  // - *ast.InterfaceType (interface {})
   687  func (fs *FileSet) parseExpr(e ast.Expr, isIface bool) (gen.Elem, error) {
   688  	switch e := e.(type) {
   689  
   690  	case *ast.MapType:
   691  		if k, ok := e.Key.(*ast.Ident); ok && k.Name == "string" {
   692  			in, err := fs.parseExpr(e.Value, false)
   693  			panicOn(err)
   694  			if in != nil {
   695  				return &gen.Map{Value: in, KeyTyp: "String", KeyDeclTyp: "string"}, nil
   696  			}
   697  		}
   698  
   699  		// support int64/int32/int keys
   700  		if k, ok := e.Key.(*ast.Ident); ok {
   701  			in, err := fs.parseExpr(e.Value, isIface)
   702  			if err != nil {
   703  				fatalf(err.Error())
   704  			}
   705  			if in != nil {
   706  				switch k.Name {
   707  				case "int64":
   708  					return &gen.Map{Value: in, KeyTyp: "Int64", KeyDeclTyp: "int64"}, nil
   709  				case "int32":
   710  					return &gen.Map{Value: in, KeyTyp: "Int32", KeyDeclTyp: "int32"}, nil
   711  				case "int":
   712  					return &gen.Map{Value: in, KeyTyp: "Int", KeyDeclTyp: "int"}, nil
   713  				}
   714  			}
   715  		}
   716  
   717  		return nil, nil
   718  
   719  	case *ast.Ident:
   720  		if !isIface && e.Obj != nil && fs != nil && fs.PackageInfo != nil &&
   721  			len(fs.PackageInfo.Info.Types) > 0 {
   722  
   723  			if tv, ok := fs.PackageInfo.Info.Types[e]; ok {
   724  				isIface = types.IsInterface(tv.Type)
   725  			}
   726  		}
   727  
   728  		b := gen.Ident(e.Name, isIface)
   729  
   730  		// work to resove this expression
   731  		// can be done later, once we've resolved
   732  		// everything else.
   733  		if b.Value == gen.IDENT {
   734  			if _, ok := fs.Specs[e.Name]; !ok {
   735  				warnf("non-local identifier: %s\n", e.Name)
   736  			}
   737  		}
   738  		return b, nil
   739  
   740  	case *ast.ArrayType:
   741  
   742  		// special case for []byte
   743  		if e.Len == nil {
   744  			if i, ok := e.Elt.(*ast.Ident); ok && i.Name == "byte" {
   745  				return &gen.BaseElem{Value: gen.Bytes}, nil
   746  			}
   747  		}
   748  
   749  		// return early if we don't know
   750  		// what the slice element type is
   751  		els, err := fs.parseExpr(e.Elt, isIface)
   752  		if err != nil {
   753  			return nil, err
   754  		}
   755  		if els == nil {
   756  			return nil, nil
   757  		}
   758  
   759  		// array and not a slice
   760  		if e.Len != nil {
   761  			switch s := e.Len.(type) {
   762  			case *ast.BasicLit:
   763  				return &gen.Array{
   764  					SizeNamed:    s.Value,
   765  					SizeResolved: s.Value,
   766  					Els:          els,
   767  				}, nil
   768  
   769  			case *ast.Ident:
   770  				return &gen.Array{
   771  					SizeNamed:    s.String(),
   772  					SizeResolved: s.String(),
   773  					Els:          els,
   774  				}, nil
   775  
   776  			case *ast.SelectorExpr:
   777  				// fmt.Printf("debug SelectorExpr s where s.X is type %T/%#v:\n", s.X, s.X) // *ast.Ident
   778  				// get the package, e.g. msgp in the _generated/def.go
   779  				// type Things struct{Arr [msgp.ExtensionPrefixSize]float64} example.
   780  
   781  				var obj types.Object
   782  				// default to current pkg
   783  				selPkg := fs.PackageInfo
   784  				// but actually lookup in the imported package, if one is used:
   785  				switch y := s.X.(type) {
   786  				case *ast.Ident:
   787  					found := false
   788  					selPkg, found = fs.QuickPack[y.Name]
   789  					if !found {
   790  						fmt.Fprintf(os.Stderr, "%v",
   791  							fmt.Errorf("\nparse/getast.go:parseExpr() fatal "+
   792  								"error: could not find package "+
   793  								"named '%s' for selector '%s'. Try "+
   794  								"omitting the -no-load flag if it is in use.\n",
   795  								y.Name, stringify(s)))
   796  						os.Exit(1)
   797  					}
   798  				default:
   799  					// ignore, no package
   800  					fmt.Printf("ignoring, no package; s.X=%#v\n", s.X)
   801  				}
   802  
   803  				// get the scope:
   804  				_, obj = selPkg.Pkg.Scope().LookupParent(s.Sel.Name, token.NoPos)
   805  				switch cnst := obj.(type) {
   806  				case *types.Const:
   807  					asStr := cnst.Val().String()
   808  					//fmt.Printf("debug s.Sel.Name '%s' resolved to '%s'\n", s.Sel.Name, asStr)
   809  					return &gen.Array{
   810  						SizeNamed:    stringify(s),
   811  						SizeResolved: asStr,
   812  						Els:          els,
   813  					}, nil
   814  				default:
   815  					panic(fmt.Errorf("what to do with type %T here???", cnst))
   816  				}
   817  			default:
   818  				return nil, nil
   819  			}
   820  		}
   821  		return &gen.Slice{Els: els}, nil
   822  
   823  	case *ast.StarExpr:
   824  		v, err := fs.parseExpr(e.X, isIface)
   825  		if err != nil {
   826  			return nil, err
   827  		}
   828  		if v != nil {
   829  			return &gen.Ptr{Value: v}, nil
   830  		}
   831  		return nil, nil
   832  
   833  	case *ast.StructType:
   834  		fields, missingZid, err := fs.parseFieldList(e.Fields)
   835  		if err != nil {
   836  			return nil, err
   837  		}
   838  		skipN := 0
   839  		for i := range fields {
   840  			if fields[i].Skip {
   841  				skipN++
   842  			}
   843  		}
   844  		if len(fields) > 0 {
   845  			if fs.Cfg.UseMsgp2 || !missingZid {
   846  				return &gen.Struct{Fields: fields, SkipCount: skipN}, nil
   847  			}
   848  		}
   849  		return nil, nil
   850  
   851  	case *ast.SelectorExpr:
   852  		if !isIface && e.Sel.Obj != nil && fs != nil && fs.PackageInfo != nil &&
   853  			len(fs.PackageInfo.Info.Types) > 0 {
   854  
   855  			if tv, ok := fs.PackageInfo.Info.Types[e]; ok {
   856  				isIface = types.IsInterface(tv.Type)
   857  			}
   858  		}
   859  		return gen.Ident(stringify(e), isIface), nil
   860  
   861  	case *ast.InterfaceType:
   862  		// support `interface{}`
   863  		if len(e.Methods.List) == 0 {
   864  			return &gen.BaseElem{Value: gen.Intf}, nil
   865  		}
   866  		return nil, nil
   867  
   868  	default: // other types not supported
   869  		return nil, nil
   870  	}
   871  }
   872  
   873  func infof(s string, v ...interface{}) {
   874  	pushstate(s)
   875  	fmt.Printf(strings.Join(logctx, ": "), v...)
   876  	popstate()
   877  }
   878  
   879  func infoln(s string) {
   880  	pushstate(s)
   881  	fmt.Println(strings.Join(logctx, ": "))
   882  	popstate()
   883  }
   884  
   885  func warnf(s string, v ...interface{}) {
   886  	pushstate(s)
   887  	fmt.Printf(strings.Join(logctx, ": "), v...)
   888  	popstate()
   889  }
   890  
   891  func warnln(s string) {
   892  	pushstate(s)
   893  	fmt.Println(strings.Join(logctx, ": "))
   894  	popstate()
   895  }
   896  
   897  func fatalf(s string, v ...interface{}) {
   898  	pushstate(s)
   899  	fmt.Printf(strings.Join(logctx, ": "), v...)
   900  	popstate()
   901  }
   902  
   903  var logctx []string
   904  
   905  // push logging state
   906  func pushstate(s string) {
   907  	logctx = append(logctx, s)
   908  }
   909  
   910  // pop logging state
   911  func popstate() {
   912  	logctx = logctx[:len(logctx)-1]
   913  }
   914  
   915  func panicOn(err error) {
   916  	if err != nil {
   917  		panic(err)
   918  	}
   919  }
   920  
   921  func (fs *FileSet) getZebraSchemaId(f *ast.File) {
   922  	//fmt.Printf("\n starting getZebraSchemaId\n")
   923  
   924  	for i := range f.Decls {
   925  		switch g := f.Decls[i].(type) {
   926  		case *ast.GenDecl:
   927  
   928  			for _, s := range g.Specs {
   929  				switch ts := s.(type) {
   930  				case *ast.ValueSpec:
   931  
   932  					if len(ts.Names) > 0 && len(ts.Values) > 0 {
   933  						if ts.Names[0].Name == "zebraSchemaId64" {
   934  							switch specid := ts.Values[0].(type) {
   935  							case *ast.BasicLit:
   936  
   937  								//fmt.Printf("\n !!!!! \n got a BasicLit %T/%#v\n", specid, specid)
   938  								n, err := strconv.ParseInt(specid.Value, 0, 64)
   939  								if err != nil {
   940  									panic(fmt.Errorf("could not convert to integer this zebraSchemaId64 value: '%v': %v", specid.Value, err))
   941  								}
   942  								fs.ZebraSchemaId = int64(n)
   943  								return
   944  							}
   945  						}
   946  						//fmt.Printf("\n !!!!! \n got a ValueSpec %T/%#v/names=%#v\n", ts, ts, ts.Names[0].Name)
   947  					}
   948  				}
   949  			}
   950  		}
   951  	}
   952  }
   953  
   954  func fileOrDir(name string) (ok, isDir bool) {
   955  	fi, err := os.Stat(name)
   956  	if err != nil {
   957  		return false, false
   958  	}
   959  	if fi.IsDir() {
   960  		return true, true
   961  	}
   962  	return true, false
   963  }
   964  
   965  func ListOfGoFilesInDir(path string) (gofiles []string, err error) {
   966  	fd, err := os.Open(path)
   967  	if err != nil {
   968  		return nil, err
   969  	}
   970  	defer fd.Close()
   971  
   972  	list, err := fd.Readdir(-1)
   973  	if err != nil {
   974  		return nil, err
   975  	}
   976  
   977  	for _, d := range list {
   978  		if strings.HasSuffix(d.Name(), ".go") {
   979  			gofiles = append(gofiles, filepath.Join(path, d.Name()))
   980  		}
   981  	}
   982  
   983  	return
   984  }
   985  
   986  func getPackageNameFromGoFile(gofile string) (packageName string, err error) {
   987  
   988  	fset := token.NewFileSet()
   989  	f, err := parser.ParseFile(fset, gofile, nil, parser.PackageClauseOnly)
   990  	if err != nil {
   991  		return "", err
   992  	}
   993  	packageName = f.Name.Name
   994  	return packageName, nil
   995  }
   996  
   997  // nodeString formats a syntax tree in the style of gofmt.
   998  func nodeString(n ast.Node, fset *token.FileSet) string {
   999  	var buf bytes.Buffer
  1000  	format.Node(&buf, fset, n)
  1001  	return buf.String()
  1002  }
  1003  
  1004  // mode returns a string describing the mode of an expression.
  1005  func mode(tv types.TypeAndValue) string {
  1006  	s := ""
  1007  	if tv.IsVoid() {
  1008  		s += ",void"
  1009  	}
  1010  	if tv.IsType() {
  1011  		s += ",type"
  1012  	}
  1013  	if tv.IsBuiltin() {
  1014  		s += ",builtin"
  1015  	}
  1016  	if tv.IsValue() {
  1017  		s += ",value"
  1018  	}
  1019  	if tv.IsNil() {
  1020  		s += ",nil"
  1021  	}
  1022  	if tv.Addressable() {
  1023  		s += ",addressable"
  1024  	}
  1025  	if tv.Assignable() {
  1026  		s += ",assignable"
  1027  	}
  1028  	if tv.HasOk() {
  1029  		s += ",ok"
  1030  	}
  1031  	return s[1:]
  1032  }
  1033  
  1034  // sample code for diagnostics on the tree
  1035  func (fs *FileSet) walkAstHelper(selPkg *loader.PackageInfo) {
  1036  	for k, file := range selPkg.Files {
  1037  		fmt.Printf("=============== for the %v-th file in package '%s'...\n", k, file.Name.Name)
  1038  		ast.Inspect(file, func(n ast.Node) bool {
  1039  			if expr, ok := n.(ast.Expr); ok {
  1040  				if tv, ok := selPkg.Info.Types[expr]; ok {
  1041  					fmt.Printf("%-24s\tmode:  %s\n", nodeString(expr, fs.Fset), mode(tv))
  1042  					fmt.Printf("\t\t\t\ttype:  %v\n", tv.Type)
  1043  					if tv.Value != nil {
  1044  						fmt.Printf("\t\t\t\tvalue: %v\n", tv.Value)
  1045  					}
  1046  				}
  1047  			}
  1048  			return true
  1049  		})
  1050  	}
  1051  }