2 * Copyright (c) 2019 Pantheon Technologies, s.r.o. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.xpath.impl;
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;
15 import com.google.common.collect.ImmutableSet;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import javax.xml.xpath.XPathExpressionException;
19 import org.antlr.v4.runtime.CharStreams;
20 import org.antlr.v4.runtime.CommonTokenStream;
21 import org.opendaylight.yangtools.yang.common.UnresolvedQName;
22 import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
23 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser;
24 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.EqQuotedStringContext;
25 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.InstanceIdentifierContext;
26 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.KeyPredicateContext;
27 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.KeyPredicateExprContext;
28 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.LeafListPredicateContext;
29 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.LeafListPredicateExprContext;
30 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.NodeIdentifierContext;
31 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.PathArgumentContext;
32 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.PosContext;
33 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.PredicateContext;
34 import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.QuotedStringContext;
35 import org.opendaylight.yangtools.yang.xpath.antlr.xpathLexer;
36 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
37 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
38 import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
39 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
40 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Absolute;
41 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
42 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
43 import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
44 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
45 import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
46 import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathSupport;
48 abstract class InstanceIdentifierParser {
49 static final class Base extends InstanceIdentifierParser {
50 Base(final YangXPathMathMode mathMode) {
55 YangQNameExpr createExpr(final String prefix, final String localName) {
56 return YangQNameExpr.of(UnresolvedQName.Qualified.of(prefix, localName));
60 QNameStep createChildStep(final String prefix, final String localName, final Collection<YangExpr> predicates) {
61 return YangXPathAxis.CHILD.asStep(UnresolvedQName.Qualified.of(prefix, localName), predicates);
65 static final class Qualified extends InstanceIdentifierParser {
66 final YangNamespaceContext namespaceContext;
68 Qualified(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext) {
70 this.namespaceContext = requireNonNull(namespaceContext);
74 QNameStep createChildStep(final String prefix, final String localName, final Collection<YangExpr> predicates) {
75 return YangXPathAxis.CHILD.asStep(namespaceContext.createQName(prefix, localName), predicates);
80 YangQNameExpr createExpr(final String prefix, final String localName) {
81 return YangQNameExpr.of(namespaceContext.createQName(prefix, localName));
86 private final YangXPathMathSupport mathSupport;
88 InstanceIdentifierParser(final YangXPathMathMode mathMode) {
89 mathSupport = mathMode.getSupport();
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);
101 final InstanceIdentifierContext id = parser.instanceIdentifier();
102 listener.reportError();
104 final int length = id.getChildCount();
105 final var steps = new ArrayList<Step>(length / 2);
106 for (int i = 1; i < length; i += 2) {
107 steps.add(parsePathArgument(getChild(id, PathArgumentContext.class, i)));
110 return YangLocationPath.absolute(steps);
113 abstract YangQNameExpr createExpr(String prefix, String localName);
115 abstract QNameStep createChildStep(String prefix, String localName, Collection<YangExpr> predicates);
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);
122 return switch (expr.getChildCount()) {
123 case 1 -> createChildStep(prefix, localName, ImmutableSet.of());
124 case 2 -> createChildStep(prefix, localName, parsePredicate(getChild(expr, PredicateContext.class, 1)));
125 default -> throw illegalShape(expr);
129 private Collection<YangExpr> parsePredicate(final PredicateContext expr) {
130 final var first = expr.getChild(0);
131 if (first instanceof LeafListPredicateContext llp) {
132 return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(YangLocationPath.self(),
133 parseEqStringValue(getChild(llp.getChild(LeafListPredicateExprContext.class, 0),
134 EqQuotedStringContext.class, 1))));
135 } else if (first instanceof PosContext pc) {
136 return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(FunctionSupport.POSITION,
137 mathSupport.createNumber(pc.getToken(instanceIdentifierParser.PositiveIntegerValue, 0).getText())));
140 final int length = expr.getChildCount();
141 final var ret = new ArrayList<YangExpr>(length);
142 for (int i = 0; i < length; ++i) {
143 final var pred = getChild(expr, KeyPredicateContext.class, i).getChild(KeyPredicateExprContext.class, 0);
144 ret.add(YangBinaryOperator.EQUALS.exprWith(
145 createChildExpr(getChild(pred, NodeIdentifierContext.class, 0)),
146 parseEqStringValue(getChild(pred, EqQuotedStringContext.class, 1))));
152 private YangQNameExpr createChildExpr(final NodeIdentifierContext expr) {
153 return createExpr(verifyIdentifier(expr, 0), verifyIdentifier(expr, 2));
156 private static String verifyIdentifier(final NodeIdentifierContext expr, final int child) {
157 return verifyToken(expr, child, instanceIdentifierParser.Identifier).getText();
160 private static YangLiteralExpr parseEqStringValue(final EqQuotedStringContext expr) {
161 return YangLiteralExpr.of(verifyToken(getChild(expr, QuotedStringContext.class, expr.getChildCount() - 1), 1,
162 instanceIdentifierParser.STRING).getText());