diff options
Diffstat (limited to 'src/pkg/go/ast/scope.go')
-rw-r--r-- | src/pkg/go/ast/scope.go | 259 |
1 files changed, 204 insertions, 55 deletions
diff --git a/src/pkg/go/ast/scope.go b/src/pkg/go/ast/scope.go index b5a38484e..956a208ae 100644 --- a/src/pkg/go/ast/scope.go +++ b/src/pkg/go/ast/scope.go @@ -2,25 +2,110 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// This file implements scopes, the objects they contain, +// and object types. + package ast -import "go/token" +// 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 + Objects []*Object // in declaration order + // Implementation note: In some cases (struct fields, + // function parameters) we need the source order of + // variables. Thus for now, we store scope entries + // in a linear list. If scopes become very large + // (say, for packages), we may need to change this + // to avoid slow lookups. +} + + +// NewScope creates a new scope nested in the outer scope. +func NewScope(outer *Scope) *Scope { + const n = 4 // initial scope capacity, must be > 0 + return &Scope{outer, make([]*Object, 0, n)} +} + + +// Lookup returns the object with the given name if it is +// found in scope s, otherwise it returns nil. Outer scopes +// are ignored. +// +// Lookup always returns nil if name is "_", even if the scope +// contains objects with that name. +// +func (s *Scope) Lookup(name string) *Object { + if name != "_" { + for _, obj := range s.Objects { + if obj.Name == name { + return obj + } + } + } + return nil +} + + +// Insert attempts to insert a named object into the scope s. +// If the scope does not contain an object with that name yet +// or if the object is named "_", Insert inserts the object +// and returns it. Otherwise, Insert leaves the scope unchanged +// and returns the object found in the scope instead. +// +func (s *Scope) Insert(obj *Object) *Object { + alt := s.Lookup(obj.Name) + if alt == nil { + s.append(obj) + alt = obj + } + return alt +} + + +func (s *Scope) append(obj *Object) { + s.Objects = append(s.Objects, obj) +} + +// ---------------------------------------------------------------------------- +// Objects + +// An Object describes a language entity such as a package, +// constant, type, variable, or function (incl. methods). +// +type Object struct { + Kind Kind + Name string // declared name + Type *Type + Decl interface{} // corresponding Field, XxxSpec or FuncDecl + N int // value of iota for this declaration +} + + +// NewObj creates a new object of a given kind and name. +func NewObj(kind Kind, name string) *Object { + return &Object{Kind: kind, Name: name} +} + -type ObjKind int +// Kind describes what an object represents. +type Kind int // The list of possible Object kinds. const ( - Err ObjKind = iota // object kind unknown (forward reference or error) - Pkg // package - Con // constant - Typ // type - Var // variable - Fun // function or method + Bad Kind = iota // for error handling + Pkg // package + Con // constant + Typ // type + Var // variable + Fun // function or method ) var objKindStrings = [...]string{ - Err: "<unknown object kind>", + Bad: "bad", Pkg: "package", Con: "const", Typ: "type", @@ -29,65 +114,129 @@ var objKindStrings = [...]string{ } -func (kind ObjKind) String() string { return objKindStrings[kind] } +func (kind Kind) String() string { return objKindStrings[kind] } -// An Object describes a language entity such as a package, -// constant, type, variable, or function (incl. methods). -// -type Object struct { - Kind ObjKind - Pos token.Position // declaration position - Name string // declared name +// IsExported returns whether obj is exported. +func (obj *Object) IsExported() bool { return IsExported(obj.Name) } + + +// ---------------------------------------------------------------------------- +// Types + +// A Type represents a Go type. +type Type struct { + Form Form + Obj *Object // corresponding type name, or nil + Scope *Scope // fields and methods, always present + N uint // basic type id, array length, number of function results, or channel direction + Key, Elt *Type // map key and array, pointer, slice, map or channel element + Params *Scope // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil + Expr Expr // corresponding AST expression } -func NewObj(kind ObjKind, pos token.Position, name string) *Object { - return &Object{kind, pos, name} +// NewType creates a new type of a given form. +func NewType(form Form) *Type { + return &Type{Form: form, Scope: NewScope(nil)} } -// IsExported returns whether obj is exported. -func (obj *Object) IsExported() bool { return IsExported(obj.Name) } +// Form describes the form of a type. +type Form int +// The list of possible type forms. +const ( + BadType Form = iota // for error handling + Unresolved // type not fully setup + Basic + Array + Struct + Pointer + Function + Method + Interface + Slice + Map + Channel + Tuple +) -// A Scope maintains the set of named language entities visible -// in the scope and a link to the immediately surrounding (outer) -// scope. -// -type Scope struct { - Outer *Scope - Objects map[string]*Object + +var formStrings = [...]string{ + BadType: "badType", + Unresolved: "unresolved", + Basic: "basic", + Array: "array", + Struct: "struct", + Pointer: "pointer", + Function: "function", + Method: "method", + Interface: "interface", + Slice: "slice", + Map: "map", + Channel: "channel", + Tuple: "tuple", } -// NewScope creates a new scope nested in the outer scope. -func NewScope(outer *Scope) *Scope { return &Scope{outer, make(map[string]*Object)} } - - -// Declare attempts to insert a named object into the scope s. -// If the scope does not contain an object with that name yet, -// Declare inserts the object, and returns it. Otherwise, the -// scope remains unchanged and Declare returns the object found -// in the scope instead. -func (s *Scope) Declare(obj *Object) *Object { - decl, found := s.Objects[obj.Name] - if !found { - s.Objects[obj.Name] = obj - decl = obj - } - return decl -} +func (form Form) String() string { return formStrings[form] } -// Lookup looks up an object in the current scope chain. -// The result is nil if the object is not found. -// -func (s *Scope) Lookup(name string) *Object { - for ; s != nil; s = s.Outer { - if obj, found := s.Objects[name]; found { - return obj - } - } - return nil +// The list of basic type id's. +const ( + Bool = iota + Byte + Uint + Int + Float + Complex + Uintptr + String + + Uint8 + Uint16 + Uint32 + Uint64 + + Int8 + Int16 + Int32 + Int64 + + Float32 + Float64 + + Complex64 + Complex128 + + // TODO(gri) ideal types are missing +) + + +var BasicTypes = map[uint]string{ + Bool: "bool", + Byte: "byte", + Uint: "uint", + Int: "int", + Float: "float", + Complex: "complex", + Uintptr: "uintptr", + String: "string", + + Uint8: "uint8", + Uint16: "uint16", + Uint32: "uint32", + Uint64: "uint64", + + Int8: "int8", + Int16: "int16", + Int32: "int32", + Int64: "int64", + + Float32: "float32", + Float64: "float64", + + Complex64: "complex64", + Complex128: "complex128", } |