// This file is machine generated by gen.go.
// 6g gen.go && 6l gen.6 && ./6.out >expr1.go

package eval

import (
	"bignum";
	"log";
)

/*
 * "As" functions.  These retrieve evaluator functions from an
 * expr, panicking if the requested evaluator has the wrong type.
 */
func (a *expr) asBool() (func(*Thread) bool) {
	return a.eval.(func(*Thread) bool);
}
func (a *expr) asUint() (func(*Thread) uint64) {
	return a.eval.(func(*Thread) uint64);
}
func (a *expr) asInt() (func(*Thread) int64) {
	return a.eval.(func(*Thread) int64);
}
func (a *expr) asIdealInt() (func() *bignum.Integer) {
	return a.eval.(func() *bignum.Integer);
}
func (a *expr) asFloat() (func(*Thread) float64) {
	return a.eval.(func(*Thread) float64);
}
func (a *expr) asIdealFloat() (func() *bignum.Rational) {
	return a.eval.(func() *bignum.Rational);
}
func (a *expr) asString() (func(*Thread) string) {
	return a.eval.(func(*Thread) string);
}
func (a *expr) asArray() (func(*Thread) ArrayValue) {
	return a.eval.(func(*Thread) ArrayValue);
}
func (a *expr) asStruct() (func(*Thread) StructValue) {
	return a.eval.(func(*Thread) StructValue);
}
func (a *expr) asPtr() (func(*Thread) Value) {
	return a.eval.(func(*Thread) Value);
}
func (a *expr) asFunc() (func(*Thread) Func) {
	return a.eval.(func(*Thread) Func);
}
func (a *expr) asSlice() (func(*Thread) Slice) {
	return a.eval.(func(*Thread) Slice);
}
func (a *expr) asMap() (func(*Thread) Map) {
	return a.eval.(func(*Thread) Map);
}
func (a *expr) asMulti() (func(*Thread) []Value) {
	return a.eval.(func(*Thread) []Value);
}

func (a *expr) asInterface() (func(*Thread) interface{}) {
	switch sf := a.eval.(type) {
	case func(t *Thread) bool:
		return func(t *Thread) interface{} { return sf(t) };
	case func(t *Thread) uint64:
		return func(t *Thread) interface{} { return sf(t) };
	case func(t *Thread) int64:
		return func(t *Thread) interface{} { return sf(t) };
	case func() *bignum.Integer:
		return func(*Thread) interface{} { return sf() };
	case func(t *Thread) float64:
		return func(t *Thread) interface{} { return sf(t) };
	case func() *bignum.Rational:
		return func(*Thread) interface{} { return sf() };
	case func(t *Thread) string:
		return func(t *Thread) interface{} { return sf(t) };
	case func(t *Thread) ArrayValue:
		return func(t *Thread) interface{} { return sf(t) };
	case func(t *Thread) StructValue:
		return func(t *Thread) interface{} { return sf(t) };
	case func(t *Thread) Value:
		return func(t *Thread) interface{} { return sf(t) };
	case func(t *Thread) Func:
		return func(t *Thread) interface{} { return sf(t) };
	case func(t *Thread) Slice:
		return func(t *Thread) interface{} { return sf(t) };
	case func(t *Thread) Map:
		return func(t *Thread) interface{} { return sf(t) };
	default:
		log.Crashf("unexpected expression node type %T at %v", a.eval, a.pos);
	}
	panic();
}

/*
 * Operator generators.
 */

func (a *expr) genConstant(v Value) {
	switch a.t.lit().(type) {
	case *boolType:
		a.eval = func(t *Thread) bool { return v.(BoolValue).Get(t) };
	case *uintType:
		a.eval = func(t *Thread) uint64 { return v.(UintValue).Get(t) };
	case *intType:
		a.eval = func(t *Thread) int64 { return v.(IntValue).Get(t) };
	case *idealIntType:
		val := v.(IdealIntValue).Get();
		a.eval = func() *bignum.Integer { return val };
	case *floatType:
		a.eval = func(t *Thread) float64 { return v.(FloatValue).Get(t) };
	case *idealFloatType:
		val := v.(IdealFloatValue).Get();
		a.eval = func() *bignum.Rational { return val };
	case *stringType:
		a.eval = func(t *Thread) string { return v.(StringValue).Get(t) };
	case *ArrayType:
		a.eval = func(t *Thread) ArrayValue { return v.(ArrayValue).Get(t) };
	case *StructType:
		a.eval = func(t *Thread) StructValue { return v.(StructValue).Get(t) };
	case *PtrType:
		a.eval = func(t *Thread) Value { return v.(PtrValue).Get(t) };
	case *FuncType:
		a.eval = func(t *Thread) Func { return v.(FuncValue).Get(t) };
	case *SliceType:
		a.eval = func(t *Thread) Slice { return v.(SliceValue).Get(t) };
	case *MapType:
		a.eval = func(t *Thread) Map { return v.(MapValue).Get(t) };
	default:
		log.Crashf("unexpected constant type %v at %v", a.t, a.pos);
	}
}

func (a *expr) genIdentOp(level, index int) {
	a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) };
	switch a.t.lit().(type) {
	case *boolType:
		a.eval = func(t *Thread) bool {
			return t.f.Get(level, index).(BoolValue).Get(t);
		};
	case *uintType:
		a.eval = func(t *Thread) uint64 {
			return t.f.Get(level, index).(UintValue).Get(t);
		};
	case *intType:
		a.eval = func(t *Thread) int64 {
			return t.f.Get(level, index).(IntValue).Get(t);
		};
	case *floatType:
		a.eval = func(t *Thread) float64 {
			return t.f.Get(level, index).(FloatValue).Get(t);
		};
	case *stringType:
		a.eval = func(t *Thread) string {
			return t.f.Get(level, index).(StringValue).Get(t);
		};
	case *ArrayType:
		a.eval = func(t *Thread) ArrayValue {
			return t.f.Get(level, index).(ArrayValue).Get(t);
		};
	case *StructType:
		a.eval = func(t *Thread) StructValue {
			return t.f.Get(level, index).(StructValue).Get(t);
		};
	case *PtrType:
		a.eval = func(t *Thread) Value {
			return t.f.Get(level, index).(PtrValue).Get(t);
		};
	case *FuncType:
		a.eval = func(t *Thread) Func {
			return t.f.Get(level, index).(FuncValue).Get(t);
		};
	case *SliceType:
		a.eval = func(t *Thread) Slice {
			return t.f.Get(level, index).(SliceValue).Get(t);
		};
	case *MapType:
		a.eval = func(t *Thread) Map {
			return t.f.Get(level, index).(MapValue).Get(t);
		};
	default:
		log.Crashf("unexpected identifier type %v at %v", a.t, a.pos);
	}
}

func (a *expr) genFuncCall(call func(t *Thread) []Value) {
	a.exec = func(t *Thread) { call(t) };
	switch a.t.lit().(type) {
	case *boolType:
		a.eval = func(t *Thread) bool { return call(t)[0].(BoolValue).Get(t) };
	case *uintType:
		a.eval = func(t *Thread) uint64 { return call(t)[0].(UintValue).Get(t) };
	case *intType:
		a.eval = func(t *Thread) int64 { return call(t)[0].(IntValue).Get(t) };
	case *floatType:
		a.eval = func(t *Thread) float64 { return call(t)[0].(FloatValue).Get(t) };
	case *stringType:
		a.eval = func(t *Thread) string { return call(t)[0].(StringValue).Get(t) };
	case *ArrayType:
		a.eval = func(t *Thread) ArrayValue { return call(t)[0].(ArrayValue).Get(t) };
	case *StructType:
		a.eval = func(t *Thread) StructValue { return call(t)[0].(StructValue).Get(t) };
	case *PtrType:
		a.eval = func(t *Thread) Value { return call(t)[0].(PtrValue).Get(t) };
	case *FuncType:
		a.eval = func(t *Thread) Func { return call(t)[0].(FuncValue).Get(t) };
	case *SliceType:
		a.eval = func(t *Thread) Slice { return call(t)[0].(SliceValue).Get(t) };
	case *MapType:
		a.eval = func(t *Thread) Map { return call(t)[0].(MapValue).Get(t) };
	case *MultiType:
		a.eval = func(t *Thread) []Value { return call(t) };
	default:
		log.Crashf("unexpected result type %v at %v", a.t, a.pos);
	}
}

func (a *expr) genValue(vf func(*Thread) Value) {
	a.evalAddr = vf;
	switch a.t.lit().(type) {
	case *boolType:
		a.eval = func(t *Thread) bool { return vf(t).(BoolValue).Get(t) };
	case *uintType:
		a.eval = func(t *Thread) uint64 { return vf(t).(UintValue).Get(t) };
	case *intType:
		a.eval = func(t *Thread) int64 { return vf(t).(IntValue).Get(t) };
	case *floatType:
		a.eval = func(t *Thread) float64 { return vf(t).(FloatValue).Get(t) };
	case *stringType:
		a.eval = func(t *Thread) string { return vf(t).(StringValue).Get(t) };
	case *ArrayType:
		a.eval = func(t *Thread) ArrayValue { return vf(t).(ArrayValue).Get(t) };
	case *StructType:
		a.eval = func(t *Thread) StructValue { return vf(t).(StructValue).Get(t) };
	case *PtrType:
		a.eval = func(t *Thread) Value { return vf(t).(PtrValue).Get(t) };
	case *FuncType:
		a.eval = func(t *Thread) Func { return vf(t).(FuncValue).Get(t) };
	case *SliceType:
		a.eval = func(t *Thread) Slice { return vf(t).(SliceValue).Get(t) };
	case *MapType:
		a.eval = func(t *Thread) Map { return vf(t).(MapValue).Get(t) };
	default:
		log.Crashf("unexpected result type %v at %v", a.t, a.pos);
	}
}

func (a *expr) genUnaryOpNeg(v *expr) {
	switch a.t.lit().(type) {
	case *uintType:
		vf := v.asUint();
		a.eval = func(t *Thread) uint64 {
			v := vf(t);
			return -v;
		};
	case *intType:
		vf := v.asInt();
		a.eval = func(t *Thread) int64 {
			v := vf(t);
			return -v;
		};
	case *idealIntType:
		v := v.asIdealInt()();
		val := v.Neg();
		a.eval = func() *bignum.Integer { return val };
	case *floatType:
		vf := v.asFloat();
		a.eval = func(t *Thread) float64 {
			v := vf(t);
			return -v;
		};
	case *idealFloatType:
		v := v.asIdealFloat()();
		val := v.Neg();
		a.eval = func() *bignum.Rational { return val };
	default:
		log.Crashf("unexpected type %v at %v", a.t, a.pos);
	}
}

func (a *expr) genUnaryOpNot(v *expr) {
	switch a.t.lit().(type) {
	case *boolType:
		vf := v.asBool();
		a.eval = func(t *Thread) bool {
			v := vf(t);
			return !v;
		};
	default:
		log.Crashf("unexpected type %v at %v", a.t, a.pos);
	}
}

func (a *expr) genUnaryOpXor(v *expr) {
	switch a.t.lit().(type) {
	case *uintType:
		vf := v.asUint();
		a.eval = func(t *Thread) uint64 {
			v := vf(t);
			return ^v;
		};
	case *intType:
		vf := v.asInt();
		a.eval = func(t *Thread) int64 {
			v := vf(t);
			return ^v;
		};
	case *idealIntType:
		v := v.asIdealInt()();
		val := v.Neg().Sub(bignum.Int(1));
		a.eval = func() *bignum.Integer { return val };
	default:
		log.Crashf("unexpected type %v at %v", a.t, a.pos);
	}
}

func (a *expr) genBinOpLogAnd(l, r *expr) {
	lf := l.asBool();
	rf := r.asBool();
	a.eval = func(t *Thread) bool { return lf(t) && rf(t) };
}

func (a *expr) genBinOpLogOr(l, r *expr) {
	lf := l.asBool();
	rf := r.asBool();
	a.eval = func(t *Thread) bool { return lf(t) || rf(t) };
}

func (a *expr) genBinOpAdd(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l+r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l+r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l+r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l+r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l+r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l+r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l+r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l+r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l+r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l+r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Add(r);
		a.eval = func() *bignum.Integer { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		switch t.Bits {
		case 32:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l+r;
				return float64(float32(ret));
			};
		case 64:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l+r;
				return float64(float64(ret));
			};
		case 0:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l+r;
				return float64(float(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Add(r);
		a.eval = func() *bignum.Rational { return val };
	case *stringType:
		lf := l.asString();
		rf := r.asString();
		a.eval = func(t *Thread) string {
			l, r := lf(t), rf(t);
			return l+r;
		};
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpSub(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l-r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l-r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l-r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l-r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l-r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l-r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l-r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l-r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l-r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l-r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Sub(r);
		a.eval = func() *bignum.Integer { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		switch t.Bits {
		case 32:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l-r;
				return float64(float32(ret));
			};
		case 64:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l-r;
				return float64(float64(ret));
			};
		case 0:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l-r;
				return float64(float(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Sub(r);
		a.eval = func() *bignum.Rational { return val };
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpMul(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l*r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l*r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l*r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l*r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l*r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l*r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l*r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l*r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l*r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l*r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Mul(r);
		a.eval = func() *bignum.Integer { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		switch t.Bits {
		case 32:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l*r;
				return float64(float32(ret));
			};
		case 64:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l*r;
				return float64(float64(ret));
			};
		case 0:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				ret = l*r;
				return float64(float(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Mul(r);
		a.eval = func() *bignum.Rational { return val };
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpQuo(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Quo(r);
		a.eval = func() *bignum.Integer { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		switch t.Bits {
		case 32:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return float64(float32(ret));
			};
		case 64:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return float64(float64(ret));
			};
		case 0:
			a.eval = func(t *Thread) float64 {
				l, r := lf(t), rf(t);
				var ret float64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l/r;
				return float64(float(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Quo(r);
		a.eval = func() *bignum.Rational { return val };
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpRem(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				if r == 0 {
					t.Abort(DivByZeroError{});
				}
				ret = l%r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Rem(r);
		a.eval = func() *bignum.Integer { return val };
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpAnd(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.And(r);
		a.eval = func() *bignum.Integer { return val };
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpOr(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l|r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l|r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l|r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l|r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l|r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l|r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l|r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l|r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l|r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l|r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Or(r);
		a.eval = func() *bignum.Integer { return val };
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpXor(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l^r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l^r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l^r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l^r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l^r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l^r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l^r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l^r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l^r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l^r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Xor(r);
		a.eval = func() *bignum.Integer { return val };
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpAndNot(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&^r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&^r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&^r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&^r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l&^r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&^r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&^r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&^r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&^r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l&^r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.AndNot(r);
		a.eval = func() *bignum.Integer { return val };
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpShl(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l<<r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l<<r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l<<r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l<<r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l<<r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l<<r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l<<r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l<<r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l<<r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l<<r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpShr(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l>>r;
				return uint64(uint8(ret));
			};
		case 16:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l>>r;
				return uint64(uint16(ret));
			};
		case 32:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l>>r;
				return uint64(uint32(ret));
			};
		case 64:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l>>r;
				return uint64(uint64(ret));
			};
		case 0:
			a.eval = func(t *Thread) uint64 {
				l, r := lf(t), rf(t);
				var ret uint64;
				ret = l>>r;
				return uint64(uint(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	case *intType:
		lf := l.asInt();
		rf := r.asUint();
		switch t.Bits {
		case 8:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l>>r;
				return int64(int8(ret));
			};
		case 16:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l>>r;
				return int64(int16(ret));
			};
		case 32:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l>>r;
				return int64(int32(ret));
			};
		case 64:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l>>r;
				return int64(int64(ret));
			};
		case 0:
			a.eval = func(t *Thread) int64 {
				l, r := lf(t), rf(t);
				var ret int64;
				ret = l>>r;
				return int64(int(ret));
			};
		default:
			log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
		}
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpLss(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l < r;
		};
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l < r;
		};
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Cmp(r) < 0;
		a.eval = func(t *Thread) bool { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l < r;
		};
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Cmp(r) < 0;
		a.eval = func(t *Thread) bool { return val };
	case *stringType:
		lf := l.asString();
		rf := r.asString();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l < r;
		};
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpGtr(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l > r;
		};
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l > r;
		};
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Cmp(r) > 0;
		a.eval = func(t *Thread) bool { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l > r;
		};
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Cmp(r) > 0;
		a.eval = func(t *Thread) bool { return val };
	case *stringType:
		lf := l.asString();
		rf := r.asString();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l > r;
		};
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpLeq(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l <= r;
		};
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l <= r;
		};
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Cmp(r) <= 0;
		a.eval = func(t *Thread) bool { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l <= r;
		};
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Cmp(r) <= 0;
		a.eval = func(t *Thread) bool { return val };
	case *stringType:
		lf := l.asString();
		rf := r.asString();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l <= r;
		};
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpGeq(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l >= r;
		};
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l >= r;
		};
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Cmp(r) >= 0;
		a.eval = func(t *Thread) bool { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l >= r;
		};
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Cmp(r) >= 0;
		a.eval = func(t *Thread) bool { return val };
	case *stringType:
		lf := l.asString();
		rf := r.asString();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l >= r;
		};
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpEql(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *boolType:
		lf := l.asBool();
		rf := r.asBool();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l == r;
		};
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l == r;
		};
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l == r;
		};
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Cmp(r) == 0;
		a.eval = func(t *Thread) bool { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l == r;
		};
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Cmp(r) == 0;
		a.eval = func(t *Thread) bool { return val };
	case *stringType:
		lf := l.asString();
		rf := r.asString();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l == r;
		};
	case *PtrType:
		lf := l.asPtr();
		rf := r.asPtr();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l == r;
		};
	case *FuncType:
		lf := l.asFunc();
		rf := r.asFunc();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l == r;
		};
	case *MapType:
		lf := l.asMap();
		rf := r.asMap();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l == r;
		};
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func (a *expr) genBinOpNeq(l, r *expr) {
	switch t := l.t.lit().(type) {
	case *boolType:
		lf := l.asBool();
		rf := r.asBool();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l != r;
		};
	case *uintType:
		lf := l.asUint();
		rf := r.asUint();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l != r;
		};
	case *intType:
		lf := l.asInt();
		rf := r.asInt();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l != r;
		};
	case *idealIntType:
		l := l.asIdealInt()();
		r := r.asIdealInt()();
		val := l.Cmp(r) != 0;
		a.eval = func(t *Thread) bool { return val };
	case *floatType:
		lf := l.asFloat();
		rf := r.asFloat();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l != r;
		};
	case *idealFloatType:
		l := l.asIdealFloat()();
		r := r.asIdealFloat()();
		val := l.Cmp(r) != 0;
		a.eval = func(t *Thread) bool { return val };
	case *stringType:
		lf := l.asString();
		rf := r.asString();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l != r;
		};
	case *PtrType:
		lf := l.asPtr();
		rf := r.asPtr();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l != r;
		};
	case *FuncType:
		lf := l.asFunc();
		rf := r.asFunc();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l != r;
		};
	case *MapType:
		lf := l.asMap();
		rf := r.asMap();
		a.eval = func(t *Thread) bool {
			l, r := lf(t), rf(t);
			return l != r;
		};
	default:
		log.Crashf("unexpected type %v at %v", l.t, a.pos);
	}
}

func genAssign(lt Type, r *expr) (func(lv Value, t *Thread)) {
	switch lt.lit().(type) {
	case *boolType:
		rf := r.asBool();
		return func(lv Value, t *Thread) { lv.(BoolValue).Set(t, rf(t)) };
	case *uintType:
		rf := r.asUint();
		return func(lv Value, t *Thread) { lv.(UintValue).Set(t, rf(t)) };
	case *intType:
		rf := r.asInt();
		return func(lv Value, t *Thread) { lv.(IntValue).Set(t, rf(t)) };
	case *floatType:
		rf := r.asFloat();
		return func(lv Value, t *Thread) { lv.(FloatValue).Set(t, rf(t)) };
	case *stringType:
		rf := r.asString();
		return func(lv Value, t *Thread) { lv.(StringValue).Set(t, rf(t)) };
	case *ArrayType:
		rf := r.asArray();
		return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) };
	case *StructType:
		rf := r.asStruct();
		return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) };
	case *PtrType:
		rf := r.asPtr();
		return func(lv Value, t *Thread) { lv.(PtrValue).Set(t, rf(t)) };
	case *FuncType:
		rf := r.asFunc();
		return func(lv Value, t *Thread) { lv.(FuncValue).Set(t, rf(t)) };
	case *SliceType:
		rf := r.asSlice();
		return func(lv Value, t *Thread) { lv.(SliceValue).Set(t, rf(t)) };
	case *MapType:
		rf := r.asMap();
		return func(lv Value, t *Thread) { lv.(MapValue).Set(t, rf(t)) };
	default:
		log.Crashf("unexpected left operand type %v at %v", lt, r.pos);
	}
	panic();
}
