2 * Copyright (c) 2019 PANTHEON.tech, 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.parser.rfc7950.stmt.path;
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
13 import com.google.common.collect.ImmutableList;
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.antlr.v4.runtime.CharStreams;
17 import org.antlr.v4.runtime.CommonTokenStream;
18 import org.antlr.v4.runtime.tree.ParseTree;
19 import org.antlr.v4.runtime.tree.TerminalNode;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
22 import org.opendaylight.yangtools.yang.model.api.PathExpression;
23 import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps;
24 import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
25 import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps;
26 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathLexer;
27 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser;
28 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Absolute_pathContext;
29 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Deref_exprContext;
30 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Deref_function_invocationContext;
31 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Descendant_pathContext;
32 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Node_identifierContext;
33 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_argContext;
34 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_equality_exprContext;
35 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_key_exprContext;
36 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_predicateContext;
37 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_strContext;
38 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Rel_path_keyexprContext;
39 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Relative_pathContext;
40 import org.opendaylight.yangtools.yang.parser.rfc7950.antlr.SourceExceptionParser;
41 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
42 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
43 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
44 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryExpr;
45 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
46 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
47 import org.opendaylight.yangtools.yang.xpath.api.YangFunction;
48 import org.opendaylight.yangtools.yang.xpath.api.YangFunctionCallExpr;
49 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
50 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Absolute;
51 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
52 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Relative;
53 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
54 import org.opendaylight.yangtools.yang.xpath.api.YangPathExpr;
55 import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
56 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
60 class PathExpressionParser {
61 static final class Lenient extends PathExpressionParser {
62 private static final Logger LOG = LoggerFactory.getLogger(Lenient.class);
65 PathExpression parseExpression(final StmtContext<?, ?, ?> ctx, final String pathArg) {
67 return super.parseExpression(ctx, pathArg);
68 } catch (IllegalStateException | SourceException e) {
69 LOG.warn("Failed to parse expression '{}'", pathArg, e);
70 return new UnparsedPathExpression(pathArg, e);
75 private static final YangFunctionCallExpr CURRENT_CALL = YangFunctionCallExpr.of(
76 YangFunction.CURRENT.getIdentifier());
78 PathExpression parseExpression(final StmtContext<?, ?, ?> ctx, final String pathArg) {
79 final LeafRefPathLexer lexer = new LeafRefPathLexer(CharStreams.fromString(pathArg));
80 final LeafRefPathParser parser = new LeafRefPathParser(new CommonTokenStream(lexer));
81 final Path_argContext path = SourceExceptionParser.parse(lexer, parser, parser::path_arg,
82 ctx.getStatementSourceReference());
84 final ParseTree childPath = path.getChild(0);
86 if (childPath instanceof Path_strContext) {
87 steps = new LocationPathSteps(parsePathStr(ctx, pathArg, (Path_strContext) childPath));
88 } else if (childPath instanceof Deref_exprContext) {
89 final Deref_exprContext deref = (Deref_exprContext) childPath;
90 steps = new DerefSteps(parseRelative(ctx, pathArg,
91 getChild(deref, 0, Deref_function_invocationContext.class).getChild(Relative_pathContext.class, 0)),
92 parseRelative(ctx, pathArg, getChild(deref, deref.getChildCount() - 1, Relative_pathContext.class)));
94 throw new IllegalStateException("Unsupported child " + childPath);
96 return new ParsedPathExpression(steps, pathArg);
99 private static YangLocationPath parsePathStr(final StmtContext<?, ?, ?> ctx, final String pathArg,
100 final Path_strContext path) {
101 final ParseTree childPath = path.getChild(0);
102 if (childPath instanceof Absolute_pathContext) {
103 return parseAbsolute(ctx, pathArg, (Absolute_pathContext) childPath);
104 } else if (childPath instanceof Relative_pathContext) {
105 return parseRelative(ctx, pathArg, (Relative_pathContext) childPath);
107 throw new IllegalStateException("Unsupported child " + childPath);
111 private static Absolute parseAbsolute(final StmtContext<?, ?, ?> ctx, final String pathArg,
112 final Absolute_pathContext absolute) {
113 final List<Step> steps = new ArrayList<>();
114 fillSteps(ctx, pathArg, absolute, steps);
115 return YangLocationPath.absolute(steps);
118 private static Relative parseRelative(final StmtContext<?, ?, ?> ctx, final String pathArg,
119 final Relative_pathContext relative) {
120 final int relativeChildren = relative.getChildCount();
121 verify(relativeChildren % 2 != 0, "Unexpected child count %s", relativeChildren);
123 final int stepCount = relativeChildren / 2;
124 final List<Step> steps = new ArrayList<>(stepCount);
125 for (int i = 0; i < stepCount; ++i) {
126 steps.add(YangXPathAxis.PARENT.asStep());
128 return parseRelative(ctx, pathArg, relative, steps);
131 private static Relative parseRelative(final StmtContext<?, ?, ?> ctx, final String pathArg,
132 final Relative_pathContext relative, final List<Step> steps) {
133 final int relativeChildren = relative.getChildCount();
134 final Descendant_pathContext descendant = getChild(relative, relativeChildren - 1,
135 Descendant_pathContext.class);
136 final Node_identifierContext qname = getChild(descendant, 0, Node_identifierContext.class);
137 final int descandantChildren = descendant.getChildCount();
138 if (descandantChildren > 1) {
139 final List<YangExpr> predicates = new ArrayList<>(descandantChildren);
140 for (int i = 1; i < descandantChildren - 1; ++i) {
141 predicates.add(parsePathPredicate(ctx, getChild(descendant, i, Path_predicateContext.class)));
143 steps.add(createChildStep(ctx, qname, predicates));
144 fillSteps(ctx, pathArg, getChild(descendant, descandantChildren - 1, Absolute_pathContext.class), steps);
146 steps.add(createChildStep(ctx, qname, ImmutableList.of()));
149 return YangLocationPath.relative(steps);
152 private static void fillSteps(final StmtContext<?, ?, ?> ctx, final String pathArg,
153 final Absolute_pathContext absolute, final List<Step> output) {
155 final List<YangExpr> predicates = new ArrayList<>();
156 Node_identifierContext qname = getChild(absolute, 1, Node_identifierContext.class);
158 final int children = absolute.getChildCount();
159 for (int i = 2; i < children; ++i) {
160 final ParseTree child = absolute.getChild(i);
161 if (child instanceof Node_identifierContext) {
162 output.add(createChildStep(ctx, qname, predicates));
164 qname = (Node_identifierContext) child;
165 } else if (child instanceof Path_predicateContext) {
166 predicates.add(parsePathPredicate(ctx, (Path_predicateContext) child));
170 output.add(createChildStep(ctx, qname, predicates));
173 private static <T> T getChild(final ParseTree parent, final int offset, final Class<T> clazz) {
174 final ParseTree child = parent.getChild(offset);
175 verify(clazz.isInstance(child), "Unexpected child %s at offset %s of %s when expecting %s", child, offset,
177 return clazz.cast(child);
180 private static YangBinaryExpr parsePathPredicate(final StmtContext<?, ?, ?> ctx,
181 final Path_predicateContext predicate) {
182 final Path_equality_exprContext eqExpr = verifyNotNull(predicate.path_equality_expr());
183 return YangBinaryOperator.EQUALS.exprWith(
184 createChildExpr(ctx, getChild(eqExpr, 0, Node_identifierContext.class)),
185 parsePathKeyExpr(ctx, verifyNotNull(eqExpr.path_key_expr())));
188 private static YangExpr parsePathKeyExpr(final StmtContext<?, ?, ?> ctx, final Path_key_exprContext expr) {
189 final Rel_path_keyexprContext relPath = verifyNotNull(expr.rel_path_keyexpr());
190 final int children = relPath.getChildCount();
192 // Process dots first
193 final List<Step> steps = new ArrayList<>();
195 while (offset < children - 1) {
196 final ParseTree child = relPath.getChild(offset);
197 if (child instanceof Node_identifierContext) {
200 if (child instanceof TerminalNode
201 && ((TerminalNode) child).getSymbol().getType() == LeafRefPathLexer.DOTS) {
202 steps.add(YangXPathAxis.PARENT.asStep());
208 // Process node identifiers
209 while (offset < children) {
210 final ParseTree child = relPath.getChild(offset);
211 if (child instanceof Node_identifierContext) {
212 steps.add(createChildStep(ctx, (Node_identifierContext) child, ImmutableList.of()));
217 return steps.isEmpty() ? CURRENT_CALL : YangPathExpr.of(CURRENT_CALL, YangLocationPath.relative(steps));
220 private static YangQNameExpr createChildExpr(final StmtContext<?, ?, ?> ctx, final Node_identifierContext qname) {
221 switch (qname.getChildCount()) {
223 return YangQNameExpr.of(UnqualifiedQName.of(qname.getText()).intern());
225 return YangQNameExpr.of(parseQName(ctx, qname));
227 throw new IllegalStateException("Unexpected shape " + qname.getText());
231 private static QNameStep createChildStep(final StmtContext<?, ?, ?> ctx, final Node_identifierContext qname,
232 final List<YangExpr> predicates) {
233 switch (qname.getChildCount()) {
235 return YangXPathAxis.CHILD.asStep(UnqualifiedQName.of(qname.getText()).intern(), predicates);
237 return YangXPathAxis.CHILD.asStep(parseQName(ctx, qname), predicates);
239 throw new IllegalStateException("Unexpected shape " + qname.getText());
243 private static QName parseQName(final StmtContext<?, ?, ?> ctx, final Node_identifierContext qname) {
244 return StmtContextUtils.parseNodeIdentifier(ctx, qname.getChild(0).getText(), qname.getChild(2).getText());