...

Source file src/go/ast/scope.go

Documentation: go/ast

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

View as plain text