Add YangXPathExpression.getYangVersion() 46/85446/1
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 30 Oct 2019 20:21:10 +0000 (21:21 +0100)
committerRobert Varga <nite@hq.sk>
Thu, 31 Oct 2019 07:20:40 +0000 (07:20 +0000)
Retrofit awareness of features contained in a particular expression,
so that runtime can properly evaluate them.

Also update parser to intercept RuntimeExceptions and turn them into
checked XPathExpressionExceptions.

JIRA: YANGTOOLS-1036
Change-Id: I7beab757d6f8fa45f9064a77b6c20f2076903b8e
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit ff01f3e5609c9527cfcc6823c3c20683fa6fc3a6)

yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParser.java
yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrYangXPathExpression.java

index 3d7dc728086d275b2aef2609544aa48624ee5b75..771b191af5366f1921f5dedee306ac5748935740 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QualifiedQName;
 import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
+import org.opendaylight.yangtools.yang.common.YangVersion;
 
 /**
  * An XPath expression. This interface defines a parsed representation of an XPath defined in a YANG context, as
@@ -72,6 +73,17 @@ public interface YangXPathExpression extends Immutable {
      */
     YangXPathMathMode getMathMode();
 
+    /**
+     * Return the minimum YangVersion runtime required to interpret this expression. The default implementation returns
+     * {@link YangVersion#VERSION_1_1}. Implementations are encouraged to provide a less conservative estimate.
+     *
+     * @return YangVersion runtime version compatibility level required to accurately interpret this expression.
+     */
+    // FIXME: 5.0.0: make this method non-default.
+    default YangVersion getYangVersion() {
+        return YangVersion.VERSION_1_1;
+    }
+
     /**
      * 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
index cc24c1d9e71e93adb37862c56984c5561ae7c071..cbec6455aa5a805fa982e40278d0fe73ea8a2f5d 100644 (file)
@@ -21,8 +21,8 @@ import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyTr
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterators;
-import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -31,6 +31,7 @@ import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Set;
 import javax.xml.xpath.XPathExpressionException;
@@ -45,6 +46,7 @@ import org.opendaylight.yangtools.yang.common.QualifiedQName;
 import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
 import org.opendaylight.yangtools.yang.common.YangConstants;
 import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
+import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
 import org.opendaylight.yangtools.yang.xpath.api.YangBooleanConstantExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
@@ -109,7 +111,8 @@ abstract class AntlrXPathParser implements YangXPathParser {
 
         @Override
         public YangXPathExpression parseExpression(final String xpath) throws XPathExpressionException {
-            return new AntlrYangXPathExpression.Base(mathMode, parseExpr(xpath), xpath);
+            final Entry<YangVersion, YangExpr> result = parseExpr(xpath);
+            return new AntlrYangXPathExpression.Base(mathMode, result.getKey(), result.getValue(), xpath);
         }
 
         @Override
@@ -145,7 +148,9 @@ abstract class AntlrXPathParser implements YangXPathParser {
 
         @Override
         public YangXPathExpression.QualifiedBound parseExpression(final String xpath) throws XPathExpressionException {
-            return new AntlrYangXPathExpression.Qualified(mathMode, parseExpr(xpath), xpath, namespaceContext);
+            final Entry<YangVersion, YangExpr> result = parseExpr(xpath);
+            return new AntlrYangXPathExpression.Qualified(mathMode, result.getKey(), result.getValue(), xpath,
+                namespaceContext);
         }
 
         @Override
@@ -172,8 +177,10 @@ abstract class AntlrXPathParser implements YangXPathParser {
         @Override
         public YangXPathExpression.UnqualifiedBound parseExpression(final String xpath)
                 throws XPathExpressionException {
-            return new AntlrYangXPathExpression.Unqualified(mathMode, parseExpr(xpath), xpath, namespaceContext,
-                defaultNamespace);
+            final Entry<YangVersion, YangExpr> result = parseExpr(xpath);
+
+            return new AntlrYangXPathExpression.Unqualified(mathMode, result.getKey(), result.getValue(), xpath,
+                namespaceContext, defaultNamespace);
         }
 
         @Override
@@ -204,6 +211,8 @@ abstract class AntlrXPathParser implements YangXPathParser {
     private final YangXPathMathSupport mathSupport;
     private final FunctionSupport functionSupport;
 
+    private YangVersion minimumYangVersion = YangVersion.VERSION_1;
+
     AntlrXPathParser(final YangXPathMathMode mathMode) {
         this.mathMode = requireNonNull(mathMode);
         this.mathSupport = mathMode.getSupport();
@@ -230,7 +239,8 @@ abstract class AntlrXPathParser implements YangXPathParser {
         }
     }
 
-    final YangExpr parseExpr(final String xpath) throws XPathExpressionException {
+    @SuppressWarnings("checkstyle:illegalCatch")
+    final Entry<YangVersion, YangExpr> parseExpr(final String xpath) throws XPathExpressionException {
         // Create a parser and disconnect it from console error output
         final xpathLexer lexer = new xpathLexer(CharStreams.fromString(xpath));
         final xpathParser parser = new xpathParser(new CommonTokenStream(lexer));
@@ -240,15 +250,25 @@ abstract class AntlrXPathParser implements YangXPathParser {
         lexer.addErrorListener(listener);
         parser.removeErrorListeners();
         parser.addErrorListener(listener);
-
-        final YangExpr expr = parseExpr(parser.main().expr());
+        final ExprContext antlr = parser.main().expr();
         listener.reportError();
-        return expr;
+
+        // Reset our internal context
+        minimumYangVersion = YangVersion.VERSION_1;
+
+        final YangExpr expr;
+        try {
+            expr = parseExpr(antlr);
+        } catch (RuntimeException e) {
+            throw new XPathExpressionException(e);
+        }
+        return new SimpleImmutableEntry<>(minimumYangVersion, expr);
     }
 
     /**
      * Parse and simplify an XPath expression in {@link ExprContext} representation.
      *
+     * @param ctx Current parsing context
      * @param expr ANTLR ExprContext
      * @return A {@link YangExpr}
      * @throws NullPointerException if {@code expr} is null
@@ -315,9 +335,12 @@ abstract class AntlrXPathParser implements YangXPathParser {
                 throw illegalShape(name);
         }
 
-        final List<YangExpr> args = ImmutableList.copyOf(Lists.transform(expr.expr(), this::parseExpr));
+        final List<YangExpr> args = expr.expr().stream().map(this::parseExpr).collect(ImmutableList.toImmutableList());
         final YangFunction func = YANG_FUNCTIONS.get(parsed);
         if (func != null) {
+            if (minimumYangVersion.compareTo(func.getYangVersion()) < 0) {
+                minimumYangVersion = func.getYangVersion();
+            }
             return functionSupport.functionToExpr(func, args);
         }
 
index 52560c5d4c4e1b5cac29d5101ed5b500f3c51bff..90212383534997b54bd664e5bed47bbb2b49dfb7 100644 (file)
@@ -12,6 +12,7 @@ import static java.util.Objects.requireNonNull;
 import javax.xml.xpath.XPathExpressionException;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
+import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
@@ -22,8 +23,9 @@ import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
 
 abstract class AntlrYangXPathExpression implements YangXPathExpression {
     static final class Base extends AntlrYangXPathExpression {
-        Base(final YangXPathMathMode mathMode, final YangExpr rootExpr, final String origStr) {
-            super(mathMode, rootExpr, origStr);
+        Base(final YangXPathMathMode mathMode, final YangVersion yangVersion, final YangExpr rootExpr,
+                final String origStr) {
+            super(mathMode, yangVersion, rootExpr, origStr);
         }
 
         @Override
@@ -40,9 +42,9 @@ abstract class AntlrYangXPathExpression implements YangXPathExpression {
     static class Qualified extends AntlrYangXPathExpression implements QualifiedBound {
         final YangNamespaceContext namespaceContext;
 
-        Qualified(final YangXPathMathMode mathMode, final YangExpr rootExpr,
-            final String origStr, final YangNamespaceContext namespaceContext) {
-            super(mathMode, rootExpr, origStr);
+        Qualified(final YangXPathMathMode mathMode, final YangVersion yangVersion, final YangExpr rootExpr,
+                final String origStr, final YangNamespaceContext namespaceContext) {
+            super(mathMode, yangVersion, rootExpr, origStr);
             this.namespaceContext = requireNonNull(namespaceContext);
         }
 
@@ -64,9 +66,9 @@ abstract class AntlrYangXPathExpression implements YangXPathExpression {
     static final class Unqualified extends Qualified implements UnqualifiedBound {
         private final QNameModule defaultNamespace;
 
-        Unqualified(final YangXPathMathMode mathMode, final YangExpr rootExpr,
-            final String origStr, final YangNamespaceContext namespaceContext, final QNameModule defaultNamespace) {
-            super(mathMode, rootExpr, origStr, namespaceContext);
+        Unqualified(final YangXPathMathMode mathMode, final YangVersion yangVersion, final YangExpr rootExpr,
+                final String origStr, final YangNamespaceContext namespaceContext, final QNameModule defaultNamespace) {
+            super(mathMode, yangVersion, rootExpr, origStr, namespaceContext);
             this.defaultNamespace = requireNonNull(defaultNamespace);
         }
 
@@ -77,11 +79,14 @@ abstract class AntlrYangXPathExpression implements YangXPathExpression {
     }
 
     private final YangXPathMathMode mathMode;
+    private final YangVersion yangVersion;
     private final YangExpr rootExpr;
     private final String origStr;
 
-    AntlrYangXPathExpression(final YangXPathMathMode mathMode, final YangExpr rootExpr, final String origStr) {
+    AntlrYangXPathExpression(final YangXPathMathMode mathMode, final YangVersion yangVersion, final YangExpr rootExpr,
+            final String origStr) {
         this.mathMode = requireNonNull(mathMode);
+        this.yangVersion = requireNonNull(yangVersion);
         this.rootExpr = requireNonNull(rootExpr);
         this.origStr = requireNonNull(origStr);
     }
@@ -91,6 +96,11 @@ abstract class AntlrYangXPathExpression implements YangXPathExpression {
         return mathMode;
     }
 
+    @Override
+    public final YangVersion getYangVersion() {
+        return yangVersion;
+    }
+
     @Override
     public final YangExpr getRootExpr() {
         return rootExpr;