Add yang-xpath-api 18/71818/20
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 4 May 2018 21:46:12 +0000 (23:46 +0200)
committerRobert Varga <nite@hq.sk>
Wed, 1 Aug 2018 17:17:58 +0000 (17:17 +0000)
This patch adds the basic model of a YANG-extended XPath 1.0
expression.

JIRA: YANGTOOLS-877
Change-Id: Id5f619e6acd956b7b43f9faba75f34051e3dc509
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
30 files changed:
common/artifacts/pom.xml
features/features-yangtools-experimental/pom.xml
features/odl-yangtools-exp-xpath-api/pom.xml [new file with mode: 0644]
features/pom.xml
yang/pom.xml
yang/yang-xpath-api/pom.xml [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryOperator.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBooleanConstantExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangConstantExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFilterExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunction.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLiteralExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLocationPath.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryOperator.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNegateExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNumberExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPathExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPredicateAware.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangQNameExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangVariableReferenceExpr.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathAxis.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathNodeType.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParser.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParserFactory.java [new file with mode: 0644]
yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/package-info.java [new file with mode: 0644]

index c6920d4328c16e2a67c8aeb5244d6a98aad8b486..554944b6af625d5a94fd93282a33e67cc64ee01f 100644 (file)
                 <version>2.0.10-SNAPSHOT</version>
             </dependency>
 
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-xpath-api</artifactId>
+                <version>0.1.10-SNAPSHOT</version>
+            </dependency>
+
             <dependency>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>util</artifactId>
                 <type>xml</type>
                 <classifier>features</classifier>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>odl-yangtools-exp-xpath-api</artifactId>
+                <version>0.1.10-SNAPSHOT</version>
+                <type>xml</type>
+                <classifier>features</classifier>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 
index 7fab6f67673419268f1fbcb750db8b5ee422378f..8e6047a498f7c81f4a772d00da9a23663f131f50 100644 (file)
             <classifier>features</classifier>
             <type>xml</type>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>odl-yangtools-exp-xpath-api</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
     </dependencies>
 </project>
diff --git a/features/odl-yangtools-exp-xpath-api/pom.xml b/features/odl-yangtools-exp-xpath-api/pom.xml
new file mode 100644 (file)
index 0000000..acd8c80
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright © 2016 Red Hat, Inc. 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
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>single-feature-parent</artifactId>
+        <version>3.1.3</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.yangtools</groupId>
+    <artifactId>odl-yangtools-exp-xpath-api</artifactId>
+    <version>0.1.10-SNAPSHOT</version>
+    <packaging>feature</packaging>
+    <name>OpenDaylight :: Yangtools :: Experimental :: XPath API</name>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yangtools-artifacts</artifactId>
+                <version>2.0.10-SNAPSHOT</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>odl-yangtools-common</artifactId>
+            <type>xml</type>
+            <classifier>features</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-xpath-api</artifactId>
+        </dependency>
+    </dependencies>
+</project>
index dc306ee9d788fa628e23bb8708ccdc6ea10c3c72..21f386ea5dcd49ed4eba6e6870978677dfb5374a 100644 (file)
@@ -40,6 +40,7 @@
 
         <!-- Experimental features -->
         <module>odl-exp-objcache</module>
+        <module>odl-yangtools-exp-xpath-api</module>
 
         <!-- Experimental feature repostitory -->
         <module>features-yangtools-experimental</module>
index 316de1113aa117a5133caac197f8a294ce6542f2..f94618d137d3fda27ae4e84b08dab62ca5f95995 100644 (file)
@@ -39,6 +39,9 @@
         <module>yang-model-immutable</module>
         <module>yang-model-util</module>
 
+        <!-- YANG XPath API and implementation -->
+        <module>yang-xpath-api</module>
+
         <!-- End-user utility for validating YANG models -->
         <module>yang-model-validator</module>
 
diff --git a/yang/yang-xpath-api/pom.xml b/yang/yang-xpath-api/pom.xml
new file mode 100644 (file)
index 0000000..cc15476
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2018 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>bundle-parent</artifactId>
+        <version>3.1.3</version>
+        <relativePath/>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.opendaylight.yangtools</groupId>
+    <artifactId>yang-xpath-api</artifactId>
+    <version>0.1.10-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+    <name>${project.artifactId}</name>
+    <description>YANG XPath ${project.artifactId}</description>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yangtools-artifacts</artifactId>
+                <version>2.0.10-SNAPSHOT</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <configuration>
+                    <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryExpr.java
new file mode 100644 (file)
index 0000000..373b106
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import java.util.Objects;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * A binary expression formed of a {@link #getLeftExpr()}, an {@link #getOperator()} and a {@link #getRightExpr()}.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public abstract class YangBinaryExpr implements YangExpr {
+    private static final long serialVersionUID = 1L;
+
+    private final YangExpr leftExpr;
+    private final YangExpr rightExpr;
+
+    YangBinaryExpr(final YangExpr leftExpr, final YangExpr rightExpr) {
+        this.leftExpr = requireNonNull(leftExpr);
+        this.rightExpr = requireNonNull(rightExpr);
+    }
+
+    public final YangExpr getLeftExpr() {
+        return leftExpr;
+    }
+
+    public final YangExpr getRightExpr() {
+        return rightExpr;
+    }
+
+    public abstract YangBinaryOperator getOperator();
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(leftExpr, rightExpr, getOperator());
+    }
+
+    @Override
+    public final boolean equals(final @Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof YangBinaryExpr)) {
+            return false;
+        }
+        final YangBinaryExpr other = (YangBinaryExpr) obj;
+        return getOperator().equals(other.getOperator()) && leftExpr.equals(other.leftExpr)
+                && rightExpr.equals(other.rightExpr);
+    }
+
+    @Override
+    public final String toString() {
+        return leftExpr.toString() + " " + getOperator() + " " + rightExpr;
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryOperator.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryOperator.java
new file mode 100644 (file)
index 0000000..2718716
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * YANG XPath binary operator.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public enum YangBinaryOperator {
+    /**
+     * Operands are equal.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-EqualityExpr">EqualityExpr</a>
+     */
+    EQUALS("="),
+    /**
+     * Operands do not equal.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-EqualityExpr">EqualityExpr</a>
+     */
+    NOT_EQUALS("!="),
+
+    /**
+     * Left-hand operand is greater than right-hand operand.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-RelationalExpr">RelationalExpr</a>
+     */
+    GT(">"),
+    /**
+     * Left-hand operand is greater than or equal to right-hand operand.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-RelationalExpr">RelationalExpr</a>
+     */
+    GTE(">="),
+    /**
+     * Left-hand operand is less than right-hand operand.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-RelationalExpr">RelationalExpr</a>
+     */
+    LT("<"),
+    /**
+      * Left-hand operand is less than or equal to right-hand operand.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-RelationalExpr">RelationalExpr</a>
+     */
+    LTE("<="),
+
+    /**
+     * Arithmetic addition.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-AdditiveExpr">AdditiveExpr</a>
+     */
+    PLUS("+"),
+    /**
+     * Arithmetic subtraction.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-AdditiveExpr">AdditiveExpr</a>
+     */
+    MINUS("-"),
+
+    /**
+     * Arithmetic multiplication.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-MultiplicativeExpr">MultiplicativeExpr</a>
+     */
+    MUL("*"),
+    /**
+     * Arithmetic division.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-MultiplicativeExpr">MultiplicativeExpr</a>
+     */
+    DIV("div"),
+    /**
+     * Arithmetic modulus after truncating division.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-MultiplicativeExpr">MultiplicativeExpr</a>
+     */
+    MOD("mod");
+
+    private final class Expr extends YangBinaryExpr {
+        private static final long serialVersionUID = 1L;
+
+        Expr(final YangExpr leftExpr, final YangExpr rightExpr) {
+            super(leftExpr, rightExpr);
+        }
+
+        @Override
+        public YangBinaryOperator getOperator() {
+            return YangBinaryOperator.this;
+        }
+    }
+
+    private final String str;
+
+    YangBinaryOperator(final String str) {
+        this.str = requireNonNull(str);
+    }
+
+    @Override
+    public String toString() {
+        return str;
+    }
+
+    public YangBinaryExpr exprWith(final YangExpr leftExpr, final YangExpr rightExpr) {
+        return new Expr(leftExpr, rightExpr);
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBooleanConstantExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBooleanConstantExpr.java
new file mode 100644 (file)
index 0000000..cd7f8d7
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+/**
+ * Expressions which evaluate to a logical {@code true} or {@code false}. These expressions are equivalent to the result
+ * returned by {@code true()} and {@code false()} functions defined in XPath 1.0.
+ *
+ * <p>
+ * They also map these functions' names to the constant pool under their {@link YangFunctionCallExpr#getName()}
+ * identity. All users should use these constants in favor of their equivalent function calls.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public enum YangBooleanConstantExpr implements YangConstantExpr<Boolean> {
+    /**
+     * A constant {@code false} expression.
+     */
+    FALSE(Boolean.FALSE, YangFunction.FALSE),
+    /**
+     * A constant {@code true} expression.
+     */
+    TRUE(Boolean.TRUE, YangFunction.TRUE);
+
+    private final YangFunctionCallExpr function;
+    private final Boolean value;
+
+    @SuppressWarnings("null")
+    YangBooleanConstantExpr(final @Nullable Boolean value, final YangFunction function) {
+        this.value = requireNonNull(value);
+        this.function = YangFunctionCallExpr.of(function.getIdentifier());
+    }
+
+    @Override
+    public QName getIdentifier() {
+        return function.getName();
+    }
+
+    @Override
+    public Boolean getValue() {
+        return value;
+    }
+
+    /**
+     * Convert this constant into the equivalent function. This function is provided for bridging purposes only.
+     *
+     * @return Equivalent function invocation.
+     */
+    public YangFunctionCallExpr asFunction() {
+        return function;
+    }
+
+    public static YangBooleanConstantExpr of(final boolean bool) {
+        return bool ? TRUE : FALSE;
+    }
+
+    public static Optional<YangFunctionCallExpr> forFunctionName(final String functionName) {
+        switch (functionName) {
+            case "false":
+                return Optional.of(FALSE.function);
+            case "true":
+                return Optional.of(TRUE.function);
+            default:
+                return Optional.empty();
+        }
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangConstantExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangConstantExpr.java
new file mode 100644 (file)
index 0000000..26336f7
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.api;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+/**
+ * Common interface for all YANG XPath constant expressions. Each constant has a unique {@link QName}, which acts as its
+ * globally-unique identifier.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public interface YangConstantExpr<T> extends YangExpr, Identifiable<QName> {
+    /**
+     * Return this constant's value.
+     *
+     * @return this constant's value.
+     */
+    // FIXME: this seems dicey w.r.t. empty nodeset constant.
+    T getValue();
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangExpr.java
new file mode 100644 (file)
index 0000000..6ef826c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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.api;
+
+import com.google.common.annotations.Beta;
+import java.io.Serializable;
+import org.opendaylight.yangtools.concepts.Immutable;
+
+/**
+ * Common base interface for all YANG Expression components.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public interface YangExpr extends Immutable, Serializable {
+
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFilterExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFilterExpr.java
new file mode 100644 (file)
index 0000000..7343e56
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Set;
+import org.eclipse.jdt.annotation.Nullable;
+
+@Beta
+public class YangFilterExpr implements YangExpr, YangPredicateAware {
+    private static final class WithPredicates extends YangFilterExpr {
+        private static final long serialVersionUID = 1L;
+
+        private final Set<YangExpr> predicates;
+
+        WithPredicates(final YangExpr expr, final Set<YangExpr> predicates) {
+            super(expr);
+            this.predicates = requireNonNull(predicates);
+        }
+
+        @Override
+        public Set<YangExpr> getPredicates() {
+            return predicates;
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    private final YangExpr expr;
+
+    private YangFilterExpr(final YangExpr expr) {
+        this.expr = requireNonNull(expr);
+    }
+
+    public static YangFilterExpr of(final YangExpr expr) {
+        return new YangFilterExpr(expr);
+    }
+
+    public static YangFilterExpr of(final YangExpr expr, final YangExpr... predicates) {
+        return of(expr, Arrays.asList(predicates));
+    }
+
+    public static YangFilterExpr of(final YangExpr expr, final Collection<YangExpr> predicates) {
+        return predicates.isEmpty() ? new YangFilterExpr(expr)
+                : new WithPredicates(expr, ImmutableSet.copyOf(predicates));
+    }
+
+    public final YangExpr getExpr() {
+        return expr;
+    }
+
+    @Override
+    public Set<YangExpr> getPredicates() {
+        return ImmutableSet.of();
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(expr, getPredicates());
+    }
+
+    @Override
+    public final boolean equals(final @Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof YangFilterExpr)) {
+            return false;
+        }
+        final YangFilterExpr other = (YangFilterExpr) obj;
+        return expr.equals(((YangFilterExpr) obj).expr) && getPredicates().equals(other.getPredicates());
+    }
+
+    @Override
+    public final String toString() {
+        // FIXME: this is not right
+        return "-(" + expr + ")";
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunction.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunction.java
new file mode 100644 (file)
index 0000000..7e893eb
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.api;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+
+/**
+ * Functions known to a YANG XPath.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public enum YangFunction implements Identifiable<QName> {
+    // XPath 1.0 functions
+    BOOLEAN("boolean"),
+    CEILING("ceiling"),
+    CONCAT("concat"),
+    CONTAINS("contains"),
+    COUNT("count"),
+    FALSE("false"),
+    FLOOR("floor"),
+    ID("id"),
+    LANG("lang"),
+    LAST("last"),
+    LOCAL_NAME("local-name"),
+    NAME("name"),
+    NUMBER("number"),
+    NAMESPACE_URI("namespace-uri"),
+    NORMALIZE_SPACE("normalize-space"),
+    NOT("not"),
+    POSITION("position"),
+    ROUND("round"),
+    STARTS_WITH("starts-with"),
+    STRING("string"),
+    STRING_LENGTH("string-length"),
+    SUM("sum"),
+    SUBSTRING("substring"),
+    SUBSTRING_AFTER("substring-after"),
+    SUBSTRING_BEFORE("substring-before"),
+    TRANSLATE("translate"),
+    TRUE("true"),
+
+    // RFC7950 functions
+    BIT_IS_SET("bit-is-set"),
+    CURRENT("current"),
+    DEREF("deref"),
+    DERIVED_FROM("derived-from"),
+    DERIVED_FROM_OR_SELF("derived-from-or-self"),
+    ENUM_VALUE("enum-value"),
+    RE_MATCH("re-match");
+
+    private final QName identifier;
+
+    YangFunction(final String localName) {
+        identifier = QName.create(YangConstants.RFC6020_YIN_MODULE, localName).intern();
+    }
+
+    @Override
+    public QName getIdentifier() {
+        return identifier;
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java
new file mode 100644 (file)
index 0000000..4cf1fbf
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+
+/**
+ * Function call invocation. Function names without a prefix are mapped into {@link YangConstants#RFC6020_YIN_MODULE},
+ * as they are required to be mapped into YANG as per RFC7950 definitions.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public abstract class YangFunctionCallExpr implements YangExpr {
+    static class NoArgs 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;
+
+        WithArgs(final QName name, final List<YangExpr> arguments) {
+            super(name);
+            this.arguments = ImmutableList.copyOf(arguments);
+        }
+
+        @Override
+        public List<YangExpr> getArguments() {
+            return arguments;
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    YangFunctionCallExpr() {
+        // Hidden
+    }
+
+    public static YangFunctionCallExpr of(final QName name) {
+        return new NoArgs(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 List<YangExpr> getArguments() {
+        return ImmutableList.of();
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(getName(), getArguments());
+    }
+
+    @Override
+    public final boolean equals(final @Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof YangFunctionCallExpr)) {
+            return false;
+        }
+        final YangFunctionCallExpr other = (YangFunctionCallExpr) obj;
+        return getName().equals(other.getName()) && getArguments().equals(other.getArguments());
+    }
+
+    @Override
+    public final String toString() {
+        final StringBuilder sb = new StringBuilder().append(getName()).append('(');
+        final Iterator<YangExpr> it = getArguments().iterator();
+        if (it.hasNext()) {
+            sb.append(it.next());
+            while (it.hasNext()) {
+                sb.append(", ").append(it.next());
+            }
+        }
+        return sb.append(')').toString();
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLiteralExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLiteralExpr.java
new file mode 100644 (file)
index 0000000..1ece060
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * An XPath literal expression.
+ *
+ * <p>
+ * Note that a literal may be required to hold a value of {@code instance-identifier} or {@code identityref} type,
+ * when the corresponding {@link YangXPathExpression} was parsed from reference String specification defined in RFC7950.
+ * When such conversion is required, it should be performed through
+ * {@link YangXPathExpression#interpretAsQName(YangLiteralExpr)} or
+ * {@link YangXPathExpression#interpretAsInstanceIdentifier(YangLiteralExpr)}.
+ *
+ * <p>
+ * A more type-safe alternative is {@link YangQNameExpr}, which should be preferred and used whenever possible.
+ *
+ * @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();
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+    private static final YangLiteralExpr EMPTY = new Empty();
+
+    private final String literal;
+
+    protected YangLiteralExpr(final String literal) {
+        this.literal = requireNonNull(literal);
+    }
+
+    public static final YangLiteralExpr empty() {
+        return EMPTY;
+    }
+
+    public static final YangLiteralExpr of(final String literal) {
+        return literal.isEmpty() ? EMPTY : new YangLiteralExpr(literal);
+    }
+
+    public final String getLiteral() {
+        return literal;
+    }
+
+    @Override
+    public final int hashCode() {
+        return literal.hashCode();
+    }
+
+    @Override
+    public final boolean equals(final @Nullable Object obj) {
+        return this == obj || obj instanceof YangLiteralExpr && literal.equals(((YangLiteralExpr) obj).literal);
+    }
+
+    @Override
+    public final String toString() {
+        return literal;
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLocationPath.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLocationPath.java
new file mode 100644 (file)
index 0000000..be9351f
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+@Beta
+public class YangLocationPath implements YangExpr {
+    public abstract static class Step implements Serializable, YangPredicateAware {
+        private static final long serialVersionUID = 1L;
+
+        private final YangXPathAxis axis;
+
+        Step(final YangXPathAxis axis) {
+            this.axis = requireNonNull(axis);
+        }
+
+        public final YangXPathAxis getAxis() {
+            return axis;
+        }
+
+        @Override
+        public abstract int hashCode();
+
+        @Override
+        public abstract boolean equals(@Nullable Object obj);
+
+        @Override
+        public final String toString() {
+            return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
+        }
+
+        protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+            helper.add("axis", axis);
+            final Set<YangExpr> predicates = getPredicates();
+            if (!predicates.isEmpty()) {
+                helper.add("predicates", predicates);
+            }
+            return helper;
+        }
+    }
+
+    public static class AxisStep extends Step {
+        private static final long serialVersionUID = 1L;
+
+        AxisStep(final YangXPathAxis axis) {
+            super(axis);
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(getAxis(), getPredicates());
+        }
+
+        @Override
+        public final boolean equals(@Nullable final Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof AxisStep)) {
+                return false;
+            }
+            final AxisStep other = (AxisStep) obj;
+            return getAxis().equals(other.getAxis()) && getPredicates().equals(other.getPredicates());
+        }
+
+        private Object readResolve() {
+            return getAxis().asStep();
+        }
+    }
+
+    static final class AxisStepWithPredicates extends AxisStep {
+        private static final long serialVersionUID = 1L;
+
+        private final Set<YangExpr> predicates;
+
+        AxisStepWithPredicates(final YangXPathAxis axis, final Set<YangExpr> predicates) {
+            super(axis);
+            this.predicates = requireNonNull(predicates);
+        }
+
+        @Override
+        public Set<YangExpr> getPredicates() {
+            return predicates;
+        }
+    }
+
+    // match a particular namespace
+    public static class NamespaceStep extends Step {
+        private static final long serialVersionUID = 1L;
+
+        private final QNameModule namespace;
+
+        NamespaceStep(final YangXPathAxis axis, final QNameModule namespace) {
+            super(axis);
+            this.namespace = requireNonNull(namespace);
+        }
+
+        public final QNameModule getNamespace() {
+            return namespace;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(getAxis(), namespace, getPredicates());
+        }
+
+        @Override
+        public final boolean equals(@Nullable final Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof NamespaceStep)) {
+                return false;
+            }
+            final NamespaceStep other = (NamespaceStep) obj;
+            return getAxis().equals(other.getAxis()) && namespace.equals(other.namespace)
+                    && getPredicates().equals(other.getPredicates());
+        }
+
+        @Override
+        protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+            return super.addToStringAttributes(helper).add("namespace", namespace);
+        }
+    }
+
+    public static class QNameStep extends Step {
+        private static final long serialVersionUID = 1L;
+
+        private final QName qname;
+
+        QNameStep(final YangXPathAxis axis, final QName qname) {
+            super(axis);
+            this.qname = requireNonNull(qname);
+        }
+
+        public final QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(getAxis(), qname, getPredicates());
+        }
+
+        @Override
+        public final boolean equals(@Nullable final Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof QNameStep)) {
+                return false;
+            }
+            final QNameStep other = (QNameStep) obj;
+            return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
+                    && getPredicates().equals(other.getPredicates());
+        }
+
+        @Override
+        protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+            return super.addToStringAttributes(helper).add("qname", qname);
+        }
+    }
+
+    static final class QNameStepWithPredicates extends QNameStep {
+        private static final long serialVersionUID = 1L;
+
+        private final Set<YangExpr> predicates;
+
+        QNameStepWithPredicates(final YangXPathAxis axis, final QName qname, final Set<YangExpr> predicates) {
+            super(axis, qname);
+            this.predicates = requireNonNull(predicates);
+        }
+
+        @Override
+        public Set<YangExpr> getPredicates() {
+            return predicates;
+        }
+    }
+
+    public static class NodeTypeStep extends Step {
+        private static final long serialVersionUID = 1L;
+
+        private final YangXPathNodeType nodeType;
+
+        NodeTypeStep(final YangXPathAxis axis, final YangXPathNodeType nodeType) {
+            super(axis);
+            this.nodeType = requireNonNull(nodeType);
+        }
+
+        public final YangXPathNodeType getNodeType() {
+            return nodeType;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(getAxis(), nodeType, getPredicates());
+        }
+
+        @Override
+        public boolean equals(@Nullable final Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || !getClass().equals(obj.getClass())) {
+                return false;
+            }
+            final NodeTypeStep other = (NodeTypeStep) obj;
+            return nodeType.equals(other.nodeType) && getAxis().equals(other.getAxis())
+                    && getPredicates().equals(other.getPredicates());
+        }
+
+        @Override
+        protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+            return super.addToStringAttributes(helper).add("nodeType", nodeType);
+        }
+    }
+
+    static final class NodeTypeStepWithPredicates extends NodeTypeStep {
+        private static final long serialVersionUID = 1L;
+
+        private final Set<YangExpr> predicates;
+
+        NodeTypeStepWithPredicates(final YangXPathAxis axis, final YangXPathNodeType type,
+                final Set<YangExpr> predicates) {
+            super(axis, type);
+            this.predicates = requireNonNull(predicates);
+        }
+
+        @Override
+        public Set<YangExpr> getPredicates() {
+            return predicates;
+        }
+    }
+
+    public static class ProcessingInstructionStep extends NodeTypeStep {
+        private static final long serialVersionUID = 1L;
+
+        private final String name;
+
+        ProcessingInstructionStep(final YangXPathAxis axis, final String name) {
+            super(axis, YangXPathNodeType.PROCESSING_INSTRUCTION);
+            this.name = requireNonNull(name);
+        }
+
+        public final String getName() {
+            return name;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(getAxis(), getNodeType(), name, getPredicates());
+        }
+
+        @Override
+        public final boolean equals(final @Nullable Object obj) {
+            return obj == this || super.equals(obj) && name.equals(((ProcessingInstructionStep) obj).name);
+        }
+
+        @Override
+        protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+            return super.addToStringAttributes(helper).add("name", name);
+        }
+    }
+
+    static final class ProcessingInstructionStepWithPredicates extends ProcessingInstructionStep {
+        private static final long serialVersionUID = 1L;
+
+        private final Set<YangExpr> predicates;
+
+        ProcessingInstructionStepWithPredicates(final YangXPathAxis axis, final String name,
+                final Set<YangExpr> predicates) {
+            super(axis, name);
+            this.predicates = requireNonNull(predicates);
+        }
+
+        @Override
+        public Set<YangExpr> getPredicates() {
+            return predicates;
+        }
+    }
+
+    public static class Absolute extends YangLocationPath {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public final boolean isAbsolute() {
+            return true;
+        }
+    }
+
+    private static final class AbsoluteWithSteps extends Absolute {
+        private static final long serialVersionUID = 1L;
+
+        private final List<Step> steps;
+
+        AbsoluteWithSteps(final List<Step> steps) {
+            this.steps = requireNonNull(steps);
+        }
+
+        @Override
+        public List<Step> getSteps() {
+            return steps;
+        }
+    }
+
+    private static final class WithSteps extends YangLocationPath {
+        private static final long serialVersionUID = 1L;
+
+        private final List<Step> steps;
+
+        WithSteps(final List<Step> steps) {
+            this.steps = requireNonNull(steps);
+        }
+
+        @Override
+        public List<Step> getSteps() {
+            return steps;
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+    private static final YangLocationPath ROOT = new Absolute();
+    private static final YangLocationPath SELF = new YangLocationPath();
+
+    YangLocationPath() {
+        // Hidden to prevent external instantiation
+    }
+
+    public static final YangLocationPath of(final boolean absolute) {
+        return absolute ? ROOT : SELF;
+    }
+
+    public static final YangLocationPath of(final boolean absolute, final Step... steps) {
+        return of(absolute, Arrays.asList(steps));
+    }
+
+    public static final YangLocationPath of(final boolean absolute, final Collection<Step> steps) {
+        if (steps.isEmpty()) {
+            return of(absolute);
+        }
+
+        final List<Step> copy = ImmutableList.copyOf(steps);
+        return absolute ? new AbsoluteWithSteps(copy) : new WithSteps(copy);
+    }
+
+    /**
+     * The conceptual {@code root} {@link YangLocationPath}. This path is an absolute path and has no steps.
+     *
+     * @return Empty absolute {@link YangLocationPath}
+     */
+    public static final YangLocationPath root() {
+        return ROOT;
+    }
+
+    /**
+     * The conceptual {@code same} {@link YangLocationPath}. This path is a relative path and has no steps and is
+     * equivalent to a step along {@link YangXPathAxis#SELF}.
+     *
+     * @return Empty relative {@link YangLocationPath}
+     */
+    public static YangLocationPath self() {
+        return SELF;
+    }
+
+    public boolean isAbsolute() {
+        return false;
+    }
+
+    public List<Step> getSteps() {
+        return ImmutableList.of();
+    }
+
+    @Override
+    public final int hashCode() {
+        return Boolean.hashCode(isAbsolute()) * 31 + getSteps().hashCode();
+    }
+
+    @Override
+    public final boolean equals(final @Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof YangLocationPath)) {
+            return false;
+        }
+        final YangLocationPath other = (YangLocationPath) obj;
+        return isAbsolute() == other.isAbsolute() && getSteps().equals(other.getSteps());
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryExpr.java
new file mode 100644 (file)
index 0000000..a59705c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import java.util.Objects;
+import java.util.Set;
+import org.eclipse.jdt.annotation.Nullable;
+
+@Beta
+public abstract class YangNaryExpr implements YangExpr {
+    private static final long serialVersionUID = 1L;
+
+    private final Set<YangExpr> expressions;
+
+    YangNaryExpr(final Set<YangExpr> expressions) {
+        this.expressions = requireNonNull(expressions);
+    }
+
+    public final Set<YangExpr> getExpressions() {
+        return expressions;
+    }
+
+    public abstract YangNaryOperator getOperator();
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(getOperator(), expressions);
+    }
+
+    @Override
+    public final boolean equals(final @Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof YangNaryExpr)) {
+            return false;
+        }
+        final YangNaryExpr other = (YangNaryExpr) obj;
+        return getOperator().equals(other.getOperator()) && expressions.equals(other.expressions);
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryOperator.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryOperator.java
new file mode 100644 (file)
index 0000000..84c94d5
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * YANG XPath binary operator.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public enum YangNaryOperator {
+    /**
+     * Logical 'and' operator on operands.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-AndExpr">AndExpr</a>
+     */
+    AND("and"),
+    /**
+     * Logical 'or' operator on operands.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-OrExpr">OrExpr</a>
+     */
+    OR("or"),
+    /**
+     * Set union operator on operands.
+     *
+     * @see <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-UnionExpr">UnionExpr</a>
+     */
+    UNION("|");
+
+    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) {
+        this.str = requireNonNull(str);
+    }
+
+    @Override
+    public String toString() {
+        return str;
+    }
+
+    public YangExpr exprWith(final Collection<YangExpr> exprs) {
+        final Set<YangExpr> set = ImmutableSet.copyOf(exprs);
+        return set.size() == 1 ? set.iterator().next() : new Expr(set);
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNegateExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNegateExpr.java
new file mode 100644 (file)
index 0000000..41fd77f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.Nullable;
+
+@Beta
+public final class YangNegateExpr implements YangExpr {
+    private static final long serialVersionUID = 1L;
+
+    private final YangExpr subExpr;
+
+    private YangNegateExpr(final YangExpr subExpr) {
+        this.subExpr = requireNonNull(subExpr);
+    }
+
+    public static YangNegateExpr of(final YangExpr subExpr) {
+        return new YangNegateExpr(subExpr);
+    }
+
+    public YangExpr getSubExpr() {
+        return subExpr;
+    }
+
+    @Override
+    public int hashCode() {
+        return subExpr.hashCode();
+    }
+
+    @Override
+    public boolean equals(final @Nullable Object obj) {
+        return this == obj || obj instanceof YangNegateExpr && subExpr.equals(((YangNegateExpr) obj).subExpr);
+    }
+
+    @Override
+    public String toString() {
+        return "-(" + subExpr + ")";
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNumberExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNumberExpr.java
new file mode 100644 (file)
index 0000000..85deadb
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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.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();
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPathExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPathExpr.java
new file mode 100644 (file)
index 0000000..d695d2e
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import java.util.Objects;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.Nullable;
+
+@Beta
+public class YangPathExpr implements YangExpr {
+    private static final class WithLocation extends YangPathExpr {
+        private static final long serialVersionUID = 1L;
+
+        private final YangLocationPath locationPath;
+
+        WithLocation(final YangExpr filterExpr, final YangLocationPath locationPath) {
+            super(filterExpr);
+            this.locationPath = requireNonNull(locationPath);
+        }
+
+        @Override
+        public Optional<YangLocationPath> getLocationPath() {
+            return Optional.of(locationPath);
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    private final YangExpr filterExpr;
+
+    YangPathExpr(final YangExpr filterExpr) {
+        this.filterExpr = requireNonNull(filterExpr);
+    }
+
+    public static YangPathExpr of(final YangExpr filterExpr) {
+        return new YangPathExpr(filterExpr);
+    }
+
+    public static YangExpr of(final YangExpr expr, final YangLocationPath locationPath) {
+        return new WithLocation(expr, locationPath);
+    }
+
+    public final YangExpr getFilterExpr() {
+        return filterExpr;
+    }
+
+    public Optional<YangLocationPath> getLocationPath() {
+        return Optional.empty();
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(filterExpr, getLocationPath());
+    }
+
+    @Override
+    public final boolean equals(final @Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof YangPathExpr)) {
+            return false;
+        }
+        final YangPathExpr other = (YangPathExpr) obj;
+        return filterExpr.equals(((YangPathExpr) obj).filterExpr) && getLocationPath().equals(other.getLocationPath());
+    }
+
+    @Override
+    public final String toString() {
+        // FIXME: this is not right
+        return "-(" + filterExpr + ")";
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPredicateAware.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPredicateAware.java
new file mode 100644 (file)
index 0000000..fd07ec2
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
+
+/**
+ * Common interface for {@link YangFilterExpr} and {@link Step}, both of which can contain predicates. Predicates are
+ * expressed in terms of {@link YangExpr}.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public interface YangPredicateAware {
+    default Set<YangExpr> getPredicates() {
+        return ImmutableSet.of();
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangQNameExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangQNameExpr.java
new file mode 100644 (file)
index 0000000..c1306a1
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+/**
+ * An XPath QName expression. This is an exact QName, which cannot be converted to a string literal compatible with
+ * XPath string representation, because it does not define a prefix/namespace mapping. It represents a strong binding
+ * to a particular namespace at a particular revision.
+ *
+ * <p>
+ * Parsers and users of this package are encouraged to use this class in place of {@link YangLiteralExpr} where
+ * appropriate, as it retains type safety and more semantic context.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public final class YangQNameExpr implements YangExpr {
+    private static final long serialVersionUID = 1L;
+
+    private final QName qname;
+
+    private YangQNameExpr(final QName qname) {
+        this.qname = requireNonNull(qname);
+    }
+
+    public static YangQNameExpr of(final QName qname) {
+        return new YangQNameExpr(qname);
+    }
+
+    public QName getQName() {
+        return qname;
+    }
+
+    @Override
+    public int hashCode() {
+        return qname.hashCode();
+    }
+
+    @Override
+    public boolean equals(final @Nullable Object obj) {
+        return this == obj || obj instanceof YangQNameExpr && qname.equals(((YangQNameExpr) obj).qname);
+    }
+
+    @Override
+    public String toString() {
+        return qname.toString();
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangVariableReferenceExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangVariableReferenceExpr.java
new file mode 100644 (file)
index 0000000..ec7c112
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+@Beta
+public final class YangVariableReferenceExpr implements YangExpr {
+    private static final long serialVersionUID = 1L;
+
+    private final QName variableName;
+
+    private YangVariableReferenceExpr(final QName variableName) {
+        this.variableName = requireNonNull(variableName);
+    }
+
+    public static YangVariableReferenceExpr of(final QName variableName) {
+        return new YangVariableReferenceExpr(variableName);
+    }
+
+    public QName getVariableName() {
+        return variableName;
+    }
+
+    @Override
+    public int hashCode() {
+        return variableName.hashCode();
+    }
+
+    @Override
+    public boolean equals(final @Nullable Object obj) {
+        return this == obj || obj instanceof YangVariableReferenceExpr
+                && variableName.equals(((YangVariableReferenceExpr) obj).variableName);
+    }
+
+    @Override
+    public String toString() {
+        return "$" + variableName;
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathAxis.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathAxis.java
new file mode 100644 (file)
index 0000000..452102c
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.AxisStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.AxisStepWithPredicates;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.NodeTypeStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.NodeTypeStepWithPredicates;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.ProcessingInstructionStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.ProcessingInstructionStepWithPredicates;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStepWithPredicates;
+
+/**
+ * XPath evaluation axis, as defined in <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#axes">XPath 1.0</a>.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public enum YangXPathAxis {
+    /**
+     * The {@code child} axis.
+     */
+    CHILD("child"),
+    /**
+     * The {@code descendant} axis.
+     */
+    DESCENDANT("descendant"),
+    /**
+     * The {@code parent} axis.
+     */
+    PARENT("parent"),
+    /**
+     * The {@code ancestor} axis.
+     */
+    ANCESTOR("ancestor"),
+    /**
+     * The {@code following-sibling} axis.
+     */
+    FOLLOWING_SIBLING("following-sibling"),
+    /**
+     * The {@code preceding-sibling} axis.
+     */
+    PRECEDING_SIBLING("preceding-sibling"),
+    /**
+     * The {@code following} axis.
+     */
+    FOLLOWING("following"),
+    /**
+     * The {@code preceding} axis.
+     */
+    PRECEDING("preceding"),
+    /**
+     * The {@code attribute} axis.
+     */
+    ATTRIBUTE("attribute"),
+    /**
+     * The {@code namespace} axis.
+     */
+    NAMESPACE("namespace"),
+    /**
+     * The {@code self} axis.
+     */
+    SELF("self"),
+    /**
+     * The {@code descendant-or-self} axis.
+     */
+    DESCENDANT_OR_SELF("descendant-or-self"),
+    /**
+     * The {@code ancestor-or-self} axis.
+     */
+    ANCESTOR_OR_SELF("ancestor-or-self");
+
+    private final AxisStep step = new AxisStep(this);
+    private final String str;
+
+    YangXPathAxis(final String str) {
+        this.str = requireNonNull(str);
+    }
+
+    /**
+     * Return the name-independent {@link AxisStep} along this axis. XPath defines following axis {@code AxisStep}s:
+     * <ul>
+     *     <li>{@link #SELF} axis this equals to the "." step</li>
+     *     <li>{@link #PARENT} axis this equals to the ".." step</li>
+     *     <li>{@link #DESCENDANT_OR_SELF} axis this equals to the "//" separator</li>
+     * </ul>
+     * other axes have these defined as a courtesy.
+     *
+     * @return Name-independent AnyNameStep.
+     */
+    public final AxisStep asStep() {
+        return step;
+    }
+
+    public final AxisStep asStep(final Collection<YangExpr> predicates) {
+        final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(predicates);
+        return set.isEmpty() ? step : new AxisStepWithPredicates(this, set);
+    }
+
+    public final QNameStep asStep(final QName qname, final Collection<YangExpr> predicates) {
+        final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(predicates);
+        return set.isEmpty() ? new QNameStep(this, qname) : new QNameStepWithPredicates(this, qname, set);
+    }
+
+    public final NodeTypeStep asStep(final YangXPathNodeType type, final Collection<YangExpr> predicates) {
+        final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(predicates);
+        return set.isEmpty() ? new NodeTypeStep(this, type) : new NodeTypeStepWithPredicates(this, type, set);
+    }
+
+    public final ProcessingInstructionStep asStep(final String name, final Collection<YangExpr> predicates) {
+        final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(predicates);
+        return set.isEmpty() ? new ProcessingInstructionStep(this, name)
+                : new ProcessingInstructionStepWithPredicates(this, name, set);
+    }
+
+    @Override
+    public String toString() {
+        return str;
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java
new file mode 100644 (file)
index 0000000..91d3e7c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.api;
+
+import com.google.common.annotations.Beta;
+import javax.xml.xpath.XPathExpressionException;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+@Beta
+public interface YangXPathExpression extends Immutable {
+
+    YangExpr getRootExpr();
+
+    /**
+     * 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
+     * a reference to an {@code identity}.
+     *
+     * <p>
+     * The syntax of expr is required to conform to
+     * <a href="https://www.w3.org/TR/REC-xml-names/#NT-QName">XML QName format</a>, as further restricted by
+     * <a href="https://tools.ietf.org/html/rfc7950#section-9.10.3">YANG {@code identityref} Lexical Representation</a>.
+     *
+     * <p>
+     * Unfortunately we do not know when a literal will need to be interpreted in this way, as that can only be known
+     * at evaluation.
+     *
+     * @param expr Literal to be reinterpreted
+     * @return QName representation of the literal
+     * @throws XPathExpressionException when the literal cannot be interpreted as a QName
+     */
+    QName interpretAsQName(YangLiteralExpr expr) throws XPathExpressionException;
+
+    // API design: 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/YangXPathNodeType.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathNodeType.java
new file mode 100644 (file)
index 0000000..62f40ec
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018 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.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * XPath node type as defined in <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-NodeType">XPath 1.0</a>.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public enum YangXPathNodeType {
+    /**
+     * A {@code comment}.
+     */
+    COMMENT("comment"),
+    /**
+     * A {@code text}.
+     */
+    TEXT("text"),
+    /**
+     * A {@code processing-instruction}.
+     */
+    PROCESSING_INSTRUCTION("processing-instruction"),
+    /**
+     * A {@code node}.
+     */
+    NODE("node");
+
+    private final String str;
+
+    YangXPathNodeType(final String str) {
+        this.str = requireNonNull(str);
+    }
+
+    @Override
+    public String toString() {
+        return str;
+    }
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParser.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParser.java
new file mode 100644 (file)
index 0000000..f0e5949
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * 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.api;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.xml.xpath.XPathExpressionException;
+
+@Beta
+@NotThreadSafe
+public interface YangXPathParser {
+
+    YangXPathExpression parseExpression(String xpath) throws XPathExpressionException;
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParserFactory.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParserFactory.java
new file mode 100644 (file)
index 0000000..77a02ff
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.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;
+
+/**
+ * Factory for creating {@link YangXPathParser}s.
+ *
+ * @author Robert Varga
+ */
+@Beta
+@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}.
+     *
+     * @param prefixResolver Prefix-to-namespace resolver function
+     * @return An XPathParser
+     * @throws IllegalArgumentException if {@code IEEE754} is not supported.
+     */
+    default YangXPathParser newParser(final Function<String, QNameModule> prefixResolver) {
+        return newParser(prefixResolver, MathMode.IEEE754);
+    }
+
+    /**
+     * Return a {@link YangXPathParser} compliant with {@link MathMode}.
+     *
+     * @param prefixResolver Prefix-to-namespace resolver function
+     * @param mathMode Requested XPath number compliance
+     * @return An XPathParser
+     * @throws NullPointerException if {@code mathMode} is null
+     * @throws IllegalArgumentException if {@code mathMode} is not supported.
+     */
+    YangXPathParser newParser(Function<String, QNameModule> prefixResolver, MathMode mathMode);
+}
diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/package-info.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/package-info.java
new file mode 100644 (file)
index 0000000..c883d78
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018 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
+ */
+/**
+ * Model of a RFC7950 XPath Expression. This model is namespace-bound to a particular set of models as conveyed
+ * by their {@link org.opendaylight.yangtools.yang.common.QNameModule}s. Function names are bound either to their
+ * defining {@link org.opendaylight.yangtools.yang.common.QName}, unprefixed functions are bound to
+ * {@link org.opendaylight.yangtools.yang.common.YangConstants#RFC6020_YIN_MODULE} the same way unprefixed statements
+ * are.
+ *
+ * <p>
+ * The model supports multiple number storage and math operations -- with IEEE754 being the default as per XPath 1.0
+ * specifications, but additional exact operations being available.
+ *
+ * @author Robert Varga
+ */
+@NonNullByDefault
+package org.opendaylight.yangtools.yang.xpath.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
\ No newline at end of file