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.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.common.UnresolvedQName;
23 import org.opendaylight.yangtools.yang.model.api.PathExpression;
24 import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps;
25 import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
26 import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps;
27 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathLexer;
28 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser;
29 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Absolute_pathContext;
30 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Deref_exprContext;
31 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Deref_function_invocationContext;
32 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Descendant_pathContext;
33 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Node_identifierContext;
34 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_argContext;
35 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_equality_exprContext;
36 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_key_exprContext;
37 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_predicateContext;
38 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Path_strContext;
39 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Rel_path_keyexprContext;
40 import org.opendaylight.yangtools.yang.parser.antlr.LeafRefPathParser.Relative_pathContext;
41 import org.opendaylight.yangtools.yang.parser.rfc7950.antlr.SourceExceptionParser;
42 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
43 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
44 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
45 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryExpr;
46 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
47 import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
48 import org.opendaylight.yangtools.yang.xpath.api.YangFunction;
49 import org.opendaylight.yangtools.yang.xpath.api.YangFunctionCallExpr;
50 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
51 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Absolute;
52 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
53 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Relative;
54 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
55 import org.opendaylight.yangtools.yang.xpath.api.YangPathExpr;
56 import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
57 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
61 class PathExpressionParser {
62 static final class Lenient extends PathExpressionParser {
63 private static final Logger LOG = LoggerFactory.getLogger(Lenient.class);
66 PathExpression parseExpression(final StmtContext<?, ?, ?> ctx, final String pathArg) {
68 return super.parseExpression(ctx, pathArg);
69 } catch (IllegalStateException | SourceException e) {
70 LOG.warn("Failed to parse expression '{}'", pathArg, e);
71 return new UnparsedPathExpression(pathArg, e);
76 private static final YangFunctionCallExpr CURRENT_CALL = YangFunctionCallExpr.of(
77 YangFunction.CURRENT.getIdentifier());
79 PathExpression parseExpression(final StmtContext<?, ?, ?> ctx, final String pathArg) {
80 final LeafRefPathLexer lexer = new LeafRefPathLexer(CharStreams.fromString(pathArg));
81 final LeafRefPathParser parser = new LeafRefPathParser(new CommonTokenStream(lexer));
82 final Path_argContext path = SourceExceptionParser.parse(lexer, parser, parser::path_arg,
83 ctx.sourceReference());
85 final ParseTree childPath = path.getChild(0);
87 if (childPath instanceof Path_strContext) {
88 steps = new LocationPathSteps(parsePathStr(ctx, pathArg, (Path_strContext) childPath));
89 } else if (childPath instanceof Deref_exprContext) {
90 final Deref_exprContext deref = (Deref_exprContext) childPath;
91 steps = new DerefSteps(parseRelative(ctx, pathArg,
92 getChild(deref, 0, Deref_function_invocationContext.class).getChild(Relative_pathContext.class, 0)),
93 parseRelative(ctx, pathArg, getChild(deref, deref.getChildCount() - 1, Relative_pathContext.class)));
95 throw new IllegalStateException("Unsupported child " + childPath);
97 return new ParsedPathExpression(steps, pathArg);
100 private static YangLocationPath parsePathStr(final StmtContext<?, ?, ?> ctx, final String pathArg,
101 final Path_strContext path) {
102 final ParseTree childPath = path.getChild(0);
103 if (childPath instanceof Absolute_pathContext) {
104 return parseAbsolute(ctx, pathArg, (Absolute_pathContext) childPath);
105 } else if (childPath instanceof Relative_pathContext) {
106 return parseRelative(ctx, pathArg, (Relative_pathContext) childPath);
108 throw new IllegalStateException("Unsupported child " + childPath);
112 private static Absolute parseAbsolute(final StmtContext<?, ?, ?> ctx, final String pathArg,
113 final Absolute_pathContext absolute) {
114 final List<Step> steps = new ArrayList<>();
115 fillSteps(ctx, pathArg, absolute, steps);
116 return YangLocationPath.absolute(steps);
119 private static Relative parseRelative(final StmtContext<?, ?, ?> ctx, final String pathArg,
120 final Relative_pathContext relative) {
121 final int relativeChildren = relative.getChildCount();
122 verify(relativeChildren % 2 != 0, "Unexpected child count %s", relativeChildren);
124 final int stepCount = relativeChildren / 2;
125 final List<Step> steps = new ArrayList<>(stepCount);
126 for (int i = 0; i < stepCount; ++i) {
127 steps.add(YangXPathAxis.PARENT.asStep());
129 return parseRelative(ctx, pathArg, relative, steps);
132 private static Relative parseRelative(final StmtContext<?, ?, ?> ctx, final String pathArg,
133 final Relative_pathContext relative, final List<Step> steps) {
134 final int relativeChildren = relative.getChildCount();
135 final Descendant_pathContext descendant = getChild(relative, relativeChildren - 1,
136 Descendant_pathContext.class);
137 final Node_identifierContext qname = getChild(descendant, 0, Node_identifierContext.class);
138 final int descandantChildren = descendant.getChildCount();
139 if (descandantChildren > 1) {
140 final List<YangExpr> predicates = new ArrayList<>(descandantChildren);
141 for (int i = 1; i < descandantChildren - 1; ++i) {
142 predicates.add(parsePathPredicate(ctx, getChild(descendant, i, Path_predicateContext.class)));
144 steps.add(createChildStep(ctx, qname, predicates));
145 fillSteps(ctx, pathArg, getChild(descendant, descandantChildren - 1, Absolute_pathContext.class), steps);
147 steps.add(createChildStep(ctx, qname, ImmutableList.of()));
150 return YangLocationPath.relative(steps);
153 private static void fillSteps(final StmtContext<?, ?, ?> ctx, final String pathArg,
154 final Absolute_pathContext absolute, final List<Step> output) {
156 final List<YangExpr> predicates = new ArrayList<>();
157 Node_identifierContext qname = getChild(absolute, 1, Node_identifierContext.class);
159 final int children = absolute.getChildCount();
160 for (int i = 2; i < children; ++i) {
161 final ParseTree child = absolute.getChild(i);
162 if (child instanceof Node_identifierContext) {
163 output.add(createChildStep(ctx, qname, predicates));
165 qname = (Node_identifierContext) child;
166 } else if (child instanceof Path_predicateContext) {
167 predicates.add(parsePathPredicate(ctx, (Path_predicateContext) child));
171 output.add(createChildStep(ctx, qname, predicates));
174 private static <T> T getChild(final ParseTree parent, final int offset, final Class<T> clazz) {
175 final ParseTree child = parent.getChild(offset);
176 verify(clazz.isInstance(child), "Unexpected child %s at offset %s of %s when expecting %s", child, offset,
178 return clazz.cast(child);
181 private static YangBinaryExpr parsePathPredicate(final StmtContext<?, ?, ?> ctx,
182 final Path_predicateContext predicate) {
183 final Path_equality_exprContext eqExpr = verifyNotNull(predicate.path_equality_expr());
184 return YangBinaryOperator.EQUALS.exprWith(
185 createChildExpr(ctx, getChild(eqExpr, 0, Node_identifierContext.class)),
186 parsePathKeyExpr(ctx, verifyNotNull(eqExpr.path_key_expr())));
189 private static YangExpr parsePathKeyExpr(final StmtContext<?, ?, ?> ctx, final Path_key_exprContext expr) {
190 final Rel_path_keyexprContext relPath = verifyNotNull(expr.rel_path_keyexpr());
191 final int children = relPath.getChildCount();
193 // Process dots first
194 final List<Step> steps = new ArrayList<>();
196 while (offset < children - 1) {
197 final ParseTree child = relPath.getChild(offset);
198 if (child instanceof Node_identifierContext) {
201 if (child instanceof TerminalNode
202 && ((TerminalNode) child).getSymbol().getType() == LeafRefPathLexer.DOTS) {
203 steps.add(YangXPathAxis.PARENT.asStep());
209 // Process node identifiers
210 while (offset < children) {
211 final ParseTree child = relPath.getChild(offset);
212 if (child instanceof Node_identifierContext) {
213 steps.add(createChildStep(ctx, (Node_identifierContext) child, ImmutableList.of()));
218 return steps.isEmpty() ? CURRENT_CALL : YangPathExpr.of(CURRENT_CALL, YangLocationPath.relative(steps));
221 private static YangQNameExpr createChildExpr(final StmtContext<?, ?, ?> ctx, final Node_identifierContext qname) {
222 switch (qname.getChildCount()) {
224 return YangQNameExpr.of(UnresolvedQName.unqualified(qname.getText()).intern());
226 return YangQNameExpr.of(parseQName(ctx, qname));
228 throw new IllegalStateException("Unexpected shape " + qname.getText());
232 private static QNameStep createChildStep(final StmtContext<?, ?, ?> ctx, final Node_identifierContext qname,
233 final List<YangExpr> predicates) {
234 switch (qname.getChildCount()) {
236 return YangXPathAxis.CHILD.asStep(UnresolvedQName.unqualified(qname.getText()).intern(), predicates);
238 return YangXPathAxis.CHILD.asStep(parseQName(ctx, qname), predicates);
240 throw new IllegalStateException("Unexpected shape " + qname.getText());
244 private static @NonNull QName parseQName(final StmtContext<?, ?, ?> ctx, final Node_identifierContext qname) {
245 return StmtContextUtils.parseNodeIdentifier(ctx, qname.getChild(0).getText(), qname.getChild(2).getText());