static Object binaryOp()

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));
  }