]> Cypherpunks repositories - gostls13.git/commitdiff
Flatten the Frame tree. Now each function call produces a
authorAustin Clements <aclements@csail.mit.edu>
Wed, 29 Jul 2009 18:57:46 +0000 (11:57 -0700)
committerAustin Clements <aclements@csail.mit.edu>
Wed, 29 Jul 2009 18:57:46 +0000 (11:57 -0700)
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

usr/austin/eval/compiler.go
usr/austin/eval/decls.go
usr/austin/eval/expr.go
usr/austin/eval/func.go
usr/austin/eval/scope.go
usr/austin/eval/stmt.go
usr/austin/eval/type.go
usr/austin/eval/typec.go

index 6dd6437e1387df328751d9f52ddcf2483df3a065..641e6a293b7de07d410559b03a5d53894daf6c98 100644 (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;
 }
index 08dc1c14820eb83abf05fbed53cdbc48c32a4441..2f71f11f3b27cfa433450b797f8fe1b08dc43e06 100644 (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
 
index 7aebedb48ef3f31a029bc42486354f427246ce0c..fbd4b5ac4eafd42fb0639cf387cb39ef9c7e48cf 100644 (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);
        }
index cc790452b7af06ef7c512e9897fe556d36ee3413..3fc5e71afe2f11e0cecf860bed639c88ea7414c2 100644 (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) {
index 8c9177b419b35270676f71aebf0e56a07fbf9720..6d89d00d789cda52ab613e0d74dc5c318a7f732b 100644 (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 (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)};
 }
index f769d29a2d8c77f79c3963c8192d68afe3991e82..65d97ac3e5cae35357235096786c914312b01761 100644 (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));
index cc107115aa7d8e9b080d5038edf555ff515e468d..b189b5379dd8260322d6630b618fb51914d4a799 100644 (file)
@@ -672,8 +672,6 @@ type ChanType struct {
  */
 
 type NamedType struct {
-       // Declaration scope
-       scope *Scope;
        name string;
        // Underlying type
        def Type;
index d9357271ac6794a06e75d0e3cc8b5d47ed679574..3d672c4aa098a26adbccb53eff6adb552d4efcb9 100644 (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);
 }