Commit 8f694f66 authored by Austin Clements's avatar Austin Clements

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
parent 4152b925
...@@ -32,16 +32,16 @@ func (a *compiler) diagAt(pos positioned, format string, args ...) { ...@@ -32,16 +32,16 @@ func (a *compiler) diagAt(pos positioned, format string, args ...) {
} }
type FuncDecl struct 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 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 type assignCompiler struct
func (a *compiler) checkAssign(pos token.Position, rs []*exprCompiler, errOp, errPosName string) (*assignCompiler, bool) 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) 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) compileType(b *block, typ ast.Expr) Type
func (a *compiler) compileFuncType(scope *Scope, typ *ast.FuncType) *FuncDecl 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 type codeBuf struct
...@@ -63,7 +63,7 @@ type funcCompiler struct { ...@@ -63,7 +63,7 @@ type funcCompiler struct {
// of a single block within a function. // of a single block within a function.
type blockCompiler struct { type blockCompiler struct {
*funcCompiler; *funcCompiler;
scope *Scope; block *block;
returned bool; returned bool;
// The PC break statements should jump to, or nil if a break // The PC break statements should jump to, or nil if a break
// statement is invalid. // statement is invalid.
...@@ -74,9 +74,6 @@ type blockCompiler struct { ...@@ -74,9 +74,6 @@ type blockCompiler struct {
// The blockCompiler for the block enclosing this one, or nil // The blockCompiler for the block enclosing this one, or nil
// for a function-level block. // for a function-level block.
parent *blockCompiler; 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) func (a *blockCompiler) compileStmt(s ast.Stmt)
...@@ -92,6 +89,6 @@ func (a *blockCompiler) exit() ...@@ -92,6 +89,6 @@ func (a *blockCompiler) exit()
// this to exprCompiler. // this to exprCompiler.
type exprContext struct { type exprContext struct {
*compiler; *compiler;
scope *Scope; block *block;
constant bool; constant bool;
} }
...@@ -140,23 +140,59 @@ type Constant struct { ...@@ -140,23 +140,59 @@ type Constant struct {
// A definition can be a *Variable, *Constant, or Type. // A definition can be a *Variable, *Constant, or Type.
type Def interface {} type Def interface {}
type Scope struct { type Scope struct
outer *Scope;
// 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; 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; numVars int;
varTypes []Type;
} }
func (s *Scope) Fork() *Scope // A Scope is the compile-time analogue of a Frame, which captures
func (s *Scope) DefineVar(name string, t Type) *Variable // some subtree of blocks.
func (s *Scope) DefineTemp(t Type) *Variable type Scope struct {
func (s *Scope) DefineConst(name string, t Type, v Value) *Constant // The root block of this scope.
func (s *Scope) DefineType(name string, t Type) Type *block;
func (s *Scope) Lookup(name string) (Def, *Scope) // 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 // 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 * Frames
...@@ -164,12 +200,11 @@ var universe = &Scope{defs: make(map[string] Def), temps: make(map[int] *Variabl ...@@ -164,12 +200,11 @@ var universe = &Scope{defs: make(map[string] Def), temps: make(map[int] *Variabl
type Frame struct { type Frame struct {
Outer *Frame; Outer *Frame;
Scope *Scope;
Vars []Value; Vars []Value;
} }
func (f *Frame) Get(s *Scope, index int) Value func (f *Frame) Get(level int, index int) Value
func (f *Frame) String() string func (f *Frame) child(numVars int) *Frame
func (s *Scope) NewFrame(outer *Frame) *Frame func (s *Scope) NewFrame(outer *Frame) *Frame
......
...@@ -61,7 +61,7 @@ func newExprCompiler(c *exprContext, pos token.Position) *exprCompiler { ...@@ -61,7 +61,7 @@ func newExprCompiler(c *exprContext, pos token.Position) *exprCompiler {
// Operator generators // Operator generators
// TODO(austin) Remove these forward declarations // TODO(austin) Remove these forward declarations
func (a *exprCompiler) genConstant(v Value) 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) genIndexArray(l *exprCompiler, r *exprCompiler)
func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value)
func (a *exprCompiler) genStarOp(v *exprCompiler) func (a *exprCompiler) genStarOp(v *exprCompiler)
...@@ -470,7 +470,7 @@ func (a *exprCompiler) DoBadExpr(x *ast.BadExpr) { ...@@ -470,7 +470,7 @@ func (a *exprCompiler) DoBadExpr(x *ast.BadExpr) {
} }
func (a *exprCompiler) DoIdent(x *ast.Ident) { func (a *exprCompiler) DoIdent(x *ast.Ident) {
def, dscope := a.scope.Lookup(x.Value); level, def := a.block.Lookup(x.Value);
if def == nil { if def == nil {
a.diag("%s: undefined", x.Value); a.diag("%s: undefined", x.Value);
return; return;
...@@ -491,7 +491,7 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) { ...@@ -491,7 +491,7 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) {
} }
a.t = def.Type; a.t = def.Type;
defidx := def.Index; defidx := def.Index;
a.genIdentOp(dscope, defidx); a.genIdentOp(level, defidx);
a.desc = "variable"; a.desc = "variable";
case Type: case Type:
a.diag("type %v used as expression", x.Value); a.diag("type %v used as expression", x.Value);
...@@ -566,14 +566,14 @@ func (a *exprCompiler) DoFuncLit(x *ast.FuncLit) { ...@@ -566,14 +566,14 @@ func (a *exprCompiler) DoFuncLit(x *ast.FuncLit) {
// TODO(austin) Closures capture their entire defining frame // TODO(austin) Closures capture their entire defining frame
// instead of just the variables they use. // instead of just the variables they use.
decl := a.compileFuncType(a.scope, x.Type); decl := a.compileFuncType(a.block, x.Type);
if decl == nil { if decl == nil {
// TODO(austin) Try compiling the body, perhaps with // TODO(austin) Try compiling the body, perhaps with
// dummy definitions for the arguments // dummy definitions for the arguments
return; return;
} }
evalFunc := a.compileFunc(a.scope, decl, x.Body); evalFunc := a.compileFunc(a.block, decl, x.Body);
if evalFunc == nil { if evalFunc == nil {
return; return;
} }
...@@ -728,13 +728,11 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { ...@@ -728,13 +728,11 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
bad = true; bad = true;
} }
as := make([]*exprCompiler, len(x.Args)); as := make([]*exprCompiler, len(x.Args));
ats := make([]Type, len(as));
for i := 0; i < len(x.Args); i++ { for i := 0; i < len(x.Args); i++ {
as[i] = a.copyVisit(x.Args[i]); as[i] = a.copyVisit(x.Args[i]);
if as[i].t == nil { if as[i].t == nil {
bad = true; bad = true;
} }
ats[i] = as[i].t;
} }
if bad { if bad {
return; return;
...@@ -763,6 +761,7 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { ...@@ -763,6 +761,7 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
// //
// XXX(Spec) The spec is wrong. It can also be a single // XXX(Spec) The spec is wrong. It can also be a single
// multi-valued expression. // multi-valued expression.
nin := len(lt.In);
assign := a.compileAssign(x.Pos(), NewMultiType(lt.In), as, "function call", "argument"); assign := a.compileAssign(x.Pos(), NewMultiType(lt.In), as, "function call", "argument");
if assign == nil { if assign == nil {
return; return;
...@@ -778,12 +777,23 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { ...@@ -778,12 +777,23 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
a.t = NewMultiType(lt.Out); 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 // Compile
lf := l.asFunc(); lf := l.asFunc();
nin := len(lt.In);
call := func(f *Frame) []Value { call := func(f *Frame) []Value {
fun := lf(f); fun := lf(f);
fr := fun.NewFrame(); fr := fun.NewFrame();
for i, t := range vts {
fr.Vars[i] = t.Zero();
}
assign(multiV(fr.Vars[0:nin]), f); assign(multiV(fr.Vars[0:nin]), f);
fun.Call(fr); fun.Call(fr);
return fr.Vars[nin:nin+nout]; return fr.Vars[nin:nin+nout];
...@@ -1275,8 +1285,8 @@ func (a *exprCompiler) DoChanType(x *ast.ChanType) { ...@@ -1275,8 +1285,8 @@ func (a *exprCompiler) DoChanType(x *ast.ChanType) {
// TODO(austin) This is a hack to eliminate a circular dependency // TODO(austin) This is a hack to eliminate a circular dependency
// between type.go and expr.go // between type.go and expr.go
func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool) { func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
lenExpr := a.compileExpr(scope, expr, true); lenExpr := a.compileExpr(b, expr, true);
if lenExpr == nil { if lenExpr == nil {
return 0, false; return 0, false;
} }
...@@ -1302,8 +1312,8 @@ func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool) { ...@@ -1302,8 +1312,8 @@ func (a *compiler) compileArrayLen(scope *Scope, expr ast.Expr) (int64, bool) {
return 0, false; return 0, false;
} }
func (a *compiler) compileExpr(scope *Scope, expr ast.Expr, constant bool) *exprCompiler { func (a *compiler) compileExpr(b *block, expr ast.Expr, constant bool) *exprCompiler {
ec := newExprCompiler(&exprContext{a, scope, constant}, expr.Pos()); ec := newExprCompiler(&exprContext{a, b, constant}, expr.Pos());
expr.Visit(ec); expr.Visit(ec);
if ec.t == nil { if ec.t == nil {
return nil; return nil;
...@@ -1325,10 +1335,11 @@ func (a *exprCompiler) extractEffect() (func(f *Frame), *exprCompiler) { ...@@ -1325,10 +1335,11 @@ func (a *exprCompiler) extractEffect() (func(f *Frame), *exprCompiler) {
} }
// Create temporary // Create temporary
tempScope := a.scope; tempBlock := a.block;
tempType := NewPtrType(a.t); tempType := NewPtrType(a.t);
// TODO(austin) These temporaries accumulate in the scope. // TODO(austin) These temporaries accumulate in the scope. We
temp := tempScope.DefineTemp(tempType); // could enter a temporary block, but the caller has to exit it.
temp := tempBlock.DefineTemp(tempType);
tempIdx := temp.Index; tempIdx := temp.Index;
// Generate "temp := &e" // Generate "temp := &e"
...@@ -1342,14 +1353,15 @@ func (a *exprCompiler) extractEffect() (func(f *Frame), *exprCompiler) { ...@@ -1342,14 +1353,15 @@ func (a *exprCompiler) extractEffect() (func(f *Frame), *exprCompiler) {
} }
effect := func(f *Frame) { effect := func(f *Frame) {
tempVal := f.Get(tempScope, tempIdx); tempVal := tempType.Zero();
f.Vars[tempIdx] = tempVal;
assign(tempVal, f); assign(tempVal, f);
}; };
// Generate "*temp" // Generate "*temp"
getTemp := a.copy(); getTemp := a.copy();
getTemp.t = tempType; getTemp.t = tempType;
getTemp.genIdentOp(tempScope, tempIdx); getTemp.genIdentOp(0, tempIdx);
deref := a.copy(); deref := a.copy();
deref.t = a.t; deref.t = a.t;
...@@ -1377,7 +1389,7 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) { ...@@ -1377,7 +1389,7 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) {
errors := scanner.NewErrorVector(); errors := scanner.NewErrorVector();
cc := &compiler{errors}; cc := &compiler{errors};
ec := cc.compileExpr(scope, expr, false); ec := cc.compileExpr(scope.block, expr, false);
if ec == nil { if ec == nil {
return nil, errors.GetError(scanner.Sorted); return nil, errors.GetError(scanner.Sorted);
} }
...@@ -1447,25 +1459,25 @@ func (a *exprCompiler) genConstant(v Value) { ...@@ -1447,25 +1459,25 @@ func (a *exprCompiler) genConstant(v Value) {
} }
} }
func (a *exprCompiler) genIdentOp(s *Scope, index int) { func (a *exprCompiler) genIdentOp(level int, index int) {
a.evalAddr = func(f *Frame) Value { return f.Get(s, index) }; a.evalAddr = func(f *Frame) Value { return f.Get(level, index) };
switch _ := a.t.rep().(type) { switch _ := a.t.rep().(type) {
case *boolType: 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: 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: 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: 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: 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: 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: 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: 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: default:
log.Crashf("unexpected identifier type %v at %v", a.t, a.pos); log.Crashf("unexpected identifier type %v at %v", a.t, a.pos);
} }
......
...@@ -15,19 +15,15 @@ import ( ...@@ -15,19 +15,15 @@ import (
type vm struct { type vm struct {
pc uint; pc uint;
// The current execution frame. If execution is within a // The execution frame of this function. This remains the
// block, this may be a child of the original function // same throughout a function invocation.
// activation frame.
f *Frame; f *Frame;
// The original function activation frame. This is used to
// access function out args.
activation *Frame;
} }
type code []func(*vm) type code []func(*vm)
func (i code) exec(fr *Frame) { func (i code) exec(fr *Frame) {
v := vm{0, fr, fr}; v := vm{0, fr};
l := uint(len(i)); l := uint(len(i));
for v.pc < l { for v.pc < l {
...@@ -80,13 +76,13 @@ func (b *codeBuf) get() code { ...@@ -80,13 +76,13 @@ func (b *codeBuf) get() code {
*/ */
type evalFunc struct { type evalFunc struct {
sc *Scope; outer *Frame;
fr *Frame; frameSize int;
code code; code code;
} }
func (f *evalFunc) NewFrame() *Frame { func (f *evalFunc) NewFrame() *Frame {
return f.sc.NewFrame(f.fr); return f.outer.child(f.frameSize);
} }
func (f *evalFunc) Call(fr *Frame) { func (f *evalFunc) Call(fr *Frame) {
......
...@@ -7,130 +7,117 @@ package eval ...@@ -7,130 +7,117 @@ package eval
import ( import (
"eval"; "eval";
"fmt"; "fmt";
"log";
) )
func (s *Scope) Fork() *Scope { func (b *block) enterChild() *block {
return &Scope{ if b.inner != nil {
outer: s, log.Crash("Failed to exit child block before entering another child");
}
sub := &block{
outer: b,
scope: b.scope,
defs: make(map[string] Def), 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 { func (b *block) ChildScope() *Scope {
if _, ok := s.defs[name]; ok { 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; return nil;
} }
v := &Variable{s.numVars, t}; v := b.DefineTemp(t);
s.defs[name] = v; if v != nil {
s.numVars++; b.defs[name] = v;
}
return v; return v;
} }
func (s *Scope) DefineTemp(t Type) *Variable { func (b *block) DefineTemp(t Type) *Variable {
v := &Variable{s.numVars, t}; if b.inner != nil {
s.temps[s.numVars] = v; log.Crash("Failed to exit child block before defining variable");
s.numVars++; }
index := b.offset+b.numVars;
v := &Variable{index, t};
b.numVars++;
if index+1 > b.scope.maxVars {
b.scope.maxVars = index+1;
}
return v; return v;
} }
func (s *Scope) DefineConst(name string, t Type, v Value) *Constant { func (b *block) DefineConst(name string, t Type, v Value) *Constant {
if _, ok := s.defs[name]; ok { if _, ok := b.defs[name]; ok {
return nil; return nil;
} }
c := &Constant{t, v}; c := &Constant{t, v};
s.defs[name] = c; b.defs[name] = c;
return c; return c;
} }
func (s *Scope) DefineType(name string, t Type) Type { func (b *block) DefineType(name string, t Type) Type {
if _, ok := s.defs[name]; ok { if _, ok := b.defs[name]; ok {
return nil; return nil;
} }
// We take the representative type of t because multiple // We take the representative type of t because multiple
// levels of naming are useless. // levels of naming are useless.
nt := &NamedType{s, name, t.rep()}; nt := &NamedType{name, t.rep()};
s.defs[name] = nt; b.defs[name] = nt;
return nt; return nt;
} }
func (s *Scope) Lookup(name string) (Def, *Scope) { func (b *block) Lookup(name string) (level int, def Def) {
for s != nil { for b != nil {
if d, ok := s.defs[name]; ok { if d, ok := b.defs[name]; ok {
return d, s; 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 { func (s *Scope) NewFrame(outer *Frame) *Frame {
if s.varTypes == nil { return outer.child(s.maxVars);
// 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};
} }
func (f *Frame) Get(s *Scope, index int) Value { func (f *Frame) Get(level int, index int) Value {
for f.Scope != s { for ; level > 0; level-- {
f = f.Outer; f = f.Outer;
} }
return f.Vars[index]; return f.Vars[index];
} }
func stringFrame(f *Frame) (string, string) { func (f *Frame) child(numVars int) *Frame {
res := ""; // TODO(austin) This is probably rather expensive. All values
indent := ""; // require heap allocation and zeroing them when we execute a
if f.Outer != nil { // definition typically requires some computation.
res, indent = stringFrame(f.Outer); return &Frame{f, make([]Value, numVars)};
}
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;
} }
...@@ -55,7 +55,7 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) { ...@@ -55,7 +55,7 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) {
} }
func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) { 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 { if e == nil {
return; return;
} }
...@@ -73,7 +73,7 @@ func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) { ...@@ -73,7 +73,7 @@ func (a *stmtCompiler) DoExprStmt(s *ast.ExprStmt) {
} }
func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) { 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 { if l == nil {
return; return;
} }
...@@ -132,7 +132,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -132,7 +132,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// made on the left side. // made on the left side.
rs := make([]*exprCompiler, len(s.Rhs)); rs := make([]*exprCompiler, len(s.Rhs));
for i, re := range 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 { if rs[i] == nil {
bad = true; bad = true;
continue; continue;
...@@ -172,7 +172,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -172,7 +172,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
} }
// Is this simply an assignment? // Is this simply an assignment?
if _, ok := a.scope.defs[ident.Value]; ok { if _, ok := a.block.defs[ident.Value]; ok {
goto assignment; goto assignment;
} }
nDefs++; nDefs++;
...@@ -213,14 +213,19 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -213,14 +213,19 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
} }
// Define identifier // Define identifier
v := a.scope.DefineVar(ident.Value, lt); v := a.block.DefineVar(ident.Value, lt);
if v == nil { if v == nil {
log.Crashf("Failed to define %s", ident.Value); 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: assignment:
ls[i] = a.compileExpr(a.scope, le, false); ls[i] = a.compileExpr(a.block, le, false);
if ls[i] == nil { if ls[i] == nil {
bad = true; bad = true;
continue; continue;
...@@ -325,8 +330,8 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) { ...@@ -325,8 +330,8 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
return; return;
} }
l := a.compileExpr(a.scope, s.Lhs[0], false); l := a.compileExpr(a.block, s.Lhs[0], false);
r := a.compileExpr(a.scope, s.Rhs[0], false); r := a.compileExpr(a.block, s.Rhs[0], false);
if l == nil || r == nil { if l == nil || r == nil {
return; return;
} }
...@@ -397,7 +402,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) { ...@@ -397,7 +402,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
bad := false; bad := false;
rs := make([]*exprCompiler, len(s.Results)); rs := make([]*exprCompiler, len(s.Results));
for i, re := range 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 { if rs[i] == nil {
bad = true; bad = true;
} }
...@@ -425,7 +430,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) { ...@@ -425,7 +430,7 @@ func (a *stmtCompiler) DoReturnStmt(s *ast.ReturnStmt) {
start := len(a.fnType.In); start := len(a.fnType.In);
nout := len(a.fnType.Out); nout := len(a.fnType.Out);
a.push(func(v *vm) { 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); v.pc = ^uint(0);
}); });
a.err = false; a.err = false;
...@@ -496,8 +501,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) { ...@@ -496,8 +501,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
// says when there's a non-block else clause, because that // says when there's a non-block else clause, because that
// else claus has to execute in a scope that is *not* the // else claus has to execute in a scope that is *not* the
// surrounding scope. // surrounding scope.
bc := a.blockCompiler; bc := a.enterChild();
bc = bc.enterChild();
defer bc.exit(); defer bc.exit();
// Compile init statement, if any // Compile init statement, if any
...@@ -511,7 +515,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) { ...@@ -511,7 +515,7 @@ func (a *stmtCompiler) DoIfStmt(s *ast.IfStmt) {
// fall through to the body. // fall through to the body.
bad := false; bad := false;
if s.Cond != nil { if s.Cond != nil {
e := bc.compileExpr(bc.scope, s.Cond, false); e := bc.compileExpr(bc.block, s.Cond, false);
switch { switch {
case e == nil: case e == nil:
bad = true; bad = true;
...@@ -580,11 +584,12 @@ func (a *stmtCompiler) DoSelectStmt(s *ast.SelectStmt) { ...@@ -580,11 +584,12 @@ func (a *stmtCompiler) DoSelectStmt(s *ast.SelectStmt) {
} }
func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) { 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 // Compile init statement, if any
bc := a.blockCompiler;
if s.Init != nil { if s.Init != nil {
bc = bc.enterChild();
defer bc.exit();
bc.compileStmt(s.Init); bc.compileStmt(s.Init);
} }
...@@ -617,7 +622,7 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) { ...@@ -617,7 +622,7 @@ func (a *stmtCompiler) DoForStmt(s *ast.ForStmt) {
// If the condition is absent, it is equivalent to true. // If the condition is absent, it is equivalent to true.
a.push(func(v *vm) { v.pc = bodyPC }); a.push(func(v *vm) { v.pc = bodyPC });
} else { } else {
e := bc.compileExpr(bc.scope, s.Cond, false); e := bc.compileExpr(bc.block, s.Cond, false);
switch { switch {
case e == nil: case e == nil:
bad = true; bad = true;
...@@ -650,12 +655,12 @@ func (a *stmtCompiler) DoRangeStmt(s *ast.RangeStmt) { ...@@ -650,12 +655,12 @@ func (a *stmtCompiler) DoRangeStmt(s *ast.RangeStmt) {
*/ */
func (a *blockCompiler) compileStmt(s ast.Stmt) { func (a *blockCompiler) compileStmt(s ast.Stmt) {
if a.child != nil { if a.block.inner != nil {
log.Crash("Child scope still entered"); log.Crash("Child scope still entered");
} }
sc := &stmtCompiler{a, s.Pos(), true}; sc := &stmtCompiler{a, s.Pos(), true};
s.Visit(sc); s.Visit(sc);
if a.child != nil { if a.block.inner != nil {
log.Crash("Forgot to exit child scope"); log.Crash("Forgot to exit child scope");
} }
a.err = a.err || sc.err; a.err = a.err || sc.err;
...@@ -668,49 +673,30 @@ func (a *blockCompiler) compileStmts(block *ast.BlockStmt) { ...@@ -668,49 +673,30 @@ func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
} }
func (a *blockCompiler) enterChild() *blockCompiler { func (a *blockCompiler) enterChild() *blockCompiler {
if a.child != nil { block := a.block.enterChild();
log.Crash("Failed to exit child block before entering another child"); return &blockCompiler{
}
blockScope := a.scope.Fork();
bc := &blockCompiler{
funcCompiler: a.funcCompiler, funcCompiler: a.funcCompiler,
scope: blockScope, block: block,
returned: false, returned: false,
parent: a, parent: a,
}; };
a.child = bc;
a.push(func(v *vm) {
v.f = blockScope.NewFrame(v.f);
});
return bc;
} }
func (a *blockCompiler) exit() { func (a *blockCompiler) exit() {
if a.parent == nil { a.block.exit();
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;
} }
/* /*
* Function compiler * 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 // Create body scope
// //
// The scope of a parameter or result is the body of the // The scope of a parameter or result is the body of the
// corresponding function. // corresponding function.
bodyScope := scope.Fork(); bodyScope := b.ChildScope();
defer bodyScope.exit();
for i, t := range decl.Type.In { for i, t := range decl.Type.In {
if decl.InNames[i] != nil { if decl.InNames[i] != nil {
bodyScope.DefineVar(decl.InNames[i].Value, t); bodyScope.DefineVar(decl.InNames[i].Value, t);
...@@ -734,7 +720,7 @@ func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt ...@@ -734,7 +720,7 @@ func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt
} }
bc := &blockCompiler{ bc := &blockCompiler{
funcCompiler: fc, funcCompiler: fc,
scope: bodyScope, block: bodyScope.block,
returned: false, returned: false,
}; };
...@@ -756,7 +742,8 @@ func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt ...@@ -756,7 +742,8 @@ func (a *compiler) compileFunc(scope *Scope, decl *FuncDecl, body *ast.BlockStmt
} }
code := fc.get(); 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) { ...@@ -777,7 +764,7 @@ func CompileStmts(scope *Scope, stmts []ast.Stmt) (*Stmt, os.Error) {
fc := &funcCompiler{cc, nil, false, newCodeBuf(), false}; fc := &funcCompiler{cc, nil, false, newCodeBuf(), false};
bc := &blockCompiler{ bc := &blockCompiler{
funcCompiler: fc, funcCompiler: fc,
scope: scope, block: scope.block,
returned: false returned: false
}; };
out := make([]*Stmt, len(stmts)); out := make([]*Stmt, len(stmts));
......
...@@ -672,8 +672,6 @@ type ChanType struct { ...@@ -672,8 +672,6 @@ type ChanType struct {
*/ */
type NamedType struct { type NamedType struct {
// Declaration scope
scope *Scope;
name string; name string;
// Underlying type // Underlying type
def Type; def Type;
......
...@@ -23,13 +23,13 @@ type exprCompiler struct ...@@ -23,13 +23,13 @@ type exprCompiler struct
type typeCompiler struct { type typeCompiler struct {
*compiler; *compiler;
scope *Scope; block *block;
} }
func (a *typeCompiler) compileType(x ast.Expr) Type func (a *typeCompiler) compileType(x ast.Expr) Type
func (a *typeCompiler) compileIdent(x *ast.Ident) 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 { if def == nil {
a.diagAt(x, "%s: undefined", x.Value); a.diagAt(x, "%s: undefined", x.Value);
return nil; return nil;
...@@ -58,7 +58,7 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType) *ArrayType { ...@@ -58,7 +58,7 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType) *ArrayType {
a.diagAt(x.Len, "... array initailizers not implemented"); a.diagAt(x.Len, "... array initailizers not implemented");
return nil; return nil;
} }
l, ok := a.compileArrayLen(a.scope, x.Len); l, ok := a.compileArrayLen(a.block, x.Len);
// Compile element type // Compile element type
elem := a.compileType(x.Elt); elem := a.compileType(x.Elt);
...@@ -191,12 +191,12 @@ notimpl: ...@@ -191,12 +191,12 @@ notimpl:
* Type compiler interface * Type compiler interface
*/ */
func (a *compiler) compileType(scope *Scope, typ ast.Expr) Type { func (a *compiler) compileType(b *block, typ ast.Expr) Type {
tc := &typeCompiler{a, scope}; tc := &typeCompiler{a, b};
return tc.compileType(typ); return tc.compileType(typ);
} }
func (a *compiler) compileFuncType(scope *Scope, typ *ast.FuncType) *FuncDecl { func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
tc := &typeCompiler{a, scope}; tc := &typeCompiler{a, b};
return tc.compileFuncType(typ); return tc.compileFuncType(typ);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment