/
scope.go
93 lines (82 loc) · 3.01 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
package compiler
import (
"github.com/llir/llvm/ir/value"
)
// wraps a ir ir alloca + ir type for a variable
type varwrapper struct {
val value.Value // alloca or global-Def in the ir
typ ddpIrType // ir type of the variable
isRef bool
protected bool // this variable should not be freed in exitScope() or similar, because it will be freed by hand
}
// wraps local variables of a scope + the enclosing scope
type scope struct {
enclosing *scope // enclosing scope, nil if it is the global scope
variables map[string]varwrapper // variables in this scope
temporaries []varwrapper // intermediate values that need to be freed when the scope ends
}
// create a new scope in the enclosing scope
func newScope(enclosing *scope) *scope {
return &scope{
enclosing: enclosing,
variables: make(map[string]varwrapper),
}
}
// returns the named variable
// if not present the enclosing scopes are checked
// until the global scope
func (s *scope) lookupVar(name string) varwrapper {
if v, ok := s.variables[name]; !ok {
if s.enclosing != nil {
return s.enclosing.lookupVar(name)
}
return varwrapper{val: nil, typ: nil} // variable doesn't exist (should not happen, resolver should take care of that)
} else {
return v
}
}
// add a variable to the scope
func (scope *scope) addVar(name string, val value.Value, ty ddpIrType, isRef bool) value.Value {
scope.variables[name] = varwrapper{val: val, typ: ty, isRef: isRef, protected: false}
return val
}
func (scope *scope) addProtected(name string, val value.Value, ty ddpIrType, isRef bool) value.Value {
scope.variables[name] = varwrapper{val: val, typ: ty, isRef: isRef, protected: true}
return val
}
func (scope *scope) protectTemporary(val value.Value) {
for i := len(scope.temporaries) - 1; i >= 0; i-- {
if scope.temporaries[i].val == val {
scope.temporaries[i].protected = true
return
}
}
panic("attempted Value protection not found in scope.temporaries")
}
func (scope *scope) unprotectTemporary(val value.Value) {
for i := len(scope.temporaries) - 1; i >= 0; i-- {
if scope.temporaries[i].val == val {
scope.temporaries[i].protected = false
return
}
}
panic("attempted Value unprotection not found in scope.temporaries")
}
func (scope *scope) addTemporary(val value.Value, typ ddpIrType) (value.Value, ddpIrType) {
scope.temporaries = append(scope.temporaries, varwrapper{val: val, typ: typ, isRef: false, protected: false})
return val, typ
}
// removes the given value from scope.temporaries giving ownership to the caller
// who now has to make sure it is freed
// returns the value
func (scope *scope) claimTemporary(val value.Value) value.Value {
// loop backwards, because we mostlikely claim new values more frequently
for i := len(scope.temporaries) - 1; i >= 0; i-- {
// remove the found value and return
if scope.temporaries[i].val == val {
scope.temporaries = append(scope.temporaries[0:i], scope.temporaries[i+1:]...)
return val
}
}
panic("attempted Value claim not found in scope.temporaries")
}