]> Cypherpunks repositories - gostls13.git/commitdiff
Cleanup of Type/Value interface. Add Type.ZeroVal, replace
authorAustin Clements <aclements@csail.mit.edu>
Tue, 21 Jul 2009 20:31:23 +0000 (13:31 -0700)
committerAustin Clements <aclements@csail.mit.edu>
Tue, 21 Jul 2009 20:31:23 +0000 (13:31 -0700)
all type-specific value functions, and use ZeroVal to create
new frames.  Remove Value.Type; it was unused and difficult
for values with composite types.  Add Value.Assign methods.

R=rsc
APPROVED=rsc
DELTA=282  (135 added, 90 deleted, 57 changed)
OCL=31894
CL=31930

usr/austin/eval/decls.go
usr/austin/eval/expr.go
usr/austin/eval/scope.go
usr/austin/eval/type.go
usr/austin/eval/value.go

index f5b667970c074ad32a7ee7c1cc6ca8567173e0ba..e39a20c43d533f53d2134cd2efdc0e498fee380e 100644 (file)
@@ -12,6 +12,8 @@ import (
  * Types
  */
 
+type Value interface
+
 type Type interface {
        // literal returns this type with all names recursively
        // stripped.
@@ -28,6 +30,8 @@ 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() Value;
        // String returns the string representation of this type.
        String() string;
 }
@@ -45,9 +49,12 @@ type BoundedType interface {
  */
 
 type Value interface {
-       // TODO(austin) Is Type even necessary?
-       Type() Type;
        String() string;
+       // Assign copies another value into this one.  It should
+       // assume that the other value satisfies the same specific
+       // value interface (BoolValue, etc.), but must not assume
+       // anything about its specific type.
+       Assign(o Value);
 }
 
 type BoolValue interface {
@@ -117,7 +124,6 @@ type Variable struct {
 }
 
 type Constant struct {
-       // TODO(austin) Need Type?
        Type Type;
        Value Value;
 }
@@ -129,12 +135,13 @@ type Scope struct {
        outer *Scope;
        defs map[string] Def;
        numVars int;
+       varTypes []Type;
 }
 
 func NewRootScope() *Scope
 func (s *Scope) Fork() *Scope
 func (s *Scope) DefineVar(name string, t Type) *Variable
-func (s *Scope) DefineConst(name string, v Value) *Constant
+func (s *Scope) DefineConst(name string, t Type, v Value) *Constant
 func (s *Scope) DefineType(name string, t Type) bool
 func (s *Scope) Lookup(name string) (Def, *Scope)
 
@@ -149,3 +156,5 @@ type Frame struct {
 }
 
 func (f *Frame) Get(s *Scope, index int) Value
+
+func (s *Scope) NewFrame(outer *Frame) *Frame
index 3368b44fccfcf2ecdd77f930c5245fe6f6d3667b..6c8c9c819ed98fb98c8adf5aabf5c6dcf91ebf14 100644 (file)
@@ -632,6 +632,8 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
        }
 
        // Useful type predicates
+       // TODO(austin) The spec is wrong here.  The types must be
+       // identical, not compatible.
        compat := func() bool {
                return l.t.compatible(r.t);
        };
@@ -829,9 +831,6 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
                a.genBinOpXor(l, r);
 
        case token.AND_NOT:
-               if l.t.isIdeal() || r.t.isIdeal() {
-                       log.Crashf("&^ for ideals not implemented");
-               }
                a.genBinOpAndNot(l, r);
 
        case token.SHL:
@@ -911,11 +910,14 @@ func compileExpr(expr ast.Expr, scope *Scope, errors scanner.ErrorHandler) *expr
  */
 
 type Expr struct {
-       f func(f *Frame) Value;
+       t Type;
+       f func(f *Frame, out Value);
 }
 
 func (expr *Expr) Eval(f *Frame) Value {
-       return expr.f(f);
+       v := expr.t.Zero();
+       expr.f(f, v);
+       return v;
 }
 
 func CompileExpr(expr ast.Expr, scope *Scope) (*Expr, os.Error) {
@@ -925,26 +927,23 @@ func CompileExpr(expr ast.Expr, scope *Scope) (*Expr, os.Error) {
        if ec == nil {
                return nil, errors.GetError(scanner.Sorted);
        }
-       // TODO(austin) This still uses Value as a generic container
-       // and is the only user of the 'value' methods on each type.
-       // Need to figure out a better way to do this.
        switch t := ec.t.(type) {
        case *boolType:
-               return &Expr{func(f *Frame) Value { return t.value(ec.evalBool(f)) }}, nil;
+               return &Expr{t, func(f *Frame, out Value) { out.(BoolValue).Set(ec.evalBool(f)) }}, nil;
        case *uintType:
-               return &Expr{func(f *Frame) Value { return t.value(ec.evalUint(f)) }}, nil;
+               return &Expr{t, func(f *Frame, out Value) { out.(UintValue).Set(ec.evalUint(f)) }}, nil;
        case *intType:
-               return &Expr{func(f *Frame) Value { return t.value(ec.evalInt(f)) }}, nil;
+               return &Expr{t, func(f *Frame, out Value) { out.(IntValue).Set(ec.evalInt(f)) }}, nil;
        case *idealIntType:
-               return &Expr{func(f *Frame) Value { return t.value(ec.evalIdealInt()) }}, nil;
+               return &Expr{t, func(f *Frame, out Value) { out.(*idealIntV).V = ec.evalIdealInt() }}, nil;
        case *floatType:
-               return &Expr{func(f *Frame) Value { return t.value(ec.evalFloat(f)) }}, nil;
+               return &Expr{t, func(f *Frame, out Value) { out.(FloatValue).Set(ec.evalFloat(f)) }}, nil;
        case *idealFloatType:
-               return &Expr{func(f *Frame) Value { return t.value(ec.evalIdealFloat()) }}, nil;
+               return &Expr{t, func(f *Frame, out Value) { out.(*idealFloatV).V = ec.evalIdealFloat() }}, nil;
        case *stringType:
-               return &Expr{func(f *Frame) Value { return t.value(ec.evalString(f)) }}, nil;
+               return &Expr{t, func(f *Frame, out Value) { out.(StringValue).Set(ec.evalString(f)) }}, nil;
        case *PtrType:
-               return &Expr{func(f *Frame) Value { return t.value(ec.evalPtr(f)) }}, nil;
+               return &Expr{t, func(f *Frame, out Value) { out.(PtrValue).Set(ec.evalPtr(f)) }}, nil;
        }
        log.Crashf("unexpected type %v", ec.t);
        panic();
@@ -1282,6 +1281,11 @@ func (a *exprCompiler) genBinOpAndNot(l *exprCompiler, r *exprCompiler) {
                lf := l.asInt();
                rf := r.asInt();
                a.evalInt = func(f *Frame) int64 { return lf(f) &^ rf(f) };
+       case *idealIntType:
+               lf := l.asIdealInt();
+               rf := r.asIdealInt();
+               val := lf().AndNot(rf());
+               a.evalIdealInt = func() *bignum.Integer { return val };
        default:
                log.Crashf("unexpected result type %v at %v", l.t.literal(), a.pos);
        }
index b3622588ca6df19773eec54276a8d05bb74fbf7b..2b1a968e6f31402e5400ce3e536cd9dc96554276 100644 (file)
@@ -9,11 +9,11 @@ import (
 )
 
 func NewRootScope() *Scope {
-       return &Scope{nil, make(map[string] Def), 0};
+       return &Scope{defs: make(map[string] Def)};
 }
 
 func (s *Scope) Fork() *Scope {
-       return &Scope{s, make(map[string] Def), 0};
+       return &Scope{outer: s, defs: make(map[string] Def)};
 }
 
 func (s *Scope) DefineVar(name string, t Type) *Variable {
@@ -26,11 +26,11 @@ func (s *Scope) DefineVar(name string, t Type) *Variable {
        return v;
 }
 
-func (s *Scope) DefineConst(name string, v Value) *Constant {
+func (s *Scope) DefineConst(name string, t Type, v Value) *Constant {
        if _, ok := s.defs[name]; ok {
                return nil;
        }
-       c := &Constant{v.Type(), v};
+       c := &Constant{t, v};
        s.defs[name] = c;
        return c;
 }
@@ -53,6 +53,27 @@ func (s *Scope) Lookup(name string) (Def, *Scope) {
        return nil, 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 {
+                               ts[v.Index] = v.Type;
+                       }
+               }
+               s.varTypes = ts;
+       }
+
+       // Create frame
+       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 {
        for f.Scope != s {
                f = f.Outer;
index 1638182cd161e4434f813334fe8af60a99eb5fb0..76910402e398e1cf91ceb1cb3df8d82531dd5c3e 100644 (file)
@@ -68,7 +68,7 @@ func (boolType) String() string {
        return "bool";
 }
 
-func (t *boolType) value(v bool) BoolValue
+func (t *boolType) Zero() Value
 
 type uintType struct {
        commonType;
@@ -110,7 +110,7 @@ func (t *uintType) String() string {
        return t.name;
 }
 
-func (t *uintType) value(v uint64) UintValue
+func (t *uintType) Zero() Value
 
 func (t *uintType) minVal() *bignum.Rational {
        return bignum.Rat(0, 1);
@@ -158,7 +158,7 @@ func (t *intType) String() string {
        return t.name;
 }
 
-func (t *intType) value(v int64) IntValue
+func (t *intType) Zero() Value
 
 func (t *intType) minVal() *bignum.Rational {
        return bignum.MakeRat(bignum.Int(-1).Shl(t.Bits - 1), bignum.Nat(1));
@@ -194,7 +194,7 @@ func (t *idealIntType) String() string {
        return "ideal integer";
 }
 
-func (t *idealIntType) value(v *bignum.Integer) IdealIntValue
+func (t *idealIntType) Zero() Value
 
 type floatType struct {
        commonType;
@@ -223,7 +223,7 @@ func (t *floatType) String() string {
        return "float";
 }
 
-func (t *floatType) value(v float64) FloatValue
+func (t *floatType) Zero() Value
 
 var maxFloat32Val = bignum.MakeRat(bignum.Int(0xffffff).Shl(127-23), bignum.Nat(1));
 var maxFloat64Val = bignum.MakeRat(bignum.Int(0x1fffffffffffff).Shl(1023-52), bignum.Nat(1));
@@ -278,7 +278,7 @@ func (t *idealFloatType) String() string {
        return "ideal float";
 }
 
-func (t *idealFloatType) value(v *bignum.Rational) IdealFloatValue
+func (t *idealFloatType) Zero() Value
 
 type stringType struct {
        commonType;
@@ -298,7 +298,7 @@ func (t *stringType) String() string {
        return "string";
 }
 
-func (t *stringType) value(v string) StringValue
+func (t *stringType) Zero() Value
 
 type ArrayType struct {
        commonType;
@@ -338,7 +338,7 @@ func (t *ArrayType) String() string {
        return "[]" + t.Elem.String();
 }
 
-func (t *ArrayType) value(v []Value) ArrayValue
+func (t *ArrayType) Zero() Value
 
 /*
 func (t *ArrayType) literal() Type {
@@ -383,7 +383,7 @@ func (t *PtrType) String() string {
        return "*" + t.Elem.String();
 }
 
-func (t *PtrType) value(v Value) PtrValue
+func (t *PtrType) Zero() Value
 
 /*
 type FuncType struct {
index 7f58b55f68121bd49d317653083cac81d1aa7a5f..9847803729cc705b47bfb48f8e4a10bbd6d3ac7b 100644 (file)
@@ -16,14 +16,14 @@ import (
 
 type boolV bool
 
-func (*boolV) Type() Type {
-       return BoolType;
-}
-
 func (v *boolV) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *boolV) Assign(o Value) {
+       *v = boolV(o.(BoolValue).Get());
+}
+
 func (v *boolV) Get() bool {
        return bool(*v);
 }
@@ -32,8 +32,8 @@ func (v *boolV) Set(x bool) {
        *v = boolV(x);
 }
 
-func (t *boolType) value(v bool) BoolValue {
-       res := boolV(v);
+func (t *boolType) Zero() Value {
+       res := boolV(false);
        return &res;
 }
 
@@ -43,14 +43,14 @@ func (t *boolType) value(v bool) BoolValue {
 
 type uint8V uint8
 
-func (*uint8V) Type() Type {
-       return Uint8Type;
-}
-
 func (v *uint8V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *uint8V) Assign(o Value) {
+       *v = uint8V(o.(UintValue).Get());
+}
+
 func (v *uint8V) Get() uint64 {
        return uint64(*v);
 }
@@ -61,14 +61,14 @@ func (v *uint8V) Set(x uint64) {
 
 type uint16V uint16
 
-func (*uint16V) Type() Type {
-       return Uint16Type;
-}
-
 func (v *uint16V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *uint16V) Assign(o Value) {
+       *v = uint16V(o.(UintValue).Get());
+}
+
 func (v *uint16V) Get() uint64 {
        return uint64(*v);
 }
@@ -79,14 +79,14 @@ func (v *uint16V) Set(x uint64) {
 
 type uint32V uint32
 
-func (*uint32V) Type() Type {
-       return Uint32Type;
-}
-
 func (v *uint32V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *uint32V) Assign(o Value) {
+       *v = uint32V(o.(UintValue).Get());
+}
+
 func (v *uint32V) Get() uint64 {
        return uint64(*v);
 }
@@ -97,14 +97,14 @@ func (v *uint32V) Set(x uint64) {
 
 type uint64V uint64
 
-func (*uint64V) Type() Type {
-       return Uint64Type;
-}
-
 func (v *uint64V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *uint64V) Assign(o Value) {
+       *v = uint64V(o.(UintValue).Get());
+}
+
 func (v *uint64V) Get() uint64 {
        return uint64(*v);
 }
@@ -115,14 +115,14 @@ func (v *uint64V) Set(x uint64) {
 
 type uintV uint
 
-func (*uintV) Type() Type {
-       return UintType;
-}
-
 func (v *uintV) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *uintV) Assign(o Value) {
+       *v = uintV(o.(UintValue).Get());
+}
+
 func (v *uintV) Get() uint64 {
        return uint64(*v);
 }
@@ -133,14 +133,14 @@ func (v *uintV) Set(x uint64) {
 
 type uintptrV uintptr
 
-func (*uintptrV) Type() Type {
-       return UintptrType;
-}
-
 func (v *uintptrV) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *uintptrV) Assign(o Value) {
+       *v = uintptrV(o.(UintValue).Get());
+}
+
 func (v *uintptrV) Get() uint64 {
        return uint64(*v);
 }
@@ -149,29 +149,28 @@ func (v *uintptrV) Set(x uint64) {
        *v = uintptrV(x);
 }
 
-func (t *uintType) value(v uint64) UintValue {
-       // TODO(austin) The 'value' methods are only used for
-       // testing right now.  Get rid of them.
-       // TODO(austin) Deal with named types
+func (t *uintType) Zero() Value {
+       // TODO(austin) t may be a named type instead of one of the
+       // base types.
        switch Type(t) {
        case Uint8Type:
-               res := uint8V(v);
+               res := uint8V(0);
                return &res;
        case Uint16Type:
-               res := uint16V(v);
+               res := uint16V(0);
                return &res;
        case Uint32Type:
-               res := uint32V(v);
+               res := uint32V(0);
                return &res;
        case Uint64Type:
-               res := uint64V(v);
+               res := uint64V(0);
                return &res;
 
        case UintType:
-               res := uintV(v);
+               res := uintV(0);
                return &res;
        case UintptrType:
-               res := uintptrV(v);
+               res := uintptrV(0);
                return &res;
        }
        panic("unknown uint type ", t.String());
@@ -183,14 +182,14 @@ func (t *uintType) value(v uint64) UintValue {
 
 type int8V int8
 
-func (*int8V) Type() Type {
-       return Int8Type;
-}
-
 func (v *int8V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *int8V) Assign(o Value) {
+       *v = int8V(o.(IntValue).Get());
+}
+
 func (v *int8V) Get() int64 {
        return int64(*v);
 }
@@ -201,14 +200,14 @@ func (v *int8V) Set(x int64) {
 
 type int16V int16
 
-func (*int16V) Type() Type {
-       return Int16Type;
-}
-
 func (v *int16V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *int16V) Assign(o Value) {
+       *v = int16V(o.(IntValue).Get());
+}
+
 func (v *int16V) Get() int64 {
        return int64(*v);
 }
@@ -219,14 +218,14 @@ func (v *int16V) Set(x int64) {
 
 type int32V int32
 
-func (*int32V) Type() Type {
-       return Int32Type;
-}
-
 func (v *int32V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *int32V) Assign(o Value) {
+       *v = int32V(o.(IntValue).Get());
+}
+
 func (v *int32V) Get() int64 {
        return int64(*v);
 }
@@ -237,14 +236,14 @@ func (v *int32V) Set(x int64) {
 
 type int64V int64
 
-func (*int64V) Type() Type {
-       return Int64Type;
-}
-
 func (v *int64V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *int64V) Assign(o Value) {
+       *v = int64V(o.(IntValue).Get());
+}
+
 func (v *int64V) Get() int64 {
        return int64(*v);
 }
@@ -255,14 +254,14 @@ func (v *int64V) Set(x int64) {
 
 type intV int
 
-func (*intV) Type() Type {
-       return IntType;
-}
-
 func (v *intV) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *intV) Assign(o Value) {
+       *v = intV(o.(IntValue).Get());
+}
+
 func (v *intV) Get() int64 {
        return int64(*v);
 }
@@ -271,23 +270,23 @@ func (v *intV) Set(x int64) {
        *v = intV(x);
 }
 
-func (t *intType) value(v int64) IntValue {
+func (t *intType) Zero() Value {
        switch Type(t) {
        case Int8Type:
-               res := int8V(v);
+               res := int8V(0);
                return &res;
        case Int16Type:
-               res := int16V(v);
+               res := int16V(0);
                return &res;
        case Int32Type:
-               res := int32V(v);
+               res := int32V(0);
                return &res;
        case Int64Type:
-               res := int64V(v);
+               res := int64V(0);
                return &res;
 
        case IntType:
-               res := intV(v);
+               res := intV(0);
                return &res;
        }
        panic("unknown int type ", t.String());
@@ -301,20 +300,20 @@ type idealIntV struct {
        V *bignum.Integer;
 }
 
-func (*idealIntV) Type() Type {
-       return IdealIntType;
-}
-
 func (v *idealIntV) String() string {
        return v.V.String();
 }
 
+func (v *idealIntV) Assign(o Value) {
+       v.V = o.(IdealIntValue).Get();
+}
+
 func (v *idealIntV) Get() *bignum.Integer {
        return v.V;
 }
 
-func (t *idealIntType) value(v *bignum.Integer) IdealIntValue {
-       return &idealIntV{v};
+func (t *idealIntType) Zero() Value {
+       return &idealIntV{bignum.Int(0)};
 }
 
 /*
@@ -323,14 +322,14 @@ func (t *idealIntType) value(v *bignum.Integer) IdealIntValue {
 
 type float32V float32
 
-func (*float32V) Type() Type {
-       return Float32Type;
-}
-
 func (v *float32V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *float32V) Assign(o Value) {
+       *v = float32V(o.(FloatValue).Get());
+}
+
 func (v *float32V) Get() float64 {
        return float64(*v);
 }
@@ -341,14 +340,14 @@ func (v *float32V) Set(x float64) {
 
 type float64V float64
 
-func (*float64V) Type() Type {
-       return Float64Type;
-}
-
 func (v *float64V) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *float64V) Assign(o Value) {
+       *v = float64V(o.(FloatValue).Get());
+}
+
 func (v *float64V) Get() float64 {
        return float64(*v);
 }
@@ -359,14 +358,14 @@ func (v *float64V) Set(x float64) {
 
 type floatV float
 
-func (*floatV) Type() Type {
-       return FloatType;
-}
-
 func (v *floatV) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *floatV) Assign(o Value) {
+       *v = floatV(o.(FloatValue).Get());
+}
+
 func (v *floatV) Get() float64 {
        return float64(*v);
 }
@@ -375,16 +374,16 @@ func (v *floatV) Set(x float64) {
        *v = floatV(x);
 }
 
-func (t *floatType) value(v float64) FloatValue {
+func (t *floatType) Zero() Value {
        switch Type(t) {
        case Float32Type:
-               res := float32V(v);
+               res := float32V(0);
                return &res;
        case Float64Type:
-               res := float64V(v);
+               res := float64V(0);
                return &res;
        case FloatType:
-               res := floatV(v);
+               res := floatV(0);
                return &res;
        }
        panic("unknown float type ", t.String());
@@ -398,20 +397,20 @@ type idealFloatV struct {
        V *bignum.Rational;
 }
 
-func (*idealFloatV) Type() Type {
-       return IdealFloatType;
-}
-
 func (v *idealFloatV) String() string {
        return ratToString(v.V);
 }
 
+func (v *idealFloatV) Assign(o Value) {
+       v.V = o.(IdealFloatValue).Get();
+}
+
 func (v *idealFloatV) Get() *bignum.Rational {
        return v.V;
 }
 
-func (t *idealFloatType) value(v *bignum.Rational) IdealFloatValue {
-       return &idealFloatV{v};
+func (t *idealFloatType) Zero() Value {
+       return &idealFloatV{bignum.Rat(1, 0)};
 }
 
 /*
@@ -420,14 +419,14 @@ func (t *idealFloatType) value(v *bignum.Rational) IdealFloatValue {
 
 type stringV string
 
-func (*stringV) Type() Type {
-       return StringType;
-}
-
 func (v *stringV) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *stringV) Assign(o Value) {
+       *v = stringV(o.(StringValue).Get());
+}
+
 func (v *stringV) Get() string {
        return string(*v);
 }
@@ -436,8 +435,8 @@ func (v *stringV) Set(x string) {
        *v = stringV(x);
 }
 
-func (t *stringType) value(v string) StringValue {
-       res := stringV(v);
+func (t *stringType) Zero() Value {
+       res := stringV("");
        return &res;
 }
 
@@ -447,14 +446,18 @@ func (t *stringType) value(v string) StringValue {
 
 type arrayV []Value
 
-func (*arrayV) Type() Type {
-       panic("Not implemented");
-}
-
 func (v *arrayV) String() string {
        return fmt.Sprint(*v);
 }
 
+func (v *arrayV) Assign(o Value) {
+       oa := o.(ArrayValue);
+       l := int64(len(*v));
+       for i := int64(0); i < l; i++ {
+               (*v)[i].Assign(oa.Elem(i));
+       }
+}
+
 func (v *arrayV) Get() ArrayValue {
        return v;
 }
@@ -463,8 +466,16 @@ func (v *arrayV) Elem(i int64) Value {
        return (*v)[i];
 }
 
-func (t *ArrayType) value(v []Value) ArrayValue {
-       res := arrayV(v);
+func (t *ArrayType) Zero() Value {
+       res := arrayV(make([]Value, t.Len));
+       // TODO(austin) It's unfortunate that each element is
+       // separately heap allocated.  We could add ZeroArray to
+       // everything, though that doesn't help with multidimensional
+       // arrays.  Or we could do something unsafe.  We'll have this
+       // same problem with structs.
+       for i := int64(0); i < t.Len; i++ {
+               res[i] = t.Elem.Zero();
+       }
        return &res;
 }
 
@@ -477,14 +488,14 @@ type ptrV struct {
        target Value;
 }
 
-func (v *ptrV) Type() Type {
-       return NewPtrType(v.target.Type());
-}
-
 func (v *ptrV) String() string {
        return "&" + v.target.String();
 }
 
+func (v *ptrV) Assign(o Value) {
+       v.target = o.(PtrValue).Get();
+}
+
 func (v *ptrV) Get() Value {
        return v.target;
 }
@@ -493,7 +504,7 @@ func (v *ptrV) Set(x Value) {
        v.target = x;
 }
 
-func (t *PtrType) value(v Value) PtrValue {
-       res := ptrV{v};
+func (t *PtrType) Zero() Value {
+       res := ptrV{nil};
        return &res;
 }