Modulo.java

/*
 * SPDX-FileCopyrightText: none
 * SPDX-License-Identifier: CC0-1.0
 */

package gov.nist.secauto.metaschema.core.metapath.cst.math;

import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
import gov.nist.secauto.metaschema.core.metapath.ISequence;
import gov.nist.secauto.metaschema.core.metapath.cst.IExpression;
import gov.nist.secauto.metaschema.core.metapath.cst.IExpressionVisitor;
import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
import gov.nist.secauto.metaschema.core.metapath.function.OperationFunctions;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;

public class Modulo
    extends AbstractArithmeticExpression<INumericItem> {

  /**
   * Create an expression that gets the numeric remainder from dividing the
   * dividend by the divisor, also called the "modulo operation".
   *
   * @param dividend
   *          the item to be divided
   * @param divisor
   *          the item to divide by
   */
  public Modulo(@NonNull IExpression dividend, @NonNull IExpression divisor) {
    super(dividend, divisor, INumericItem.class);
  }

  @Override
  public Class<INumericItem> getBaseResultType() {
    return INumericItem.class;
  }

  @Override
  public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
    return visitor.visitModulo(this, context);
  }

  @Override
  public ISequence<? extends INumericItem> accept(DynamicContext dynamicContext, ISequence<?> focus) {
    INumericItem dividend = FunctionUtils.toNumeric(getLeft().accept(dynamicContext, focus), true);
    INumericItem divisor = FunctionUtils.toNumeric(getRight().accept(dynamicContext, focus), true);
    return resultOrEmpty(dividend, divisor);
  }

  /**
   * Get the numeric remainder from dividing the dividend by the divisor.
   *
   * @param dividend
   *          the item to be divided
   * @param divisor
   *          the item to divide by
   * @return the remainder or an empty {@link ISequence} if either item is
   *         {@code null}
   */
  @NonNull
  protected static ISequence<? extends INumericItem> resultOrEmpty(@Nullable INumericItem dividend,
      @Nullable INumericItem divisor) {
    ISequence<? extends INumericItem> retval;
    if (dividend == null || divisor == null) {
      retval = ISequence.empty();
    } else {
      INumericItem result = OperationFunctions.opNumericMod(dividend, divisor);
      retval = ISequence.of(result);
    }
    return retval;
  }
}