summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/austin/eval/compiler.go17
-rw-r--r--usr/austin/eval/decls.go63
-rw-r--r--usr/austin/eval/expr.go68
-rw-r--r--usr/austin/eval/func.go16
-rw-r--r--usr/austin/eval/scope.go161
-rw-r--r--usr/austin/eval/stmt.go83
-rw-r--r--usr/austin/eval/type.go2
-rw-r--r--usr/austin/eval/typec.go14
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);
}