2 * Copyright (c) 2018 Pantheon Technologies, s.r.o. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.xpath.impl;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import java.util.List;
13 import org.opendaylight.yangtools.yang.xpath.api.YangBooleanConstantExpr;
14 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
15 import org.opendaylight.yangtools.yang.xpath.api.YangFunction;
16 import org.opendaylight.yangtools.yang.xpath.api.YangFunctionCallExpr;
17 import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
18 import org.opendaylight.yangtools.yang.xpath.api.YangNumberExpr;
20 final class Functions {
21 private static final YangFunctionCallExpr CURRENT = YangFunctionCallExpr.of(YangFunction.CURRENT.getIdentifier());
22 private static final YangFunctionCallExpr LAST = YangFunctionCallExpr.of(YangFunction.LAST.getIdentifier());
23 private static final YangFunctionCallExpr LOCAL_NAME = YangFunctionCallExpr.of(
24 YangFunction.LOCAL_NAME.getIdentifier());
25 private static final YangFunctionCallExpr NAME = YangFunctionCallExpr.of(YangFunction.NAME.getIdentifier());
26 private static final YangFunctionCallExpr NAMESPACE_URI = YangFunctionCallExpr.of(
27 YangFunction.NAMESPACE_URI.getIdentifier());
28 private static final YangFunctionCallExpr NORMALIZE_SPACE = YangFunctionCallExpr.of(
29 YangFunction.NORMALIZE_SPACE.getIdentifier());
30 private static final YangFunctionCallExpr NUMBER = YangFunctionCallExpr.of(YangFunction.NUMBER.getIdentifier());
31 static final YangFunctionCallExpr POSITION = YangFunctionCallExpr.of(YangFunction.POSITION.getIdentifier());
32 private static final YangFunctionCallExpr STRING = YangFunctionCallExpr.of(YangFunction.STRING.getIdentifier());
33 private static final YangFunctionCallExpr STRING_LENGTH = YangFunctionCallExpr.of(
34 YangFunction.STRING_LENGTH.getIdentifier());
40 static YangExpr functionToExpr(final YangFunction func, final List<YangExpr> args) {
43 checkArgument(args.size() == 2, "bit-is-set(node-set, string) takes two arguments");
46 return booleanExpr(args);
48 checkArgument(args.size() == 1, "ceiling(number) takes one argument");
49 // TODO: constant folding requires math support
52 return concatExpr(args);
54 return containsExpr(args);
56 checkArgument(args.size() == 1, "count(node-set) takes one argument");
57 // TODO: constant folding requires math support
60 checkArgument(args.isEmpty(), "current() does not take any arguments");
63 checkArgument(args.size() == 1, "deref(node-set) takes one argument");
66 return derivedFromExpr(args);
67 case DERIVED_FROM_OR_SELF:
68 return derivedFromOrSelfExpr(args);
70 checkArgument(args.size() == 1, "enum-value(node-set) takes one argument");
73 checkArgument(args.isEmpty(), "false() does not take any arguments");
74 return YangBooleanConstantExpr.FALSE;
76 checkArgument(args.size() == 1, "floor(number) takes one argument");
77 // TODO: constant folding requires math support
80 checkArgument(args.size() == 1, "id(object) takes one argument");
83 checkArgument(args.size() == 1, "lang(string) takes one argument");
86 checkArgument(args.isEmpty(), "last() does not take any arguments");
89 checkArgument(args.size() <= 1, "local-name(node-set?) takes at most one argument");
95 checkArgument(args.size() <= 1, "name(node-set?) takes at most one argument");
101 checkArgument(args.size() <= 1, "namespace-uri(node-set?) takes at most one argument");
102 if (args.isEmpty()) {
103 return NAMESPACE_URI;
106 case NORMALIZE_SPACE:
107 return normalizeSpaceExpr(args);
109 return notExpr(args);
111 return numberExpr(args);
113 checkArgument(args.isEmpty(), "position() does not take any arguments");
116 checkArgument(args.size() == 2, "re-match(string, string) takes two arguments");
117 // TODO: static analysis requires XSD regex support -- we should validate args[1] and match it to
118 // args[0] if that is a literal
121 checkArgument(args.size() == 1, "round(number) takes one argument");
122 // TODO: constant folding requires math support
125 return startsWithExpr(args);
127 return stringExpr(args);
129 return stringLengthExpr(args);
131 return substringExpr(args);
132 case SUBSTRING_AFTER:
133 return substringAfterExpr(args);
134 case SUBSTRING_BEFORE:
135 return substringBeforeExpr(args);
137 checkArgument(args.size() == 1, "sub(node-set) takes one argument");
138 // TODO: constant folding requires math support
141 checkArgument(args.size() == 3, "translate(string, string, string) takes three arguments");
142 // TODO: constant folding?
145 checkArgument(args.isEmpty(), "true() does not take any arguments");
146 return YangBooleanConstantExpr.TRUE;
148 throw new IllegalStateException("Unhandled function " + func);
151 return YangFunctionCallExpr.of(func.getIdentifier(), args);
154 private static YangExpr booleanExpr(final List<YangExpr> args) {
155 checkArgument(args.size() == 1, "boolean(object) takes one argument");
156 final YangExpr arg = args.get(0);
157 if (arg instanceof YangBooleanConstantExpr) {
160 if (arg instanceof YangLiteralExpr) {
161 return YangBooleanConstantExpr.of(((YangLiteralExpr) arg).getLiteral().isEmpty());
163 // TODO: handling YangNumberExpr requires math support
164 return YangFunctionCallExpr.of(YangFunction.BOOLEAN.getIdentifier(), args);
167 private static YangExpr concatExpr(final List<YangExpr> args) {
168 checkArgument(args.size() >= 2, "concat(string, string, string*) takes at least two arguments");
170 // TODO: constant folding
172 return YangFunctionCallExpr.of(YangFunction.CONCAT.getIdentifier(), args);
175 private static YangExpr containsExpr(final List<YangExpr> args) {
176 checkArgument(args.size() == 2, "contains(string, string) takes two arguments");
177 final YangExpr first = args.get(0);
178 if (first instanceof YangLiteralExpr) {
179 final YangExpr second = args.get(1);
180 if (second instanceof YangLiteralExpr) {
181 return YangBooleanConstantExpr.of(
182 ((YangLiteralExpr) first).getLiteral().contains(((YangLiteralExpr) second).getLiteral()));
186 // TODO: handling YangNumberExpr requires math support
187 return YangFunctionCallExpr.of(YangFunction.CONTAINS.getIdentifier(), args);
190 private static YangExpr derivedFromExpr(final List<YangExpr> args) {
191 checkArgument(args.size() == 2, "derived-from(node-set, string) takes two arguments");
192 // FIXME: coerce second arg to a QName
193 return YangFunctionCallExpr.of(YangFunction.DERIVED_FROM.getIdentifier(), args);
196 private static YangExpr derivedFromOrSelfExpr(final List<YangExpr> args) {
197 checkArgument(args.size() == 2, "derived-from-or-self(node-set, string) takes two arguments");
198 // FIXME: coerce second arg to a QName
199 return YangFunctionCallExpr.of(YangFunction.DERIVED_FROM_OR_SELF.getIdentifier(), args);
202 private static YangExpr notExpr(final List<YangExpr> args) {
203 checkArgument(args.size() == 1, "not(boolean) takes one argument");
204 final YangExpr arg = args.get(0);
205 if (arg instanceof YangBooleanConstantExpr) {
206 return YangBooleanConstantExpr.of(((YangBooleanConstantExpr) arg).getValue());
209 return YangFunctionCallExpr.of(YangFunction.NOT.getIdentifier(), args);
212 private static YangExpr normalizeSpaceExpr(final List<YangExpr> args) {
213 checkArgument(args.size() <= 1, "number(object?) takes at most one argument");
214 if (args.isEmpty()) {
215 return NORMALIZE_SPACE;
217 final YangExpr arg = args.get(0);
218 if (arg instanceof YangLiteralExpr) {
219 // TODO: normalize value
222 return YangFunctionCallExpr.of(YangFunction.NORMALIZE_SPACE.getIdentifier(), args);
225 private static YangExpr numberExpr(final List<YangExpr> args) {
226 checkArgument(args.size() <= 1, "number(object?) takes at most one argument");
227 if (args.isEmpty()) {
231 final YangExpr arg = args.get(0);
232 if (arg instanceof YangNumberExpr) {
236 // TODO: constant literal folding requires math support
237 return YangFunctionCallExpr.of(YangFunction.NUMBER.getIdentifier(), args);
240 private static YangExpr startsWithExpr(final List<YangExpr> args) {
241 checkArgument(args.size() == 2, "starts-with(string, string) takes two arguments");
243 // TODO: constant folding
245 return YangFunctionCallExpr.of(YangFunction.STARTS_WITH.getIdentifier(), args);
248 private static YangExpr substringBeforeExpr(final List<YangExpr> args) {
249 checkArgument(args.size() == 2, "substring-before(string, string) takes two arguments");
251 // TODO: constant folding
253 return YangFunctionCallExpr.of(YangFunction.SUBSTRING_BEFORE.getIdentifier(), args);
256 private static YangExpr substringAfterExpr(final List<YangExpr> args) {
257 checkArgument(args.size() == 2, "substring-after(string, string) takes two arguments");
259 // TODO: constant folding
261 return YangFunctionCallExpr.of(YangFunction.SUBSTRING_AFTER.getIdentifier(), args);
264 private static YangExpr substringExpr(final List<YangExpr> args) {
265 final int size = args.size();
266 checkArgument(size == 2 || size == 3, "substring-(string, number, number?) takes two or three arguments");
268 // TODO: constant folding
270 return YangFunctionCallExpr.of(YangFunction.SUBSTRING.getIdentifier(), args);
273 private static YangExpr stringExpr(final List<YangExpr> args) {
274 checkArgument(args.size() <= 1, "string(object?) takes at most one argument");
275 if (args.isEmpty()) {
279 final YangExpr arg = args.get(0);
280 if (arg instanceof YangLiteralExpr) {
284 // TODO: handling YangNumberExpr requires math support
285 return YangFunctionCallExpr.of(YangFunction.STRING.getIdentifier(), args);
288 private static YangExpr stringLengthExpr(final List<YangExpr> args) {
289 checkArgument(args.size() <= 1, "string(object?) takes at most one argument");
290 if (args.isEmpty()) {
291 return STRING_LENGTH;
294 // TODO: constant literal requires math support
296 return YangFunctionCallExpr.of(YangFunction.STRING_LENGTH.getIdentifier(), args);