]> Cypherpunks repositories - gostls13.git/commitdiff
Make Value always represent an l-value and never a generic
authorAustin Clements <aclements@csail.mit.edu>
Thu, 16 Jul 2009 00:56:17 +0000 (17:56 -0700)
committerAustin Clements <aclements@csail.mit.edu>
Thu, 16 Jul 2009 00:56:17 +0000 (17:56 -0700)
container for values.

Instead of having one evaluator function that returns a
generic Value, there is now an evaluator function for each
generalized type that simply returns a native type.

The compiler is more type-safe now because there are almost no
type conversions at evaluation time and it's impossible to
invoke a nil evaluator function during evaluation.  This also
makes ideals and pointers really clean.

As an added bonus, expression evaluation should be faster
because it doesn't require heap allocation for every
intermediate value, type switches, or lots of conversions to
and from Value.  It also involves fewer function calls.

R=rsc
APPROVED=rsc
DELTA=431  (280 added, 115 deleted, 36 changed)
OCL=31705
CL=31709

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 2881a334b590cd00eea42e538ed54f89eb7881d9..ead2a4d859703f7a0b7501171e2dd89f70f8303c 100644 (file)
@@ -136,3 +136,5 @@ type Frame struct {
        Scope *Scope;
        Vars []Value;
 }
+
+func (f *Frame) Get(s *Scope, index int) Value
index a96e293d01e3319823ee850a1fcb57187b7884be..78b17668ed05461046f3e9edd5cfd4658b9144ae 100644 (file)
@@ -30,20 +30,30 @@ type exprCompiler struct {
        *exprContext;
        pos token.Position;
        t Type;
-       // TODO(austin) Should there be separate f's for each specific
-       // Value interface?  We spend a lot of time calling f's and
-       // just blindly casting the result since we already know its type.
-       f func (f *Frame) Value;
+       // Evaluate this node as the given type.
+       evalBool func (f *Frame) bool;
+       evalUint func (f *Frame) uint64;
+       evalInt func (f *Frame) int64;
+       evalIdealInt func () *bignum.Integer;
+       evalFloat func (f *Frame) float64;
+       evalIdealFloat func () *bignum.Rational;
+       evalString func (f *Frame) string;
+       evalPtr func (f *Frame) Value;
+       // Evaluate to the "address of" this value; that is, the
+       // settable Value object.  nil for expressions whose address
+       // cannot be taken.
+       evalAddr func (f *Frame) Value;
        // A short string describing this expression for error
        // messages.  Only necessary if t != nil.
        desc string;
-       // True if the address-of operator can be applied to this
-       // result.
-       addressable bool;
 }
 
 func newExprCompiler(c *exprContext, pos token.Position) *exprCompiler {
-       return &exprCompiler{c, pos, nil, nil, "<missing description>", false};
+       return &exprCompiler{
+               exprContext: c,
+               pos: pos,
+               desc: "<missing description>"
+       };
 }
 
 func (a *exprCompiler) fork(x ast.Expr) *exprCompiler {
@@ -64,10 +74,85 @@ func (a *exprCompiler) diagOpTypes(op token.Token, lt Type, rt Type) {
        a.diag("illegal operand types for '%v' operator\n\t%v\n\t%v", op, lt, rt);
 }
 
+func (a *exprCompiler) asBool() (func (f *Frame) bool) {
+       if a.evalBool == nil {
+               log.Crashf("tried to get %v node as boolType", a.t);
+       }
+       return a.evalBool;
+}
+
+func (a *exprCompiler) asUint() (func (f *Frame) uint64) {
+       if a.evalUint == nil {
+               log.Crashf("tried to get %v node as uintType", a.t);
+       }
+       return a.evalUint;
+}
+
+func (a *exprCompiler) asInt() (func (f *Frame) int64) {
+       if a.evalInt == nil {
+               log.Crashf("tried to get %v node as intType", a.t);
+       }
+       return a.evalInt;
+}
+
+func (a *exprCompiler) asIdealInt() (func () *bignum.Integer) {
+       if a.evalIdealInt == nil {
+               log.Crashf("tried to get %v node as idealIntType", a.t);
+       }
+       return a.evalIdealInt;
+}
+
+func (a *exprCompiler) asFloat() (func (f *Frame) float64) {
+       if a.evalFloat == nil {
+               log.Crashf("tried to get %v node as floatType", a.t);
+       }
+       return a.evalFloat;
+}
+
+func (a *exprCompiler) asIdealFloat() (func () *bignum.Rational) {
+       if a.evalIdealFloat == nil {
+               log.Crashf("tried to get %v node as idealFloatType", a.t);
+       }
+       return a.evalIdealFloat;
+}
+
+func (a *exprCompiler) asString() (func (f *Frame) string) {
+       if a.evalString == nil {
+               log.Crashf("tried to get %v node as stringType", a.t);
+       }
+       return a.evalString;
+}
+
+func (a *exprCompiler) asPtr() (func (f *Frame) Value) {
+       if a.evalPtr == nil {
+               log.Crashf("tried to get %v node as PtrType", a.t);
+       }
+       return a.evalPtr;
+}
+
 func (a *exprCompiler) DoBadExpr(x *ast.BadExpr) {
        // Do nothing.  Already reported by parser.
 }
 
+func (a *exprCompiler) genIdent(t Type, s *Scope, index int) {
+       switch _ := t.literal().(type) {
+       case *boolType:
+               a.evalBool = func (f *Frame) bool { return f.Get(s, index).(BoolValue).Get() };
+       case *uintType:
+               a.evalUint = func (f *Frame) uint64 { return f.Get(s, index).(UintValue).Get() };
+       case *intType:
+               a.evalInt = func (f *Frame) int64 { return f.Get(s, index).(IntValue).Get() };
+       case *floatType:
+               a.evalFloat = func (f *Frame) float64 { return f.Get(s, index).(FloatValue).Get() };
+       case *stringType:
+               a.evalString = func (f *Frame) string { return f.Get(s, index).(StringValue).Get() };
+       case *PtrType:
+               a.evalPtr = func (f *Frame) Value { return f.Get(s, index).(PtrValue).Get() };
+       default:
+               log.Crashf("unexpected variable type %v at %v", t.literal(), a.pos);
+       }
+}
+
 func (a *exprCompiler) DoIdent(x *ast.Ident) {
        def, dscope := a.scope.Lookup(x.Value);
        if def == nil {
@@ -77,7 +162,16 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) {
        switch def := def.(type) {
        case *Constant:
                a.t = def.Type;
-               a.f = func (*Frame) Value { return def.Value };
+               switch _ := a.t.literal().(type) {
+               case *idealIntType:
+                       val := def.Value.(IdealIntValue).Get();
+                       a.evalIdealInt = func () *bignum.Integer { return val; };
+               case *idealFloatType:
+                       val := def.Value.(IdealFloatValue).Get();
+                       a.evalIdealFloat = func () *bignum.Rational { return val; };
+               default:
+                       log.Crashf("unexpected constant type: %v", a.t);
+               }
                a.desc = "constant";
        case *Variable:
                if a.constant {
@@ -86,15 +180,11 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) {
                }
                a.t = def.Type;
                defidx := def.Index;
-               a.f = func (f *Frame) Value {
-                       // TODO(austin) Make Frame do this?
-                       for f.Scope != dscope {
-                               f = f.Outer;
-                       }
-                       return f.Vars[defidx];
+               a.genIdent(def.Type, dscope, defidx);
+               a.evalAddr = func (f *Frame) Value {
+                       return f.Get(dscope, defidx);
                };
                a.desc = "variable";
-               a.addressable = true;
        case Type:
                a.diag("type %v used as expression", x.Value);
        default:
@@ -104,8 +194,7 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) {
 
 func (a *exprCompiler) doIdealInt(i *bignum.Integer) {
        a.t = IdealIntType;
-       val := &idealIntV{i};
-       a.f = func (*Frame) Value { return val };
+       a.evalIdealInt = func () *bignum.Integer { return i };
 }
 
 func (a *exprCompiler) DoIntLit(x *ast.IntLit) {
@@ -134,16 +223,14 @@ func (a *exprCompiler) DoCharLit(x *ast.CharLit) {
 
 func (a *exprCompiler) DoFloatLit(x *ast.FloatLit) {
        a.t = IdealFloatType;
-       i, _, _2 := bignum.RatFromString(string(x.Value), 0);
-       val := &idealFloatV{i};
-       a.f = func (*Frame) Value { return val };
+       f, _, _2 := bignum.RatFromString(string(x.Value), 0);
+       a.evalIdealFloat = func () *bignum.Rational { return f };
        a.desc = "float literal";
 }
 
 func (a *exprCompiler) doString(s string) {
        a.t = StringType;
-       val := stringV(s);
-       a.f = func (*Frame) Value { return &val };
+       a.evalString = func (*Frame) string { return s };
 }
 
 func (a *exprCompiler) DoStringLit(x *ast.StringLit) {
@@ -198,6 +285,26 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
        log.Crash("Not implemented");
 }
 
+func (a *exprCompiler) genStarOp(v *exprCompiler) {
+       vf := v.asPtr();
+       switch _ := v.t.literal().(type) {
+       case *boolType:
+               a.evalBool = func (f *Frame) bool { return vf(f).(BoolValue).Get() };
+       case *uintType:
+               a.evalUint = func (f *Frame) uint64 { return vf(f).(UintValue).Get() };
+       case *intType:
+               a.evalInt = func (f *Frame) int64 { return vf(f).(IntValue).Get() };
+       case *floatType:
+               a.evalFloat = func (f *Frame) float64 { return vf(f).(FloatValue).Get() };
+       case *stringType:
+               a.evalString = func (f *Frame) string { return vf(f).(StringValue).Get() };
+       case *PtrType:
+               a.evalPtr = func (f *Frame) Value { return vf(f).(PtrValue).Get() };
+       default:
+               log.Crashf("unexpected operand type %v at %v", v.t.literal(), a.pos);
+       }
+}
+
 func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) {
        v := a.fork(x.X);
        if v.t == nil {
@@ -207,16 +314,40 @@ func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) {
        switch vt := v.t.(type) {
        case *PtrType:
                a.t = vt.Elem();
-               vf := v.f;
-               a.f = func (f *Frame) Value { return vf(f).(PtrValue).Get() };
+               a.genStarOp(v);
+               vf := v.asPtr();
+               a.evalAddr = func (f *Frame) Value { return vf(f) };
                a.desc = "* expression";
-               a.addressable = true;
 
        default:
                a.diagOpType(token.MUL, v.t);
        }
 }
 
+func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler) {
+       switch _ := v.t.literal().(type) {
+       case *uintType:
+               vf := v.asUint();
+               a.evalUint = func (f *Frame) uint64 { return -vf(f) };
+       case *intType:
+               vf := v.asInt();
+               a.evalInt = func (f *Frame) int64 { return -vf(f) };
+       case *idealIntType:
+               vf := v.asIdealInt();
+               val := vf().Neg();
+               a.evalIdealInt = func () *bignum.Integer { return val };
+       case *floatType:
+               vf := v.asFloat();
+               a.evalFloat = func (f *Frame) float64 { return -vf(f) };
+       case *idealFloatType:
+               vf := v.asIdealFloat();
+               val := vf().Neg();
+               a.evalIdealFloat = func () *bignum.Rational { return val };
+       default:
+               log.Crashf("unexpected operand type %v at %v", v.t.literal(), a.pos);
+       }
+}
+
 func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
        switch x.Op {
        case token.SUB:
@@ -226,33 +357,15 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
                        return;
                }
 
-               a.t = v.t;
-               vf := v.f;
-               switch vt := v.t.literal().(type) {
-               case *uintType:
-                       a.f = func (f *Frame) Value {
-                               return vt.value(-vf(f).(UintValue).Get());
-                       };
-               case *intType:
-                       a.f = func (f *Frame) Value {
-                               return vt.value(-vf(f).(IntValue).Get());
-                       };
-               case *idealIntType:
-                       val := vt.value(vf(nil).(IdealIntValue).Get().Neg());
-                       a.f = func (f *Frame) Value { return val };
-               case *floatType:
-                       a.f = func (f *Frame) Value {
-                               return vt.value(-vf(f).(FloatValue).Get());
-                       };
-               case *idealFloatType:
-                       val := vt.value(vf(nil).(IdealFloatValue).Get().Neg());
-                       a.f = func (f *Frame) Value { return val };
-               default:
-                       a.t = nil;
+               if !v.t.isInteger() && !v.t.isFloat() {
                        a.diagOpType(x.Op, v.t);
                        return;
                }
 
+               a.t = v.t;
+               a.genUnaryOpNeg(v);
+               a.desc = "- expression";
+
        case token.AND:
                // Address-of
                v := a.fork(x.X);
@@ -264,7 +377,7 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
                // the address of its operand, which must be a
                // variable, pointer indirection, field selector, or
                // array or slice indexing operation.
-               if !v.addressable {
+               if v.evalAddr == nil {
                        a.diag("cannot take the address of %s", v.desc);
                        return;
                }
@@ -276,8 +389,8 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
                at := NewPtrType(v.t);
                a.t = at;
 
-               vf := v.f;
-               a.f = func (f *Frame) Value { return at.value(vf(f)) };
+               vf := v.evalAddr;
+               a.evalPtr = func (f *Frame) Value { return vf(f) };
                a.desc = "& expression";
 
        default:
@@ -293,7 +406,6 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler {
                log.Crashf("attempted to convert from %v, expected ideal", a.t);
        }
 
-       val := a.f(nil);
        var rat *bignum.Rational;
 
        // It is erroneous to assign a value with a non-zero
@@ -302,13 +414,14 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler {
        // represented by the type of the variable.
        switch a.t {
        case IdealFloatType:
-               rat = val.(IdealFloatValue).Get();
+               rat = a.asIdealFloat()();
                if t.isInteger() && !rat.IsInt() {
                        a.diag("constant %v truncated to integer", ratToString(rat));
                        return nil;
                }
        case IdealIntType:
-               rat = bignum.MakeRat(val.(IdealIntValue).Get(), bignum.Nat(1));
+               i := a.asIdealInt()();
+               rat = bignum.MakeRat(i, bignum.Nat(1));
        default:
                log.Crashf("unexpected ideal type %v", a.t);
        }
@@ -326,38 +439,128 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler {
        }
 
        // Convert rat to type t.
+       res := newExprCompiler(a.exprContext, a.pos);
+       res.t = t;
+       res.desc = a.desc;
        switch t := t.(type) {
        case *uintType:
                n, d := rat.Value();
                f := n.Quo(bignum.MakeInt(false, d));
                v := f.Abs().Value();
-               val = t.value(v);
+               res.evalUint = func (*Frame) uint64 { return v };
        case *intType:
                n, d := rat.Value();
                f := n.Quo(bignum.MakeInt(false, d));
                v := f.Value();
-               val = t.value(v);
+               res.evalInt = func (*Frame) int64 { return v };
        case *idealIntType:
                n, d := rat.Value();
                f := n.Quo(bignum.MakeInt(false, d));
-               val = t.value(f);
+               res.evalIdealInt = func () *bignum.Integer { return f };
        case *floatType:
                n, d := rat.Value();
                v := float64(n.Value())/float64(d.Value());
-               val = t.value(v);
+               res.evalFloat = func (*Frame) float64 { return v };
        case *idealFloatType:
-               val = t.value(rat);
+               res.evalIdealFloat = func () *bignum.Rational { return rat };
        default:
                log.Crashf("cannot convert to type %T", t);
        }
 
-       res := newExprCompiler(a.exprContext, a.pos);
-       res.t = t;
-       res.f = func (*Frame) Value { return val };
-       res.desc = a.desc;
        return res;
 }
 
+func (a *exprCompiler) genBinOpAdd(l *exprCompiler, r *exprCompiler) {
+       switch _ := l.t.literal().(type) {
+       case *uintType:
+               lf := l.asUint();
+                rf := r.asUint();
+                a.evalUint = func (f *Frame) uint64 { return lf(f) + rf(f) };
+       case *intType:
+               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().Add(rf());
+                a.evalIdealInt = func () *bignum.Integer { return val };
+       case *floatType:
+               lf := l.asFloat();
+                rf := r.asFloat();
+                a.evalFloat = func (f *Frame) float64 { return lf(f) + rf(f) };
+       case *idealFloatType:
+               lf := l.asIdealFloat();
+                rf := r.asIdealFloat();
+               val := lf().Add(rf());
+                a.evalIdealFloat = func () *bignum.Rational { return val };
+       case *stringType:
+               lf := l.asString();
+                rf := r.asString();
+                a.evalString = func (f *Frame) string { return lf(f) + rf(f) };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genBinOpSub(l *exprCompiler, r *exprCompiler) {
+       switch _ := l.t.literal().(type) {
+       case *uintType:
+               lf := l.asUint();
+                rf := r.asUint();
+                a.evalUint = func (f *Frame) uint64 { return lf(f) - rf(f) };
+       case *intType:
+               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().Sub(rf());
+                a.evalIdealInt = func () *bignum.Integer { return val };
+       case *floatType:
+               lf := l.asFloat();
+                rf := r.asFloat();
+                a.evalFloat = func (f *Frame) float64 { return lf(f) - rf(f) };
+       case *idealFloatType:
+               lf := l.asIdealFloat();
+                rf := r.asIdealFloat();
+               val := lf().Sub(rf());
+                a.evalIdealFloat = func () *bignum.Rational { return val };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genBinOpQuo(l *exprCompiler, r *exprCompiler) {
+       switch _ := l.t.literal().(type) {
+       case *uintType:
+               lf := l.asUint();
+                rf := r.asUint();
+                a.evalUint = func (f *Frame) uint64 { return lf(f) / rf(f) };
+       case *intType:
+               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().Quo(rf());
+                a.evalIdealInt = func () *bignum.Integer { return val };
+       case *floatType:
+               lf := l.asFloat();
+                rf := r.asFloat();
+                a.evalFloat = func (f *Frame) float64 { return lf(f) / rf(f) };
+       case *idealFloatType:
+               lf := l.asIdealFloat();
+                rf := r.asIdealFloat();
+               val := lf().Quo(rf());
+                a.evalIdealFloat = func () *bignum.Rational { return val };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
 var opDescs = make(map[token.Token] string)
 
 func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
@@ -539,94 +742,18 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
        }
 
        // Compile
-       // TODO(austin) There has got to be a better way to do this.
-       lf := l.f;
-       rf := r.f;
        switch x.Op {
        case token.ADD:
-               switch lt := l.t.literal().(type) {
-               case *uintType:
-                       // TODO(austin) lt.value allocates.  It would
-                       // be awesome if we could avoid that for
-                       // intermediate values.  That might be
-                       // possible if we pass the closure a place to
-                       // store its result.
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(UintValue).Get() + rf(f).(UintValue).Get());
-                       };
-               case *intType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(IntValue).Get() + rf(f).(IntValue).Get());
-                       };
-               case *idealIntType:
-                       val := lt.value(lf(nil).(IdealIntValue).Get().Add(rf(nil).(IdealIntValue).Get()));
-                       a.f = func (f *Frame) Value { return val };
-               case *floatType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(FloatValue).Get() + rf(f).(FloatValue).Get());
-                       };
-               case *idealFloatType:
-                       val := lt.value(lf(nil).(IdealFloatValue).Get().Add(rf(nil).(IdealFloatValue).Get()));
-                       a.f = func (f *Frame) Value { return val };
-               case *stringType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(StringValue).Get() + rf(f).(StringValue).Get());
-                       };
-               default:
-                       // Shouldn't have passed type checking
-                       log.Crashf("unexpected left operand type %v at %v", l.t.literal(), x.Pos());
-               }
+               a.genBinOpAdd(l, r);
 
        case token.SUB:
-               switch lt := l.t.literal().(type) {
-               case *uintType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(UintValue).Get() - rf(f).(UintValue).Get());
-                       };
-               case *intType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(IntValue).Get() - rf(f).(IntValue).Get());
-                       };
-               case *idealIntType:
-                       val := lt.value(lf(nil).(IdealIntValue).Get().Sub(rf(nil).(IdealIntValue).Get()));
-                       a.f = func (f *Frame) Value { return val };
-               case *floatType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(FloatValue).Get() - rf(f).(FloatValue).Get());
-                       };
-               case *idealFloatType:
-                       val := lt.value(lf(nil).(IdealFloatValue).Get().Sub(rf(nil).(IdealFloatValue).Get()));
-                       a.f = func (f *Frame) Value { return val };
-               default:
-                       // Shouldn't have passed type checking
-                       log.Crashf("unexpected left operand type %v at %v", l.t.literal(), x.Pos());
-               }
+               a.genBinOpSub(l, r);
 
        case token.QUO:
                // TODO(austin) What if divisor is zero?
-               switch lt := l.t.literal().(type) {
-               case *uintType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(UintValue).Get() / rf(f).(UintValue).Get());
-                       };
-               case *intType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(IntValue).Get() / rf(f).(IntValue).Get());
-                       };
-               case *idealIntType:
-                       val := lt.value(lf(nil).(IdealIntValue).Get().Quo(rf(nil).(IdealIntValue).Get()));
-                       a.f = func (f *Frame) Value { return val };
-               case *floatType:
-                       a.f = func (f *Frame) Value {
-                               return lt.value(lf(f).(FloatValue).Get() / rf(f).(FloatValue).Get());
-                       };
-               case *idealFloatType:
-                       val := lt.value(lf(nil).(IdealFloatValue).Get().Quo(rf(nil).(IdealFloatValue).Get()));
-                       a.f = func (f *Frame) Value { return val };
-               default:
-                       // Shouldn't have passed type checking
-                       log.Crashf("unexpected left operand type %v at %v", l.t.literal(), x.Pos());
-               }
+               // TODO(austin) Clear higher bits that may have
+               // accumulated in our temporary.
+               a.genBinOpQuo(l, r);
 
        default:
                log.Crashf("Compilation of binary op %v not implemented", x.Op);
@@ -691,5 +818,27 @@ func CompileExpr(expr ast.Expr, scope *Scope) *Expr {
        if ec == nil {
                return nil;
        }
-       return &Expr{ec.f};
+       // 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)) }};
+       case *uintType:
+               return &Expr{func (f *Frame) Value { return t.value(ec.evalUint(f)) }};
+       case *intType:
+               return &Expr{func (f *Frame) Value { return t.value(ec.evalInt(f)) }};
+       case *idealIntType:
+               return &Expr{func (f *Frame) Value { return t.value(ec.evalIdealInt()) }};
+       case *floatType:
+               return &Expr{func (f *Frame) Value { return t.value(ec.evalFloat(f)) }};
+       case *idealFloatType:
+               return &Expr{func (f *Frame) Value { return t.value(ec.evalIdealFloat()) }};
+       case *stringType:
+               return &Expr{func (f *Frame) Value { return t.value(ec.evalString(f)) }};
+       case *PtrType:
+               return &Expr{func (f *Frame) Value { return t.value(ec.evalPtr(f)) }};
+       }
+       log.Crashf("unexpected type %v", ec.t);
+       return nil;
 }
index e4e54c45abf0fb47e8ca139e4d8e15d9ff44863c..b3622588ca6df19773eec54276a8d05bb74fbf7b 100644 (file)
@@ -52,3 +52,10 @@ func (s *Scope) Lookup(name string) (Def, *Scope) {
        }
        return nil, nil;
 }
+
+func (f *Frame) Get(s *Scope, index int) Value {
+       for f.Scope != s {
+               f = f.Outer;
+       }
+       return f.Vars[index];
+}
index 398d75197fd41e691f27429dd1d9bf731d6a9d90..23f74649e013a2c515f2ee0698bdf87dcb364bf2 100644 (file)
@@ -59,6 +59,8 @@ func (boolType) String() string {
        return "bool";
 }
 
+func (t *boolType) value(v bool) BoolValue
+
 type uintType struct {
        commonType;
 
index 9ca09cd358418707b78a1f2349305d3ac661b488..5849c16d81de08a5acd408dc28d14bf2e0aa8b15 100644 (file)
@@ -32,6 +32,11 @@ func (v *boolV) Set(x bool) {
        *v = boolV(x);
 }
 
+func (t *boolType) value(v bool) BoolValue {
+       res := boolV(v);
+       return &res;
+}
+
 /*
  * Uint
  */
@@ -145,8 +150,8 @@ func (v *uintptrV) Set(x uint64) {
 }
 
 func (t *uintType) value(v uint64) UintValue {
-       // TODO(austin) This executes are run-time, even though
-       // virtually all of the logic can be done at type-check time.
+       // TODO(austin) The 'value' methods are only used for
+       // testing right now.  Get rid of them.
        // TODO(austin) Deal with named types
        switch Type(t) {
        case Uint8Type: