3c28a1faf4cef3078e3e7d634fdfa4fdd6a9e20f
[yangtools.git] / yang / yang-xpath-impl / src / main / java / org / opendaylight / yangtools / yang / xpath / impl / InstanceIdentifierParser.java
1 /*
2  * Copyright (c) 2019 Pantheon Technologies, s.r.o.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.xpath.impl;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.getChild;
12 import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.illegalShape;
13 import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyToken;
14
15 import com.google.common.collect.ImmutableSet;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.List;
19 import javax.xml.xpath.XPathExpressionException;
20 import org.antlr.v4.runtime.CharStreams;
21 import org.antlr.v4.runtime.CommonTokenStream;
22 import org.antlr.v4.runtime.tree.ParseTree;
23 import org.opendaylight.yangtools.yang.common.QualifiedQName;
24 import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
25 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
26 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
27 import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
28 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
29 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Absolute;
30 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
31 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
32 import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
33 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
34 import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
35 import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathSupport;
36 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.EqQuotedStringContext;
37 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.InstanceIdentifierContext;
38 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.KeyPredicateContext;
39 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.KeyPredicateExprContext;
40 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.LeafListPredicateContext;
41 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.LeafListPredicateExprContext;
42 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.NodeIdentifierContext;
43 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PathArgumentContext;
44 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PosContext;
45 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PredicateContext;
46 import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.QuotedStringContext;
47
48 abstract class InstanceIdentifierParser {
49     static final class Base extends InstanceIdentifierParser {
50         Base(final YangXPathMathMode mathMode) {
51             super(mathMode);
52         }
53
54         @Override
55         YangQNameExpr createExpr(final String prefix, final String localName) {
56             return YangQNameExpr.of(QualifiedQName.of(prefix, localName));
57         }
58
59         @Override
60         QNameStep createChildStep(final String prefix, final String localName, final Collection<YangExpr> predicates) {
61             return YangXPathAxis.CHILD.asStep(QualifiedQName.of(prefix, localName), predicates);
62         }
63     }
64
65     static final class Qualified extends InstanceIdentifierParser {
66         final YangNamespaceContext namespaceContext;
67
68         Qualified(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext) {
69             super(mathMode);
70             this.namespaceContext = requireNonNull(namespaceContext);
71         }
72
73         @Override
74         QNameStep createChildStep(final String prefix, final String localName, final Collection<YangExpr> predicates) {
75             return YangXPathAxis.CHILD.asStep(namespaceContext.createQName(prefix, localName), predicates);
76         }
77
78
79         @Override
80         YangQNameExpr createExpr(final String prefix, final String localName) {
81             return YangQNameExpr.of(namespaceContext.createQName(prefix, localName));
82         }
83
84     }
85
86     private final YangXPathMathSupport mathSupport;
87
88     InstanceIdentifierParser(final YangXPathMathMode mathMode) {
89         this.mathSupport = mathMode.getSupport();
90     }
91
92     final Absolute interpretAsInstanceIdentifier(final YangLiteralExpr expr) throws XPathExpressionException {
93         final xpathLexer lexer = new xpathLexer(CharStreams.fromString(expr.getLiteral()));
94         final instanceIdentifierParser parser = new instanceIdentifierParser(new CommonTokenStream(lexer));
95         final CapturingErrorListener listener = new CapturingErrorListener();
96         lexer.removeErrorListeners();
97         lexer.addErrorListener(listener);
98         parser.removeErrorListeners();
99         parser.addErrorListener(listener);
100
101         final InstanceIdentifierContext id = parser.instanceIdentifier();
102         listener.reportError();
103
104         final int length = id.getChildCount();
105         final List<Step> steps = new ArrayList<>(length / 2);
106         for (int i = 1; i < length; i += 2) {
107             steps.add(parsePathArgument(getChild(id, PathArgumentContext.class, i)));
108         }
109
110         return YangLocationPath.absolute(steps);
111     }
112
113     abstract YangQNameExpr createExpr(String prefix, String localName);
114
115     abstract QNameStep createChildStep(String prefix, String localName, Collection<YangExpr> predicates);
116
117     private QNameStep parsePathArgument(final PathArgumentContext expr) {
118         final NodeIdentifierContext childExpr = getChild(expr, NodeIdentifierContext.class, 0);
119         final String prefix = verifyIdentifier(childExpr, 0);
120         final String localName = verifyIdentifier(childExpr, 2);
121
122         switch (expr.getChildCount()) {
123             case 1:
124                 return createChildStep(prefix, localName, ImmutableSet.of());
125             case 2:
126                 return createChildStep(prefix, localName, parsePredicate(getChild(expr, PredicateContext.class, 1)));
127             default:
128                 throw illegalShape(expr);
129         }
130     }
131
132     private Collection<YangExpr> parsePredicate(final PredicateContext expr) {
133         final ParseTree first = expr.getChild(0);
134         if (first instanceof LeafListPredicateContext) {
135             return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(YangLocationPath.self(),
136                 parseEqStringValue(getChild(((LeafListPredicateContext) first)
137                     .getChild(LeafListPredicateExprContext.class, 0), EqQuotedStringContext.class, 1))));
138         } else if (first instanceof PosContext) {
139             return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(FunctionSupport.POSITION,
140                 mathSupport.createNumber(((PosContext) first).getToken(instanceIdentifierParser.PositiveIntegerValue, 0)
141                     .getText())));
142         }
143
144         final int length = expr.getChildCount();
145         final List<YangExpr> ret = new ArrayList<>(length);
146         for (int i = 0; i < length; ++i) {
147             final KeyPredicateExprContext pred = getChild(expr, KeyPredicateContext.class, i)
148                     .getChild(KeyPredicateExprContext.class, 0);
149             ret.add(YangBinaryOperator.EQUALS.exprWith(
150                 createChildExpr(getChild(pred, NodeIdentifierContext.class, 0)),
151                 parseEqStringValue(getChild(pred, EqQuotedStringContext.class, 1))));
152
153         }
154
155         return ret;
156     }
157
158     private YangQNameExpr createChildExpr(final NodeIdentifierContext expr) {
159         return createExpr(verifyIdentifier(expr, 0), verifyIdentifier(expr, 2));
160     }
161
162     private static String verifyIdentifier(final NodeIdentifierContext expr, final int child) {
163         return verifyToken(expr, child, instanceIdentifierParser.Identifier).getText();
164     }
165
166     private static YangLiteralExpr parseEqStringValue(final EqQuotedStringContext expr) {
167         return YangLiteralExpr.of(verifyToken(getChild(expr, QuotedStringContext.class, expr.getChildCount() - 1), 1,
168             instanceIdentifierParser.STRING).getText());
169     }
170 }