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.Arrays;
9   import java.util.List;
10  
11  import dev.metaschema.core.metapath.DynamicContext;
12  import dev.metaschema.core.metapath.IExpression;
13  import dev.metaschema.core.metapath.cst.AbstractNAryExpression;
14  import dev.metaschema.core.metapath.cst.IExpressionVisitor;
15  import dev.metaschema.core.metapath.function.library.FnBoolean;
16  import dev.metaschema.core.metapath.item.ISequence;
17  import dev.metaschema.core.metapath.item.atomic.IBooleanItem;
18  import edu.umd.cs.findbugs.annotations.NonNull;
19  
20  /**
21   * An implementation of
22   * <a href="https://www.w3.org/TR/xpath-31/#id-logical-expressions">Or
23   * expression</a> supporting conditional evaluation.
24   * <p>
25   * Determines the logical conjunction of the result of evaluating a list of
26   * expressions. The boolean result of each expression is determined by applying
27   * {@link FnBoolean#fnBooleanAsPrimitive(ISequence)} to each function's
28   * {@link ISequence} result.
29   * <p>
30   * This implementation will short-circuit and return {@code true} when the first
31   * expression evaluates to {@code true}, otherwise it will return {@code false}.
32   */
33  public class Or
34      extends AbstractNAryExpression
35      implements IBooleanLogicExpression {
36  
37    /**
38     * Construct a new "or" logical expression.
39     *
40     * @param text
41     *          the parsed text of the expression
42     * @param expressions
43     *          the expressions to evaluate
44     *
45     */
46    @SuppressWarnings("null")
47    public Or(@NonNull String text, @NonNull IExpression... expressions) {
48      this(text, Arrays.asList(expressions));
49    }
50  
51    /**
52     * Determines the logical disjunction of the result of evaluating a list of
53     * expressions. The boolean result of each expression is determined by applying
54     * {@link FnBoolean#fnBooleanAsPrimitive(ISequence)} to each function's
55     * {@link ISequence} result.
56     *
57     * @param text
58     *          the parsed text of the expression
59     * @param expressions
60     *          the list of expressions
61     */
62    public Or(@NonNull String text, @NonNull List<IExpression> expressions) {
63      super(text, expressions);
64    }
65  
66    @Override
67    public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
68      return visitor.visitOr(this, context);
69    }
70  
71    @Override
72    protected ISequence<? extends IBooleanItem> evaluate(DynamicContext dynamicContext, ISequence<?> focus) {
73      boolean retval = false;
74      for (IExpression child : getChildren()) {
75        ISequence<?> result = child.accept(dynamicContext, focus);
76        if (FnBoolean.fnBooleanAsPrimitive(result)) {
77          retval = true;
78          break;
79        }
80      }
81      return ISequence.of(IBooleanItem.valueOf(retval));
82    }
83  }