1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.core.metapath.cst.logic;
7   
8   import java.util.List;
9   
10  import dev.metaschema.core.metapath.DynamicContext;
11  import dev.metaschema.core.metapath.IExpression;
12  import dev.metaschema.core.metapath.cst.AbstractNAryExpression;
13  import dev.metaschema.core.metapath.cst.IExpressionVisitor;
14  import dev.metaschema.core.metapath.function.library.FnBoolean;
15  import dev.metaschema.core.metapath.item.ISequence;
16  import dev.metaschema.core.metapath.item.atomic.IBooleanItem;
17  import edu.umd.cs.findbugs.annotations.NonNull;
18  
19  /**
20   * An implementation of
21   * <a href="https://www.w3.org/TR/xpath-31/#id-logical-expressions">And
22   * expression</a> supporting conditional evaluation.
23   * <p>
24   * Determines the logical conjunction of the result of evaluating a list of
25   * expressions. The boolean result of each expression is determined by applying
26   * {@link FnBoolean#fnBooleanAsPrimitive(ISequence)} to each function's
27   * {@link ISequence} result.
28   * <p>
29   * This implementation will short-circuit and return {@code false} when the
30   * first expression evaluates to {@code false}, otherwise it will return
31   * {@code true}.
32   */
33  public class And
34      extends AbstractNAryExpression
35      implements IBooleanLogicExpression {
36  
37    /**
38     * Construct a new "and" logical expression.
39     *
40     * @param text
41     *          the parsed text of the expression
42     * @param expressions
43     *          the expressions to evaluate
44     *
45     */
46    public And(@NonNull String text, @NonNull List<IExpression> expressions) {
47      super(text, expressions);
48    }
49  
50    @Override
51    public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
52      return visitor.visitAnd(this, context);
53    }
54  
55    @Override
56    protected ISequence<? extends IBooleanItem> evaluate(DynamicContext dynamicContext, ISequence<?> focus) {
57      boolean retval = true;
58      for (IExpression child : getChildren()) {
59        ISequence<?> result = child.accept(dynamicContext, focus);
60        if (!FnBoolean.fnBooleanAsPrimitive(result)) {
61          retval = false;
62          break;
63        }
64      }
65      return ISequence.of(IBooleanItem.valueOf(retval));
66    }
67  }