summaryrefslogtreecommitdiff
path: root/src/pkg/go/ast/scope.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/go/ast/scope.go')
-rw-r--r--src/pkg/go/ast/scope.go268
1 files changed, 91 insertions, 177 deletions
diff --git a/src/pkg/go/ast/scope.go b/src/pkg/go/ast/scope.go
index 956a208ae..830d88aef 100644
--- a/src/pkg/go/ast/scope.go
+++ b/src/pkg/go/ast/scope.go
@@ -2,31 +2,31 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file implements scopes, the objects they contain,
-// and object types.
+// 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 []*Object // in declaration order
- // Implementation note: In some cases (struct fields,
- // function parameters) we need the source order of
- // variables. Thus for now, we store scope entries
- // in a linear list. If scopes become very large
- // (say, for packages), we may need to change this
- // to avoid slow lookups.
+ 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, must be > 0
- return &Scope{outer, make([]*Object, 0, n)}
+ const n = 4 // initial scope capacity
+ return &Scope{outer, make(map[string]*Object, n)}
}
@@ -34,73 +34,111 @@ func NewScope(outer *Scope) *Scope {
// found in scope s, otherwise it returns nil. Outer scopes
// are ignored.
//
-// Lookup always returns nil if name is "_", even if the scope
-// contains objects with that name.
-//
func (s *Scope) Lookup(name string) *Object {
- if name != "_" {
- for _, obj := range s.Objects {
- if obj.Name == name {
- return obj
- }
- }
- }
- return nil
+ return s.Objects[name]
}
-// Insert attempts to insert a named object into the scope s.
-// If the scope does not contain an object with that name yet
-// or if the object is named "_", Insert inserts the object
-// and returns it. Otherwise, Insert leaves the scope unchanged
-// and returns the object found in the scope instead.
+// 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) *Object {
- alt := s.Lookup(obj.Name)
- if alt == nil {
- s.append(obj)
- alt = obj
+func (s *Scope) Insert(obj *Object) (alt *Object) {
+ if alt = s.Objects[obj.Name]; alt == nil {
+ s.Objects[obj.Name] = obj
}
- return alt
+ return
}
-func (s *Scope) append(obj *Object) {
- s.Objects = append(s.Objects, obj)
+// 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 language entity such as a package,
-// constant, type, variable, or function (incl. methods).
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
//
type Object struct {
- Kind Kind
- Name string // declared name
- Type *Type
- Decl interface{} // corresponding Field, XxxSpec or FuncDecl
- N int // value of iota for this declaration
+ Kind ObjKind
+ Name string // declared name
+ Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+ Type interface{} // place holder for type information; may be nil
}
// NewObj creates a new object of a given kind and name.
-func NewObj(kind Kind, name string) *Object {
+func NewObj(kind ObjKind, name string) *Object {
return &Object{Kind: kind, Name: name}
}
-// Kind describes what an object represents.
-type Kind int
+// 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()
+ }
+ }
+ return token.NoPos
+}
+
+
+// ObKind describes what an object represents.
+type ObjKind int
// The list of possible Object kinds.
const (
- Bad Kind = iota // for error handling
- Pkg // package
- Con // constant
- Typ // type
- Var // variable
- Fun // function or method
+ Bad ObjKind = iota // for error handling
+ Pkg // package
+ Con // constant
+ Typ // type
+ Var // variable
+ Fun // function or method
+ Lbl // label
)
@@ -111,132 +149,8 @@ var objKindStrings = [...]string{
Typ: "type",
Var: "var",
Fun: "func",
+ Lbl: "label",
}
-func (kind Kind) String() string { return objKindStrings[kind] }
-
-
-// IsExported returns whether obj is exported.
-func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
-
-
-// ----------------------------------------------------------------------------
-// Types
-
-// A Type represents a Go type.
-type Type struct {
- Form Form
- Obj *Object // corresponding type name, or nil
- Scope *Scope // fields and methods, always present
- N uint // basic type id, array length, number of function results, or channel direction
- Key, Elt *Type // map key and array, pointer, slice, map or channel element
- Params *Scope // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
- Expr Expr // corresponding AST expression
-}
-
-
-// NewType creates a new type of a given form.
-func NewType(form Form) *Type {
- return &Type{Form: form, Scope: NewScope(nil)}
-}
-
-
-// Form describes the form of a type.
-type Form int
-
-// The list of possible type forms.
-const (
- BadType Form = iota // for error handling
- Unresolved // type not fully setup
- Basic
- Array
- Struct
- Pointer
- Function
- Method
- Interface
- Slice
- Map
- Channel
- Tuple
-)
-
-
-var formStrings = [...]string{
- BadType: "badType",
- Unresolved: "unresolved",
- Basic: "basic",
- Array: "array",
- Struct: "struct",
- Pointer: "pointer",
- Function: "function",
- Method: "method",
- Interface: "interface",
- Slice: "slice",
- Map: "map",
- Channel: "channel",
- Tuple: "tuple",
-}
-
-
-func (form Form) String() string { return formStrings[form] }
-
-
-// The list of basic type id's.
-const (
- Bool = iota
- Byte
- Uint
- Int
- Float
- Complex
- Uintptr
- String
-
- Uint8
- Uint16
- Uint32
- Uint64
-
- Int8
- Int16
- Int32
- Int64
-
- Float32
- Float64
-
- Complex64
- Complex128
-
- // TODO(gri) ideal types are missing
-)
-
-
-var BasicTypes = map[uint]string{
- Bool: "bool",
- Byte: "byte",
- Uint: "uint",
- Int: "int",
- Float: "float",
- Complex: "complex",
- Uintptr: "uintptr",
- String: "string",
-
- Uint8: "uint8",
- Uint16: "uint16",
- Uint32: "uint32",
- Uint64: "uint64",
-
- Int8: "int8",
- Int16: "int16",
- Int32: "int32",
- Int64: "int64",
-
- Float32: "float32",
- Float64: "float64",
-
- Complex64: "complex64",
- Complex128: "complex128",
-}
+func (kind ObjKind) String() string { return objKindStrings[kind] }