1
0
mirror of https://github.com/golang/go synced 2024-10-04 08:31:22 -06:00
go/usr/austin/eval/scope.go
Austin Clements 7c9b9af76e Convert interpreter to whole-package compilation.
R=rsc
APPROVED=rsc
DELTA=334  (110 added, 211 deleted, 13 changed)
OCL=33135
CL=33137
2009-08-12 17:24:05 -07:00

126 lines
2.7 KiB
Go

// Copyright 2009 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 eval
import (
"fmt";
"go/token";
"log";
)
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),
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 (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, pos token.Position, t Type) (*Variable, Def) {
if prev, ok := b.defs[name]; ok {
return nil, prev;
}
v := b.DefineSlot(t);
v.Position = pos;
b.defs[name] = v;
return v, nil;
}
func (b *block) DefineSlot(t Type) *Variable {
if b.inner != nil {
log.Crash("Failed to exit child block before defining variable");
}
index := b.offset+b.numVars;
v := &Variable{token.Position{}, index, t};
b.numVars++;
if index+1 > b.scope.maxVars {
b.scope.maxVars = index+1;
}
return v;
}
func (b *block) DefineConst(name string, pos token.Position, t Type, v Value) *Constant {
if _, ok := b.defs[name]; ok {
return nil;
}
c := &Constant{pos, t, v};
b.defs[name] = c;
return c;
}
func (b *block) DefineType(name string, pos token.Position, 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.
if t != nil {
t = t.lit();
}
nt := &NamedType{pos, name, t, false, make(map[string] Method)};
b.defs[name] = nt;
return nt;
}
func (b *block) Lookup(name string) (level int, def Def) {
for b != nil {
if d, ok := b.defs[name]; ok {
return level, d;
}
if b.outer != nil && b.scope != b.outer.scope {
level++;
}
b = b.outer;
}
return 0, nil;
}
func (s *Scope) NewFrame(outer *Frame) *Frame {
return outer.child(s.maxVars);
}
func (f *Frame) Get(level int, index int) Value {
for ; level > 0; level-- {
f = f.Outer;
}
return f.Vars[index];
}
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)};
}