blob: 463ee40c54150c3e367a969f1f53ed2003be1a41 [file] [log] [blame]
// 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()
}