]> Cypherpunks repositories - gostls13.git/commitdiff
Implement all unary and binary arithmetic operators.
authorAustin Clements <aclements@csail.mit.edu>
Fri, 17 Jul 2009 17:38:44 +0000 (10:38 -0700)
committerAustin Clements <aclements@csail.mit.edu>
Fri, 17 Jul 2009 17:38:44 +0000 (10:38 -0700)
R=rsc
APPROVED=rsc
DELTA=689  (497 added, 169 deleted, 23 changed)
OCL=31755
CL=31772

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

index ead2a4d859703f7a0b7501171e2dd89f70f8303c..87d700538e6bbfc3b9e83c0b6fdd6460b02658d5 100644 (file)
@@ -20,6 +20,8 @@ type Type interface {
        // compatible returns true if this type is compatible with o.
        // XXX Assignment versus comparison compatibility?
        compatible(o Type) bool;
+       // isBoolean returns true if this is a boolean type.
+       isBoolean() bool;
        // isInteger returns true if this is an integer type.
        isInteger() bool;
        // isFloat returns true if this is a floating type.
index 78b17668ed05461046f3e9edd5cfd4658b9144ae..595650b87c0eb4f3813cfb6b528601585fc5bf62 100644 (file)
@@ -56,6 +56,25 @@ func newExprCompiler(c *exprContext, pos token.Position) *exprCompiler {
        };
 }
 
+// Operator generators
+// TODO(austin) Remove these forward declarations
+func (a *exprCompiler) genIdentOp(t Type, s *Scope, index int)
+func (a *exprCompiler) genStarOp(v *exprCompiler)
+func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler)
+func (a *exprCompiler) genUnaryOpNot(v *exprCompiler)
+func (a *exprCompiler) genUnaryOpXor(v *exprCompiler)
+func (a *exprCompiler) genBinOpAdd(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpSub(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpMul(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpQuo(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpRem(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpAnd(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpOr(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpXor(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpAndNot(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpShl(l *exprCompiler, r *exprCompiler)
+func (a *exprCompiler) genBinOpShr(l *exprCompiler, r *exprCompiler)
+
 func (a *exprCompiler) fork(x ast.Expr) *exprCompiler {
        ec := newExprCompiler(a.exprContext, x.Pos());
        x.Visit(ec);
@@ -134,25 +153,6 @@ 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 {
@@ -180,7 +180,7 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) {
                }
                a.t = def.Type;
                defidx := def.Index;
-               a.genIdent(def.Type, dscope, defidx);
+               a.genIdentOp(def.Type, dscope, defidx);
                a.evalAddr = func (f *Frame) Value {
                        return f.Get(dscope, defidx);
                };
@@ -285,26 +285,6 @@ 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 {
@@ -324,55 +304,39 @@ func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) {
        }
 }
 
-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);
-       }
-}
+var unaryOpDescs = make(map[token.Token] string)
 
 func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
+       v := a.fork(x.X);
+       if v.t == nil {
+               return;
+       }
+
+       // Type check
        switch x.Op {
-       case token.SUB:
-               // Negation
-               v := a.fork(x.X);
-               if v.t == nil {
+       case token.ADD, token.SUB:
+               if !v.t.isInteger() && !v.t.isFloat() {
+                       a.diagOpType(x.Op, v.t);
                        return;
                }
+               a.t = v.t;
 
-               if !v.t.isInteger() && !v.t.isFloat() {
+       case token.NOT:
+               if !v.t.isBoolean() {
                        a.diagOpType(x.Op, v.t);
                        return;
                }
+               // TODO(austin) Unnamed bool?  Named bool?
+               a.t = BoolType;
 
-               a.t = v.t;
-               a.genUnaryOpNeg(v);
-               a.desc = "- expression";
-
-       case token.AND:
-               // Address-of
-               v := a.fork(x.X);
-               if v.t == nil {
+       case token.XOR:
+               if !v.t.isInteger() {
+                       a.diagOpType(x.Op, v.t);
                        return;
                }
+               a.t = v.t;
 
+       case token.AND:
                // The unary prefix address-of operator & generates
                // the address of its operand, which must be a
                // variable, pointer indirection, field selector, or
@@ -386,15 +350,43 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
                // address of a function result variable" once I have
                // function result variables.
 
-               at := NewPtrType(v.t);
-               a.t = at;
+               a.t = NewPtrType(v.t);
+
+       case token.ARROW:
+               log.Crashf("Unary op %v not implemented", x.Op);
 
+       default:
+               log.Crashf("unknown unary operator %v", x.Op);
+       }
+
+       var ok bool;
+       a.desc, ok = unaryOpDescs[x.Op];
+       if !ok {
+               a.desc = "unary " + x.Op.String() + " expression";
+               unaryOpDescs[x.Op] = a.desc;
+       }
+
+       // Compile
+       switch x.Op {
+       case token.ADD:
+               // Just compile it out
+               a = v;
+
+       case token.SUB:
+               a.genUnaryOpNeg(v);
+
+       case token.NOT:
+               a.genUnaryOpNot(v);
+
+       case token.XOR:
+               a.genUnaryOpXor(v);
+
+       case token.AND:
                vf := v.evalAddr;
                a.evalPtr = func (f *Frame) Value { return vf(f) };
-               a.desc = "& expression";
 
        default:
-               log.Crashf("Unary op %v not implemented", x.Op);
+               log.Crashf("Compilation of unary op %v not implemented", x.Op);
        }
 }
 
@@ -470,98 +462,7 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler {
        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)
+var binOpDescs = make(map[token.Token] string)
 
 func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
        l, r := a.fork(x.X), a.fork(x.Y);
@@ -586,10 +487,11 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
        // relevant only for / and %?  If I add an ideal int and an
        // ideal float, I get an ideal float.
 
-       // Except in shift expressions, if one operand has numeric
-       // type and the other operand is an ideal number, the ideal
-       // number is converted to match the type of the other operand.
        if x.Op != token.SHL && x.Op != token.SHR {
+               // Except in shift expressions, if one operand has
+               // numeric type and the other operand is an ideal
+               // number, the ideal number is converted to match the
+               // type of the other operand.
                if l.t.isInteger() && !l.t.isIdeal() && r.t.isIdeal() {
                        r = r.convertTo(l.t);
                } else if r.t.isInteger() && !r.t.isIdeal() && l.t.isIdeal() {
@@ -657,22 +559,50 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
                a.t = l.t;
 
        case token.SHL, token.SHR:
+               // XXX(Spec) Is it okay for the right operand to be an
+               // ideal float with no fractional part?  "The right
+               // operand in a shift operation must be always be of
+               // unsigned integer type or an ideal number that can
+               // be safely converted into an unsigned integer type
+               // (§Arithmetic operators)" suggests so.
+
+               if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) {
+                       a.diagOpTypes(x.Op, origlt, origrt);
+                       return;
+               }
+
                // The right operand in a shift operation must be
                // always be of unsigned integer type or an ideal
                // number that can be safely converted into an
                // unsigned integer type.
                if r.t.isIdeal() {
-                       r = r.convertTo(UintType);
-                       if r == nil {
+                       r2 := r.convertTo(UintType);
+                       if r2 == nil {
                                return;
                        }
-               }
-
-               if !integers() {
-                       a.diagOpTypes(x.Op, origlt, origrt);
-                       return;
-               }
-               if _, ok := r.t.literal().(*uintType); !ok {
+                       // If the left operand is ideal, we use the
+                       // original right operand so we can perform
+                       // constant evaluation.  Otherwise, we use the
+                       // conversion.
+                       if !l.t.isIdeal() {
+                               r = r2;
+                               // XXX(Spec) What is the meaning of
+                               // "ideal >> non-ideal"?  Russ says
+                               // the ideal should be converted to
+                               // an int.  6g says it's illegal.
+                               l = l.convertTo(IntType);
+                               if l == nil {
+                                       return;
+                               }
+                       } else if r.t.isFloat() {
+                               // Convert it to an ideal int to
+                               // simplify the cases
+                               r = r.convertTo(IdealIntType);
+                               if r == nil {
+                                       log.Crashf("conversion to uintType succeeded, but conversion to idealIntType failed");
+                               }
+                       }
+               } else if _, ok := r.t.literal().(*uintType); !ok {
                        a.diag("right operand of shift must be unsigned");
                        return;
                }
@@ -735,10 +665,10 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
        }
 
        var ok bool;
-       a.desc, ok = opDescs[x.Op];
+       a.desc, ok = binOpDescs[x.Op];
        if !ok {
                a.desc = x.Op.String() + " expression";
-               opDescs[x.Op] = a.desc;
+               binOpDescs[x.Op] = a.desc;
        }
 
        // Compile
@@ -749,12 +679,50 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
        case token.SUB:
                a.genBinOpSub(l, r);
 
+       case token.MUL:
+               a.genBinOpMul(l, r);
+
        case token.QUO:
                // TODO(austin) What if divisor is zero?
                // TODO(austin) Clear higher bits that may have
                // accumulated in our temporary.
                a.genBinOpQuo(l, r);
 
+       case token.REM:
+               // TODO(austin) What if divisor is zero?
+               // TODO(austin) Clear higher bits that may have
+               // accumulated in our temporary.
+               a.genBinOpRem(l, r);
+
+       case token.AND:
+               a.genBinOpAnd(l, r);
+
+       case token.OR:
+               a.genBinOpOr(l, r);
+
+       case token.XOR:
+               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:
+               // TODO(austin) bignum.Integer.Shl takes a uint
+               if r.t.isIdeal() {
+                       log.Crashf("<< ideal not implemented");
+               }
+               a.genBinOpShl(l, r);
+
+       case token.SHR:
+               // TODO(austin) bignum.Integer.Shr takes a uint
+               if r.t.isIdeal() {
+                       log.Crashf(">> ideal not implemented");
+               }
+               a.genBinOpShr(l, r);
+
        default:
                log.Crashf("Compilation of binary op %v not implemented", x.Op);
        }
@@ -842,3 +810,353 @@ func CompileExpr(expr ast.Expr, scope *Scope) *Expr {
        log.Crashf("unexpected type %v", ec.t);
        return nil;
 }
+
+/*
+ * Operator generators
+ * Everything below here is MACHINE GENERATED by gen.py genOps
+ */
+
+func (a *exprCompiler) genIdentOp(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 identifier type %v at %v", t.literal(), a.pos);
+       }
+}
+
+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) 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) genUnaryOpNot(v *exprCompiler) {
+       switch _ := v.t.literal().(type) {
+       case *boolType:
+               vf := v.asBool();
+               a.evalBool = func(f *Frame) bool { return !vf(f) };
+       default:
+               log.Crashf("unexpected operand type %v at %v", v.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genUnaryOpXor(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().Sub(bignum.Int(1));
+               a.evalIdealInt = func() *bignum.Integer { return val };
+       default:
+               log.Crashf("unexpected operand type %v at %v", v.t.literal(), a.pos);
+       }
+}
+
+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) genBinOpMul(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().Mul(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().Mul(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);
+       }
+}
+
+func (a *exprCompiler) genBinOpRem(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().Rem(rf());
+               a.evalIdealInt = func() *bignum.Integer { return val };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genBinOpAnd(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().And(rf());
+               a.evalIdealInt = func() *bignum.Integer { return val };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genBinOpOr(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().Or(rf());
+               a.evalIdealInt = func() *bignum.Integer { return val };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genBinOpXor(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().Xor(rf());
+               a.evalIdealInt = func() *bignum.Integer { return val };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genBinOpAndNot(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) };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genBinOpShl(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.asUint();
+               a.evalInt = func(f *Frame) int64 { return lf(f) << rf(f) };
+       // case *idealIntType:
+       //      lf := l.asIdealInt();
+       //      rf := r.asIdealInt();
+       //      val := lf().Shl(rf());
+       //      a.evalIdealInt = func() *bignum.Integer { return val };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
+
+func (a *exprCompiler) genBinOpShr(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.asUint();
+               a.evalInt = func(f *Frame) int64 { return lf(f) >> rf(f) };
+       // case *idealIntType:
+       //      lf := l.asIdealInt();
+       //      rf := r.asIdealInt();
+       //      val := lf().Shr(rf());
+       //      a.evalIdealInt = func() *bignum.Integer { return val };
+       default:
+               log.Crashf("unexpected left operand type %v at %v", l.t.literal(), a.pos);
+       }
+}
index 23f74649e013a2c515f2ee0698bdf87dcb364bf2..f5e43b6d78be84cd0b848a3d1c62147e2b47c67d 100644 (file)
@@ -29,6 +29,10 @@ import (
 type commonType struct {
 }
 
+func (commonType) isBoolean() bool {
+       return false;
+}
+
 func (commonType) isInteger() bool {
        return false;
 }
@@ -55,6 +59,10 @@ func (t *boolType) compatible(o Type) bool {
        return Type(t) == o;
 }
 
+func (t *boolType) isBoolean() bool {
+       return true;
+}
+
 func (boolType) String() string {
        return "bool";
 }