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.
23 const trace = false // set to true for debugging
26 pkgRoot = filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH)
27 pkgExts = [...]string{".a", ".5", ".6", ".8"}
30 // findPkg returns the filename and package id for an import path.
31 // If no file was found, an empty filename is returned.
32 func findPkg(path string) (filename, id string) {
41 // "x" -> "$GOROOT/pkg/$GOOS_$GOARCH/x.ext", "x"
42 noext = filepath.Join(pkgRoot, path)
45 // "./x" -> "/this/directory/x.ext", "/this/directory/x"
46 cwd, err := os.Getwd()
50 noext = filepath.Join(cwd, path)
54 // "/x" -> "/x.ext", "/x"
59 for _, ext := range pkgExts {
60 filename = noext + ext
61 if f, err := os.Stat(filename); err == nil && f.IsRegular() {
66 filename = "" // not found
70 // gcParser parses the exports inside a gc compiler-produced
71 // object/archive file and populates its scope with the results.
72 type gcParser struct {
73 scanner scanner.Scanner
74 tok int // current token
75 lit string // literal string; only valid for Ident, Int, String tokens
76 id string // package id of imported package
77 imports map[string]*ast.Object // package id -> package object
80 func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*ast.Object) {
82 p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
83 p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
84 p.scanner.Whitespace = 1<<'\t' | 1<<' '
85 p.scanner.Filename = filename // for good error messages
91 func (p *gcParser) next() {
92 p.tok = p.scanner.Scan()
94 case scanner.Ident, scanner.Int, scanner.String:
95 p.lit = p.scanner.TokenText()
100 fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
104 // GcImporter implements the ast.Importer signature.
105 func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, err os.Error) {
106 if path == "unsafe" {
111 if r := recover(); r != nil {
112 err = r.(importError) // will re-panic if r is not an importError
114 panic(err) // force a stack trace
119 filename, id := findPkg(path)
121 err = os.NewError("can't find import: " + id)
125 if pkg = imports[id]; pkg != nil {
126 return // package was imported before
129 buf, err := ExportData(filename)
136 fmt.Printf("importing %s (%s)\n", id, filename)
140 p.init(filename, id, buf, imports)
141 pkg = p.parseExport()
145 // Declare inserts a named object of the given kind in scope.
146 func (p *gcParser) declare(scope *ast.Scope, kind ast.ObjKind, name string) *ast.Object {
147 // a type may have been declared before - if it exists
148 // already in the respective package scope, return that
151 if obj := scope.Lookup(name); obj != nil {
152 assert(obj.Kind == ast.Typ)
157 // any other object must be a newly declared object -
158 // create it and insert it into the package scope
159 obj := ast.NewObj(kind, name)
160 if scope.Insert(obj) != nil {
161 p.errorf("already declared: %v %s", kind, obj.Name)
164 // a new type object is a named type and may be referred
165 // to before the underlying type is known - set it up
167 obj.Type = &Name{Obj: obj}
173 // ----------------------------------------------------------------------------
176 // Internal errors are boxed as importErrors.
177 type importError struct {
182 func (e importError) String() string {
183 return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
186 func (p *gcParser) error(err interface{}) {
187 if s, ok := err.(string); ok {
190 // panic with a runtime.Error if err is not an os.Error
191 panic(importError{p.scanner.Pos(), err.(os.Error)})
194 func (p *gcParser) errorf(format string, args ...interface{}) {
195 p.error(fmt.Sprintf(format, args...))
198 func (p *gcParser) expect(tok int) string {
201 p.errorf("expected %q, got %q (%q)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
207 func (p *gcParser) expectSpecial(tok string) {
208 sep := 'x' // not white space
210 for i < len(tok) && p.tok == int(tok[i]) && sep > ' ' {
211 sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
216 p.errorf("expected %q, got %q", tok, tok[0:i])
220 func (p *gcParser) expectKeyword(keyword string) {
221 lit := p.expect(scanner.Ident)
223 p.errorf("expected keyword %s, got %q", keyword, lit)
227 // ----------------------------------------------------------------------------
228 // Import declarations
230 // ImportPath = string_lit .
232 func (p *gcParser) parsePkgId() *ast.Object {
233 id, err := strconv.Unquote(p.expect(scanner.String))
240 // id == "" stands for the imported package id
241 // (only known at time of package installation)
244 // package unsafe is not in the imports map - handle explicitly
250 scope = ast.NewScope(nil)
251 pkg = ast.NewObj(ast.Pkg, "")
259 // dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
260 func (p *gcParser) parseDotIdent() string {
262 if p.tok != scanner.Int {
263 sep := 'x' // not white space
264 for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
266 sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
271 p.expect(scanner.Ident) // use expect() for error handling
276 // ExportedName = "@" ImportPath "." dotIdentifier .
278 func (p *gcParser) parseExportedName() (*ast.Object, string) {
280 pkg := p.parsePkgId()
282 name := p.parseDotIdent()
286 // ----------------------------------------------------------------------------
289 // BasicType = identifier .
291 func (p *gcParser) parseBasicType() Type {
292 id := p.expect(scanner.Ident)
293 obj := Universe.Lookup(id)
294 if obj == nil || obj.Kind != ast.Typ {
295 p.errorf("not a basic type: %s", id)
297 return obj.Type.(Type)
300 // ArrayType = "[" int_lit "]" Type .
302 func (p *gcParser) parseArrayType() Type {
303 // "[" already consumed and lookahead known not to be "]"
304 lit := p.expect(scanner.Int)
307 n, err := strconv.Atoui64(lit)
311 return &Array{Len: n, Elt: elt}
314 // MapType = "map" "[" Type "]" Type .
316 func (p *gcParser) parseMapType() Type {
317 p.expectKeyword("map")
322 return &Map{Key: key, Elt: elt}
325 // Name = identifier | "?" .
327 func (p *gcParser) parseName() (name string) {
336 p.error("name expected")
341 // Field = Name Type [ string_lit ] .
343 func (p *gcParser) parseField() (fld *ast.Object, tag string) {
344 name := p.parseName()
345 ftyp := p.parseType()
347 // anonymous field - ftyp must be T or *T and T must be a type name
348 if _, ok := Deref(ftyp).(*Name); !ok {
349 p.errorf("anonymous field expected")
352 if p.tok == scanner.String {
353 tag = p.expect(scanner.String)
355 fld = ast.NewObj(ast.Var, name)
360 // StructType = "struct" "{" [ FieldList ] "}" .
361 // FieldList = Field { ";" Field } .
363 func (p *gcParser) parseStructType() Type {
364 var fields []*ast.Object
367 parseField := func() {
368 fld, tag := p.parseField()
369 fields = append(fields, fld)
370 tags = append(tags, tag)
373 p.expectKeyword("struct")
384 return &Struct{Fields: fields, Tags: tags}
387 // Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
389 func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
390 name := p.parseName()
392 name = "_" // cannot access unnamed identifiers
395 p.expectSpecial("...")
398 ptyp := p.parseType()
399 // ignore argument tag
400 if p.tok == scanner.String {
401 p.expect(scanner.String)
403 par = ast.NewObj(ast.Var, name)
408 // Parameters = "(" [ ParameterList ] ")" .
409 // ParameterList = { Parameter "," } Parameter .
411 func (p *gcParser) parseParameters() (list []*ast.Object, isVariadic bool) {
412 parseParameter := func() {
413 par, variadic := p.parseParameter()
414 list = append(list, par)
417 p.error("... not on final argument")
436 // Signature = Parameters [ Result ] .
437 // Result = Type | Parameters .
439 func (p *gcParser) parseSignature() *Func {
440 params, isVariadic := p.parseParameters()
442 // optional result type
443 var results []*ast.Object
445 case scanner.Ident, '[', '*', '<', '@':
446 // single, unnamed result
447 result := ast.NewObj(ast.Var, "_")
448 result.Type = p.parseType()
449 results = []*ast.Object{result}
451 // named or multiple result(s)
453 results, variadic = p.parseParameters()
455 p.error("... not permitted on result type")
459 return &Func{Params: params, Results: results, IsVariadic: isVariadic}
462 // MethodSpec = ( identifier | ExportedName ) Signature .
464 func (p *gcParser) parseMethodSpec() *ast.Object {
465 if p.tok == scanner.Ident {
466 p.expect(scanner.Ident)
468 p.parseExportedName()
472 // TODO(gri) compute method object
473 return ast.NewObj(ast.Fun, "_")
476 // InterfaceType = "interface" "{" [ MethodList ] "}" .
477 // MethodList = MethodSpec { ";" MethodSpec } .
479 func (p *gcParser) parseInterfaceType() Type {
482 parseMethod := func() {
483 meth := p.parseMethodSpec()
484 methods = append(methods, meth)
487 p.expectKeyword("interface")
499 return &Interface{Methods: methods}
502 // ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
504 func (p *gcParser) parseChanType() Type {
505 dir := ast.SEND | ast.RECV
506 if p.tok == scanner.Ident {
507 p.expectKeyword("chan")
509 p.expectSpecial("<-")
513 p.expectSpecial("<-")
514 p.expectKeyword("chan")
518 return &Chan{Dir: dir, Elt: elt}
522 // BasicType | TypeName | ArrayType | SliceType | StructType |
523 // PointerType | FuncType | InterfaceType | MapType | ChanType |
525 // BasicType = ident .
526 // TypeName = ExportedName .
527 // SliceType = "[" "]" Type .
528 // PointerType = "*" Type .
529 // FuncType = "func" Signature .
531 func (p *gcParser) parseType() Type {
536 return p.parseBasicType()
538 return p.parseStructType()
542 return p.parseSignature()
544 return p.parseInterfaceType()
546 return p.parseMapType()
548 return p.parseChanType()
552 pkg, name := p.parseExportedName()
553 return p.declare(pkg.Data.(*ast.Scope), ast.Typ, name).Type.(Type)
555 p.next() // look ahead
559 return &Slice{Elt: p.parseType()}
561 return p.parseArrayType()
565 return &Pointer{Base: p.parseType()}
567 return p.parseChanType()
575 p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
579 // ----------------------------------------------------------------------------
582 // ImportDecl = "import" identifier string_lit .
584 func (p *gcParser) parseImportDecl() {
585 p.expectKeyword("import")
586 // The identifier has no semantic meaning in the import data.
587 // It exists so that error messages can print the real package
588 // name: binary.ByteOrder instead of "encoding/binary".ByteOrder.
589 name := p.expect(scanner.Ident)
590 pkg := p.parsePkgId()
591 assert(pkg.Name == "" || pkg.Name == name)
595 // int_lit = [ "+" | "-" ] { "0" ... "9" } .
597 func (p *gcParser) parseInt() (sign, val string) {
605 val = p.expect(scanner.Int)
609 // number = int_lit [ "p" int_lit ] .
611 func (p *gcParser) parseNumber() Const {
613 sign, val := p.parseInt()
614 mant, ok := new(big.Int).SetString(sign+val, 10)
620 sign, val = p.parseInt()
621 exp, err := strconv.Atoui(val)
626 denom := big.NewInt(1)
627 denom.Lsh(denom, exp)
628 return Const{new(big.Rat).SetFrac(mant, denom)}
633 return Const{new(big.Rat).SetInt(mant)}
639 // ConstDecl = "const" ExportedName [ Type ] "=" Literal .
640 // Literal = bool_lit | int_lit | float_lit | complex_lit | string_lit .
641 // bool_lit = "true" | "false" .
642 // complex_lit = "(" float_lit "+" float_lit ")" .
643 // string_lit = `"` { unicode_char } `"` .
645 func (p *gcParser) parseConstDecl() {
646 p.expectKeyword("const")
647 pkg, name := p.parseExportedName()
648 obj := p.declare(pkg.Data.(*ast.Scope), ast.Con, name)
652 obj.Type = p.parseType()
658 if p.lit != "true" && p.lit != "false" {
659 p.error("expected true or false")
661 x = Const{p.lit == "true"}
662 typ = Bool.Underlying
664 case '-', scanner.Int:
668 if _, ok := x.val.(*big.Rat); ok {
669 typ = Float64.Underlying
674 re := p.parseNumber()
676 im := p.parseNumber()
678 x = Const{cmplx{re.val.(*big.Rat), im.val.(*big.Rat)}}
679 typ = Complex128.Underlying
682 x = MakeConst(token.STRING, p.lit)
684 typ = String.Underlying
686 p.error("expected literal")
694 // TypeDecl = "type" ExportedName Type .
696 func (p *gcParser) parseTypeDecl() {
697 p.expectKeyword("type")
698 pkg, name := p.parseExportedName()
699 obj := p.declare(pkg.Data.(*ast.Scope), ast.Typ, name)
701 // The type object may have been imported before and thus already
702 // have a type associated with it. We still need to parse the type
703 // structure, but throw it away if the object already has a type.
704 // This ensures that all imports refer to the same type object for
705 // a given type declaration.
708 if name := obj.Type.(*Name); name.Underlying == nil {
709 assert(Underlying(typ) == typ)
710 name.Underlying = typ
714 // VarDecl = "var" ExportedName Type .
716 func (p *gcParser) parseVarDecl() {
717 p.expectKeyword("var")
718 pkg, name := p.parseExportedName()
719 obj := p.declare(pkg.Data.(*ast.Scope), ast.Var, name)
720 obj.Type = p.parseType()
723 // FuncBody = "{" ... "}" .
725 func (p *gcParser) parseFuncBody() {
727 for i := 1; i > 0; p.next() {
737 // FuncDecl = "func" ExportedName Signature [ FuncBody ] .
739 func (p *gcParser) parseFuncDecl() {
740 // "func" already consumed
741 pkg, name := p.parseExportedName()
742 obj := p.declare(pkg.Data.(*ast.Scope), ast.Fun, name)
743 obj.Type = p.parseSignature()
749 // MethodDecl = "func" Receiver identifier Signature .
750 // Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" [ FuncBody ].
752 func (p *gcParser) parseMethodDecl() {
753 // "func" already consumed
755 p.parseParameter() // receiver
757 p.expect(scanner.Ident)
764 // Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
766 func (p *gcParser) parseDecl() {
777 p.next() // look ahead
787 // ----------------------------------------------------------------------------
790 // Export = "PackageClause { Decl } "$$" .
791 // PackageClause = "package" identifier [ "safe" ] "\n" .
793 func (p *gcParser) parseExport() *ast.Object {
794 p.expectKeyword("package")
795 name := p.expect(scanner.Ident)
797 // A package is safe if it was compiled with the -u flag,
798 // which disables the unsafe package.
799 // TODO(gri) remember "safe" package
800 p.expectKeyword("safe")
804 assert(p.imports[p.id] == nil)
805 pkg := ast.NewObj(ast.Pkg, name)
806 pkg.Data = ast.NewScope(nil)
807 p.imports[p.id] = pkg
809 for p.tok != '$' && p.tok != scanner.EOF {
813 if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
814 // don't call next()/expect() since reading past the
815 // export data may cause scanner errors (e.g. NUL chars)
816 p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
819 if n := p.scanner.ErrorCount; n != 0 {
820 p.errorf("expected no scanner errors, got %d", n)