src/pkg/go/ast/scope.go - The Go Programming Language

Golang

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] }