in src/main/java/net/starlark/java/eval/EvalUtils.java [75:380]
static Object binaryOp(TokenKind op, Object x, Object y, StarlarkThread starlarkThread)
throws EvalException {
StarlarkSemantics semantics = starlarkThread.getSemantics();
Mutability mu = starlarkThread.mutability();
switch (op) {
case PLUS:
if (x instanceof StarlarkInt) {
if (y instanceof StarlarkInt) {
// int + int
return StarlarkInt.add((StarlarkInt) x, (StarlarkInt) y);
} else if (y instanceof StarlarkFloat) {
// int + float
double z = ((StarlarkInt) x).toFiniteDouble() + ((StarlarkFloat) y).toDouble();
return StarlarkFloat.of(z);
}
} else if (x instanceof String) {
if (y instanceof String) {
// string + string
return (String) x + (String) y;
}
} else if (x instanceof Tuple) {
if (y instanceof Tuple) {
// tuple + tuple
return Tuple.concat((Tuple) x, (Tuple) y);
}
} else if (x instanceof StarlarkList) {
if (y instanceof StarlarkList) {
// list + list
return StarlarkList.concat((StarlarkList<?>) x, (StarlarkList<?>) y, mu);
}
} else if (x instanceof StarlarkFloat) {
double xf = ((StarlarkFloat) x).toDouble();
if (y instanceof StarlarkFloat) {
// float + float
double z = xf + ((StarlarkFloat) y).toDouble();
return StarlarkFloat.of(z);
} else if (y instanceof StarlarkInt) {
// float + int
double z = xf + ((StarlarkInt) y).toFiniteDouble();
return StarlarkFloat.of(z);
}
}
break;
case PIPE:
if (x instanceof StarlarkInt) {
if (y instanceof StarlarkInt) {
// int | int
return StarlarkInt.or((StarlarkInt) x, (StarlarkInt) y);
}
}
break;
case AMPERSAND:
if (x instanceof StarlarkInt && y instanceof StarlarkInt) {
// int & int
return StarlarkInt.and((StarlarkInt) x, (StarlarkInt) y);
}
break;
case CARET:
if (x instanceof StarlarkInt && y instanceof StarlarkInt) {
// int ^ int
return StarlarkInt.xor((StarlarkInt) x, (StarlarkInt) y);
}
break;
case GREATER_GREATER:
if (x instanceof StarlarkInt && y instanceof StarlarkInt) {
// x >> y
return StarlarkInt.shiftRight((StarlarkInt) x, (StarlarkInt) y);
}
break;
case LESS_LESS:
if (x instanceof StarlarkInt && y instanceof StarlarkInt) {
// x << y
return StarlarkInt.shiftLeft((StarlarkInt) x, (StarlarkInt) y);
}
break;
case MINUS:
if (x instanceof StarlarkInt) {
if (y instanceof StarlarkInt) {
// int - int
return StarlarkInt.subtract((StarlarkInt) x, (StarlarkInt) y);
} else if (y instanceof StarlarkFloat) {
// int - float
double z = ((StarlarkInt) x).toFiniteDouble() - ((StarlarkFloat) y).toDouble();
return StarlarkFloat.of(z);
}
} else if (x instanceof StarlarkFloat) {
double xf = ((StarlarkFloat) x).toDouble();
if (y instanceof StarlarkFloat) {
// float - float
double z = xf - ((StarlarkFloat) y).toDouble();
return StarlarkFloat.of(z);
} else if (y instanceof StarlarkInt) {
// float - int
double z = xf - ((StarlarkInt) y).toFiniteDouble();
return StarlarkFloat.of(z);
}
}
break;
case STAR:
if (x instanceof StarlarkInt) {
StarlarkInt xi = (StarlarkInt) x;
if (y instanceof StarlarkInt) {
// int * int
return StarlarkInt.multiply(xi, (StarlarkInt) y);
} else if (y instanceof String) {
// int * string
return repeatString((String) y, xi);
} else if (y instanceof Tuple) {
// int * tuple
return ((Tuple) y).repeat(xi);
} else if (y instanceof StarlarkList) {
// int * list
return ((StarlarkList<?>) y).repeat(xi, mu);
} else if (y instanceof StarlarkFloat) {
// int * float
double z = xi.toFiniteDouble() * ((StarlarkFloat) y).toDouble();
return StarlarkFloat.of(z);
}
} else if (x instanceof String) {
if (y instanceof StarlarkInt) {
// string * int
return repeatString((String) x, (StarlarkInt) y);
}
} else if (x instanceof Tuple) {
if (y instanceof StarlarkInt) {
// tuple * int
return ((Tuple) x).repeat((StarlarkInt) y);
}
} else if (x instanceof StarlarkList) {
if (y instanceof StarlarkInt) {
// list * int
return ((StarlarkList<?>) x).repeat((StarlarkInt) y, mu);
}
} else if (x instanceof StarlarkFloat) {
double xf = ((StarlarkFloat) x).toDouble();
if (y instanceof StarlarkFloat) {
// float * float
return StarlarkFloat.of(xf * ((StarlarkFloat) y).toDouble());
} else if (y instanceof StarlarkInt) {
// float * int
return StarlarkFloat.of(xf * ((StarlarkInt) y).toFiniteDouble());
}
}
break;
case SLASH: // real division
if (x instanceof StarlarkInt) {
double xf = ((StarlarkInt) x).toFiniteDouble();
if (y instanceof StarlarkInt) {
// int / int
return StarlarkFloat.div(xf, ((StarlarkInt) y).toFiniteDouble());
} else if (y instanceof StarlarkFloat) {
// int / float
return StarlarkFloat.div(xf, ((StarlarkFloat) y).toDouble());
}
} else if (x instanceof StarlarkFloat) {
double xf = ((StarlarkFloat) x).toDouble();
if (y instanceof StarlarkFloat) {
// float / float
return StarlarkFloat.div(xf, ((StarlarkFloat) y).toDouble());
} else if (y instanceof StarlarkInt) {
// float / int
return StarlarkFloat.div(xf, ((StarlarkInt) y).toFiniteDouble());
}
}
break;
case SLASH_SLASH:
if (x instanceof StarlarkInt) {
if (y instanceof StarlarkInt) {
// int // int
return StarlarkInt.floordiv((StarlarkInt) x, (StarlarkInt) y);
} else if (y instanceof StarlarkFloat) {
// int // float
double xf = ((StarlarkInt) x).toFiniteDouble();
double yf = ((StarlarkFloat) y).toDouble();
return StarlarkFloat.floordiv(xf, yf);
}
} else if (x instanceof StarlarkFloat) {
double xf = ((StarlarkFloat) x).toDouble();
if (y instanceof StarlarkFloat) {
// float // float
return StarlarkFloat.floordiv(xf, ((StarlarkFloat) y).toDouble());
} else if (y instanceof StarlarkInt) {
// float // int
return StarlarkFloat.floordiv(xf, ((StarlarkInt) y).toFiniteDouble());
}
}
break;
case PERCENT:
if (x instanceof StarlarkInt) {
if (y instanceof StarlarkInt) {
// int % int
return StarlarkInt.mod((StarlarkInt) x, (StarlarkInt) y);
} else if (y instanceof StarlarkFloat) {
// int % float
double xf = ((StarlarkInt) x).toFiniteDouble();
double yf = ((StarlarkFloat) y).toDouble();
return StarlarkFloat.mod(xf, yf);
}
} else if (x instanceof String) {
// string % any
String xs = (String) x;
try {
if (y instanceof Tuple) {
return Starlark.formatWithList(xs, (Tuple) y);
} else {
return Starlark.format(xs, y);
}
} catch (IllegalFormatException ex) {
throw new EvalException(ex);
}
} else if (x instanceof StarlarkFloat) {
double xf = ((StarlarkFloat) x).toDouble();
if (y instanceof StarlarkFloat) {
// float % float
return StarlarkFloat.mod(xf, ((StarlarkFloat) y).toDouble());
} else if (y instanceof StarlarkInt) {
// float % int
return StarlarkFloat.mod(xf, ((StarlarkInt) y).toFiniteDouble());
}
}
break;
case EQUALS_EQUALS:
return x.equals(y);
case NOT_EQUALS:
return !x.equals(y);
case LESS:
return compare(x, y) < 0;
case LESS_EQUALS:
return compare(x, y) <= 0;
case GREATER:
return compare(x, y) > 0;
case GREATER_EQUALS:
return compare(x, y) >= 0;
case IN:
if (y instanceof StarlarkIndexable) {
return ((StarlarkIndexable) y).containsKey(semantics, x);
} else if (y instanceof StarlarkIndexable.Threaded) {
return ((StarlarkIndexable.Threaded) y).containsKey(starlarkThread, semantics, x);
} else if (y instanceof String) {
if (!(x instanceof String)) {
throw Starlark.errorf(
"'in <string>' requires string as left operand, not '%s'", Starlark.type(x));
}
return ((String) y).contains((String) x);
}
break;
case NOT_IN:
Object z = binaryOp(TokenKind.IN, x, y, starlarkThread);
if (z != null) {
return !Starlark.truth(z);
}
break;
default:
throw new AssertionError("not a binary operator: " + op);
}
// custom binary operator?
if (x instanceof HasBinary) {
Object z = ((HasBinary) x).binaryOp(op, y, true);
if (z != null) {
return z;
}
}
if (y instanceof HasBinary) {
Object z = ((HasBinary) y).binaryOp(op, x, false);
if (z != null) {
return z;
}
}
throw Starlark.errorf(
"unsupported binary operation: %s %s %s", Starlark.type(x), op, Starlark.type(y));
}