diff options
| -rw-r--r-- | usr/austin/eval/compiler.go | 17 | ||||
| -rw-r--r-- | usr/austin/eval/decls.go | 63 | ||||
| -rw-r--r-- | usr/austin/eval/expr.go | 68 | ||||
| -rw-r--r-- | usr/austin/eval/func.go | 16 | ||||
| -rw-r--r-- | usr/austin/eval/scope.go | 161 | ||||
| -rw-r--r-- | usr/austin/eval/stmt.go | 83 | ||||
| -rw-r--r-- | usr/austin/eval/type.go | 2 | ||||
| -rw-r--r-- | usr/austin/eval/typec.go | 14 |
8 files changed, 218 insertions, 206 deletions
diff --git a/usr/austin/eval/compiler.go b/usr/austin/eval/compiler.go index 6dd6437e1..641e6a293 100644 --- a/usr/austin/eval/compiler.go +++ b/usr/austin/eval/compiler.go @@ -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; } diff --git a/usr/austin/eval/decls.go b/usr/austin/eval/decls.go index 08dc1c148..2f71f11f3 100644 --- a/usr/austin/eval/decls.go +++ b/usr/austin/eval/decls.go @@ -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 diff --git a/usr/austin/eval/expr.go b/usr/austin/eval/expr.go index 7aebedb48..fbd4b5ac4 100644 --- a/usr/austin/eval/expr.go +++ b/usr/austin/eval/expr.go @@ -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); } diff --git a/usr/austin/eval/func.go b/usr/austin/eval/func.go index cc790452b..3fc5e71af 100644 --- a/usr/austin/eval/func.go +++ b/usr/austin/eval/func.go @@ -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) { 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)}; } diff --git a/usr/austin/eval/stmt.go b/usr/austin/eval/stmt.go index f769d29a2..65d97ac3e 100644 --- a/usr/austin/eval/stmt.go +++ b/usr/austin/eval/stmt.go @@ -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)); diff --git a/usr/austin/eval/type.go b/usr/austin/eval/type.go index cc107115a..b189b5379 100644 --- a/usr/austin/eval/type.go +++ b/usr/austin/eval/type.go @@ -672,8 +672,6 @@ type ChanType struct { */ type NamedType struct { - // Declaration scope - scope *Scope; name string; // Underlying type def Type; diff --git a/usr/austin/eval/typec.go b/usr/austin/eval/typec.go index d9357271a..3d672c4aa 100644 --- a/usr/austin/eval/typec.go +++ b/usr/austin/eval/typec.go @@ -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); } |
