<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>
<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>
--- /dev/null
+<?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>
<!-- Experimental features -->
<module>odl-exp-objcache</module>
+ <module>odl-yangtools-exp-xpath-api</module>
<!-- Experimental feature repostitory -->
<module>features-yangtools-experimental</module>
<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>
--- /dev/null
+<?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>
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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 {
+
+}
--- /dev/null
+/*
+ * 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 + ")";
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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 + ")";
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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 + ")";
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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