1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.metapath.cst;
7   
8   import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
9   import gov.nist.secauto.metaschema.core.metapath.ISequence;
10  import gov.nist.secauto.metaschema.core.metapath.StaticMetapathException;
11  import gov.nist.secauto.metaschema.core.metapath.function.FunctionService;
12  import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
13  import gov.nist.secauto.metaschema.core.metapath.item.IItem;
14  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
15  
16  import java.util.List;
17  import java.util.Objects;
18  import java.util.stream.Collectors;
19  
20  import javax.xml.namespace.QName;
21  
22  import edu.umd.cs.findbugs.annotations.NonNull;
23  
24  public class StaticFunctionCall implements IExpression {
25    @NonNull
26    private final QName name;
27    @NonNull
28    private final List<IExpression> arguments;
29    private IFunction function;
30  
31    /**
32     * Construct a new function call expression.
33     *
34     * @param name
35     *          the function name
36     * @param arguments
37     *          the expressions used to provide arguments to the function call
38     */
39    public StaticFunctionCall(@NonNull QName name, @NonNull List<IExpression> arguments) {
40      this.name = Objects.requireNonNull(name, "name");
41      this.arguments = Objects.requireNonNull(arguments, "arguments");
42    }
43  
44    /**
45     * Retrieve the associated function.
46     *
47     * @return the function or {@code null} if no function matched the defined name
48     *         and arguments
49     * @throws StaticMetapathException
50     *           if the function was not found
51     */
52    public IFunction getFunction() {
53      synchronized (this) {
54        if (function == null) {
55          function = FunctionService.getInstance().getFunction(name, arguments.size());
56        }
57        return function;
58      }
59    }
60  
61    @Override
62    public List<IExpression> getChildren() {
63      return arguments;
64    }
65  
66    @Override
67    public Class<? extends IItem> getBaseResultType() {
68      Class<? extends IItem> retval = getFunction().getResult().getType();
69      if (retval == null) {
70        retval = IItem.class;
71      }
72      return retval;
73    }
74  
75    @SuppressWarnings("null")
76    @Override
77    public String toASTString() {
78      return String.format("%s[name=%s]", getClass().getName(), getFunction().getQName());
79    }
80  
81    @Override
82    public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
83      return visitor.visitFunctionCall(this, context);
84    }
85  
86    @Override
87    public ISequence<?> accept(DynamicContext dynamicContext, ISequence<?> focus) {
88      List<ISequence<?>> arguments = ObjectUtils.notNull(getChildren().stream().map(expression -> {
89        @NonNull ISequence<?> result = expression.accept(dynamicContext, focus);
90        return result;
91      }).collect(Collectors.toList()));
92  
93      IFunction function = getFunction();
94      return function.execute(arguments, dynamicContext, focus);
95    }
96  }