github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/go/ast/scope.go (about) 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 // An Object describes a named language entity such as a package, 68 // constant, type, variable, function (incl. methods), or label. 69 // 70 // The Data fields contains object-specific data: 71 // 72 // Kind Data type Data value 73 // Pkg *Scope package scope 74 // Con int iota for the respective declaration 75 // 76 type Object struct { 77 Kind ObjKind 78 Name string // declared name 79 Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil 80 Data interface{} // object-specific data; or nil 81 Type interface{} // placeholder for type information; may be nil 82 } 83 84 // NewObj creates a new object of a given kind and name. 85 func NewObj(kind ObjKind, name string) *Object { 86 return &Object{Kind: kind, Name: name} 87 } 88 89 // Pos computes the source position of the declaration of an object name. 90 // The result may be an invalid position if it cannot be computed 91 // (obj.Decl may be nil or not correct). 92 func (obj *Object) Pos() token.Pos { 93 name := obj.Name 94 switch d := obj.Decl.(type) { 95 case *Field: 96 for _, n := range d.Names { 97 if n.Name == name { 98 return n.Pos() 99 } 100 } 101 case *ImportSpec: 102 if d.Name != nil && d.Name.Name == name { 103 return d.Name.Pos() 104 } 105 return d.Path.Pos() 106 case *ValueSpec: 107 for _, n := range d.Names { 108 if n.Name == name { 109 return n.Pos() 110 } 111 } 112 case *TypeSpec: 113 if d.Name.Name == name { 114 return d.Name.Pos() 115 } 116 case *FuncDecl: 117 if d.Name.Name == name { 118 return d.Name.Pos() 119 } 120 case *LabeledStmt: 121 if d.Label.Name == name { 122 return d.Label.Pos() 123 } 124 case *AssignStmt: 125 for _, x := range d.Lhs { 126 if ident, isIdent := x.(*Ident); isIdent && ident.Name == name { 127 return ident.Pos() 128 } 129 } 130 case *Scope: 131 // predeclared object - nothing to do for now 132 } 133 return token.NoPos 134 } 135 136 // ObjKind describes what an object represents. 137 type ObjKind int 138 139 // The list of possible Object kinds. 140 const ( 141 Bad ObjKind = iota // for error handling 142 Pkg // package 143 Con // constant 144 Typ // type 145 Var // variable 146 Fun // function or method 147 Lbl // label 148 ) 149 150 var objKindStrings = [...]string{ 151 Bad: "bad", 152 Pkg: "package", 153 Con: "const", 154 Typ: "type", 155 Var: "var", 156 Fun: "func", 157 Lbl: "label", 158 } 159 160 func (kind ObjKind) String() string { return objKindStrings[kind] }