1
2
3
4
5
6 package dev.metaschema.core.metapath.cst;
7
8 import java.util.EnumSet;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.Set;
12 import java.util.UUID;
13
14 import dev.metaschema.core.metapath.DynamicContext;
15 import dev.metaschema.core.metapath.IExpression;
16 import dev.metaschema.core.metapath.function.IArgument;
17 import dev.metaschema.core.metapath.function.IFunction;
18 import dev.metaschema.core.metapath.function.impl.AbstractFunction;
19 import dev.metaschema.core.metapath.item.IItem;
20 import dev.metaschema.core.metapath.item.ISequence;
21 import dev.metaschema.core.metapath.type.ISequenceType;
22 import dev.metaschema.core.util.ObjectUtils;
23 import edu.umd.cs.findbugs.annotations.NonNull;
24 import edu.umd.cs.findbugs.annotations.Nullable;
25
26
27
28
29
30 public class AnonymousFunctionCall
31 extends AbstractExpression {
32 private final AnonymousFunction function;
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public AnonymousFunctionCall(
47 @NonNull String text,
48 @NonNull List<IArgument> arguments,
49 @NonNull ISequenceType result,
50 @NonNull IExpression body) {
51 super(text);
52 this.function = new AnonymousFunction(arguments, result, body);
53 }
54
55
56
57
58
59
60 protected AnonymousFunction getFunction() {
61 return function;
62 }
63
64 @Override
65 public List<IExpression> getChildren() {
66 return ObjectUtils.notNull(List.of(getFunction().getBody()));
67 }
68
69 @Override
70 public Class<? extends IItem> getBaseResultType() {
71 return IFunction.class;
72 }
73
74 @Override
75 public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
76 return visitor.visitAnonymousFunctionCall(this, context);
77 }
78
79 @Override
80 protected ISequence<?> evaluate(DynamicContext dynamicContext, ISequence<?> focus) {
81 return ISequence.of(getFunction());
82 }
83
84 @SuppressWarnings("null")
85 @Override
86 public String toCSTString() {
87 IFunction function = getFunction();
88 return String.format("%s[arguments=%s,return=%s]",
89 getClass().getName(),
90 function.getArguments(),
91 function.getResult().toSignature());
92 }
93
94 private static final class AnonymousFunction
95 extends AbstractFunction {
96 @NonNull
97 private static final Set<FunctionProperty> PROPERTIES = ObjectUtils.notNull(EnumSet.of(
98 FunctionProperty.DETERMINISTIC));
99 @NonNull
100 private final ISequenceType result;
101 @NonNull
102 private final IExpression body;
103
104 public AnonymousFunction(
105 @NonNull List<IArgument> arguments,
106 @NonNull ISequenceType result,
107 @NonNull IExpression body) {
108 super("(anonymous)-" + UUID.randomUUID().toString(), "", arguments);
109 this.result = result;
110 this.body = body;
111 }
112
113 @Override
114 public ISequenceType getResult() {
115 return result;
116 }
117
118 @NonNull
119 protected IExpression getBody() {
120 return body;
121 }
122
123 @Override
124 public Set<FunctionProperty> getProperties() {
125 return PROPERTIES;
126 }
127
128 @Override
129 public boolean isNamedFunction() {
130
131 return false;
132 }
133
134 @Override
135 @NonNull
136 protected ISequence<?> executeInternal(
137 @NonNull List<ISequence<?>> arguments,
138 @NonNull DynamicContext dynamicContext,
139 @Nullable IItem focus) {
140
141 DynamicContext subContext = dynamicContext.subContext();
142 if (arguments.size() != getArguments().size()) {
143 throw new IllegalArgumentException("Number of arguments does not match the number of parameters.");
144 }
145
146 Iterator<? extends ISequence<?>> args = arguments.iterator();
147 Iterator<IArgument> params = getArguments().iterator();
148 while (args.hasNext() && params.hasNext()) {
149 ISequence<?> sequence = args.next();
150 IArgument param = params.next();
151
152 subContext.bindVariableValue(param.getName(), ObjectUtils.notNull(sequence));
153 }
154
155
156
157
158 return body.accept(subContext, ISequence.empty());
159 }
160 }
161 }