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 }