From ff01f3e5609c9527cfcc6823c3c20683fa6fc3a6 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Wed, 30 Oct 2019 21:21:10 +0100 Subject: [PATCH] Add YangXPathExpression.getYangVersion() 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 --- .../yang/xpath/api/YangXPathExpression.java | 12 ++++++ .../yang/xpath/impl/AntlrXPathParser.java | 43 ++++++++++++++----- .../xpath/impl/AntlrYangXPathExpression.java | 28 ++++++++---- 3 files changed, 64 insertions(+), 19 deletions(-) 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 index 3d7dc72808..771b191af5 100644 --- 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 @@ -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 diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParser.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParser.java index cc24c1d9e7..cbec6455aa 100644 --- a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParser.java +++ b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrXPathParser.java @@ -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 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 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 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 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 args = ImmutableList.copyOf(Lists.transform(expr.expr(), this::parseExpr)); + final List 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); } diff --git a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrYangXPathExpression.java b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrYangXPathExpression.java index 52560c5d4c..9021238353 100644 --- a/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrYangXPathExpression.java +++ b/yang/yang-xpath-impl/src/main/java/org/opendaylight/yangtools/yang/xpath/impl/AntlrYangXPathExpression.java @@ -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; -- 2.36.6