Introduce yang-xpath-antlr
[yangtools.git] / yang / yang-xpath-impl / src / main / java / org / opendaylight / yangtools / yang / xpath / impl / AntlrXPathParser.java
index cc24c1d9e71e93adb37862c56984c5561ae7c071..17be3ca2cf515f224b16bfae3d7cfa8764c489bb 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,35 @@ 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.antlr.xpathLexer;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.AbbreviatedStepContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.AbsoluteLocationPathNorootContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.AdditiveExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.AndExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.AxisSpecifierContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.EqualityExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.ExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.FilterExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.FunctionCallContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.FunctionNameContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.LocationPathContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.MultiplicativeExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.NCNameContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.NameTestContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.NodeTestContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.OrExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.PathExprNoRootContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.PredicateContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.PrimaryExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.QNameContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.RelationalExprContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.RelativeLocationPathContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.StepContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.UnaryExprNoRootContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.UnionExprNoRootContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.xpathParser.VariableReferenceContext;
 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
 import org.opendaylight.yangtools.yang.xpath.api.YangBooleanConstantExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
@@ -69,32 +99,6 @@ import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathSupport;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathNodeType;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathParser;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.AbbreviatedStepContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.AbsoluteLocationPathNorootContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.AdditiveExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.AndExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.AxisSpecifierContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.EqualityExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.ExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.FilterExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.FunctionCallContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.FunctionNameContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.LocationPathContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.MultiplicativeExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.NCNameContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.NameTestContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.NodeTestContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.OrExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.PathExprNoRootContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.PredicateContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.PrimaryExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.QNameContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.RelationalExprContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.RelativeLocationPathContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.StepContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.UnaryExprNoRootContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.UnionExprNoRootContext;
-import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.VariableReferenceContext;
 
 /**
  * ANTLR-based XPath parser. Uses {@code xpath.g4} ANTLR grammar.
@@ -109,7 +113,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 +150,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 +179,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 +213,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 +241,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 +252,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 +337,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);
         }
 
@@ -411,21 +436,24 @@ abstract class AntlrXPathParser implements YangXPathParser {
     private Deque<Step> parseLocationPathSteps(final RelativeLocationPathContext expr) {
         final Deque<Step> steps = new ArrayDeque<>(expr.getChildCount());
         final Iterator<ParseTree> it = expr.children.iterator();
-        steps.add(parseStep(nextContext(it, StepContext.class)));
+        addNotSelfStep(steps, parseStep(nextContext(it, StepContext.class)));
 
         while (it.hasNext()) {
             parseStepShorthand(it.next()).ifPresent(steps::add);
 
             // Parse step and add it if it's not SELF_STEP
-            final Step step = parseStep(nextContext(it, StepContext.class));
-            if (!SELF_STEP.equals(step)) {
-                steps.add(step);
-            }
+            addNotSelfStep(steps, parseStep(nextContext(it, StepContext.class)));
         }
 
         return steps;
     }
 
+    private static void addNotSelfStep(final Deque<Step> steps, final Step step) {
+        if (!SELF_STEP.equals(step)) {
+            steps.add(step);
+        }
+    }
+
     private YangExpr parseTerminal(final TerminalNode term) {
         final String text = term.getText();
         switch (term.getSymbol().getType()) {
@@ -535,7 +563,7 @@ abstract class AntlrXPathParser implements YangXPathParser {
             final YangBinaryOperator operator = nextOperator(it);
             final YangExpr right = parseAdditive(nextContext(it, AdditiveExprContext.class));
             final Optional<YangExpr> simple = simplifyNumbers(operator, ret, right);
-            ret = simple.isPresent() ? simple.get() : nextOperator(it).exprWith(ret, right);
+            ret = simple.isPresent() ? simple.get() : operator.exprWith(ret, right);
         } while (it.hasNext());
 
         return ret;