Make it only necessary to exit blocks, not scopes. Allow

variables to be given initial values in some cases, to make
building global scopes more convenient.

R=rsc
APPROVED=rsc
DELTA=29  (17 added, 0 deleted, 12 changed)
OCL=33760
CL=33766
This commit is contained in:
Austin Clements 2009-08-24 13:48:16 -07:00
parent 14be733a25
commit 9a36b8087c
4 changed files with 29 additions and 12 deletions

View File

@ -35,7 +35,7 @@ type Type interface {
isFloat() bool;
// isIdeal returns true if this is an ideal int or float.
isIdeal() bool;
// ZeroVal returns a new zero value of this type.
// Zero returns a new zero value of this type.
Zero() Value;
// String returns the string representation of this type.
String() string;
@ -82,6 +82,8 @@ type IntValue interface {
Set(int64);
}
// TODO(austin) IdealIntValue and IdealFloatValue should not exist
// because ideals are not l-values.
type IdealIntValue interface {
Value;
Get() *bignum.Integer;
@ -183,6 +185,10 @@ type Variable struct {
Index int;
// Static type of this variable
Type Type;
// Value of this variable. This is only used by Scope.NewFrame;
// therefore, it is useful for global scopes but cannot be used
// in function scopes.
Init Value;
}
type Constant struct {

View File

@ -1705,6 +1705,8 @@ func CompileExpr(scope *Scope, expr ast.Expr) (*Expr, os.Error) {
return &Expr{t, func(f *Frame, out Value) { out.(*idealFloatV).V = ec.evalIdealFloat() }}, nil;
case *stringType:
return &Expr{t, func(f *Frame, out Value) { out.(StringValue).Set(ec.evalString(f)) }}, nil;
case *ArrayType:
return &Expr{t, func(f *Frame, out Value) { out.(ArrayValue).Assign(ec.evalArray(f)) }}, nil;
case *PtrType:
return &Expr{t, func(f *Frame, out Value) { out.(PtrValue).Set(ec.evalPtr(f)) }}, nil;
case *FuncType:

View File

@ -11,7 +11,7 @@ import (
)
func (b *block) enterChild() *block {
if b.inner != nil {
if b.inner != nil && b.inner.scope == b.scope {
log.Crash("Failed to exit child block before entering another child");
}
sub := &block{
@ -28,17 +28,19 @@ func (b *block) exit() {
if b.outer == nil {
log.Crash("Cannot exit top-level block");
}
if b.outer.scope == b.scope {
if b.outer.inner != b {
log.Crash("Already exited block");
}
if b.inner != nil {
if b.inner != nil && b.inner.scope == b.scope {
log.Crash("Exit of parent block without exit of child block");
}
}
b.outer.inner = nil;
}
func (b *block) ChildScope() *Scope {
if b.inner != nil {
if b.inner != nil && b.inner.scope == b.scope {
log.Crash("Failed to exit child block before entering a child scope");
}
sub := b.enterChild();
@ -58,11 +60,11 @@ func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, D
}
func (b *block) DefineSlot(t Type) *Variable {
if b.inner != nil {
if b.inner != nil && b.inner.scope == b.scope {
log.Crash("Failed to exit child block before defining variable");
}
index := b.offset+b.numVars;
v := &Variable{token.Position{}, index, t};
v := &Variable{token.Position{}, index, t, nil};
b.numVars++;
if index+1 > b.scope.maxVars {
b.scope.maxVars = index+1;
@ -107,7 +109,14 @@ func (b *block) Lookup(name string) (level int, def Def) {
}
func (s *Scope) NewFrame(outer *Frame) *Frame {
return outer.child(s.maxVars);
fr := outer.child(s.maxVars);
for _, v := range s.defs {
switch v := v.(type) {
case *Variable:
fr.Vars[v.Index] = v.Init;
}
}
return fr;
}
func (f *Frame) Get(level int, index int) Value {

View File

@ -400,7 +400,7 @@ func (v *structV) String() string {
res := "{";
for i, v := range *v {
if i > 0 {
res += "; ";
res += ", ";
}
res += v.String();
}