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.AbstractExpression;
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 dev.metaschema.core.util.ObjectUtils;
18  import edu.umd.cs.findbugs.annotations.NonNull;
19  
20  /**
21   * An implementation of
22   * <a href="https://www.w3.org/TR/xpath-31/#doc-xpath31-IfExpr">If
23   * expression</a> supporting conditional evaluation.
24   */
25  public class If
26      extends AbstractExpression {
27    private final IExpression testExpression;
28    private final IExpression thenExpression;
29    private final IExpression elseExpression;
30  
31    /**
32     * Construct a new conditional expression.
33     *
34     * @param text
35     *          the parsed text of the expression
36     * @param testExpression
37     *          the first expression to evaluate
38     * @param thenExpression
39     *          the expression to evaluate if the test is {@code true}
40     * @param elseExpression
41     *          the expression to evaluate if the test is {@code false}
42     */
43    public If(
44        @NonNull String text,
45        @NonNull IExpression testExpression,
46        @NonNull IExpression thenExpression,
47        @NonNull IExpression elseExpression) {
48      super(text);
49      this.testExpression = testExpression;
50      this.thenExpression = thenExpression;
51      this.elseExpression = elseExpression;
52    }
53  
54    /**
55     * Get the "test" expression.
56     *
57     * @return the expression
58     */
59    protected IExpression getTestExpression() {
60      return testExpression;
61    }
62  
63    /**
64     * Get the "then" expression.
65     *
66     * @return the expression
67     */
68    protected IExpression getThenExpression() {
69      return thenExpression;
70    }
71  
72    /**
73     * Get the "else" expression.
74     *
75     * @return the expression
76     */
77    protected IExpression getElseExpression() {
78      return elseExpression;
79    }
80  
81    @Override
82    public List<IExpression> getChildren() {
83      return ObjectUtils.notNull(List.of(testExpression, thenExpression, elseExpression));
84    }
85  
86    @Override
87    protected ISequence<?> evaluate(DynamicContext dynamicContext, ISequence<?> focus) {
88      ISequence<?> result = getTestExpression().accept(dynamicContext, focus);
89  
90      ISequence<?> retval;
91      IBooleanItem effectiveResult = FnBoolean.fnBoolean(result);
92      if (effectiveResult.toBoolean()) {
93        retval = getThenExpression().accept(dynamicContext, focus);
94      } else {
95        retval = getElseExpression().accept(dynamicContext, focus);
96      }
97      return retval;
98    }
99  
100   @Override
101   public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
102     return visitor.visitIf(this, context);
103   }
104 }