Commit 96e84439 authored by Austin Clements's avatar Austin Clements

Implement all unary and binary arithmetic operators.

R=rsc
APPROVED=rsc
DELTA=689  (497 added, 169 deleted, 23 changed)
OCL=31755
CL=31772
parent e52e9ca8
...@@ -20,6 +20,8 @@ type Type interface { ...@@ -20,6 +20,8 @@ type Type interface {
// compatible returns true if this type is compatible with o. // compatible returns true if this type is compatible with o.
// XXX Assignment versus comparison compatibility? // XXX Assignment versus comparison compatibility?
compatible(o Type) bool; 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 returns true if this is an integer type.
isInteger() bool; isInteger() bool;
// isFloat returns true if this is a floating type. // isFloat returns true if this is a floating type.
......
...@@ -56,6 +56,25 @@ func newExprCompiler(c *exprContext, pos token.Position) *exprCompiler { ...@@ -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 { func (a *exprCompiler) fork(x ast.Expr) *exprCompiler {
ec := newExprCompiler(a.exprContext, x.Pos()); ec := newExprCompiler(a.exprContext, x.Pos());
x.Visit(ec); x.Visit(ec);
...@@ -134,25 +153,6 @@ func (a *exprCompiler) DoBadExpr(x *ast.BadExpr) { ...@@ -134,25 +153,6 @@ func (a *exprCompiler) DoBadExpr(x *ast.BadExpr) {
// Do nothing. Already reported by parser. // 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) { func (a *exprCompiler) DoIdent(x *ast.Ident) {
def, dscope := a.scope.Lookup(x.Value); def, dscope := a.scope.Lookup(x.Value);
if def == nil { if def == nil {
...@@ -180,7 +180,7 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) { ...@@ -180,7 +180,7 @@ func (a *exprCompiler) DoIdent(x *ast.Ident) {
} }
a.t = def.Type; a.t = def.Type;
defidx := def.Index; defidx := def.Index;
a.genIdent(def.Type, dscope, defidx); a.genIdentOp(def.Type, dscope, defidx);
a.evalAddr = func (f *Frame) Value { a.evalAddr = func (f *Frame) Value {
return f.Get(dscope, defidx); return f.Get(dscope, defidx);
}; };
...@@ -285,26 +285,6 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) { ...@@ -285,26 +285,6 @@ func (a *exprCompiler) DoCallExpr(x *ast.CallExpr) {
log.Crash("Not implemented"); 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) { func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) {
v := a.fork(x.X); v := a.fork(x.X);
if v.t == nil { if v.t == nil {
...@@ -324,55 +304,39 @@ func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) { ...@@ -324,55 +304,39 @@ func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) {
} }
} }
func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler) { var unaryOpDescs = make(map[token.Token] string)
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) { func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
v := a.fork(x.X);
if v.t == nil {
return;
}
// Type check
switch x.Op { switch x.Op {
case token.SUB: case token.ADD, token.SUB:
// Negation if !v.t.isInteger() && !v.t.isFloat() {
v := a.fork(x.X); a.diagOpType(x.Op, v.t);
if v.t == nil {
return; 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); a.diagOpType(x.Op, v.t);
return; return;
} }
// TODO(austin) Unnamed bool? Named bool?
a.t = BoolType;
a.t = v.t; case token.XOR:
a.genUnaryOpNeg(v); if !v.t.isInteger() {
a.desc = "- expression"; a.diagOpType(x.Op, v.t);
case token.AND:
// Address-of
v := a.fork(x.X);
if v.t == nil {
return; return;
} }
a.t = v.t;
case token.AND:
// The unary prefix address-of operator & generates // The unary prefix address-of operator & generates
// the address of its operand, which must be a // the address of its operand, which must be a
// variable, pointer indirection, field selector, or // variable, pointer indirection, field selector, or
...@@ -386,15 +350,43 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) { ...@@ -386,15 +350,43 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
// address of a function result variable" once I have // address of a function result variable" once I have
// function result variables. // function result variables.
at := NewPtrType(v.t); a.t = NewPtrType(v.t);
a.t = at;
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; vf := v.evalAddr;
a.evalPtr = func (f *Frame) Value { return vf(f) }; a.evalPtr = func (f *Frame) Value { return vf(f) };
a.desc = "& expression";
default: 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 { ...@@ -470,98 +462,7 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler {
return res; return res;
} }
func (a *exprCompiler) genBinOpAdd(l *exprCompiler, r *exprCompiler) { var binOpDescs = make(map[token.Token] string)
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) { func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
l, r := a.fork(x.X), a.fork(x.Y); l, r := a.fork(x.X), a.fork(x.Y);
...@@ -586,10 +487,11 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) { ...@@ -586,10 +487,11 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
// relevant only for / and %? If I add an ideal int and an // relevant only for / and %? If I add an ideal int and an
// ideal float, I get an ideal float. // 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 { 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() { if l.t.isInteger() && !l.t.isIdeal() && r.t.isIdeal() {
r = r.convertTo(l.t); r = r.convertTo(l.t);
} else if r.t.isInteger() && !r.t.isIdeal() && l.t.isIdeal() { } else if r.t.isInteger() && !r.t.isIdeal() && l.t.isIdeal() {
...@@ -657,22 +559,50 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) { ...@@ -657,22 +559,50 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
a.t = l.t; a.t = l.t;
case token.SHL, token.SHR: 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 // The right operand in a shift operation must be
// always be of unsigned integer type or an ideal // always be of unsigned integer type or an ideal
// number that can be safely converted into an // number that can be safely converted into an
// unsigned integer type. // unsigned integer type.
if r.t.isIdeal() { if r.t.isIdeal() {
r = r.convertTo(UintType); r2 := r.convertTo(UintType);
if r == nil { if r2 == nil {
return; return;
} }
} // If the left operand is ideal, we use the
// original right operand so we can perform
if !integers() { // constant evaluation. Otherwise, we use the
a.diagOpTypes(x.Op, origlt, origrt); // conversion.
return; if !l.t.isIdeal() {
} r = r2;
if _, ok := r.t.literal().(*uintType); !ok { // 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"); a.diag("right operand of shift must be unsigned");
return; return;
} }
...@@ -735,10 +665,10 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) { ...@@ -735,10 +665,10 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
} }
var ok bool; var ok bool;
a.desc, ok = opDescs[x.Op]; a.desc, ok = binOpDescs[x.Op];
if !ok { if !ok {
a.desc = x.Op.String() + " expression"; a.desc = x.Op.String() + " expression";
opDescs[x.Op] = a.desc; binOpDescs[x.Op] = a.desc;
} }
// Compile // Compile
...@@ -749,12 +679,50 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) { ...@@ -749,12 +679,50 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
case token.SUB: case token.SUB:
a.genBinOpSub(l, r); a.genBinOpSub(l, r);
case token.MUL:
a.genBinOpMul(l, r);
case token.QUO: case token.QUO:
// TODO(austin) What if divisor is zero? // TODO(austin) What if divisor is zero?
// TODO(austin) Clear higher bits that may have // TODO(austin) Clear higher bits that may have
// accumulated in our temporary. // accumulated in our temporary.
a.genBinOpQuo(l, r); 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: default:
log.Crashf("Compilation of binary op %v not implemented", x.Op); log.Crashf("Compilation of binary op %v not implemented", x.Op);
} }
...@@ -842,3 +810,353 @@ func CompileExpr(expr ast.Expr, scope *Scope) *Expr { ...@@ -842,3 +810,353 @@ func CompileExpr(expr ast.Expr, scope *Scope) *Expr {
log.Crashf("unexpected type %v", ec.t); log.Crashf("unexpected type %v", ec.t);
return nil; 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);
}
}
...@@ -29,6 +29,10 @@ import ( ...@@ -29,6 +29,10 @@ import (
type commonType struct { type commonType struct {
} }
func (commonType) isBoolean() bool {
return false;
}
func (commonType) isInteger() bool { func (commonType) isInteger() bool {
return false; return false;
} }
...@@ -55,6 +59,10 @@ func (t *boolType) compatible(o Type) bool { ...@@ -55,6 +59,10 @@ func (t *boolType) compatible(o Type) bool {
return Type(t) == o; return Type(t) == o;
} }
func (t *boolType) isBoolean() bool {
return true;
}
func (boolType) String() string { func (boolType) String() string {
return "bool"; return "bool";
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment