summaryrefslogtreecommitdiff
path: root/usr/austin/eval/scope.go
diff options
context:
space:
mode:
Diffstat (limited to 'usr/austin/eval/scope.go')
-rw-r--r--usr/austin/eval/scope.go161
1 files changed, 74 insertions, 87 deletions
diff --git a/usr/austin/eval/scope.go b/usr/austin/eval/scope.go
index 8c9177b41..6d89d00d7 100644
--- a/usr/austin/eval/scope.go
+++ b/usr/austin/eval/scope.go
@@ -7,130 +7,117 @@ package eval
import (
"eval";
"fmt";
+ "log";
)
-func (s *Scope) Fork() *Scope {
- return &Scope{
- outer: s,
+func (b *block) enterChild() *block {
+ if b.inner != nil {
+ log.Crash("Failed to exit child block before entering another child");
+ }
+ sub := &block{
+ outer: b,
+ scope: b.scope,
defs: make(map[string] Def),
- temps: make(map[int] *Variable)
+ offset: b.offset+b.numVars,
};
+ b.inner = sub;
+ return sub;
+}
+
+func (b *block) exit() {
+ if b.outer == nil {
+ log.Crash("Cannot exit top-level block");
+ }
+ if b.outer.inner != b {
+ log.Crash("Already exited block");
+ }
+ if b.inner != nil {
+ log.Crash("Exit of parent block without exit of child block");
+ }
+ b.outer.inner = nil;
}
-func (s *Scope) DefineVar(name string, t Type) *Variable {
- if _, ok := s.defs[name]; ok {
+func (b *block) ChildScope() *Scope {
+ if b.inner != nil {
+ log.Crash("Failed to exit child block before entering a child scope");
+ }
+ sub := b.enterChild();
+ sub.offset = 0;
+ sub.scope = &Scope{sub, 0};
+ return sub.scope;
+}
+
+func (b *block) DefineVar(name string, t Type) *Variable {
+ if _, ok := b.defs[name]; ok {
return nil;
}
- v := &Variable{s.numVars, t};
- s.defs[name] = v;
- s.numVars++;
+ v := b.DefineTemp(t);
+ if v != nil {
+ b.defs[name] = v;
+ }
return v;
}
-func (s *Scope) DefineTemp(t Type) *Variable {
- v := &Variable{s.numVars, t};
- s.temps[s.numVars] = v;
- s.numVars++;
+func (b *block) DefineTemp(t Type) *Variable {
+ if b.inner != nil {
+ log.Crash("Failed to exit child block before defining variable");
+ }
+ index := b.offset+b.numVars;
+ v := &Variable{index, t};
+ b.numVars++;
+ if index+1 > b.scope.maxVars {
+ b.scope.maxVars = index+1;
+ }
return v;
}
-func (s *Scope) DefineConst(name string, t Type, v Value) *Constant {
- if _, ok := s.defs[name]; ok {
+func (b *block) DefineConst(name string, t Type, v Value) *Constant {
+ if _, ok := b.defs[name]; ok {
return nil;
}
c := &Constant{t, v};
- s.defs[name] = c;
+ b.defs[name] = c;
return c;
}
-func (s *Scope) DefineType(name string, t Type) Type {
- if _, ok := s.defs[name]; ok {
+func (b *block) DefineType(name string, t Type) Type {
+ if _, ok := b.defs[name]; ok {
return nil;
}
// We take the representative type of t because multiple
// levels of naming are useless.
- nt := &NamedType{s, name, t.rep()};
- s.defs[name] = nt;
+ nt := &NamedType{name, t.rep()};
+ b.defs[name] = nt;
return nt;
}
-func (s *Scope) Lookup(name string) (Def, *Scope) {
- for s != nil {
- if d, ok := s.defs[name]; ok {
- return d, s;
+func (b *block) Lookup(name string) (level int, def Def) {
+ for b != nil {
+ if d, ok := b.defs[name]; ok {
+ return level, d;
}
- s = s.outer;
+ if b.outer != nil && b.scope != b.outer.scope {
+ level++;
+ }
+ b = b.outer;
}
- return nil, nil;
+ return 0, nil;
}
func (s *Scope) NewFrame(outer *Frame) *Frame {
- if s.varTypes == nil {
- // First creation of a frame from this scope. Compute
- // and memoize the types of all variables.
- ts := make([]Type, s.numVars);
- for _, d := range s.defs {
- if v, ok := d.(*Variable); ok {
- // Record the representative type to
- // avoid indirecting through named
- // types every time we drop a frame.
- ts[v.Index] = v.Type.rep();
- }
- }
- for _, v := range s.temps {
- ts[v.Index] = v.Type.rep();
- }
- s.varTypes = ts;
- }
-
- // Create frame
- //
- // TODO(austin) This is probably rather expensive. All values
- // require heap allocation and the Zero method typically
- // requires some computation.
- vars := make([]Value, s.numVars);
- for i, t := range s.varTypes {
- vars[i] = t.Zero();
- }
- return &Frame{outer, s, vars};
+ return outer.child(s.maxVars);
}
-func (f *Frame) Get(s *Scope, index int) Value {
- for f.Scope != s {
+func (f *Frame) Get(level int, index int) Value {
+ for ; level > 0; level-- {
f = f.Outer;
}
return f.Vars[index];
}
-func stringFrame(f *Frame) (string, string) {
- res := "";
- indent := "";
- if f.Outer != nil {
- res, indent = stringFrame(f.Outer);
- }
-
- names := make([]string, f.Scope.numVars);
- types := make([]Type, f.Scope.numVars);
- for name, def := range f.Scope.defs {
- def, ok := def.(*Variable);
- if !ok {
- continue;
- }
- names[def.Index] = name;
- types[def.Index] = def.Type;
- }
- for _, def := range f.Scope.temps {
- names[def.Index] = "(temp)";
- types[def.Index] = def.Type;
- }
-
- for i, val := range f.Vars {
- res += fmt.Sprintf("%s%-10s %-10s %s\n", indent, names[i], types[i], val);
- }
- return res, indent + " ";
-}
-
-func (f *Frame) String() string {
- res, _ := stringFrame(f);
- return res;
+func (f *Frame) child(numVars int) *Frame {
+ // TODO(austin) This is probably rather expensive. All values
+ // require heap allocation and zeroing them when we execute a
+ // definition typically requires some computation.
+ return &Frame{f, make([]Value, numVars)};
}