| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // This file implements scopes and the objects they contain. |
| |
| package ast |
| |
| import ( |
| "bytes" |
| "fmt" |
| "go/token" |
| ) |
| |
| // A Scope maintains the set of named language entities declared |
| // in the scope and a link to the immediately surrounding (outer) |
| // scope. |
| // |
| type Scope struct { |
| Outer *Scope |
| Objects map[string]*Object |
| } |
| |
| // NewScope creates a new scope nested in the outer scope. |
| func NewScope(outer *Scope) *Scope { |
| const n = 4 // initial scope capacity |
| return &Scope{outer, make(map[string]*Object, n)} |
| } |
| |
| // Lookup returns the object with the given name if it is |
| // found in scope s, otherwise it returns nil. Outer scopes |
| // are ignored. |
| // |
| func (s *Scope) Lookup(name string) *Object { |
| return s.Objects[name] |
| } |
| |
| // Insert attempts to insert a named object obj into the scope s. |
| // If the scope already contains an object alt with the same name, |
| // Insert leaves the scope unchanged and returns alt. Otherwise |
| // it inserts obj and returns nil. |
| // |
| func (s *Scope) Insert(obj *Object) (alt *Object) { |
| if alt = s.Objects[obj.Name]; alt == nil { |
| s.Objects[obj.Name] = obj |
| } |
| return |
| } |
| |
| // Debugging support |
| func (s *Scope) String() string { |
| var buf bytes.Buffer |
| fmt.Fprintf(&buf, "scope %p {", s) |
| if s != nil && len(s.Objects) > 0 { |
| fmt.Fprintln(&buf) |
| for _, obj := range s.Objects { |
| fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name) |
| } |
| } |
| fmt.Fprintf(&buf, "}\n") |
| return buf.String() |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Objects |
| |
| // An Object describes a named language entity such as a package, |
| // constant, type, variable, function (incl. methods), or label. |
| // |
| // The Data fields contains object-specific data: |
| // |
| // Kind Data type Data value |
| // Pkg *Scope package scope |
| // Con int iota for the respective declaration |
| // |
| type Object struct { |
| Kind ObjKind |
| Name string // declared name |
| Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil |
| Data interface{} // object-specific data; or nil |
| Type interface{} // placeholder for type information; may be nil |
| } |
| |
| // NewObj creates a new object of a given kind and name. |
| func NewObj(kind ObjKind, name string) *Object { |
| return &Object{Kind: kind, Name: name} |
| } |
| |
| // Pos computes the source position of the declaration of an object name. |
| // The result may be an invalid position if it cannot be computed |
| // (obj.Decl may be nil or not correct). |
| func (obj *Object) Pos() token.Pos { |
| name := obj.Name |
| switch d := obj.Decl.(type) { |
| case *Field: |
| for _, n := range d.Names { |
| if n.Name == name { |
| return n.Pos() |
| } |
| } |
| case *ImportSpec: |
| if d.Name != nil && d.Name.Name == name { |
| return d.Name.Pos() |
| } |
| return d.Path.Pos() |
| case *ValueSpec: |
| for _, n := range d.Names { |
| if n.Name == name { |
| return n.Pos() |
| } |
| } |
| case *TypeSpec: |
| if d.Name.Name == name { |
| return d.Name.Pos() |
| } |
| case *FuncDecl: |
| if d.Name.Name == name { |
| return d.Name.Pos() |
| } |
| case *LabeledStmt: |
| if d.Label.Name == name { |
| return d.Label.Pos() |
| } |
| case *AssignStmt: |
| for _, x := range d.Lhs { |
| if ident, isIdent := x.(*Ident); isIdent && ident.Name == name { |
| return ident.Pos() |
| } |
| } |
| case *Scope: |
| // predeclared object - nothing to do for now |
| } |
| return token.NoPos |
| } |
| |
| // ObjKind describes what an object represents. |
| type ObjKind int |
| |
| // The list of possible Object kinds. |
| const ( |
| Bad ObjKind = iota // for error handling |
| Pkg // package |
| Con // constant |
| Typ // type |
| Var // variable |
| Fun // function or method |
| Lbl // label |
| ) |
| |
| var objKindStrings = [...]string{ |
| Bad: "bad", |
| Pkg: "package", |
| Con: "const", |
| Typ: "type", |
| Var: "var", |
| Fun: "func", |
| Lbl: "label", |
| } |
| |
| func (kind ObjKind) String() string { return objKindStrings[kind] } |