Source file src/pkg/go/ast/scope.go
1 // Copyright 2009 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.
4
5 // This file implements scopes and the objects they contain.
6
7 package ast
8
9 import (
10 "bytes"
11 "fmt"
12 "go/token"
13 )
14
15 // A Scope maintains the set of named language entities declared
16 // in the scope and a link to the immediately surrounding (outer)
17 // scope.
18 //
19 type Scope struct {
20 Outer *Scope
21 Objects map[string]*Object
22 }
23
24 // NewScope creates a new scope nested in the outer scope.
25 func NewScope(outer *Scope) *Scope {
26 const n = 4 // initial scope capacity
27 return &Scope{outer, make(map[string]*Object, n)}
28 }
29
30 // Lookup returns the object with the given name if it is
31 // found in scope s, otherwise it returns nil. Outer scopes
32 // are ignored.
33 //
34 func (s *Scope) Lookup(name string) *Object {
35 return s.Objects[name]
36 }
37
38 // Insert attempts to insert a named object obj into the scope s.
39 // If the scope already contains an object alt with the same name,
40 // Insert leaves the scope unchanged and returns alt. Otherwise
41 // it inserts obj and returns nil."
42 //
43 func (s *Scope) Insert(obj *Object) (alt *Object) {
44 if alt = s.Objects[obj.Name]; alt == nil {
45 s.Objects[obj.Name] = obj
46 }
47 return
48 }
49
50 // Debugging support
51 func (s *Scope) String() string {
52 var buf bytes.Buffer
53 fmt.Fprintf(&buf, "scope %p {", s)
54 if s != nil && len(s.Objects) > 0 {
55 fmt.Fprintln(&buf)
56 for _, obj := range s.Objects {
57 fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name)
58 }
59 }
60 fmt.Fprintf(&buf, "}\n")
61 return buf.String()
62 }
63
64 // ----------------------------------------------------------------------------
65 // Objects
66
67 // TODO(gri) Consider replacing the Object struct with an interface
68 // and a corresponding set of object implementations.
69
70 // An Object describes a named language entity such as a package,
71 // constant, type, variable, function (incl. methods), or label.
72 //
73 // The Data fields contains object-specific data:
74 //
75 // Kind Data type Data value
76 // Pkg *Scope package scope
77 // Con int iota for the respective declaration
78 // Con != nil constant value
79 //
80 type Object struct {
81 Kind ObjKind
82 Name string // declared name
83 Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
84 Data interface{} // object-specific data; or nil
85 Type interface{} // place holder for type information; may be nil
86 }
87
88 // NewObj creates a new object of a given kind and name.
89 func NewObj(kind ObjKind, name string) *Object {
90 return &Object{Kind: kind, Name: name}
91 }
92
93 // Pos computes the source position of the declaration of an object name.
94 // The result may be an invalid position if it cannot be computed
95 // (obj.Decl may be nil or not correct).
96 func (obj *Object) Pos() token.Pos {
97 name := obj.Name
98 switch d := obj.Decl.(type) {
99 case *Field:
100 for _, n := range d.Names {
101 if n.Name == name {
102 return n.Pos()
103 }
104 }
105 case *ImportSpec:
106 if d.Name != nil && d.Name.Name == name {
107 return d.Name.Pos()
108 }
109 return d.Path.Pos()
110 case *ValueSpec:
111 for _, n := range d.Names {
112 if n.Name == name {
113 return n.Pos()
114 }
115 }
116 case *TypeSpec:
117 if d.Name.Name == name {
118 return d.Name.Pos()
119 }
120 case *FuncDecl:
121 if d.Name.Name == name {
122 return d.Name.Pos()
123 }
124 case *LabeledStmt:
125 if d.Label.Name == name {
126 return d.Label.Pos()
127 }
128 case *AssignStmt:
129 for _, x := range d.Lhs {
130 if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
131 return ident.Pos()
132 }
133 }
134 case *Scope:
135 // predeclared object - nothing to do for now
136 }
137 return token.NoPos
138 }
139
140 // ObKind describes what an object represents.
141 type ObjKind int
142
143 // The list of possible Object kinds.
144 const (
145 Bad ObjKind = iota // for error handling
146 Pkg // package
147 Con // constant
148 Typ // type
149 Var // variable
150 Fun // function or method
151 Lbl // label
152 )
153
154 var objKindStrings = [...]string{
155 Bad: "bad",
156 Pkg: "package",
157 Con: "const",
158 Typ: "type",
159 Var: "var",
160 Fun: "func",
161 Lbl: "label",
162 }
163
164 func (kind ObjKind) String() string { return objKindStrings[kind] }