Home | History | Annotate | Download | only in types
      1 // Copyright 2013 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.
      6 
      7 package types
      8 
      9 import (
     10 	"bytes"
     11 	"fmt"
     12 	"go/token"
     13 	"io"
     14 	"sort"
     15 	"strings"
     16 )
     17 
     18 // TODO(gri) Provide scopes with a name or other mechanism so that
     19 //           objects can use that information for better printing.
     20 
     21 // A Scope maintains a set of objects and links to its containing
     22 // (parent) and contained (children) scopes. Objects may be inserted
     23 // and looked up by name. The zero value for Scope is a ready-to-use
     24 // empty scope.
     25 type Scope struct {
     26 	parent   *Scope
     27 	children []*Scope
     28 	elems    map[string]Object // lazily allocated
     29 	pos, end token.Pos         // scope extent; may be invalid
     30 	comment  string            // for debugging only
     31 }
     32 
     33 // NewScope returns a new, empty scope contained in the given parent
     34 // scope, if any. The comment is for debugging only.
     35 func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope {
     36 	s := &Scope{parent, nil, nil, pos, end, comment}
     37 	// don't add children to Universe scope!
     38 	if parent != nil && parent != Universe {
     39 		parent.children = append(parent.children, s)
     40 	}
     41 	return s
     42 }
     43 
     44 // Parent returns the scope's containing (parent) scope.
     45 func (s *Scope) Parent() *Scope { return s.parent }
     46 
     47 // Len() returns the number of scope elements.
     48 func (s *Scope) Len() int { return len(s.elems) }
     49 
     50 // Names returns the scope's element names in sorted order.
     51 func (s *Scope) Names() []string {
     52 	names := make([]string, len(s.elems))
     53 	i := 0
     54 	for name := range s.elems {
     55 		names[i] = name
     56 		i++
     57 	}
     58 	sort.Strings(names)
     59 	return names
     60 }
     61 
     62 // NumChildren() returns the number of scopes nested in s.
     63 func (s *Scope) NumChildren() int { return len(s.children) }
     64 
     65 // Child returns the i'th child scope for 0 <= i < NumChildren().
     66 func (s *Scope) Child(i int) *Scope { return s.children[i] }
     67 
     68 // Lookup returns the object in scope s with the given name if such an
     69 // object exists; otherwise the result is nil.
     70 func (s *Scope) Lookup(name string) Object {
     71 	return s.elems[name]
     72 }
     73 
     74 // LookupParent follows the parent chain of scopes starting with s until
     75 // it finds a scope where Lookup(name) returns a non-nil object, and then
     76 // returns that scope and object. If a valid position pos is provided,
     77 // only objects that were declared at or before pos are considered.
     78 // If no such scope and object exists, the result is (nil, nil).
     79 //
     80 // Note that obj.Parent() may be different from the returned scope if the
     81 // object was inserted into the scope and already had a parent at that
     82 // time (see Insert, below). This can only happen for dot-imported objects
     83 // whose scope is the scope of the package that exported them.
     84 func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) {
     85 	for ; s != nil; s = s.parent {
     86 		if obj := s.elems[name]; obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) {
     87 			return s, obj
     88 		}
     89 	}
     90 	return nil, nil
     91 }
     92 
     93 // Insert attempts to insert an object obj into scope s.
     94 // If s already contains an alternative object alt with
     95 // the same name, Insert leaves s unchanged and returns alt.
     96 // Otherwise it inserts obj, sets the object's parent scope
     97 // if not already set, and returns nil.
     98 func (s *Scope) Insert(obj Object) Object {
     99 	name := obj.Name()
    100 	if alt := s.elems[name]; alt != nil {
    101 		return alt
    102 	}
    103 	if s.elems == nil {
    104 		s.elems = make(map[string]Object)
    105 	}
    106 	s.elems[name] = obj
    107 	if obj.Parent() == nil {
    108 		obj.setParent(s)
    109 	}
    110 	return nil
    111 }
    112 
    113 // Pos and End describe the scope's source code extent [pos, end).
    114 // The results are guaranteed to be valid only if the type-checked
    115 // AST has complete position information. The extent is undefined
    116 // for Universe and package scopes.
    117 func (s *Scope) Pos() token.Pos { return s.pos }
    118 func (s *Scope) End() token.Pos { return s.end }
    119 
    120 // Contains returns true if pos is within the scope's extent.
    121 // The result is guaranteed to be valid only if the type-checked
    122 // AST has complete position information.
    123 func (s *Scope) Contains(pos token.Pos) bool {
    124 	return s.pos <= pos && pos < s.end
    125 }
    126 
    127 // Innermost returns the innermost (child) scope containing
    128 // pos. If pos is not within any scope, the result is nil.
    129 // The result is also nil for the Universe scope.
    130 // The result is guaranteed to be valid only if the type-checked
    131 // AST has complete position information.
    132 func (s *Scope) Innermost(pos token.Pos) *Scope {
    133 	// Package scopes do not have extents since they may be
    134 	// discontiguous, so iterate over the package's files.
    135 	if s.parent == Universe {
    136 		for _, s := range s.children {
    137 			if inner := s.Innermost(pos); inner != nil {
    138 				return inner
    139 			}
    140 		}
    141 	}
    142 
    143 	if s.Contains(pos) {
    144 		for _, s := range s.children {
    145 			if s.Contains(pos) {
    146 				return s.Innermost(pos)
    147 			}
    148 		}
    149 		return s
    150 	}
    151 	return nil
    152 }
    153 
    154 // WriteTo writes a string representation of the scope to w,
    155 // with the scope elements sorted by name.
    156 // The level of indentation is controlled by n >= 0, with
    157 // n == 0 for no indentation.
    158 // If recurse is set, it also writes nested (children) scopes.
    159 func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
    160 	const ind = ".  "
    161 	indn := strings.Repeat(ind, n)
    162 
    163 	fmt.Fprintf(w, "%s%s scope %p {", indn, s.comment, s)
    164 	if len(s.elems) == 0 {
    165 		fmt.Fprintf(w, "}\n")
    166 		return
    167 	}
    168 
    169 	fmt.Fprintln(w)
    170 	indn1 := indn + ind
    171 	for _, name := range s.Names() {
    172 		fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name])
    173 	}
    174 
    175 	if recurse {
    176 		for _, s := range s.children {
    177 			fmt.Fprintln(w)
    178 			s.WriteTo(w, n+1, recurse)
    179 		}
    180 	}
    181 
    182 	fmt.Fprintf(w, "%s}", indn)
    183 }
    184 
    185 // String returns a string representation of the scope, for debugging.
    186 func (s *Scope) String() string {
    187 	var buf bytes.Buffer
    188 	s.WriteTo(&buf, 0, false)
    189 	return buf.String()
    190 }
    191