AbstractExpressionVisitor.java

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

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

import gov.nist.secauto.metaschema.core.metapath.cst.comparison.GeneralComparison;
import gov.nist.secauto.metaschema.core.metapath.cst.comparison.ValueComparison;
import gov.nist.secauto.metaschema.core.metapath.cst.math.Addition;
import gov.nist.secauto.metaschema.core.metapath.cst.math.Division;
import gov.nist.secauto.metaschema.core.metapath.cst.math.IntegerDivision;
import gov.nist.secauto.metaschema.core.metapath.cst.math.Modulo;
import gov.nist.secauto.metaschema.core.metapath.cst.math.Multiplication;
import gov.nist.secauto.metaschema.core.metapath.cst.math.Subtraction;
import gov.nist.secauto.metaschema.core.metapath.cst.path.Axis;
import gov.nist.secauto.metaschema.core.metapath.cst.path.ContextItem;
import gov.nist.secauto.metaschema.core.metapath.cst.path.Flag;
import gov.nist.secauto.metaschema.core.metapath.cst.path.ModelInstance;
import gov.nist.secauto.metaschema.core.metapath.cst.path.NameTest;
import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeDoubleSlashPath;
import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeSlashPath;
import gov.nist.secauto.metaschema.core.metapath.cst.path.RootDoubleSlashPath;
import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashOnlyPath;
import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashPath;
import gov.nist.secauto.metaschema.core.metapath.cst.path.Step;
import gov.nist.secauto.metaschema.core.metapath.cst.path.Wildcard;

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

/**
 * Provides base support for processing a Metapath expression based on the
 * visitor pattern.
 *
 * @param <RESULT>
 *          the result of processing any node
 * @param <CONTEXT>
 *          additional state to pass between nodes visited
 */
@SuppressWarnings({ "PMD.CouplingBetweenObjects", "PMD.ExcessivePublicCount" })
public abstract class AbstractExpressionVisitor<RESULT, CONTEXT> implements IExpressionVisitor<RESULT, CONTEXT> {

  /**
   * This dispatch method will visit the provided {@code expression}.
   *
   * @param expression
   *          the expression to visit
   * @param context
   *          the visitor context
   * @return the result
   */
  protected RESULT visit(@NonNull IExpression expression, @NonNull CONTEXT context) {
    return expression.accept(this, context);
  }

  /**
   * Visit each child expression of the provided {@code expr}, aggregating the
   * results.
   *
   * @param expr
   *          the expression whoose children should be visited
   * @param context
   *          used to pass additional state
   * @return the aggegated result
   */
  protected RESULT visitChildren(@NonNull IExpression expr, @NonNull CONTEXT context) {
    RESULT result = defaultResult();

    for (IExpression childExpr : expr.getChildren()) {
      assert childExpr != null;
      if (!shouldVisitNextChild(expr, childExpr, result, context)) {
        break;
      }

      RESULT childResult = childExpr.accept(this, context);
      result = aggregateResult(result, childResult, context);
    }

    return result;
  }

  /**
   * Determines if a given {@code childExpr} should be visited.
   *
   * @param parent
   *          the parent expression of the child
   * @param child
   *          the child expression that can be visited
   * @param result
   *          the current result of evaluating any previous children
   * @param context
   *          additional state to pass between nodes visited
   * @return {@code true} if the child should be visited, or {@code false}
   *         otherwise
   */
  protected boolean shouldVisitNextChild(
      @NonNull IExpression parent,
      @NonNull IExpression child,
      @Nullable RESULT result,
      @NonNull CONTEXT context) {
    // allow visitation of the child
    return true;
  }

  /**
   * Aggregates the results produced by a visitation with an existing result into
   * a single result.
   *
   * @param result
   *          the existing result
   * @param nextResult
   *          the new result produced by a visitation
   * @param context
   *          the state passed to the last visitation
   * @return the aggregate result
   */
  @Nullable
  protected abstract RESULT aggregateResult(
      @Nullable RESULT result,
      @Nullable RESULT nextResult,
      @NonNull CONTEXT context);

  /**
   * Get the default result.
   *
   * @return the default result
   */
  protected abstract RESULT defaultResult();

  @Override
  public RESULT visitAddition(Addition expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitAnd(And expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitAxis(@NonNull Axis expr, @NonNull CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitStep(Step expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitValueComparison(ValueComparison expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitGeneralComparison(GeneralComparison expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitContextItem(ContextItem expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitDecimalLiteral(DecimalLiteral expr, CONTEXT context) {
    return defaultResult();
  }

  @Override
  public RESULT visitDivision(Division expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitExcept(@NonNull Except expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitFlag(Flag expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitFunctionCall(StaticFunctionCall expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitIntegerDivision(IntegerDivision expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitIntegerLiteral(IntegerLiteral expr, CONTEXT context) {
    return defaultResult();
  }

  @Override
  public RESULT visitIntersect(@NonNull Intersect expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitMetapath(Metapath expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitModulo(Modulo expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitModelInstance(ModelInstance expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitMultiplication(Multiplication expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitName(NameTest expr, CONTEXT context) {
    return defaultResult();
  }

  @Override
  public RESULT visitNegate(Negate expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitOr(Or expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitPredicate(PredicateExpression expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitRelativeDoubleSlashPath(RelativeDoubleSlashPath expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitRelativeSlashPath(RelativeSlashPath expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitRootDoubleSlashPath(RootDoubleSlashPath expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitRootSlashOnlyPath(RootSlashOnlyPath expr, CONTEXT context) {
    return defaultResult();
  }

  @Override
  public RESULT visitRootSlashPath(RootSlashPath expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitStringConcat(StringConcat expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitStringLiteral(StringLiteral expr, CONTEXT context) {
    return defaultResult();
  }

  @Override
  public RESULT visitSubtraction(Subtraction expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitUnion(Union expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitWildcard(Wildcard expr, CONTEXT context) {
    return defaultResult();
  }

  @Override
  public RESULT visitLet(Let expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitVariableReference(VariableReference expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitEmptySequence(EmptySequence<?> expr, CONTEXT context) {
    return defaultResult();
  }

  @Override
  public RESULT visitRange(Range expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitIf(If expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitQuantified(Quantified expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitFor(For expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitSimpleMap(SimpleMap expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitMapConstructor(MapConstructor expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitMapConstructorEntry(MapConstructor.Entry expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitArray(ArraySequenceConstructor expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitArray(ArraySquareConstructor expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitPostfixLookup(PostfixLookup expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitFunctionCallAccessor(FunctionCallAccessor expr, CONTEXT context) {
    return visitChildren(expr, context);
  }

  @Override
  public RESULT visitUnaryLookup(UnaryLookup expr, CONTEXT context) {
    return defaultResult();
  }
}