Flatten the Frame tree. Now each function call produces a

single frame and non-overlapping variables reuse frame slots.
As a result, entering and exiting blocks no longer requires
code execution, which means jumps across block boundaries
should be doable now.  Frame slot initialization happens at
definition time now, instead of at frame creation time.  As an
added bonus, Scope's are now exclusively compile-time objects
and we no longer need to specially track the function
activation frame for access to out vars.

R=rsc
APPROVED=rsc
DELTA=313  (102 added, 90 deleted, 121 changed)
OCL=32416
CL=32420
This commit is contained in:
Austin Clements 2009-07-29 11:57:46 -07:00
parent 4152b925f9
commit 8f694f6661
8 changed files with 218 additions and 206 deletions

View File

@ -32,16 +32,16 @@ func (a *compiler) diagAt(pos positioned, format string, args ...) {
}
type FuncDecl struct
func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt) (func (f *Frame) Func)
func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (func (f *Frame) Func)
type exprCompiler struct
func (a *compiler) compileExpr(scope *Scope, expr ast.Expr, constant bool) *exprCompiler
func (a *compiler) compileExpr(b *block, expr ast.Expr, constant bool) *exprCompiler
type assignCompiler struct
func (a *compiler) checkAssign(pos token.Position, rs []*exprCompiler, errOp, errPosName string) (*assignCompiler, bool)
func (a *compiler) compileAssign(pos token.Position, lt Type, rs []*exprCompiler, errOp, errPosName string) (func(lv Value, f *Frame))
func (a *compiler) compileType(scope *Scope, typ ast.Expr) Type
func (a *compiler) compileFuncType(scope *Scope, typ *ast.FuncType) *FuncDecl
func (a *compiler) compileType(b *block, typ ast.Expr) Type
func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl
func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool)
func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool)
type codeBuf struct
@ -63,7 +63,7 @@ type funcCompiler struct {
// of a single block within a function.
type blockCompiler struct {
*funcCompiler;
scope *Scope;
block *block;
returned bool;
// The PC break statements should jump to, or nil if a break
// statement is invalid.
@ -74,9 +74,6 @@ type blockCompiler struct {
// The blockCompiler for the block enclosing this one, or nil
// for a function-level block.
parent *blockCompiler;
// The blockCompiler for the nested block currently being
// compiled, or nil if compilation is not in a nested block.
child *blockCompiler;
}
func (a *blockCompiler) compileStmt(s ast.Stmt)
@ -92,6 +89,6 @@ func (a *blockCompiler) exit()
// this to exprCompiler.
type exprContext struct {
*compiler;
scope *Scope;
block *block;
constant bool;
}

View File

@ -140,23 +140,59 @@ type Constant struct {
// A definition can be a *Variable, *Constant, or Type.
type Def interface {}
type Scope struct {
outer *Scope;
type Scope struct
// A block represents a definition block in which a name may not be
// defined more than once.
type block struct {
// The block enclosing this one, including blocks in other
// scopes.
outer *block;
// The nested block currently being compiled, or nil.
inner *block;
// The Scope containing this block.
scope *Scope;
// The Variables, Constants, and Types defined in this block.
defs map[string] Def;
temps map[int] *Variable;
// The index of the first variable defined in this block.
// This must be greater than the index of any variable defined
// in any parent of this block within the same Scope at the
// time this block is entered.
offset int;
// The number of Variables defined in this block.
numVars int;
varTypes []Type;
}
func (s *Scope) Fork() *Scope
func (s *Scope) DefineVar(name string, t Type) *Variable
func (s *Scope) DefineTemp(t Type) *Variable
func (s *Scope) DefineConst(name string, t Type, v Value) *Constant
func (s *Scope) DefineType(name string, t Type) Type
func (s *Scope) Lookup(name string) (Def, *Scope)
// A Scope is the compile-time analogue of a Frame, which captures
// some subtree of blocks.
type Scope struct {
// The root block of this scope.
*block;
// The maximum number of variables required at any point in
// this Scope. This determines the number of slots needed in
// Frame's created from this Scope at run-time.
maxVars int;
}
func (b *block) enterChild() *block
func (b *block) exit()
func (b *block) ChildScope() *Scope
func (b *block) DefineVar(name string, t Type) *Variable
func (b *block) DefineTemp(t Type) *Variable
func (b *block) DefineConst(name string, t Type, v Value) *Constant
func (b *block) DefineType(name string, t Type) Type
func (b *block) Lookup(name string) (level int, def Def)
// The universal scope
var universe = &Scope{defs: make(map[string] Def), temps: make(map[int] *Variable)};
func newUniverse() *Scope {
sc := &Scope{nil, 0};
sc.block = &block{
scope: sc,
defs: make(map[string] Def)
};
return sc;
}
var universe *Scope = newUniverse();
/*
* Frames
@ -164,12 +200,11 @@ var universe = &Scope{defs: make(map[string] Def), temps: make(map[int] *Variabl
type Frame struct {
Outer *Frame;
Scope *Scope;
Vars []Value;
}
func (f *Frame) Get(s *Scope, index int) Value
func (f *Frame) String() string
func (f *Frame) Get(level int, index int) Value
func (f *Frame) child(numVars int) *Frame
func (s *Scope) NewFrame(outer *Frame) *Frame

View File

@ -61,7 +61,7 @@ func newExprCompiler(c *exprContext, pos token.Position) *exprCompiler {
// Operator generators
// TODO(austin) Remove these forward declarations
func (a *exprCompiler) genConstant(v Value)
func (a *exprCompiler) genIdentOp(s *Scope, index int)
func (a *exprCompiler) genIdentOp(level int, index int)
func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler)
func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value)
func (a *exprCompiler) genStarOp(v *exprCompiler)
@ -470,7 +470,7 @@ func (a *exprCompiler) DoBadExpr(x *ast.BadExpr) {
}
func (a *exprCompiler) DoIdent(x *ast.Ident) {
def, dscope := a.scope.Lookup(x.Value);
level, def := a.block.Lookup(x.Value);
if def == nil {
a.diag("%s: undefined", x.Value);
return;
@ -491,7 +491,7 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) {
}
a.t = def.Type;
defidx := def.Index;
a.genIdentOp(dscope, defidx);
a.genIdentOp(level, defidx);
a.desc = "variable";
case Type:
a.diag("type %v used as expression", x.Value);
@ -566,14 +566,14 @@ func (a *exprCompiler) DoFuncLit(x *ast.FuncLit) {
// TODO(austin) Closures capture their entire defining frame
// instead of just the variables they use.
decl := a.compileFuncType(a.scope, x.Type);
decl := a.compileFuncType(a.block, x.Type);
if decl == nil {
// TODO(austin) Try compiling the body, perhaps with
// dummy definitions for the arguments
return;
}
evalFunc := a.compileFunc(a.scope, decl, x.Body);
evalFunc := a.compileFunc(a.block, decl, x.Body);
if evalFunc == nil {
return;
}
@ -728,13 +728,11 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
bad = true;
}
as := make([]*exprCompiler, len(x.Args));
ats := make([]Type, len(as));
for i := 0; i < len(x.Args); i++ {
as[i] = a.copyVisit(x.Args[i]);
if as[i].t == nil {
bad = true;
}
ats[i] = as[i].t;
}
if bad {
return;
@ -763,6 +761,7 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
//
// XXX(Spec) The spec is wrong. It can also be a single
// multi-valued expression.
nin := len(lt.In);
assign := a.compileAssign(x.Pos(), NewMultiType(lt.In), as, "function call", "argument");
if assign == nil {
return;
@ -778,12 +777,23 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
a.t = NewMultiType(lt.Out);
}
// Gather argument and out types to initialize frame variables
vts := make([]Type, nin + nout);
for i, t := range lt.In {
vts[i] = t;
}
for i, t := range lt.Out {
vts[i+nin] = t;
}
// Compile
lf := l.asFunc();
nin := len(lt.In);
call := func(f *Frame) []Value {
fun := lf(f);
fr := fun.NewFrame();
for i, t := range vts {
fr.Vars[i] = t.Zero();
}
assign(multiV(fr.Vars[0:nin]), f);
fun.Call(fr);
return fr.Vars[nin:nin+nout];
@ -1275,8 +1285,8 @@ func (a *exprCompiler) DoChanType(x *ast.ChanType) {
// TODO(austin) This is a hack to eliminate a circular dependency
// between type.go and expr.go
func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool) {
lenExpr := a.compileExpr(scope, expr, true);
func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
lenExpr := a.compileExpr(b, expr, true);
if lenExpr == nil {
return 0, false;
}
@ -1302,8 +1312,8 @@ func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool) {
return 0, false;
}
func (a *compiler) compileExpr(scope *Scope, expr ast.Expr, constant bool) *exprCompiler {
ec := newExprCompiler(&exprContext{a, scope, constant}, expr.Pos());
func (a *compiler) compileExpr(b *block, expr ast.Expr, constant bool) *exprCompiler {
ec := newExprCompiler(&exprContext{a, b, constant}, expr.Pos());
expr.Visit(ec);
if ec.t == nil {
return nil;
@ -1325,10 +1335,11 @@ func (a *exprCompiler) extractEffect() (func(f *Frame), *exprCompiler) {
}
// Create temporary
tempScope := a.scope;
tempBlock := a.block;
tempType := NewPtrType(a.t);
// TODO(austin) These temporaries accumulate in the scope.
temp := tempScope.DefineTemp(tempType);
// TODO(austin) These temporaries accumulate in the scope. We
// could enter a temporary block, but the caller has to exit it.
temp := tempBlock.DefineTemp(tempType);
tempIdx := temp.Index;
// Generate "temp := &e"
@ -1342,14 +1353,15 @@ func (a *exprCompiler) extractEffect() (func(f *Frame), *exprCompiler) {
}
effect := func(f *Frame) {
tempVal := f.Get(tempScope, tempIdx);
tempVal := tempType.Zero();
f.Vars[tempIdx] = tempVal;
assign(tempVal, f);
};
// Generate "*temp"
getTemp := a.copy();
getTemp.t = tempType;
getTemp.genIdentOp(tempScope, tempIdx);
getTemp.genIdentOp(0, tempIdx);
deref := a.copy();
deref.t = a.t;
@ -1377,7 +1389,7 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) {
errors := scanner.NewErrorVector();
cc := &compiler{errors};
ec := cc.compileExpr(scope, expr, false);
ec := cc.compileExpr(scope.block, expr, false);
if ec == nil {
return nil, errors.GetError(scanner.Sorted);
}
@ -1447,25 +1459,25 @@ func (a *exprCompiler) genConstant(v Value) {
}
}
func (a *exprCompiler) genIdentOp(s *Scope, index int) {
a.evalAddr = func(f *Frame) Value { return f.Get(s, index) };
func (a *exprCompiler) genIdentOp(level int, index int) {
a.evalAddr = func(f *Frame) Value { return f.Get(level, index) };
switch _ := a.t.rep().(type) {
case *boolType:
a.evalBool = func(f *Frame) bool { return f.Get(s, index).(BoolValue).Get() };
a.evalBool = func(f *Frame) bool { return f.Get(level, index).(BoolValue).Get() };
case *uintType:
a.evalUint = func(f *Frame) uint64 { return f.Get(s, index).(UintValue).Get() };
a.evalUint = func(f *Frame) uint64 { return f.Get(level, index).(UintValue).Get() };
case *intType:
a.evalInt = func(f *Frame) int64 { return f.Get(s, index).(IntValue).Get() };
a.evalInt = func(f *Frame) int64 { return f.Get(level, index).(IntValue).Get() };
case *floatType:
a.evalFloat = func(f *Frame) float64 { return f.Get(s, index).(FloatValue).Get() };
a.evalFloat = func(f *Frame) float64 { return f.Get(level, index).(FloatValue).Get() };
case *stringType:
a.evalString = func(f *Frame) string { return f.Get(s, index).(StringValue).Get() };
a.evalString = func(f *Frame) string { return f.Get(level, index).(StringValue).Get() };
case *ArrayType:
a.evalArray = func(f *Frame) ArrayValue { return f.Get(s, index).(ArrayValue).Get() };
a.evalArray = func(f *Frame) ArrayValue { return f.Get(level, index).(ArrayValue).Get() };
case *PtrType:
a.evalPtr = func(f *Frame) Value { return f.Get(s, index).(PtrValue).Get() };
a.evalPtr = func(f *Frame) Value { return f.Get(level, index).(PtrValue).Get() };
case *FuncType:
a.evalFunc = func(f *Frame) Func { return f.Get(s, index).(FuncValue).Get() };
a.evalFunc = func(f *Frame) Func { return f.Get(level, index).(FuncValue).Get() };
default:
log.Crashf("unexpected identifier type %v at %v", a.t, a.pos);
}

View File

@ -15,19 +15,15 @@ import (
type vm struct {
pc uint;
// The current execution frame. If execution is within a
// block, this may be a child of the original function
// activation frame.
// The execution frame of this function. This remains the
// same throughout a function invocation.
f *Frame;
// The original function activation frame. This is used to
// access function out args.
activation *Frame;
}
type code []func(*vm)
func (i code) exec(fr *Frame) {
v := vm{0, fr, fr};
v := vm{0, fr};
l := uint(len(i));
for v.pc < l {
@ -80,13 +76,13 @@ func (b *codeBuf) get() code {
*/
type evalFunc struct {
sc *Scope;
fr *Frame;
outer *Frame;
frameSize int;
code code;
}
func (f *evalFunc) NewFrame() *Frame {
return f.sc.NewFrame(f.fr);
return f.outer.child(f.frameSize);
}
func (f *evalFunc) Call(fr *Frame) {

View File

@ -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 (s *Scope) DefineVar(name string, t Type) *Variable {
if _, ok := s.defs[name]; ok {
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, 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)};
}

View File

@ -55,7 +55,7 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) {
}
func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) {
e := a.compileExpr(a.scope, s.X, false);
e := a.compileExpr(a.block, s.X, false);
if e == nil {
return;
}
@ -73,7 +73,7 @@ func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) {
}
func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) {
l := a.compileExpr(a.scope, s.X, false);
l := a.compileExpr(a.block, s.X, false);
if l == nil {
return;
}
@ -132,7 +132,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// made on the left side.
rs := make([]*exprCompiler, len(s.Rhs));
for i, re := range s.Rhs {
rs[i] = a.compileExpr(a.scope, re, false);
rs[i] = a.compileExpr(a.block, re, false);
if rs[i] == nil {
bad = true;
continue;
@ -172,7 +172,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
}
// Is this simply an assignment?
if _, ok := a.scope.defs[ident.Value]; ok {
if _, ok := a.block.defs[ident.Value]; ok {
goto assignment;
}
nDefs++;
@ -213,14 +213,19 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
}
// Define identifier
v := a.scope.DefineVar(ident.Value, lt);
v := a.block.DefineVar(ident.Value, lt);
if v == nil {
log.Crashf("Failed to define %s", ident.Value);
}
// Initialize the variable
index := v.Index;
a.push(func(v *vm) {
v.f.Vars[index] = lt.Zero();
});
}
assignment:
ls[i] = a.compileExpr(a.scope, le, false);
ls[i] = a.compileExpr(a.block, le, false);
if ls[i] == nil {
bad = true;
continue;
@ -325,8 +330,8 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
return;
}
l := a.compileExpr(a.scope, s.Lhs[0], false);
r := a.compileExpr(a.scope, s.Rhs[0], false);
l := a.compileExpr(a.block, s.Lhs[0], false);
r := a.compileExpr(a.block, s.Rhs[0], false);
if l == nil || r == nil {
return;
}
@ -397,7 +402,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
bad := false;
rs := make([]*exprCompiler, len(s.Results));
for i, re := range s.Results {
rs[i] = a.compileExpr(a.scope, re, false);
rs[i] = a.compileExpr(a.block, re, false);
if rs[i] == nil {
bad = true;
}
@ -425,7 +430,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
start := len(a.fnType.In);
nout := len(a.fnType.Out);
a.push(func(v *vm) {
assign(multiV(v.activation.Vars[start:start+nout]), v.f);
assign(multiV(v.f.Vars[start:start+nout]), v.f);
v.pc = ^uint(0);
});
a.err = false;
@ -496,8 +501,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
// says when there's a non-block else clause, because that
// else claus has to execute in a scope that is *not* the
// surrounding scope.
bc := a.blockCompiler;
bc = bc.enterChild();
bc := a.enterChild();
defer bc.exit();
// Compile init statement, if any
@ -511,7 +515,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
// fall through to the body.
bad := false;
if s.Cond != nil {
e := bc.compileExpr(bc.scope, s.Cond, false);
e := bc.compileExpr(bc.block, s.Cond, false);
switch {
case e == nil:
bad = true;
@ -580,11 +584,12 @@ func (a *stmtCompiler) DoSelectStmt(s *ast.SelectStmt) {
}
func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
// Wrap the entire for in a block.
bc := a.enterChild();
defer bc.exit();
// Compile init statement, if any
bc := a.blockCompiler;
if s.Init != nil {
bc = bc.enterChild();
defer bc.exit();
bc.compileStmt(s.Init);
}
@ -617,7 +622,7 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
// If the condition is absent, it is equivalent to true.
a.push(func(v *vm) { v.pc = bodyPC });
} else {
e := bc.compileExpr(bc.scope, s.Cond, false);
e := bc.compileExpr(bc.block, s.Cond, false);
switch {
case e == nil:
bad = true;
@ -650,12 +655,12 @@ func (a *stmtCompiler) DoRangeStmt(s *ast.RangeStmt) {
*/
func (a *blockCompiler) compileStmt(s ast.Stmt) {
if a.child != nil {
if a.block.inner != nil {
log.Crash("Child scope still entered");
}
sc := &stmtCompiler{a, s.Pos(), true};
s.Visit(sc);
if a.child != nil {
if a.block.inner != nil {
log.Crash("Forgot to exit child scope");
}
a.err = a.err || sc.err;
@ -668,49 +673,30 @@ func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
}
func (a *blockCompiler) enterChild() *blockCompiler {
if a.child != nil {
log.Crash("Failed to exit child block before entering another child");
}
blockScope := a.scope.Fork();
bc := &blockCompiler{
block := a.block.enterChild();
return &blockCompiler{
funcCompiler: a.funcCompiler,
scope: blockScope,
block: block,
returned: false,
parent: a,
};
a.child = bc;
a.push(func(v *vm) {
v.f = blockScope.NewFrame(v.f);
});
return bc;
}
func (a *blockCompiler) exit() {
if a.parent == nil {
log.Crash("Cannot exit top-level block");
}
if a.parent.child != a {
log.Crash("Double exit of block");
}
if a.child != nil {
log.Crash("Exit of parent block without exit of child block");
}
a.push(func(v *vm) {
v.f = v.f.Outer;
});
a.parent.child = nil;
a.block.exit();
}
/*
* Function compiler
*/
func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt) (func (f *Frame) Func) {
func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (func (f *Frame) Func) {
// Create body scope
//
// The scope of a parameter or result is the body of the
// corresponding function.
bodyScope := scope.Fork();
bodyScope := b.ChildScope();
defer bodyScope.exit();
for i, t := range decl.Type.In {
if decl.InNames[i] != nil {
bodyScope.DefineVar(decl.InNames[i].Value, t);
@ -734,7 +720,7 @@ func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt
}
bc := &blockCompiler{
funcCompiler: fc,
scope: bodyScope,
block: bodyScope.block,
returned: false,
};
@ -756,7 +742,8 @@ func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt
}
code := fc.get();
return func(f *Frame) Func { return &evalFunc{bodyScope, f, code} };
maxVars := bodyScope.maxVars;
return func(f *Frame) Func { return &evalFunc{f, maxVars, code} };
}
/*
@ -777,7 +764,7 @@ func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {
fc := &funcCompiler{cc, nil, false, newCodeBuf(), false};
bc := &blockCompiler{
funcCompiler: fc,
scope: scope,
block: scope.block,
returned: false
};
out := make([]*Stmt, len(stmts));

View File

@ -672,8 +672,6 @@ type ChanType struct {
*/
type NamedType struct {
// Declaration scope
scope *Scope;
name string;
// Underlying type
def Type;

View File

@ -23,13 +23,13 @@ type exprCompiler struct
type typeCompiler struct {
*compiler;
scope *Scope;
block *block;
}
func (a *typeCompiler) compileType(x ast.Expr) Type
func (a *typeCompiler) compileIdent(x *ast.Ident) Type {
def, dscope := a.scope.Lookup(x.Value);
_, def := a.block.Lookup(x.Value);
if def == nil {
a.diagAt(x, "%s: undefined", x.Value);
return nil;
@ -58,7 +58,7 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType) *ArrayType {
a.diagAt(x.Len, "... array initailizers not implemented");
return nil;
}
l, ok := a.compileArrayLen(a.scope, x.Len);
l, ok := a.compileArrayLen(a.block, x.Len);
// Compile element type
elem := a.compileType(x.Elt);
@ -191,12 +191,12 @@ notimpl:
* Type compiler interface
*/
func (a *compiler) compileType(scope *Scope, typ ast.Expr) Type {
tc := &typeCompiler{a, scope};
func (a *compiler) compileType(b *block, typ ast.Expr) Type {
tc := &typeCompiler{a, b};
return tc.compileType(typ);
}
func (a *compiler) compileFuncType(scope *Scope, typ *ast.FuncType) *FuncDecl {
tc := &typeCompiler{a, scope};
func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
tc := &typeCompiler{a, b};
return tc.compileFuncType(typ);
}