AbstractExpressionVisitor.java

/*
 * Portions of this software was developed by employees of the National Institute
 * of Standards and Technology (NIST), an agency of the Federal Government and is
 * being made available as a public service. Pursuant to title 17 United States
 * Code Section 105, works of NIST employees are not subject to copyright
 * protection in the United States. This software may be subject to foreign
 * copyright. Permission in the United States and in foreign countries, to the
 * extent that NIST may hold copyright, to use, copy, modify, create derivative
 * works, and distribute this software and its documentation without fee is hereby
 * granted on a non-exclusive basis, provided that this notice and disclaimer
 * of warranty appears in all copies.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
 */

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

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")
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(FunctionCall 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(Name 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(Predicate 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);
  }
}