-
Notifications
You must be signed in to change notification settings - Fork 12
/
scope.go
115 lines (98 loc) · 2.24 KB
/
scope.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package ast
import (
"github.com/openllb/hlb/diagnostic"
)
type ScopeLevel string
var (
BuiltinScope ScopeLevel = "Builtins"
ModuleScope ScopeLevel = "Module"
FunctionScope ScopeLevel = "Function"
BlockScope ScopeLevel = "Block"
ArgsScope ScopeLevel = "Arguments"
)
// Scope maintains the set of named language entities declared in the scope
// and a link to the immediately surrounding (outer) scope.
type Scope struct {
Node
Level ScopeLevel
Outer *Scope
Objects map[string]*Object
}
// NewScope creates a new scope linking to an outer scope.
func NewScope(outer *Scope, level ScopeLevel, node Node) *Scope {
return &Scope{
Node: node,
Level: level,
Outer: outer,
Objects: make(map[string]*Object),
}
}
func (s *Scope) Depth() int {
depth := 1
if s.Outer != nil {
depth += s.Outer.Depth()
}
return depth
}
func (s *Scope) ByLevel(level ScopeLevel) *Scope {
if s.Level == level {
return s
}
if s.Outer != nil {
return s.Outer.ByLevel(level)
}
return nil
}
// Lookup returns the object with the given name if it is
// found in scope, otherwise it returns nil.
func (s *Scope) Lookup(name string) *Object {
obj, ok := s.Objects[name]
if ok {
return obj
}
if s.Outer != nil {
return s.Outer.Lookup(name)
}
return nil
}
func (s *Scope) Identifiers(kset *KindSet) (idents []string) {
if s.Outer != nil {
idents = s.Outer.Identifiers(kset)
}
for ident, obj := range s.Objects {
if kset == nil || kset.Has(obj.Kind) {
idents = append(idents, ident)
}
}
return idents
}
func (s *Scope) Suggestion(name string, kset *KindSet) *Object {
return s.Lookup(diagnostic.Suggestion(name, s.Identifiers(kset)))
}
// Insert inserts a named object obj into the scope.
func (s *Scope) Insert(obj *Object) {
s.Objects[obj.Ident.Text] = obj
}
func (s *Scope) Locals() []*Object {
var objs []*Object
for _, obj := range s.Objects {
objs = append(objs, obj)
}
return objs
}
// ObjKind describes what an object represents.
type ObjKind int
// The list of possible Object types.
const (
BadKind ObjKind = iota
DeclKind
FieldKind
)
// Object represents a named language entity such as a function, or variable.
type Object struct {
Kind Kind
Ident *Ident
Node Node
Data interface{}
Exported bool
}