ab149ad662492a9b10501de96994a9ae0049b63f
[yangtools.git] / xpath / 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.UnresolvedQName;
24 import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
25 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierLexer;
26 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser;
27 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.EqQuotedStringContext;
28 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.InstanceIdentifierContext;
29 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.KeyPredicateContext;
30 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.KeyPredicateExprContext;
31 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.LeafListPredicateContext;
32 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.LeafListPredicateExprContext;
33 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.NodeIdentifierContext;
34 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.PathArgumentContext;
35 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.PosContext;
36 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.PredicateContext;
37 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.QuotedStringContext;
38 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
39 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
40 import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
41 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
42 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Absolute;
43 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
44 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
45 import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
46 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
47 import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
48 import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathSupport;
49
50 abstract class InstanceIdentifierParser {
51     static final class Base extends InstanceIdentifierParser {
52         Base(final YangXPathMathMode mathMode) {
53             super(mathMode);
54         }
55
56         @Override
57         YangQNameExpr createExpr(final String prefix, final String localName) {
58             return YangQNameExpr.of(UnresolvedQName.qualified(prefix, localName));
59         }
60
61         @Override
62         QNameStep createChildStep(final String prefix, final String localName, final Collection<YangExpr> predicates) {
63             return YangXPathAxis.CHILD.asStep(UnresolvedQName.qualified(prefix, localName), predicates);
64         }
65     }
66
67     static final class Qualified extends InstanceIdentifierParser {
68         final YangNamespaceContext namespaceContext;
69
70         Qualified(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext) {
71             super(mathMode);
72             this.namespaceContext = requireNonNull(namespaceContext);
73         }
74
75         @Override
76         QNameStep createChildStep(final String prefix, final String localName, final Collection<YangExpr> predicates) {
77             return YangXPathAxis.CHILD.asStep(namespaceContext.createQName(prefix, localName), predicates);
78         }
79
80
81         @Override
82         YangQNameExpr createExpr(final String prefix, final String localName) {
83             return YangQNameExpr.of(namespaceContext.createQName(prefix, localName));
84         }
85
86     }
87
88     private final YangXPathMathSupport mathSupport;
89
90     InstanceIdentifierParser(final YangXPathMathMode mathMode) {
91         mathSupport = mathMode.getSupport();
92     }
93
94     final Absolute interpretAsInstanceIdentifier(final YangLiteralExpr expr) throws XPathExpressionException {
95         final instanceIdentifierLexer lexer = new instanceIdentifierLexer(CharStreams.fromString(expr.getLiteral()));
96         final instanceIdentifierParser parser = new instanceIdentifierParser(new CommonTokenStream(lexer));
97         final CapturingErrorListener listener = new CapturingErrorListener();
98         lexer.removeErrorListeners();
99         lexer.addErrorListener(listener);
100         parser.removeErrorListeners();
101         parser.addErrorListener(listener);
102
103         final InstanceIdentifierContext id = parser.instanceIdentifier();
104         listener.reportError();
105
106         final int length = id.getChildCount();
107         final List<Step> steps = new ArrayList<>(length / 2);
108         for (int i = 1; i < length; i += 2) {
109             steps.add(parsePathArgument(getChild(id, PathArgumentContext.class, i)));
110         }
111
112         return YangLocationPath.absolute(steps);
113     }
114
115     abstract YangQNameExpr createExpr(String prefix, String localName);
116
117     abstract QNameStep createChildStep(String prefix, String localName, Collection<YangExpr> predicates);
118
119     private QNameStep parsePathArgument(final PathArgumentContext expr) {
120         final NodeIdentifierContext childExpr = getChild(expr, NodeIdentifierContext.class, 0);
121         final String prefix = verifyIdentifier(childExpr, 0);
122         final String localName = verifyIdentifier(childExpr, 2);
123
124         switch (expr.getChildCount()) {
125             case 1:
126                 return createChildStep(prefix, localName, ImmutableSet.of());
127             case 2:
128                 return createChildStep(prefix, localName, parsePredicate(getChild(expr, PredicateContext.class, 1)));
129             default:
130                 throw illegalShape(expr);
131         }
132     }
133
134     private Collection<YangExpr> parsePredicate(final PredicateContext expr) {
135         final ParseTree first = expr.getChild(0);
136         if (first instanceof LeafListPredicateContext) {
137             return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(YangLocationPath.self(),
138                 parseEqStringValue(getChild(((LeafListPredicateContext) first)
139                     .getChild(LeafListPredicateExprContext.class, 0), EqQuotedStringContext.class, 1))));
140         } else if (first instanceof PosContext) {
141             return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(FunctionSupport.POSITION,
142                 mathSupport.createNumber(((PosContext) first).getToken(instanceIdentifierParser.PositiveIntegerValue, 0)
143                     .getText())));
144         }
145
146         final int length = expr.getChildCount();
147         final List<YangExpr> ret = new ArrayList<>(length);
148         for (int i = 0; i < length; ++i) {
149             final KeyPredicateExprContext pred = getChild(expr, KeyPredicateContext.class, i)
150                     .getChild(KeyPredicateExprContext.class, 0);
151             ret.add(YangBinaryOperator.EQUALS.exprWith(
152                 createChildExpr(getChild(pred, NodeIdentifierContext.class, 0)),
153                 parseEqStringValue(getChild(pred, EqQuotedStringContext.class, 1))));
154
155         }
156
157         return ret;
158     }
159
160     private YangQNameExpr createChildExpr(final NodeIdentifierContext expr) {
161         return createExpr(verifyIdentifier(expr, 0), verifyIdentifier(expr, 2));
162     }
163
164     private static String verifyIdentifier(final NodeIdentifierContext expr, final int child) {
165         return verifyToken(expr, child, instanceIdentifierParser.Identifier).getText();
166     }
167
168     private static YangLiteralExpr parseEqStringValue(final EqQuotedStringContext expr) {
169         return YangLiteralExpr.of(verifyToken(getChild(expr, QuotedStringContext.class, expr.getChildCount() - 1), 1,
170             instanceIdentifierParser.STRING).getText());
171     }
172 }