| // Copyright 2013 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package types |
| |
| import ( |
| "bytes" |
| "fmt" |
| ) |
| |
| // A Scope maintains the set of named language entities declared |
| // in the scope and a link to the immediately surrounding (outer) |
| // scope. |
| // |
| type Scope struct { |
| Outer *Scope |
| Entries []Object // scope entries in insertion order |
| large map[string]Object // for fast lookup - only used for larger scopes |
| } |
| |
| // Lookup returns the object with the given name if it is |
| // found in scope s, otherwise it returns nil. Outer scopes |
| // are ignored. |
| // |
| func (s *Scope) Lookup(name string) Object { |
| if s.large != nil { |
| return s.large[name] |
| } |
| for _, obj := range s.Entries { |
| if obj.GetName() == name { |
| return obj |
| } |
| } |
| return nil |
| } |
| |
| // Insert attempts to insert an object obj into scope s. |
| // If s already contains an object with the same name, |
| // Insert leaves s unchanged and returns that object. |
| // Otherwise it inserts obj and returns nil. |
| // |
| func (s *Scope) Insert(obj Object) Object { |
| name := obj.GetName() |
| if alt := s.Lookup(name); alt != nil { |
| return alt |
| } |
| s.Entries = append(s.Entries, obj) |
| |
| // If the scope size reaches a threshold, use a map for faster lookups. |
| const threshold = 20 |
| if len(s.Entries) > threshold { |
| if s.large == nil { |
| m := make(map[string]Object, len(s.Entries)) |
| for _, obj := range s.Entries { |
| m[obj.GetName()] = obj |
| } |
| s.large = m |
| } |
| s.large[name] = obj |
| } |
| |
| return nil |
| } |
| |
| // Debugging support |
| func (s *Scope) String() string { |
| var buf bytes.Buffer |
| fmt.Fprintf(&buf, "scope %p {", s) |
| if s != nil && len(s.Entries) > 0 { |
| fmt.Fprintln(&buf) |
| for _, obj := range s.Entries { |
| fmt.Fprintf(&buf, "\t%s\t%T\n", obj.GetName(), obj) |
| } |
| } |
| fmt.Fprintf(&buf, "}\n") |
| return buf.String() |
| } |