Update yang-xpath-api design 19/80619/11
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 26 Feb 2019 21:14:28 +0000 (22:14 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 27 Feb 2019 14:26:44 +0000 (15:26 +0100)
This is the first round of API design update, bringing the following
changes:
- MathMode is now a top-level enumeration
- YangXPathMathSupport is an API interface providing common functions
- Prefix resolution is done through YangNamespaceContext
- YangNaryExpr is final
- math-specific YangNumberExprs are hidden classes
- YangFunctionCallExpr.NoArgs is folded into YangFunctionCallExpr
- YangLiteralExpr is now final
- YangXPathExpression exposes MathMode
- Literal interpretation is lazy and works on subexpressions

Change-Id: Ie721678b5513dc088c1a267b98f38d9b0643cb33
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
30 files changed:
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/AbstractYangXPathMathSupport.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/BigDecimalNumberExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/BigDecimalXPathMathSupport.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/DoubleNumberExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/DoubleXPathMathSupport.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFilterExpr.java
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLiteralExpr.java
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryExpr.java
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryOperator.java
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNumberExpr.java
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathMathMode.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathMathSupport.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParser.java
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParserFactory.java
yang/yang-xpath-impl/pom.xml
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/Activator.java [new file with mode: 0644]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParser.java [moved from yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/XPathParser.java with 70% similarity]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParserFactory.java [new file with mode: 0644]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrYangXPathExpression.java
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/BigDecimalXPathParser.java [deleted file]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/DoubleXPathParser.java [deleted file]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/InstanceIdentifierLiteralExpr.java [deleted file]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/InstanceIdentifierParser.java [new file with mode: 0644]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/LiteralExprUtils.java [new file with mode: 0644]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/ParseTreeUtils.java [new file with mode: 0644]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/QNameLiteralExpr.java [deleted file]
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/QNameSupport.java [deleted file]
yang/yang-xpath-impl/src/test/java/org/opendaylight/yangtools/yang/xpath/impl/XPathParserTest.java

diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/AbstractYangXPathMathSupport.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/AbstractYangXPathMathSupport.java
new file mode 100644 (file)
index 0000000..0de1b7c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.api;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import java.util.Optional;
+
+abstract class AbstractYangXPathMathSupport<N extends YangNumberExpr<N, ?>> implements YangXPathMathSupport<N> {
+    private final Class<N> numberClass;
+
+    AbstractYangXPathMathSupport(final Class<N> numberClass) {
+        this.numberClass = requireNonNull(numberClass);
+    }
+
+    @Override
+    public final N negateNumber(final YangNumberExpr<?, ?> number) {
+        checkArgument(numberClass.isInstance(requireNonNull(number)), "Expected %s have %s", numberClass, number);
+        return doNegate(numberClass.cast(number));
+    }
+
+
+    @Override
+    public final Optional<YangExpr> tryEvaluate(final YangBinaryOperator operator,
+            final YangNumberExpr<?, ?> left, final YangNumberExpr<?, ?> right) {
+        if (!numberClass.isInstance(left) || !numberClass.isInstance(right)) {
+            requireNonNull(operator);
+            requireNonNull(left);
+            requireNonNull(right);
+            return Optional.empty();
+        }
+
+        return Optional.of(evaluate(requireNonNull(operator), numberClass.cast(left), numberClass.cast(right)));
+    }
+
+    abstract N doNegate(N number);
+
+    /**
+     * Evaluate an  operator and its left- and right-handside.
+     *
+     * @param operator Operator to apply
+     * @param left Left hand-side
+     * @param right Right hand-side
+     * @return Evaluation result
+     */
+    abstract YangExpr evaluate(YangBinaryOperator operator, N left, N right);
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/BigDecimalNumberExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/BigDecimalNumberExpr.java
new file mode 100644 (file)
index 0000000..3fa4d20
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.api;
+
+import static java.util.Objects.requireNonNull;
+
+import java.math.BigDecimal;
+import org.eclipse.jdt.annotation.Nullable;
+
+final class BigDecimalNumberExpr extends YangNumberExpr<BigDecimalNumberExpr, BigDecimal> {
+    private static final long serialVersionUID = 1L;
+
+    private final BigDecimal number;
+
+    private BigDecimalNumberExpr(final BigDecimal number) {
+        this.number = requireNonNull(number);
+    }
+
+    static BigDecimalNumberExpr of(final BigDecimal number) {
+        return new BigDecimalNumberExpr(number);
+    }
+
+    @Override
+    public BigDecimal getNumber() {
+        return number;
+    }
+
+    @Override
+    public BigDecimalXPathMathSupport getSupport() {
+        return BigDecimalXPathMathSupport.getInstance();
+    }
+
+    @Override
+    public int hashCode() {
+        return number.hashCode();
+    }
+
+    @Override
+    public boolean equals(final @Nullable Object obj) {
+        return this == obj || obj instanceof BigDecimalNumberExpr
+                && number.equals(((BigDecimalNumberExpr) obj).number);
+    }
+
+    @Override
+    public String toString() {
+        return number.toString();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/BigDecimalXPathMathSupport.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/BigDecimalXPathMathSupport.java
new file mode 100644 (file)
index 0000000..34d4829
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.api;
+
+import java.math.BigDecimal;
+
+final class BigDecimalXPathMathSupport extends AbstractYangXPathMathSupport<BigDecimalNumberExpr> {
+    private static final BigDecimalXPathMathSupport INSTANCE = new BigDecimalXPathMathSupport();
+    private static final BigDecimalNumberExpr ZERO = BigDecimalNumberExpr.of(BigDecimal.ZERO);
+    private static final BigDecimalNumberExpr ONE = BigDecimalNumberExpr.of(BigDecimal.ONE);
+    private static final BigDecimalNumberExpr TEN = BigDecimalNumberExpr.of(BigDecimal.TEN);
+
+    private BigDecimalXPathMathSupport() {
+        super(BigDecimalNumberExpr.class);
+    }
+
+    static BigDecimalXPathMathSupport getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    public BigDecimalNumberExpr createNumber(final String str) {
+        switch (str) {
+            case "0":
+                return ZERO;
+            case "1":
+                return ONE;
+            case "10":
+                return TEN;
+            default:
+                return BigDecimalNumberExpr.of(new BigDecimal(str));
+        }
+    }
+
+    @Override
+    BigDecimalNumberExpr doNegate(final BigDecimalNumberExpr number) {
+        return BigDecimalNumberExpr.of(number.getNumber().negate());
+    }
+
+    @Override
+    YangExpr evaluate(final YangBinaryOperator operator, final BigDecimalNumberExpr left,
+            final BigDecimalNumberExpr right) {
+        final BigDecimal l = left.getNumber();
+        final BigDecimal r = right.getNumber();
+
+        final BigDecimal result;
+        switch (operator) {
+            case DIV:
+                result = l.divide(r);
+                break;
+            case EQUALS:
+                return YangBooleanConstantExpr.of(l.equals(r));
+            case GT:
+                return YangBooleanConstantExpr.of(l.compareTo(r) > 0);
+            case GTE:
+                return YangBooleanConstantExpr.of(l.compareTo(r) >= 0);
+            case LT:
+                return YangBooleanConstantExpr.of(l.compareTo(r) < 0);
+            case LTE:
+                return YangBooleanConstantExpr.of(l.compareTo(r) <= 0);
+            case MINUS:
+                result = l.subtract(r);
+                break;
+            case MOD:
+                result = l.remainder(r);
+                break;
+            case MUL:
+                result = l.multiply(r);
+                break;
+            case NOT_EQUALS:
+                return YangBooleanConstantExpr.of(!l.equals(r));
+            case PLUS:
+                result = l.add(r);
+                break;
+            default:
+                throw new IllegalStateException("Unhandled operator " + operator);
+        }
+
+        return BigDecimalNumberExpr.of(result);
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/DoubleNumberExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/DoubleNumberExpr.java
new file mode 100644 (file)
index 0000000..52cdf0b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.api;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.eclipse.jdt.annotation.Nullable;
+
+final class DoubleNumberExpr extends YangNumberExpr<DoubleNumberExpr, Double> {
+    private static final long serialVersionUID = 1L;
+
+    private final double value;
+
+    private DoubleNumberExpr(final double value) {
+        this.value = value;
+    }
+
+    static DoubleNumberExpr of(final double value) {
+        return new DoubleNumberExpr(value);
+    }
+
+    double getValue() {
+        return value;
+    }
+
+    @Override
+    public Double getNumber() {
+        return value;
+    }
+
+    @Override
+    public DoubleXPathMathSupport getSupport() {
+        return DoubleXPathMathSupport.getInstance();
+    }
+
+    @Override
+    public int hashCode() {
+        return Double.hashCode(value);
+    }
+
+    @Override
+    @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY", justification = "")
+    public boolean equals(final @Nullable Object obj) {
+        return this == obj || obj instanceof DoubleNumberExpr && bitEqual(((DoubleNumberExpr) obj).value);
+    }
+
+    private boolean bitEqual(final double other) {
+        return Double.doubleToLongBits(value) == Double.doubleToLongBits(other);
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(value);
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/DoubleXPathMathSupport.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/DoubleXPathMathSupport.java
new file mode 100644 (file)
index 0000000..fb396ef
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.api;
+
+final class DoubleXPathMathSupport extends AbstractYangXPathMathSupport<DoubleNumberExpr> {
+    private static final DoubleXPathMathSupport INSTANCE = new DoubleXPathMathSupport();
+
+    private DoubleXPathMathSupport() {
+        super(DoubleNumberExpr.class);
+    }
+
+    static DoubleXPathMathSupport getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    public DoubleNumberExpr createNumber(final String str) {
+        return DoubleNumberExpr.of(Double.parseDouble(str));
+    }
+
+    @Override
+    DoubleNumberExpr doNegate(final DoubleNumberExpr number) {
+        return DoubleNumberExpr.of(-number.getValue());
+    }
+
+    @Override
+    YangExpr evaluate(final YangBinaryOperator operator, final DoubleNumberExpr left, final DoubleNumberExpr right) {
+        final double l = left.getValue();
+        final double r = right.getValue();
+
+        final double result;
+        switch (operator) {
+            case DIV:
+                result = l / r;
+                break;
+            case EQUALS:
+                return YangBooleanConstantExpr.of(left.equals(right));
+            case GT:
+                return YangBooleanConstantExpr.of(l > r);
+            case GTE:
+                return YangBooleanConstantExpr.of(l >= r);
+            case LT:
+                return YangBooleanConstantExpr.of(l < r);
+            case LTE:
+                return YangBooleanConstantExpr.of(l <= r);
+            case MINUS:
+                result = l - r;
+                break;
+            case MOD:
+                result = l % r;
+                break;
+            case MUL:
+                result = l * r;
+                break;
+            case NOT_EQUALS:
+                return YangBooleanConstantExpr.of(!left.equals(right));
+            case PLUS:
+                result = l + r;
+                break;
+            default:
+                throw new IllegalStateException("Unhandled operator " + operator);
+        }
+
+        return DoubleNumberExpr.of(result);
+    }
+}
index 7343e569ff462d372cafb76a7a657eb12276104e..8b1291bc7e86c4e66ccbade03334236f85dec726 100644 (file)
@@ -22,9 +22,9 @@ public class YangFilterExpr implements YangExpr, YangPredicateAware {
     private static final class WithPredicates extends YangFilterExpr {
         private static final long serialVersionUID = 1L;
 
-        private final Set<YangExpr> predicates;
+        private final ImmutableSet<YangExpr> predicates;
 
-        WithPredicates(final YangExpr expr, final Set<YangExpr> predicates) {
+        WithPredicates(final YangExpr expr, final ImmutableSet<YangExpr> predicates) {
             super(expr);
             this.predicates = requireNonNull(predicates);
         }
@@ -60,11 +60,6 @@ public class YangFilterExpr implements YangExpr, YangPredicateAware {
         return expr;
     }
 
-    @Override
-    public Set<YangExpr> getPredicates() {
-        return ImmutableSet.of();
-    }
-
     @Override
     public final int hashCode() {
         return Objects.hash(expr, getPredicates());
index 4cf1fbf4af81ad17a446581c2a30aed7cd218908..df27ca2c5798ccaa6fb19209acd1729f3299d94e 100644 (file)
@@ -25,26 +25,11 @@ import org.opendaylight.yangtools.yang.common.YangConstants;
  * @author Robert Varga
  */
 @Beta
-public abstract class YangFunctionCallExpr implements YangExpr {
-    static class NoArgs extends YangFunctionCallExpr {
+public class YangFunctionCallExpr implements YangExpr {
+    private static final class WithArgs extends YangFunctionCallExpr {
         private static final long serialVersionUID = 1L;
 
-        private final QName name;
-
-        NoArgs(final QName name) {
-            this.name = requireNonNull(name);
-        }
-
-        @Override
-        public QName getName() {
-            return name;
-        }
-    }
-
-    private static final class WithArgs extends NoArgs {
-        private static final long serialVersionUID = 1L;
-
-        private final List<YangExpr> arguments;
+        private final ImmutableList<YangExpr> arguments;
 
         WithArgs(final QName name, final List<YangExpr> arguments) {
             super(name);
@@ -59,19 +44,23 @@ public abstract class YangFunctionCallExpr implements YangExpr {
 
     private static final long serialVersionUID = 1L;
 
-    YangFunctionCallExpr() {
-        // Hidden
+    private final QName name;
+
+    YangFunctionCallExpr(final QName name) {
+        this.name = requireNonNull(name);
     }
 
     public static YangFunctionCallExpr of(final QName name) {
-        return new NoArgs(name);
+        return new YangFunctionCallExpr(name);
     }
 
     public static YangFunctionCallExpr of(final QName name, final List<YangExpr> arguments) {
         return arguments.isEmpty() ? of(name) : new WithArgs(name, arguments);
     }
 
-    public abstract QName getName();
+    public final QName getName() {
+        return name;
+    }
 
     public List<YangExpr> getArguments() {
         return ImmutableList.of();
index 1ece060f05e1ec00c3d6b731440f8a7bb6ce817b..efff7c6929ae6f0bea91b81a8a64532ba34a9815 100644 (file)
@@ -28,22 +28,9 @@ import org.eclipse.jdt.annotation.Nullable;
  * @author Robert Varga
  */
 @Beta
-public class YangLiteralExpr implements YangExpr {
-    private static final class Empty extends YangLiteralExpr {
-        private static final long serialVersionUID = 1L;
-
-        Empty() {
-            super("");
-        }
-
-        @SuppressWarnings("static-method")
-        Object readResolve() {
-            return empty();
-        }
-    }
-
+public final class YangLiteralExpr implements YangExpr {
     private static final long serialVersionUID = 1L;
-    private static final YangLiteralExpr EMPTY = new Empty();
+    private static final YangLiteralExpr EMPTY = new YangLiteralExpr("");
 
     private final String literal;
 
@@ -51,30 +38,34 @@ public class YangLiteralExpr implements YangExpr {
         this.literal = requireNonNull(literal);
     }
 
-    public static final YangLiteralExpr empty() {
+    public static YangLiteralExpr empty() {
         return EMPTY;
     }
 
-    public static final YangLiteralExpr of(final String literal) {
+    public static YangLiteralExpr of(final String literal) {
         return literal.isEmpty() ? EMPTY : new YangLiteralExpr(literal);
     }
 
-    public final String getLiteral() {
+    public String getLiteral() {
         return literal;
     }
 
     @Override
-    public final int hashCode() {
+    public int hashCode() {
         return literal.hashCode();
     }
 
     @Override
-    public final boolean equals(final @Nullable Object obj) {
+    public boolean equals(final @Nullable Object obj) {
         return this == obj || obj instanceof YangLiteralExpr && literal.equals(((YangLiteralExpr) obj).literal);
     }
 
     @Override
-    public final String toString() {
+    public String toString() {
         return literal;
     }
+
+    protected Object readResolve() {
+        return literal.isEmpty() ? EMPTY : this;
+    }
 }
index fe513a8adb33c262b70a3deb836962fe4fe47091..982b3380957445e8f0469754840e7df0a2f969c8 100644 (file)
@@ -11,33 +11,41 @@ import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
 import java.util.Objects;
 import java.util.Set;
 import org.eclipse.jdt.annotation.Nullable;
 
+/**
+ * A {@link YangExpr} combining a {@link YangNaryOperator} with a set of expressions.
+ */
 @Beta
-public abstract class YangNaryExpr implements YangExpr {
+public final class YangNaryExpr implements YangExpr {
     private static final long serialVersionUID = 1L;
 
-    private final Set<YangExpr> expressions;
+    private final YangNaryOperator operator;
+    private final ImmutableSet<YangExpr> expressions;
 
-    YangNaryExpr(final Set<YangExpr> expressions) {
+    YangNaryExpr(final YangNaryOperator operator, final ImmutableSet<YangExpr> expressions) {
+        this.operator = requireNonNull(operator);
         this.expressions = requireNonNull(expressions);
     }
 
-    public final Set<YangExpr> getExpressions() {
+    public Set<YangExpr> getExpressions() {
         return expressions;
     }
 
-    public abstract YangNaryOperator getOperator();
+    public YangNaryOperator getOperator() {
+        return operator;
+    }
 
     @Override
-    public final int hashCode() {
+    public int hashCode() {
         return Objects.hash(getOperator(), expressions);
     }
 
     @Override
-    public final boolean equals(final @Nullable Object obj) {
+    public boolean equals(final @Nullable Object obj) {
         if (this == obj) {
             return true;
         }
@@ -49,10 +57,10 @@ public abstract class YangNaryExpr implements YangExpr {
     }
 
     @Override
-    public final String toString() {
+    public String toString() {
         return MoreObjects.toStringHelper(YangNaryExpr.class)
-                .add("operator", getOperator())
-                .add("expressions", getExpressions())
+                .add("operator", operator)
+                .add("expressions", expressions)
                 .toString();
     }
 }
index b358b219027e369b04add8ffb0e484278e962011..a4fc4051d94dbc5fb1eb9bfdc7e14edea6301797 100644 (file)
@@ -11,9 +11,7 @@ import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
 import com.google.common.collect.ImmutableSet;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.Collection;
-import java.util.Set;
 
 /**
  * YANG XPath binary operator.
@@ -41,20 +39,6 @@ public enum YangNaryOperator {
      */
     UNION("|");
 
-    @SuppressFBWarnings(value = "SE_INNER_CLASS", justification = "Outer class is a retained enumeration")
-    private final class Expr extends YangNaryExpr {
-        private static final long serialVersionUID = 1L;
-
-        Expr(final Set<YangExpr> exprs) {
-            super(exprs);
-        }
-
-        @Override
-        public YangNaryOperator getOperator() {
-            return YangNaryOperator.this;
-        }
-    }
-
     private final String str;
 
     YangNaryOperator(final String str) {
@@ -67,7 +51,7 @@ public enum YangNaryOperator {
     }
 
     public YangExpr exprWith(final Collection<YangExpr> exprs) {
-        final Set<YangExpr> set = ImmutableSet.copyOf(exprs);
-        return set.size() == 1 ? set.iterator().next() : new Expr(set);
+        final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(exprs);
+        return set.size() == 1 ? set.iterator().next() : new YangNaryExpr(this, set);
     }
 }
index 96f6bd7051f393450f643736c0b3fe45e8902e72..f5b5d1b62d57a331c54458e68424c8e2b167d566 100644 (file)
@@ -7,95 +7,20 @@
  */
 package org.opendaylight.yangtools.yang.xpath.api;
 
-import static java.util.Objects.requireNonNull;
-
 import com.google.common.annotations.Beta;
-import java.math.BigDecimal;
-import org.eclipse.jdt.annotation.Nullable;
 
 /**
  * A number-bearing expression.
  */
 @Beta
 public abstract class YangNumberExpr<T extends YangNumberExpr<T, N>, N extends Number> implements YangExpr {
-    public static final class YangBigDecimal extends YangNumberExpr<YangBigDecimal, BigDecimal> {
-        private static final long serialVersionUID = 1L;
-
-        private final BigDecimal number;
-
-        YangBigDecimal(final BigDecimal number) {
-            this.number = requireNonNull(number);
-        }
-
-        @Override
-        public BigDecimal getNumber() {
-            return number;
-        }
-
-        @Override
-        public int hashCode() {
-            return number.hashCode();
-        }
-
-        @Override
-        public boolean equals(final @Nullable Object obj) {
-            return this == obj || obj instanceof YangBigDecimal
-                    && number.equals(((YangBigDecimal) obj).number);
-        }
-
-        @Override
-        public String toString() {
-            return number.toString();
-        }
-    }
-
-    public static final class YangDouble extends YangNumberExpr<YangDouble, Double> {
-        private static final long serialVersionUID = 1L;
-
-        private final double value;
-
-        YangDouble(final double value) {
-            this.value = value;
-        }
-
-        public double getValue() {
-            return value;
-        }
-
-        @Override
-        public Double getNumber() {
-            return value;
-        }
-
-        @Override
-        public int hashCode() {
-            return Double.hashCode(value);
-        }
-
-        @Override
-        public boolean equals(final @Nullable Object obj) {
-            return this == obj || obj instanceof YangDouble && value == ((YangDouble) obj).value;
-        }
-
-        @Override
-        public String toString() {
-            return String.valueOf(value);
-        }
-    }
-
     private static final long serialVersionUID = 1L;
 
     YangNumberExpr() {
         // Hidden to prevent external subclassing
     }
 
-    public static YangBigDecimal of(final BigDecimal number) {
-        return new YangBigDecimal(number);
-    }
-
-    public static YangDouble of(final double value) {
-        return new YangDouble(value);
-    }
-
     public abstract N getNumber();
+
+    public abstract YangXPathMathSupport<T> getSupport();
 }
index 91d3e7c37df91a8a6fdd7e6472abf3bec24473ea..da7ac0068fa3037ba012850e25f28ccfd2b487ca 100644 (file)
@@ -12,11 +12,28 @@ import javax.xml.xpath.XPathExpressionException;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
 
+/**
+ * An XPath expression.
+ *
+ * @author Robert Varga
+ */
 @Beta
 public interface YangXPathExpression extends Immutable {
-
+    /**
+     * Return the root {@link YangExpr}.
+     *
+     * @return Root expression.
+     */
     YangExpr getRootExpr();
 
+    /**
+     * Return the {@link YangXPathMathMode} used in this expression. All {@link YangNumberExpr} objects used by this
+     * expression are expected to be handled by this mode's {@link YangXPathMathSupport}.
+     *
+     * @return YangXPathMathMode
+     */
+    YangXPathMathMode getMathMode();
+
     /**
      * Attempt to interpret a {@link YangLiteralExpr} referenced by this expression as a {@link QName}. This method
      * is required to perform late value binding of the expression when the literal needs to be interpreted as
@@ -32,12 +49,12 @@ public interface YangXPathExpression extends Immutable {
      * at evaluation.
      *
      * @param expr Literal to be reinterpreted
-     * @return QName representation of the literal
+     * @return YangQNameExpr result of interpretation
      * @throws XPathExpressionException when the literal cannot be interpreted as a QName
      */
-    QName interpretAsQName(YangLiteralExpr expr) throws XPathExpressionException;
+    YangQNameExpr interpretAsQName(YangLiteralExpr expr) throws XPathExpressionException;
 
-    // API design: this really should be YangInstanceIdentifier without AugmentationIdentifier. Implementations are
-    //             strongly encouraged to validate it as such.
+    // FIXME: this really should be YangInstanceIdentifier without AugmentationIdentifier. Implementations are
+    //        strongly encouraged to validate it as such.
     YangLocationPath interpretAsInstanceIdentifier(YangLiteralExpr expr) throws XPathExpressionException;
 }
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathMathMode.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathMathMode.java
new file mode 100644 (file)
index 0000000..073ad60
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * {@link YangXPathParser} number compliance knobs. This enumeration defines what assumptions the parser can make --
+ * affecting its optimization properties around
+ * <a href="https://en.wikipedia.org/wiki/Constant_folding">constant folding</a> when number expressions are
+ * involved.
+ */
+@Beta
+public enum YangXPathMathMode {
+    /**
+     * All number expressions are treated as {@code double}. This in spirit of XPath 1.0 -- any number expression
+     * starts its life as a double, making all operations subject to IEEE754 rounding and range rules.
+     */
+    IEEE754(DoubleXPathMathSupport.getInstance()),
+
+    /**
+     * All number expressions are treated as infinite-precision numbers. This follows the spirit of YANG 1.1 --
+     * where mostly have integral types and decimal64 mapped to BigDecimal. Non-decimal numbers are mapped either to
+     * {@code int}, {@code long} or {@code BigInteger}.
+     */
+    EXACT(BigDecimalXPathMathSupport.getInstance());
+
+    /*
+     * FIXME: 3.0.0: specify and implement this:
+     *
+     * All number expressions are treated either as {@code org.opendaylight.yangtools.yang.common} types with
+     * precision required to hold them. Decimal types are mapped to {@link Decimal64} with all range restrictions
+     * and rounding error implied by it.
+     */
+    // ODL_COMMON;
+
+    private YangXPathMathSupport<?> support;
+
+    YangXPathMathMode(final YangXPathMathSupport<?> support) {
+        this.support = requireNonNull(support);
+    }
+
+    /**
+     * Return {@link YangXPathMathSupport} which provides support for the this mode.
+     *
+     * @return YangXPathMathSupport supporting this mode.
+     */
+    public YangXPathMathSupport<?> getSupport() {
+        return support;
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathMathSupport.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathMathSupport.java
new file mode 100644 (file)
index 0000000..20ee96b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.api;
+
+import com.google.common.annotations.Beta;
+import java.util.Optional;
+
+@Beta
+public interface YangXPathMathSupport<N extends YangNumberExpr<N, ?>> {
+    /**
+     * Create a {@link YangNumberExpr} backed by specified string.
+     *
+     * @param str String
+     * @return number expression
+     * @throws NullPointerException if {@code str} is null
+     * @throws NumberFormatException if the string does not represent a valid number
+     */
+    N createNumber(String str);
+
+    /**
+     * Create a {@link YangNumberExpr} representing the negated value of a number.
+     *
+     * @param number input number
+     * @return negated number expression
+     * @throws NullPointerException if {@code number} is null
+     * @throws IllegalArgumentException if {@code number} has unrecognized type
+     */
+    N negateNumber(YangNumberExpr<?, ?> number);
+
+    /**
+     * Attempt to evaluate an  operator and its left- and right-handside.
+     *
+     * @param operator Operator to apply
+     * @param left Left hand-side
+     * @param right Right hand-side
+     * @return Evaluation result, if evaluation succeeded
+     * @throws NullPointerException if any of the arguments is null
+     */
+    Optional<YangExpr> tryEvaluate(YangBinaryOperator operator, YangNumberExpr<?, ?> left, YangNumberExpr<?, ?> right);
+}
index f0e594909a36e5f96390068da33edfe6ba31b378..0545366427621528de12990052ffe3252b425997 100644 (file)
@@ -11,9 +11,21 @@ import com.google.common.annotations.Beta;
 import javax.annotation.concurrent.NotThreadSafe;
 import javax.xml.xpath.XPathExpressionException;
 
+/**
+ * Interface for converting a String into a {@link YangXPathExpression}.
+ *
+ * @author Robert Varga
+ */
 @Beta
 @NotThreadSafe
 public interface YangXPathParser {
-
+    /**
+     * Parse a string containing an XPath expression.
+     *
+     * @param xpath XPath expression string
+     * @return A parsed {@link YangXPathExpression}
+     * @throws NullPointerException if {@code xpath} is null
+     * @throws XPathExpressionException when the expression cannot be parsed
+     */
     YangXPathExpression parseExpression(String xpath) throws XPathExpressionException;
 }
index 77a02ff01b2818a46d4dfb8d4ae2ce221fed837f..49e29ad438d5cbc905000ad3c3818e3080f385f7 100644 (file)
@@ -8,10 +8,8 @@
 package org.opendaylight.yangtools.yang.xpath.api;
 
 import com.google.common.annotations.Beta;
-import java.util.Set;
-import java.util.function.Function;
 import javax.annotation.concurrent.ThreadSafe;
-import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
 
 /**
  * Factory for creating {@link YangXPathParser}s.
@@ -22,57 +20,23 @@ import org.opendaylight.yangtools.yang.common.QNameModule;
 @ThreadSafe
 public interface YangXPathParserFactory {
     /**
-     * {@link YangXPathParser} number compliance knobs. This enumeration defines what assumptions the parser can make --
-     * affecting its optimization properties around
-     * <a href="https://en.wikipedia.org/wiki/Constant_folding">constant folding</a> when number expressions are
-     * involved.
-     */
-    @Beta
-    enum MathMode {
-        /**
-         * All number expressions are treated as {@code double}. This in spirit of XPath 1.0 -- any number expression
-         * starts its life as a double, making all operations subject to IEEE754 rounding and range rules.
-         */
-        IEEE754,
-
-        /**
-         * All number expressions are treated as infinite-precision numbers. This follows the spirit of YANG 1.1 --
-         * where mostly have integral types and decimal64 mapped to BigDecimal. Non-decimal numbers are mapped either to
-         * {@code int}, {@code long} or {@code BigInteger}.
-         */
-        EXACT,
-
-        /*
-         * FIXME: 3.0.0: specify and implement this:
-         *
-         * All number expressions are treated either as {@code org.opendaylight.yangtools.yang.common} types with
-         * precision required to hold them. Decimal types are mapped to {@link Decimal64} with all range restrictions
-         * and rounding error implied by it.
-         */
-        // ODL_COMMON,
-    }
-
-    Set<MathMode> getSupportedMathModes();
-
-    /**
-     * Return a {@link YangXPathParser} compliant with {@link MathMode#IEEE754}.
+     * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode#IEEE754}.
      *
-     * @param prefixResolver Prefix-to-namespace resolver function
+     * @param namespaceContext Prefix-to-namespace resolver
      * @return An XPathParser
-     * @throws IllegalArgumentException if {@code IEEE754} is not supported.
+     * @throws NullPointerException if {@code namespaceContext} is null
      */
-    default YangXPathParser newParser(final Function<String, QNameModule> prefixResolver) {
-        return newParser(prefixResolver, MathMode.IEEE754);
+    default YangXPathParser newParser(final YangNamespaceContext namespaceContext) {
+        return newParser(namespaceContext, YangXPathMathMode.IEEE754);
     }
 
     /**
-     * Return a {@link YangXPathParser} compliant with {@link MathMode}.
+     * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode}.
      *
-     * @param prefixResolver Prefix-to-namespace resolver function
+     * @param namespaceContext Prefix-to-namespace resolver
      * @param mathMode Requested XPath number compliance
      * @return An XPathParser
-     * @throws NullPointerException if {@code mathMode} is null
-     * @throws IllegalArgumentException if {@code mathMode} is not supported.
+     * @throws NullPointerException if any argument is null
      */
-    YangXPathParser newParser(Function<String, QNameModule> prefixResolver, MathMode mathMode);
+    YangXPathParser newParser(YangNamespaceContext namespaceContext, YangXPathMathMode mathMode);
 }
index f4661ca63d5d487da24e8a6b07a5784893d3a3e7..e9aded9ba4d82d0e22eeb86441793f63b57b0169 100644 (file)
             <groupId>org.antlr</groupId>
             <artifactId>antlr4-runtime</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.kohsuke.metainf-services</groupId>
+            <artifactId>metainf-services</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
                     <listener>false</listener>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Include-Resource>{META-INF/services=${project.build.directory}/classes/META-INF/services}</Include-Resource>
+                        <Bundle-Activator>org.opendaylight.yangtools.yang.xpath.impl.Activator</Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-checkstyle-plugin</artifactId>
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/Activator.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/Activator.java
new file mode 100644 (file)
index 0000000..665631b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.impl;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathParserFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * YANG XPath implementation activator. Publishes a {@link YangXPathParserFactory} implementation on bundle start.
+ *
+ * @author Robert Varga
+ */
+public final class Activator implements BundleActivator {
+    private @Nullable ServiceRegistration<YangXPathParserFactory> registration;
+
+    @Override
+    public void start(final @Nullable BundleContext context) throws Exception {
+        registration = context.registerService(YangXPathParserFactory.class, new AntlrXPathParserFactory(), null);
+    }
+
+    @Override
+    public void stop(final @Nullable BundleContext context) throws Exception {
+        if (registration != null) {
+            registration.unregister();
+            registration = null;
+        }
+    }
+}
similarity index 70%
rename from yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/XPathParser.java
rename to yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParser.java
index b035c696e88c392a84b86b4dae5abe7651c3ecf0..2b53a3b2f9f769bedee01d387d639f32b3dc1b5d 100644 (file)
@@ -10,17 +10,22 @@ package org.opendaylight.yangtools.yang.xpath.impl;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.getChild;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.illegalShape;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyAtLeastChildren;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyChildCount;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyTerminal;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyToken;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyTree;
 
-import com.google.common.base.VerifyException;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
@@ -28,7 +33,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Function;
 import javax.xml.xpath.XPathExpressionException;
 import org.antlr.v4.runtime.BaseErrorListener;
 import org.antlr.v4.runtime.CharStreams;
@@ -36,13 +40,12 @@ import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.RecognitionException;
 import org.antlr.v4.runtime.Recognizer;
-import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.TerminalNode;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
 import org.opendaylight.yangtools.yang.xpath.api.YangBooleanConstantExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
@@ -57,22 +60,13 @@ import org.opendaylight.yangtools.yang.xpath.api.YangNaryExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangNaryOperator;
 import org.opendaylight.yangtools.yang.xpath.api.YangNegateExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangNumberExpr;
-import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangVariableReferenceExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathSupport;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathNodeType;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathParser;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.EqQuotedStringContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.InstanceIdentifierContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.KeyPredicateContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.KeyPredicateExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.LeafListPredicateContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.LeafListPredicateExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.NodeIdentifierContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PathArgumentContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PosContext;
-import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.QuotedStringContext;
 import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.AbbreviatedStepContext;
 import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.AbsoluteLocationPathNorootContext;
 import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.AdditiveExprContext;
@@ -107,8 +101,8 @@ import org.slf4j.LoggerFactory;
  *
  * @author Robert Varga
  */
-abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathParser {
-    private static final Logger LOG = LoggerFactory.getLogger(XPathParser.class);
+final class AntlrXPathParser implements YangXPathParser {
+    private static final Logger LOG = LoggerFactory.getLogger(AntlrXPathParser.class);
     private static final Map<String, YangBinaryOperator> BINARY_OPERATORS = Maps.uniqueIndex(
         Arrays.asList(YangBinaryOperator.values()), YangBinaryOperator::toString);
     private static final Map<String, YangXPathNodeType> NODE_TYPES = Maps.uniqueIndex(Arrays.asList(
@@ -121,10 +115,14 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
     // Cached for checks in hot path
     private static final AxisStep SELF_STEP = YangXPathAxis.SELF.asStep();
 
-    private final QNameSupport qnameSupport;
+    private final YangXPathMathMode mathMode;
+    private final YangXPathMathSupport<?> mathSupport;
+    private final YangNamespaceContext namespaceContext;
 
-    XPathParser(final QNameModule implicitNamespace, final Function<String, QNameModule> prefixes) {
-        qnameSupport = new QNameSupport(implicitNamespace, prefixes);
+    AntlrXPathParser(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext) {
+        this.mathMode = requireNonNull(mathMode);
+        this.mathSupport = mathMode.getSupport();
+        this.namespaceContext = requireNonNull(namespaceContext);
     }
 
     @Override
@@ -159,7 +157,7 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
             throw errors.get(0);
         }
 
-        return new AntlrYangXPathExpression(qnameSupport, expr, xpath);
+        return new AntlrYangXPathExpression(namespaceContext, mathMode, expr, xpath);
     }
 
     /**
@@ -183,24 +181,6 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
         return YangNaryOperator.OR.exprWith(tmp);
     }
 
-    /**
-     * Create a {@link YangNumberExpr} backed by specified string.
-     *
-     * @param str String, matching {@link xpathParser#Number} production.
-     * @return number expression
-     * @throws NullPointerException if {@code str} is null
-     */
-    abstract N createNumber(String str);
-
-    /**
-     * Create a {@link YangNumberExpr} representing the negated value of a number.
-     *
-     * @param number input number
-     * @return negated number expression
-     * @throws NullPointerException if {@code number} is null
-     */
-    abstract N negateNumber(N number);
-
     private YangExpr parseAdditive(final AdditiveExprContext expr) {
         final Iterator<ParseTree> it = expr.children.iterator();
         final YangExpr first = parseMultiplicative(nextContext(it, MultiplicativeExprContext.class));
@@ -243,7 +223,7 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
                 parsed = QName.create(YangConstants.RFC6020_YIN_MODULE, name.getChild(0).getText());
                 break;
             case 3:
-                parsed = qnameSupport.createQName(name.getChild(0).getText(), name.getChild(2).getText());
+                parsed = namespaceContext.createQName(name.getChild(0).getText(), name.getChild(2).getText());
                 break;
             default:
                 throw illegalShape(name);
@@ -385,114 +365,14 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
         switch (term.getSymbol().getType()) {
             case xpathParser.Literal:
                 // We have to strip quotes
-                return parseLiteral(text.substring(1, text.length() - 1));
+                return YangLiteralExpr.of(text.substring(1, text.length() - 1));
             case xpathParser.Number:
-                return createNumber(text);
+                return mathSupport.createNumber(text);
             default:
                 throw illegalShape(term);
         }
     }
 
-    private YangLiteralExpr parseLiteral(final String text) {
-        if (text.isEmpty()) {
-            return YangLiteralExpr.empty();
-        }
-        if (text.charAt(0) == '/') {
-            return parseLocationLiteral(text);
-        }
-        return parseQNameLiteral(text);
-    }
-
-    private YangLiteralExpr parseLocationLiteral(final String text) {
-        final xpathLexer lexer = new xpathLexer(CharStreams.fromString(text));
-        final instanceIdentifierParser parser = new instanceIdentifierParser(new CommonTokenStream(lexer));
-        lexer.removeErrorListeners();
-        parser.removeErrorListeners();
-
-        // FIXME: add listeners
-
-        final InstanceIdentifierContext id = parser.instanceIdentifier();
-        final int length = id.getChildCount();
-        final List<Step> steps = new ArrayList<>(length / 2);
-        for (int i = 1; i < length; i += 2) {
-            steps.add(parsePathArgument(getChild(id, PathArgumentContext.class, i)));
-        }
-
-        return new InstanceIdentifierLiteralExpr(text, steps);
-    }
-
-    private Step parsePathArgument(final PathArgumentContext expr) {
-        final QName qname = parseInstanceIdentifierQName(getChild(expr, NodeIdentifierContext.class, 0));
-        switch (expr.getChildCount()) {
-            case 1:
-                return YangXPathAxis.CHILD.asStep(qname, ImmutableSet.of());
-            case 2:
-                return YangXPathAxis.CHILD.asStep(qname,
-                    parsePathArgumentPredicate(getChild(expr, instanceIdentifierParser.PredicateContext.class, 1)));
-            default:
-                throw illegalShape(expr);
-        }
-    }
-
-    private Collection<YangExpr> parsePathArgumentPredicate(final instanceIdentifierParser.PredicateContext expr) {
-        final ParseTree first = expr.getChild(0);
-        if (first instanceof LeafListPredicateContext) {
-            return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(YangLocationPath.self(),
-                parseEqStringValue(getChild(((LeafListPredicateContext) first)
-                    .getChild(LeafListPredicateExprContext.class, 0), EqQuotedStringContext.class, 1))));
-        } else if (first instanceof PosContext) {
-            return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(Functions.POSITION,
-                createNumber(((PosContext) first).getToken(instanceIdentifierParser.PositiveIntegerValue, 0)
-                    .getText())));
-        }
-
-        final int length = expr.getChildCount();
-        final List<YangExpr> ret = new ArrayList<>(length);
-        for (int i = 0; i < length; ++i) {
-            final KeyPredicateExprContext pred = getChild(expr, KeyPredicateContext.class, i)
-                    .getChild(KeyPredicateExprContext.class, 0);
-            ret.add(YangBinaryOperator.EQUALS.exprWith(
-                YangQNameExpr.of(parseInstanceIdentifierQName(getChild(pred, NodeIdentifierContext.class, 0))),
-                parseEqStringValue(getChild(pred, EqQuotedStringContext.class, 1))));
-
-        }
-
-        return ret;
-    }
-
-    private YangLiteralExpr parseEqStringValue(final EqQuotedStringContext expr) {
-        return parseLiteral(verifyToken(getChild(expr, QuotedStringContext.class, expr.getChildCount() - 1), 1,
-            instanceIdentifierParser.STRING).getText());
-    }
-
-    private QName parseInstanceIdentifierQName(final NodeIdentifierContext expr) {
-        return qnameSupport.createQName(verifyToken(expr, 0, instanceIdentifierParser.Identifier).getText(),
-            verifyToken(expr, 2, instanceIdentifierParser.Identifier).getText());
-    }
-
-    private YangLiteralExpr parseQNameLiteral(final String text) {
-        final int firstColon = text.indexOf(':');
-        if (firstColon != -1) {
-            // If we have two colons this node cannot be interpreted as a QName -- this may explode at evaluation-time,
-            // but that's fine as it will just result in evaluation error. Users do have unit tests, right?
-            final int secondColon = text.indexOf(':', firstColon + 1);
-            if (secondColon == -1) {
-                final Optional<QNameModule> optNamespace = qnameSupport.resolvePrefix(text.substring(0, firstColon));
-                // If we cannot resolve the namespace at evaluation-time has to deal with it.
-                if (optNamespace.isPresent()) {
-                    try {
-                        return new QNameLiteralExpr(text, QName.create(optNamespace.get(),
-                            text.substring(firstColon + 1)));
-                    } catch (IllegalArgumentException e) {
-                        LOG.trace("Cannot interpret {} as a QName", text, e);
-                        return YangLiteralExpr.of(text);
-                    }
-                }
-            }
-        }
-        return YangLiteralExpr.of(text);
-    }
-
     private YangExpr parseUnary(final UnaryExprNoRootContext expr) {
         // any number of '-' and an union expr
         final int size = verifyAtLeastChildren(expr, 1);
@@ -502,7 +382,8 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
             return ret;
         }
 
-        return ret instanceof YangNumberExpr ? negateNumber((N) ret) : YangNegateExpr.of(ret);
+        return ret instanceof YangNumberExpr ? mathSupport.negateNumber((YangNumberExpr<?, ?>) ret)
+                : YangNegateExpr.of(ret);
     }
 
     private YangExpr parseUnion(final UnionExprNoRootContext expr) {
@@ -554,22 +435,11 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
             final YangExpr right) {
         if (left instanceof YangNumberExpr && right instanceof YangNumberExpr) {
             // Constant folding on numbers -- precision plays a role here
-            return simplifyNumbers(operator, (N) left, (N) right);
+            return mathSupport.tryEvaluate(operator, (YangNumberExpr<?, ?>)left, (YangNumberExpr<?, ?>)right);
         }
         return Optional.empty();
     }
 
-    Optional<YangExpr> simplifyNumbers(final YangBinaryOperator operator, final N left, final N right) {
-        switch (operator) {
-            case EQUALS:
-                return Optional.of(YangBooleanConstantExpr.of(left.getNumber().equals(right.getNumber())));
-            case NOT_EQUALS:
-                return Optional.of(YangBooleanConstantExpr.of(!left.getNumber().equals(right.getNumber())));
-            default:
-                return Optional.empty();
-        }
-    }
-
     private YangExpr parseEqualityExpr(final YangExpr left, final Iterator<ParseTree> it) {
         YangExpr ret = left;
         do {
@@ -610,9 +480,9 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
     private QName parseQName(final QNameContext expr) {
         switch (expr.getChildCount()) {
             case 1:
-                return qnameSupport.createQName(getChild(expr, NCNameContext.class, 0).getText());
+                return namespaceContext.createQName(getChild(expr, NCNameContext.class, 0).getText());
             case 3:
-                return qnameSupport.createQName(getChild(expr, NCNameContext.class, 0).getText(),
+                return namespaceContext.createQName(getChild(expr, NCNameContext.class, 0).getText(),
                     getChild(expr, NCNameContext.class, 2).getText());
             default:
                 throw illegalShape(expr);
@@ -683,18 +553,6 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
         return parseOperator(it.next());
     }
 
-    private static <T extends ParseTree> T getChild(final ParseTree parent, final Class<T> type, final int offset) {
-        return verifyTree(type, parent.getChild(offset));
-    }
-
-    private static Token verifyToken(final ParseTree parent, final int offset, final int expected) {
-        final TerminalNode node = verifyTerminal(parent.getChild(offset));
-        final Token ret = node.getSymbol();
-        final int type = ret.getType();
-        verify(type == expected, "Item %s has type %s, expected %s", node, type, expected);
-        return ret;
-    }
-
     private static int getTerminalType(final ParseTree parent, final int offset) {
         return verifyTerminal(parent.getChild(offset)).getSymbol().getType();
     }
@@ -708,36 +566,4 @@ abstract class XPathParser<N extends YangNumberExpr<N, ?>> implements YangXPathP
         final String str = verifyTerminal(tree).getText();
         return verifyNotNull(BINARY_OPERATORS.get(str), "Unhandled operator %s", str);
     }
-
-    private static void verifyChildCount(final ParseTree tree, final int expected) {
-        if (tree.getChildCount() != expected) {
-            throw illegalShape(tree);
-        }
-    }
-
-    private static int verifyAtLeastChildren(final ParseTree tree, final int expected) {
-        final int count = tree.getChildCount();
-        if (count < expected) {
-            throw illegalShape(tree);
-        }
-        return count;
-    }
-
-    private static TerminalNode verifyTerminal(final ParseTree tree) {
-        if (tree instanceof TerminalNode) {
-            return (TerminalNode) tree;
-        }
-        throw new VerifyException(String.format("'%s' is not a terminal node", tree.getText()));
-    }
-
-    private static <T extends ParseTree> T verifyTree(final Class<T> type, final ParseTree tree) {
-        if (type.isInstance(tree)) {
-            return type.cast(tree);
-        }
-        throw new VerifyException(String.format("'%s' does not have expected type %s", tree.getText(), type));
-    }
-
-    private static VerifyException illegalShape(final ParseTree tree) {
-        return new VerifyException(String.format("Invalid parser shape of '%s'", tree.getText()));
-    }
 }
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParserFactory.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParserFactory.java
new file mode 100644 (file)
index 0000000..48e4f50
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.impl;
+
+import org.kohsuke.MetaInfServices;
+import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathParser;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathParserFactory;
+
+@MetaInfServices
+public final class AntlrXPathParserFactory implements YangXPathParserFactory {
+    @Override
+    public YangXPathParser newParser(final YangNamespaceContext namespaceContext,
+            final YangXPathMathMode mathMode) {
+        return new AntlrXPathParser(mathMode, namespaceContext);
+    }
+}
index fa663d2ded39d3548a9e96e2c591e80d3536760f..5d14aeaf7d83eab8c466b2f9b79687ee3c37a91b 100644 (file)
@@ -10,49 +10,46 @@ package org.opendaylight.yangtools.yang.xpath.impl;
 import static java.util.Objects.requireNonNull;
 
 import javax.xml.xpath.XPathExpressionException;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
+import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
 
 final class AntlrYangXPathExpression implements YangXPathExpression {
-    private final QNameSupport qnameSupport;
+    private final YangNamespaceContext namespaceContext;
+    private final YangXPathMathMode mathMode;
     private final YangExpr rootExpr;
     private final String origStr;
 
-    AntlrYangXPathExpression(final QNameSupport qnameSupport, final YangExpr rootExpr, final String origStr) {
-        this.qnameSupport = requireNonNull(qnameSupport);
+    AntlrYangXPathExpression(final YangNamespaceContext namespaceContext, final YangXPathMathMode mathMode,
+            final YangExpr rootExpr, final String origStr) {
+        this.namespaceContext = requireNonNull(namespaceContext);
+        this.mathMode = requireNonNull(mathMode);
         this.rootExpr = requireNonNull(rootExpr);
         this.origStr = requireNonNull(origStr);
     }
 
+    @Override
+    public YangXPathMathMode getMathMode() {
+        return mathMode;
+    }
+
     @Override
     public YangExpr getRootExpr() {
         return rootExpr;
     }
 
     @Override
-    public QName interpretAsQName(final YangLiteralExpr expr) throws XPathExpressionException {
-        // We are eagerly interpreting PrefixedName-compliant strings, hence they have a specific subclass
-        if (expr instanceof QNameLiteralExpr) {
-            return ((QNameLiteralExpr) expr).getQName();
-        }
-
-        try {
-            // Deal with UnprefixedNames by interpreting them in implicit namespace
-            return qnameSupport.createQName(expr.getLiteral());
-        } catch (IllegalArgumentException e) {
-            throw new XPathExpressionException(e);
-        }
+    public YangQNameExpr interpretAsQName(final YangLiteralExpr expr) throws XPathExpressionException {
+        return LiteralExprUtils.interpretAsQName(namespaceContext, expr);
     }
 
     @Override
     public YangLocationPath interpretAsInstanceIdentifier(final YangLiteralExpr expr) throws XPathExpressionException {
-        if (expr instanceof InstanceIdentifierLiteralExpr) {
-            return YangLocationPath.of(true, ((InstanceIdentifierLiteralExpr)expr).getSteps());
-        }
-        throw new XPathExpressionException("Invalid instance-identifier " + expr);
+        return new InstanceIdentifierParser(namespaceContext, mathMode).interpretAsInstanceIdentifier(expr);
     }
 
     @Override
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/BigDecimalXPathParser.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/BigDecimalXPathParser.java
deleted file mode 100644 (file)
index 37a6131..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.xpath.impl;
-
-import java.math.BigDecimal;
-import java.util.Optional;
-import java.util.function.Function;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
-import org.opendaylight.yangtools.yang.xpath.api.YangBooleanConstantExpr;
-import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
-import org.opendaylight.yangtools.yang.xpath.api.YangNumberExpr.YangBigDecimal;
-
-final class BigDecimalXPathParser extends XPathParser<YangBigDecimal> {
-    private static final YangBigDecimal ZERO = YangBigDecimal.of(BigDecimal.ZERO);
-    private static final YangBigDecimal ONE = YangBigDecimal.of(BigDecimal.ONE);
-    private static final YangBigDecimal TEN = YangBigDecimal.of(BigDecimal.TEN);
-
-    BigDecimalXPathParser(final QNameModule implicitNamespace, final Function<String, QNameModule> prefixes) {
-        super(implicitNamespace, prefixes);
-    }
-
-    @Override
-    YangBigDecimal createNumber(final String str) {
-        switch (str) {
-            case "0":
-                return ZERO;
-            case "1":
-                return ONE;
-            case "10":
-                return TEN;
-            default:
-                return YangBigDecimal.of(new BigDecimal(str));
-        }
-    }
-
-    @Override
-    YangBigDecimal negateNumber(final YangBigDecimal number) {
-        return YangBigDecimal.of(number.getNumber().negate());
-    }
-
-    @Override
-    Optional<YangExpr> simplifyNumbers(final YangBinaryOperator operator, final YangBigDecimal left,
-            final YangBigDecimal right) {
-        final BigDecimal l = left.getNumber();
-        final BigDecimal r = right.getNumber();
-
-        final BigDecimal result;
-        switch (operator) {
-            case DIV:
-                result = l.divide(r);
-                break;
-            case EQUALS:
-                return of(l.equals(r));
-            case GT:
-                return of(l.compareTo(r) > 0);
-            case GTE:
-                return of(l.compareTo(r) >= 0);
-            case LT:
-                return of(l.compareTo(r) < 0);
-            case LTE:
-                return of(l.compareTo(r) <= 0);
-            case MINUS:
-                result = l.subtract(r);
-                break;
-            case MOD:
-                result = l.remainder(r);
-                break;
-            case MUL:
-                result = l.multiply(r);
-                break;
-            case NOT_EQUALS:
-                return of(!l.equals(r));
-            case PLUS:
-                result = l.add(r);
-                break;
-            default:
-                throw new IllegalStateException("Unhandled operator " + operator);
-        }
-
-        return Optional.of(YangBigDecimal.of(result));
-    }
-
-    private static Optional<YangExpr> of(final boolean value) {
-        return Optional.of(YangBooleanConstantExpr.of(value));
-    }
-}
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/DoubleXPathParser.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/DoubleXPathParser.java
deleted file mode 100644 (file)
index 40e459c..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.xpath.impl;
-
-import java.util.Optional;
-import java.util.function.Function;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
-import org.opendaylight.yangtools.yang.xpath.api.YangBooleanConstantExpr;
-import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
-import org.opendaylight.yangtools.yang.xpath.api.YangNumberExpr.YangDouble;
-
-final class DoubleXPathParser extends XPathParser<YangDouble> {
-
-    DoubleXPathParser(final QNameModule implicitNamespace, final Function<String, QNameModule> prefixes) {
-        super(implicitNamespace, prefixes);
-    }
-
-    @Override
-    YangDouble createNumber(final String str) {
-        return YangDouble.of(Double.parseDouble(str));
-    }
-
-    @Override
-    YangDouble negateNumber(final YangDouble number) {
-        return YangDouble.of(-number.getValue());
-    }
-
-    @Override
-    Optional<YangExpr> simplifyNumbers(final YangBinaryOperator operator, final YangDouble left,
-            final YangDouble right) {
-        final double l = left.getValue();
-        final double r = right.getValue();
-
-        final double result;
-        switch (operator) {
-            case DIV:
-                result = l / r;
-                break;
-            case EQUALS:
-                return of(l == r);
-            case GT:
-                return of(l > r);
-            case GTE:
-                return of(l >= r);
-            case LT:
-                return of(l < r);
-            case LTE:
-                return of(l <= r);
-            case MINUS:
-                result = l - r;
-                break;
-            case MOD:
-                result = l % r;
-                break;
-            case MUL:
-                result = l * r;
-                break;
-            case NOT_EQUALS:
-                return of(l != r);
-            case PLUS:
-                result = l + r;
-                break;
-            default:
-                throw new IllegalStateException("Unhandled operator " + operator);
-        }
-
-        return Optional.of(YangDouble.of(result));
-    }
-
-    private static Optional<YangExpr> of(final boolean value) {
-        return Optional.of(YangBooleanConstantExpr.of(value));
-    }
-}
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/InstanceIdentifierLiteralExpr.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/InstanceIdentifierLiteralExpr.java
deleted file mode 100644 (file)
index d936286..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.xpath.impl;
-
-import com.google.common.collect.ImmutableList;
-import java.util.List;
-import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
-import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
-
-final class InstanceIdentifierLiteralExpr extends YangLiteralExpr {
-    private static final long serialVersionUID = 1L;
-
-    private final List<Step> steps;
-
-    InstanceIdentifierLiteralExpr(final String str, final List<Step> steps) {
-        super(str);
-        this.steps = ImmutableList.copyOf(steps);
-    }
-
-    List<Step> getSteps() {
-        return steps;
-    }
-}
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/InstanceIdentifierParser.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/InstanceIdentifierParser.java
new file mode 100644 (file)
index 0000000..cc6b3d8
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.impl;
+
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.getChild;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.illegalShape;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyToken;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.xml.xpath.XPathExpressionException;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
+import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
+import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
+import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
+import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathSupport;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.EqQuotedStringContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.KeyPredicateContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.KeyPredicateExprContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.LeafListPredicateContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.LeafListPredicateExprContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.NodeIdentifierContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PathArgumentContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PosContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PredicateContext;
+import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.QuotedStringContext;
+
+final class InstanceIdentifierParser {
+
+    private final YangNamespaceContext namespaceContext;
+    private final YangXPathMathSupport<?> mathSupport;
+
+    InstanceIdentifierParser(final YangNamespaceContext namespaceContext, final YangXPathMathMode mathMode) {
+        this.namespaceContext = requireNonNull(namespaceContext);
+        this.mathSupport = mathMode.getSupport();
+    }
+
+    YangLocationPath interpretAsInstanceIdentifier(final YangLiteralExpr expr) throws XPathExpressionException {
+        final xpathLexer lexer = new xpathLexer(CharStreams.fromString(expr.getLiteral()));
+        final instanceIdentifierParser parser = new instanceIdentifierParser(new CommonTokenStream(lexer));
+        lexer.removeErrorListeners();
+        parser.removeErrorListeners();
+
+        // FIXME: add listeners
+
+        final InstanceIdentifierContext id = parser.instanceIdentifier();
+        final int length = id.getChildCount();
+        final List<Step> steps = new ArrayList<>(length / 2);
+        for (int i = 1; i < length; i += 2) {
+            steps.add(parsePathArgument(getChild(id, PathArgumentContext.class, i)));
+        }
+
+        return YangLocationPath.of(true, steps);
+    }
+
+    private Step parsePathArgument(final PathArgumentContext expr) {
+        final QName qname = parseQName(getChild(expr, NodeIdentifierContext.class, 0));
+        switch (expr.getChildCount()) {
+            case 1:
+                return YangXPathAxis.CHILD.asStep(qname, ImmutableSet.of());
+            case 2:
+                return YangXPathAxis.CHILD.asStep(qname, parsePredicate(getChild(expr, PredicateContext.class, 1)));
+            default:
+                throw illegalShape(expr);
+        }
+    }
+
+    private Collection<YangExpr> parsePredicate(final PredicateContext expr) {
+        final ParseTree first = expr.getChild(0);
+        if (first instanceof LeafListPredicateContext) {
+            return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(YangLocationPath.self(),
+                parseEqStringValue(getChild(((LeafListPredicateContext) first)
+                    .getChild(LeafListPredicateExprContext.class, 0), EqQuotedStringContext.class, 1))));
+        } else if (first instanceof PosContext) {
+            return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(Functions.POSITION, mathSupport.createNumber(
+                ((PosContext) first).getToken(instanceIdentifierParser.PositiveIntegerValue, 0).getText())));
+        }
+
+        final int length = expr.getChildCount();
+        final List<YangExpr> ret = new ArrayList<>(length);
+        for (int i = 0; i < length; ++i) {
+            final KeyPredicateExprContext pred = getChild(expr, KeyPredicateContext.class, i)
+                    .getChild(KeyPredicateExprContext.class, 0);
+            ret.add(YangBinaryOperator.EQUALS.exprWith(
+                YangQNameExpr.of(parseQName(getChild(pred, NodeIdentifierContext.class, 0))),
+                parseEqStringValue(getChild(pred, EqQuotedStringContext.class, 1))));
+
+        }
+
+        return ret;
+    }
+
+    private QName parseQName(final NodeIdentifierContext expr) {
+        return namespaceContext.createQName(
+            verifyToken(expr, 0, instanceIdentifierParser.Identifier).getText(),
+            verifyToken(expr, 2, instanceIdentifierParser.Identifier).getText());
+    }
+
+    private static YangLiteralExpr parseEqStringValue(final EqQuotedStringContext expr) {
+        return YangLiteralExpr.of(verifyToken(getChild(expr, QuotedStringContext.class, expr.getChildCount() - 1), 1,
+            instanceIdentifierParser.STRING).getText());
+    }
+}
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/LiteralExprUtils.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/LiteralExprUtils.java
new file mode 100644 (file)
index 0000000..2d0ed0c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.impl;
+
+import javax.xml.xpath.XPathExpressionException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
+import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
+import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
+
+/**
+ * Utilities for interpreting {@link YangLiteralExpr}s as {@link YangQNameExpr}s and {@link YangLocationPath}s.
+ */
+final class LiteralExprUtils {
+    private LiteralExprUtils() {
+
+    }
+
+    static YangQNameExpr interpretAsQName(final YangNamespaceContext namespaceContext, final YangLiteralExpr expr)
+            throws XPathExpressionException {
+        final String text = expr.getLiteral();
+        final int colon = text.indexOf(':');
+        final QName qname;
+        if (colon != -1) {
+            try {
+                qname = namespaceContext.createQName(text.substring(0, colon), text.substring(colon + 1));
+            } catch (IllegalArgumentException e) {
+                throw new XPathExpressionException(e);
+            }
+        } else {
+            try {
+                // Deal with UnprefixedNames by interpreting them in implicit namespace
+                qname = namespaceContext.createQName(expr.getLiteral());
+            } catch (IllegalArgumentException | IllegalStateException e) {
+                throw new XPathExpressionException(e);
+            }
+        }
+
+        return YangQNameExpr.of(qname);
+    }
+}
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/ParseTreeUtils.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/ParseTreeUtils.java
new file mode 100644 (file)
index 0000000..8e6c035
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.xpath.impl;
+
+import static com.google.common.base.Verify.verify;
+
+import com.google.common.base.VerifyException;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * Utility methods for dealing with {@link ParseTree}s.
+ */
+final class ParseTreeUtils {
+    private ParseTreeUtils() {
+
+    }
+
+    static <T extends ParseTree> T getChild(final ParseTree parent, final Class<T> type, final int offset) {
+        return verifyTree(type, parent.getChild(offset));
+    }
+
+    static void verifyChildCount(final ParseTree tree, final int expected) {
+        if (tree.getChildCount() != expected) {
+            throw illegalShape(tree);
+        }
+    }
+
+    static int verifyAtLeastChildren(final ParseTree tree, final int expected) {
+        final int count = tree.getChildCount();
+        if (count < expected) {
+            throw illegalShape(tree);
+        }
+        return count;
+    }
+
+    static TerminalNode verifyTerminal(final ParseTree tree) {
+        if (tree instanceof TerminalNode) {
+            return (TerminalNode) tree;
+        }
+        throw new VerifyException(String.format("'%s' is not a terminal node", tree.getText()));
+    }
+
+    static Token verifyToken(final ParseTree parent, final int offset, final int expected) {
+        final TerminalNode node = verifyTerminal(parent.getChild(offset));
+        final Token ret = node.getSymbol();
+        final int type = ret.getType();
+        verify(type == expected, "Item %s has type %s, expected %s", node, type, expected);
+        return ret;
+    }
+
+    static <T extends ParseTree> T verifyTree(final Class<T> type, final ParseTree tree) {
+        if (type.isInstance(tree)) {
+            return type.cast(tree);
+        }
+        throw new VerifyException(String.format("'%s' does not have expected type %s", tree.getText(), type));
+    }
+
+    static VerifyException illegalShape(final ParseTree tree) {
+        return new VerifyException(String.format("Invalid parser shape of '%s'", tree.getText()));
+    }
+}
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/QNameLiteralExpr.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/QNameLiteralExpr.java
deleted file mode 100644 (file)
index 6f8d9a2..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.xpath.impl;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.requireNonNull;
-
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
-
-/**
- * Eagerly-bound literal interpreted a PrefixName.
- *
- * @author Robert Varga
- */
-final class QNameLiteralExpr extends YangLiteralExpr {
-    private static final long serialVersionUID = 1L;
-
-    private final QName qname;
-
-    QNameLiteralExpr(final String str, final QName qname) {
-        super(str);
-        checkArgument(str.endsWith(qname.getLocalName()));
-        this.qname = requireNonNull(qname);
-    }
-
-    QName getQName() {
-        return qname;
-    }
-}
diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/QNameSupport.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/QNameSupport.java
deleted file mode 100644 (file)
index 68a2f8d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.xpath.impl;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.requireNonNull;
-
-import java.util.Optional;
-import java.util.function.Function;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-
-final class QNameSupport {
-    private final Function<String, QNameModule> prefixes;
-    private final QNameModule implicitNamespace;
-
-    QNameSupport(final QNameModule implicitNamespace, final Function<String, QNameModule> prefixes) {
-        this.implicitNamespace = requireNonNull(implicitNamespace);
-        this.prefixes = requireNonNull(prefixes);
-    }
-
-    QName createQName(final String localName) {
-        return QName.create(implicitNamespace, localName);
-    }
-
-    QName createQName(final String prefix, final String localName) {
-        final QNameModule namespace = prefixes.apply(prefix);
-        checkArgument(namespace != null, "Failed to lookup namespace for prefix %s", prefix);
-        return QName.create(namespace, localName);
-    }
-
-    Optional<QNameModule> resolvePrefix(final String prefix) {
-        return Optional.ofNullable(prefixes.apply(requireNonNull(prefix)));
-    }
-}
index 2a3882235698323ae4f3a98fc14012f9ac3c0ae9..3fe300bd0fd969b9ef6f2207719f5005cbe57fba 100644 (file)
@@ -9,29 +9,32 @@ package org.opendaylight.yangtools.yang.xpath.impl;
 
 import static org.junit.Assert.assertEquals;
 
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableBiMap;
 import java.net.URI;
-import java.util.Map;
 import javax.xml.xpath.XPathExpressionException;
 import org.eclipse.jdt.annotation.Nullable;
 import org.junit.Before;
 import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.BiMapYangNamespaceContext;
 import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
 import org.opendaylight.yangtools.yang.xpath.api.YangBooleanConstantExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
 
 @SuppressWarnings("null")
 public class XPathParserTest {
-    private static final QNameModule DEF_NS = QNameModule.create(URI.create("defaultns"));
-    private static final Map<String, QNameModule> NAMESPACES = ImmutableMap.of(
+    private static final QNameModule DEFNS = QNameModule.create(URI.create("defaultns"));
+    private static final YangNamespaceContext CONTEXT = new BiMapYangNamespaceContext(ImmutableBiMap.of(
+        "def", DEFNS,
         "foo", QNameModule.create(URI.create("foo")),
-        "bar", QNameModule.create(URI.create("bar")));
+        "bar", QNameModule.create(URI.create("bar"))), DEFNS);
 
-    private @Nullable XPathParser<?> parser;
+    private @Nullable AntlrXPathParser parser;
 
     @Before
     public void before() {
-        parser = new BigDecimalXPathParser(DEF_NS, NAMESPACES::get);
+        parser = new AntlrXPathParser(YangXPathMathMode.IEEE754, CONTEXT);
     }
 
     @Test