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