1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file implements an ast.Importer for gc-generated object files.
6 // TODO(gri) Eventually move this into a separate package outside types.
26 const trace = false // set to true for debugging
28 var pkgExts = [...]string{".a", ".5", ".6", ".8"}
30 // FindPkg returns the filename and unique package id for an import
31 // path based on package information provided by build.Import (using
32 // the build.Default build.Context).
33 // If no file was found, an empty filename is returned.
35 func FindPkg(path, srcDir string) (filename, id string) {
44 // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
45 bp, _ := build.Import(path, srcDir, build.FindOnly)
50 if strings.HasSuffix(noext, ".a") {
51 noext = noext[:len(noext)-len(".a")]
54 case build.IsLocalImport(path):
55 // "./x" -> "/this/directory/x.ext", "/this/directory/x"
56 noext = filepath.Join(srcDir, path)
59 case filepath.IsAbs(path):
60 // for completeness only - go/build.Import
61 // does not support absolute imports
62 // "/x" -> "/x.ext", "/x"
67 for _, ext := range pkgExts {
68 filename = noext + ext
69 if f, err := os.Stat(filename); err == nil && !f.IsDir() {
74 filename = "" // not found
78 // GcImportData imports a package by reading the gc-generated export data,
79 // adds the corresponding package object to the imports map indexed by id,
80 // and returns the object.
82 // The imports map must contains all packages already imported, and no map
83 // entry with id as the key must be present. The data reader position must
84 // be the beginning of the export data section. The filename is only used
87 func GcImportData(imports map[string]*ast.Object, filename, id string, data *bufio.Reader) (pkg *ast.Object, err error) {
89 fmt.Printf("importing %s (%s)\n", id, filename)
92 if imports[id] != nil {
93 panic(fmt.Sprintf("package %s already imported", id))
96 // support for gcParser error handling
98 if r := recover(); r != nil {
99 err = r.(importError) // will re-panic if r is not an importError
104 p.init(filename, id, data, imports)
105 pkg = p.parseExport()
110 // GcImport imports a gc-generated package given its import path, adds the
111 // corresponding package object to the imports map, and returns the object.
112 // Local import paths are interpreted relative to the current working directory.
113 // The imports map must contains all packages already imported.
114 // GcImport satisfies the ast.Importer signature.
116 func GcImport(imports map[string]*ast.Object, path string) (pkg *ast.Object, err error) {
117 if path == "unsafe" {
121 srcDir, err := os.Getwd()
125 filename, id := FindPkg(path, srcDir)
127 err = errors.New("can't find import: " + id)
131 if pkg = imports[id]; pkg != nil {
132 return // package was imported before
136 f, err := os.Open(filename)
143 // Add file name to error.
144 err = fmt.Errorf("reading export data: %s: %v", filename, err)
148 buf := bufio.NewReader(f)
149 if err = FindGcExportData(buf); err != nil {
153 pkg, err = GcImportData(imports, filename, id, buf)
158 // ----------------------------------------------------------------------------
161 // gcParser parses the exports inside a gc compiler-produced
162 // object/archive file and populates its scope with the results.
163 type gcParser struct {
164 scanner scanner.Scanner
165 tok rune // current token
166 lit string // literal string; only valid for Ident, Int, String tokens
167 id string // package id of imported package
168 imports map[string]*ast.Object // package id -> package object
171 func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*ast.Object) {
173 p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
174 p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
175 p.scanner.Whitespace = 1<<'\t' | 1<<' '
176 p.scanner.Filename = filename // for good error messages
182 func (p *gcParser) next() {
183 p.tok = p.scanner.Scan()
185 case scanner.Ident, scanner.Int, scanner.String:
186 p.lit = p.scanner.TokenText()
191 fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
195 // Declare inserts a named object of the given kind in scope.
196 func (p *gcParser) declare(scope *ast.Scope, kind ast.ObjKind, name string) *ast.Object {
197 // the object may have been imported before - if it exists
198 // already in the respective package scope, return that object
199 if obj := scope.Lookup(name); obj != nil {
200 assert(obj.Kind == kind)
204 // otherwise create a new object and insert it into the package scope
205 obj := ast.NewObj(kind, name)
206 if scope.Insert(obj) != nil {
207 p.errorf("already declared: %v %s", kind, obj.Name)
210 // a new type object is a named type and may be referred
211 // to before the underlying type is known - set it up
213 obj.Type = &Name{Obj: obj}
219 // ----------------------------------------------------------------------------
222 // Internal errors are boxed as importErrors.
223 type importError struct {
228 func (e importError) Error() string {
229 return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
232 func (p *gcParser) error(err interface{}) {
233 if s, ok := err.(string); ok {
236 // panic with a runtime.Error if err is not an error
237 panic(importError{p.scanner.Pos(), err.(error)})
240 func (p *gcParser) errorf(format string, args ...interface{}) {
241 p.error(fmt.Sprintf(format, args...))
244 func (p *gcParser) expect(tok rune) string {
248 p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
254 func (p *gcParser) expectSpecial(tok string) {
255 sep := 'x' // not white space
257 for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' {
258 sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
263 p.errorf("expected %q, got %q", tok, tok[0:i])
267 func (p *gcParser) expectKeyword(keyword string) {
268 lit := p.expect(scanner.Ident)
270 p.errorf("expected keyword %s, got %q", keyword, lit)
274 // ----------------------------------------------------------------------------
275 // Import declarations
277 // ImportPath = string_lit .
279 func (p *gcParser) parsePkgId() *ast.Object {
280 id, err := strconv.Unquote(p.expect(scanner.String))
287 // id == "" stands for the imported package id
288 // (only known at time of package installation)
291 // package unsafe is not in the imports map - handle explicitly
297 scope = ast.NewScope(nil)
298 pkg = ast.NewObj(ast.Pkg, "")
306 // dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
307 func (p *gcParser) parseDotIdent() string {
309 if p.tok != scanner.Int {
310 sep := 'x' // not white space
311 for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
313 sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
318 p.expect(scanner.Ident) // use expect() for error handling
323 // ExportedName = "@" ImportPath "." dotIdentifier .
325 func (p *gcParser) parseExportedName() (*ast.Object, string) {
327 pkg := p.parsePkgId()
329 name := p.parseDotIdent()
333 // ----------------------------------------------------------------------------
336 // BasicType = identifier .
338 func (p *gcParser) parseBasicType() Type {
339 id := p.expect(scanner.Ident)
340 obj := Universe.Lookup(id)
341 if obj == nil || obj.Kind != ast.Typ {
342 p.errorf("not a basic type: %s", id)
344 return obj.Type.(Type)
347 // ArrayType = "[" int_lit "]" Type .
349 func (p *gcParser) parseArrayType() Type {
350 // "[" already consumed and lookahead known not to be "]"
351 lit := p.expect(scanner.Int)
354 n, err := strconv.ParseUint(lit, 10, 64)
358 return &Array{Len: n, Elt: elt}
361 // MapType = "map" "[" Type "]" Type .
363 func (p *gcParser) parseMapType() Type {
364 p.expectKeyword("map")
369 return &Map{Key: key, Elt: elt}
372 // Name = identifier | "?" | ExportedName .
374 func (p *gcParser) parseName() (name string) {
383 // exported name prefixed with package path
384 _, name = p.parseExportedName()
386 p.error("name expected")
391 // Field = Name Type [ string_lit ] .
393 func (p *gcParser) parseField() (fld *ast.Object, tag string) {
394 name := p.parseName()
395 ftyp := p.parseType()
397 // anonymous field - ftyp must be T or *T and T must be a type name
398 if _, ok := Deref(ftyp).(*Name); !ok {
399 p.errorf("anonymous field expected")
402 if p.tok == scanner.String {
403 tag = p.expect(scanner.String)
405 fld = ast.NewObj(ast.Var, name)
410 // StructType = "struct" "{" [ FieldList ] "}" .
411 // FieldList = Field { ";" Field } .
413 func (p *gcParser) parseStructType() Type {
414 var fields []*ast.Object
417 parseField := func() {
418 fld, tag := p.parseField()
419 fields = append(fields, fld)
420 tags = append(tags, tag)
423 p.expectKeyword("struct")
434 return &Struct{Fields: fields, Tags: tags}
437 // Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
439 func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
440 name := p.parseName()
442 name = "_" // cannot access unnamed identifiers
445 p.expectSpecial("...")
448 ptyp := p.parseType()
449 // ignore argument tag
450 if p.tok == scanner.String {
451 p.expect(scanner.String)
453 par = ast.NewObj(ast.Var, name)
458 // Parameters = "(" [ ParameterList ] ")" .
459 // ParameterList = { Parameter "," } Parameter .
461 func (p *gcParser) parseParameters() (list []*ast.Object, isVariadic bool) {
462 parseParameter := func() {
463 par, variadic := p.parseParameter()
464 list = append(list, par)
467 p.error("... not on final argument")
486 // Signature = Parameters [ Result ] .
487 // Result = Type | Parameters .
489 func (p *gcParser) parseSignature() *Func {
490 params, isVariadic := p.parseParameters()
492 // optional result type
493 var results []*ast.Object
495 case scanner.Ident, '[', '*', '<', '@':
496 // single, unnamed result
497 result := ast.NewObj(ast.Var, "_")
498 result.Type = p.parseType()
499 results = []*ast.Object{result}
501 // named or multiple result(s)
503 results, variadic = p.parseParameters()
505 p.error("... not permitted on result type")
509 return &Func{Params: params, Results: results, IsVariadic: isVariadic}
512 // MethodOrEmbedSpec = Name [ Signature ] .
514 func (p *gcParser) parseMethodOrEmbedSpec() *ast.Object {
518 // TODO(gri) compute method object
519 return ast.NewObj(ast.Fun, "_")
521 // TODO lookup name and return that type
522 return ast.NewObj(ast.Typ, "_")
525 // InterfaceType = "interface" "{" [ MethodOrEmbedList ] "}" .
526 // MethodOrEmbedList = MethodOrEmbedSpec { ";" MethodOrEmbedSpec } .
528 func (p *gcParser) parseInterfaceType() Type {
531 parseMethod := func() {
532 switch m := p.parseMethodOrEmbedSpec(); m.Kind {
534 // TODO expand embedded methods
536 methods = append(methods, m)
540 p.expectKeyword("interface")
552 return &Interface{Methods: methods}
555 // ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
557 func (p *gcParser) parseChanType() Type {
558 dir := ast.SEND | ast.RECV
559 if p.tok == scanner.Ident {
560 p.expectKeyword("chan")
562 p.expectSpecial("<-")
566 p.expectSpecial("<-")
567 p.expectKeyword("chan")
571 return &Chan{Dir: dir, Elt: elt}
575 // BasicType | TypeName | ArrayType | SliceType | StructType |
576 // PointerType | FuncType | InterfaceType | MapType | ChanType |
578 // BasicType = ident .
579 // TypeName = ExportedName .
580 // SliceType = "[" "]" Type .
581 // PointerType = "*" Type .
582 // FuncType = "func" Signature .
584 func (p *gcParser) parseType() Type {
589 return p.parseBasicType()
591 return p.parseStructType()
595 return p.parseSignature()
597 return p.parseInterfaceType()
599 return p.parseMapType()
601 return p.parseChanType()
605 pkg, name := p.parseExportedName()
606 return p.declare(pkg.Data.(*ast.Scope), ast.Typ, name).Type.(Type)
608 p.next() // look ahead
612 return &Slice{Elt: p.parseType()}
614 return p.parseArrayType()
618 return &Pointer{Base: p.parseType()}
620 return p.parseChanType()
628 p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
632 // ----------------------------------------------------------------------------
635 // ImportDecl = "import" identifier string_lit .
637 func (p *gcParser) parseImportDecl() {
638 p.expectKeyword("import")
639 // The identifier has no semantic meaning in the import data.
640 // It exists so that error messages can print the real package
641 // name: binary.ByteOrder instead of "encoding/binary".ByteOrder.
642 name := p.expect(scanner.Ident)
643 pkg := p.parsePkgId()
644 assert(pkg.Name == "" || pkg.Name == name)
648 // int_lit = [ "+" | "-" ] { "0" ... "9" } .
650 func (p *gcParser) parseInt() (sign, val string) {
658 val = p.expect(scanner.Int)
662 // number = int_lit [ "p" int_lit ] .
664 func (p *gcParser) parseNumber() Const {
666 sign, val := p.parseInt()
667 mant, ok := new(big.Int).SetString(sign+val, 10)
673 sign, val = p.parseInt()
674 exp64, err := strconv.ParseUint(val, 10, 0)
680 denom := big.NewInt(1)
681 denom.Lsh(denom, exp)
682 return Const{new(big.Rat).SetFrac(mant, denom)}
687 return Const{new(big.Rat).SetInt(mant)}
693 // ConstDecl = "const" ExportedName [ Type ] "=" Literal .
694 // Literal = bool_lit | int_lit | float_lit | complex_lit | string_lit .
695 // bool_lit = "true" | "false" .
696 // complex_lit = "(" float_lit "+" float_lit ")" .
697 // rune_lit = "(" int_lit "+" int_lit ")" .
698 // string_lit = `"` { unicode_char } `"` .
700 func (p *gcParser) parseConstDecl() {
701 p.expectKeyword("const")
702 pkg, name := p.parseExportedName()
703 obj := p.declare(pkg.Data.(*ast.Scope), ast.Con, name)
707 obj.Type = p.parseType()
713 if p.lit != "true" && p.lit != "false" {
714 p.error("expected true or false")
716 x = Const{p.lit == "true"}
717 typ = Bool.Underlying
719 case '-', scanner.Int:
723 if _, ok := x.val.(*big.Rat); ok {
724 typ = Float64.Underlying
727 // complex_lit or rune_lit
729 if p.tok == scanner.Char {
737 re := p.parseNumber()
739 im := p.parseNumber()
741 x = Const{cmplx{re.val.(*big.Rat), im.val.(*big.Rat)}}
742 typ = Complex128.Underlying
748 x = MakeConst(token.STRING, p.lit)
750 typ = String.Underlying
752 p.errorf("expected literal got %s", scanner.TokenString(p.tok))
760 // TypeDecl = "type" ExportedName Type .
762 func (p *gcParser) parseTypeDecl() {
763 p.expectKeyword("type")
764 pkg, name := p.parseExportedName()
765 obj := p.declare(pkg.Data.(*ast.Scope), ast.Typ, name)
767 // The type object may have been imported before and thus already
768 // have a type associated with it. We still need to parse the type
769 // structure, but throw it away if the object already has a type.
770 // This ensures that all imports refer to the same type object for
771 // a given type declaration.
774 if name := obj.Type.(*Name); name.Underlying == nil {
775 assert(Underlying(typ) == typ)
776 name.Underlying = typ
780 // VarDecl = "var" ExportedName Type .
782 func (p *gcParser) parseVarDecl() {
783 p.expectKeyword("var")
784 pkg, name := p.parseExportedName()
785 obj := p.declare(pkg.Data.(*ast.Scope), ast.Var, name)
786 obj.Type = p.parseType()
789 // FuncBody = "{" ... "}" .
791 func (p *gcParser) parseFuncBody() {
793 for i := 1; i > 0; p.next() {
803 // FuncDecl = "func" ExportedName Signature [ FuncBody ] .
805 func (p *gcParser) parseFuncDecl() {
806 // "func" already consumed
807 pkg, name := p.parseExportedName()
808 obj := p.declare(pkg.Data.(*ast.Scope), ast.Fun, name)
809 obj.Type = p.parseSignature()
815 // MethodDecl = "func" Receiver Name Signature .
816 // Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" [ FuncBody ].
818 func (p *gcParser) parseMethodDecl() {
819 // "func" already consumed
821 p.parseParameter() // receiver
823 p.parseName() // unexported method names in imports are qualified with their package.
830 // Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
832 func (p *gcParser) parseDecl() {
843 p.next() // look ahead
853 // ----------------------------------------------------------------------------
856 // Export = "PackageClause { Decl } "$$" .
857 // PackageClause = "package" identifier [ "safe" ] "\n" .
859 func (p *gcParser) parseExport() *ast.Object {
860 p.expectKeyword("package")
861 name := p.expect(scanner.Ident)
863 // A package is safe if it was compiled with the -u flag,
864 // which disables the unsafe package.
865 // TODO(gri) remember "safe" package
866 p.expectKeyword("safe")
870 assert(p.imports[p.id] == nil)
871 pkg := ast.NewObj(ast.Pkg, name)
872 pkg.Data = ast.NewScope(nil)
873 p.imports[p.id] = pkg
875 for p.tok != '$' && p.tok != scanner.EOF {
879 if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
880 // don't call next()/expect() since reading past the
881 // export data may cause scanner errors (e.g. NUL chars)
882 p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
885 if n := p.scanner.ErrorCount; n != 0 {
886 p.errorf("expected no scanner errors, got %d", n)