* An expression as defined in <a href="https://tools.ietf.org/html/rfc7950#section-9.9.2">RFC7950 Section 9.9.2</a>,
* i.e. the argument of a {@code path} statement.
*
+ * <p>
+ * Semantically a {@link PathExpression} is similar to a {@link YangXPathExpression} with guarantees around what
+ * subexpressions it can contain:
+ * <ul>
+ * <li>the root expression must be a {@link YangLocationPath}</li>
+ * <li>it can contain steps only along {@link YangXPathAxis#CHILD} and {@link YangXPathAxis#PARENT} axis</li>
+ * <li>all steps along {@link YangXPathAxis#CHILD} axis are {@link QNameStep}</li>
+ * <li>the only function invocation is {@link YangFunction#CURRENT}</li>
+ * <li>only {@link YangBinaryOperator#EQUALS} is allowed</li>
+ * <li>no literals nor numbers are allowed</li>
+ * <li>all qualified node identifiers must me resolved</li>
+ * </ul>
+ *
* @author Robert Varga
*/
@Beta
String getOriginalString();
/**
- * Returns <code>true</code> if the XPapth starts in root of YANG model, otherwise returns <code>false</code>.
+ * Return the {@link YangLocationPath} of this expression.
*
- * @return <code>true</code> if the XPapth starts in root of YANG model, otherwise returns <code>false</code>
+ * @return The location path
+ * @throws UnsupportedOperationException if the implementation has not parsed the string. Implementations are
+ * strongly encouraged to perform proper parsing.
*/
- boolean isAbsolute();
+ YangLocationPath getLocation();
/**
- * XPath-aware extension of PathExpression. Additionally to exposing {@link #getOriginalString()}, implementations
- * of this interface expose a parsed {@link YangLocationPath}.
+ * Returns <code>true</code> if the XPapth starts in root of YANG model, otherwise returns <code>false</code>.
*
- * <p>
- * Semantically a {@link PathExpression} is similar to a {@link YangXPathExpression} with guarantees around what
- * subexpressions it can contain:
- * <ul>
- * <li>the root expression must be a {@link YangLocationPath}</li>
- * <li>it can contain steps only along {@link YangXPathAxis#CHILD} and {@link YangXPathAxis#PARENT} axis</li>
- * <li>all steps along {@link YangXPathAxis#CHILD} axis are {@link QNameStep}</li>
- * <li>the only function invocation is {@link YangFunction#CURRENT}</li>
- * <li>only {@link YangBinaryOperator#EQUALS} is allowed</li>
- * <li>no literals nor numbers are allowed</li>
- * <li>all qualified node identifiers must me resolved</li>
- * </ul>
+ * @return <code>true</code> if the XPapth starts in root of YANG model, otherwise returns <code>false</code>
*/
- // FIXME: 4.0.0: this is a transitional interface and needs to be integrated directly in PathExpression
- interface WithLocation extends PathExpression {
- /**
- * Return the {@link YangLocationPath} of this expression.
- *
- * @return The location path
- */
- YangLocationPath getLocation();
-
- @Override
- default boolean isAbsolute() {
- return getLocation().isAbsolute();
- }
+ default boolean isAbsolute() {
+ return getLocation().isAbsolute();
}
}
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.yang.model.api.PathExpression;
+
+@Beta
+@NonNullByDefault
+public abstract class AbstractPathExpression implements PathExpression {
+ private final String originalString;
+
+ protected AbstractPathExpression(final String originalString) {
+ this.originalString = requireNonNull(originalString);
+ }
+
+ @Override
+ public final String getOriginalString() {
+ return originalString;
+ }
+
+ @Override
+ public final String toString() {
+ return addToStringAttributes(MoreObjects.toStringHelper(this).omitNullValues()).toString();
+ }
+
+ protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return helper.add("originalString", originalString);
+ }
+}
*/
package org.opendaylight.yangtools.yang.model.util;
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.opendaylight.yangtools.yang.model.api.PathExpression;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
/**
* A simple XPathExpression implementation.
*/
@Deprecated
@NonNullByDefault
-public final class PathExpressionImpl implements PathExpression {
- private final String originalString;
+public final class PathExpressionImpl extends AbstractPathExpression {
+ private final @Nullable YangLocationPath location;
private final boolean absolute;
+ @SuppressFBWarnings(value = "NP_STORE_INTO_NONNULL_FIELD", justification = "Non-grok on SpotBugs part")
public PathExpressionImpl(final String xpath, final boolean absolute) {
- this.originalString = requireNonNull(xpath);
+ super(xpath);
this.absolute = absolute;
+ this.location = null;
}
- @Override
- public String getOriginalString() {
- return originalString;
+ public PathExpressionImpl(final String xpath, final YangLocationPath location) {
+ super(xpath);
+ this.absolute = location.isAbsolute();
+ this.location = location;
}
@Override
}
@Override
- public String toString() {
- return MoreObjects.toStringHelper(this).add("absolute", absolute).add("originalString", originalString)
- .toString();
+ public YangLocationPath getLocation() {
+ final YangLocationPath loc = location;
+ if (loc == null) {
+ throw new UnsupportedOperationException("Location has not been provided");
+ }
+ return loc;
+ }
+
+ @Override
+ protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return super.addToStringAttributes(helper.add("absolute", absolute).add("location", location));
}
}
.addSupport(RequireInstanceStatementSupport.getInstance())
.addVersionSpecificSupport(VERSION_1, BitStatementRFC6020Support.getInstance())
.addVersionSpecificSupport(VERSION_1_1, BitStatementRFC7950Support.getInstance())
- .addSupport(PathStatementSupport.getInstance())
+ .addSupport(PathStatementSupport.strictInstance())
.addVersionSpecificSupport(VERSION_1, EnumStatementRFC6020Support.getInstance())
.addVersionSpecificSupport(VERSION_1_1, EnumStatementRFC7950Support.getInstance())
.addSupport(LengthStatementSupport.getInstance())
LOG.warn("Argument \"{}\" is not valid XPath string at \"{}\"", path, ctx.getStatementSourceReference(), e);
}
- return new RevisionAwareXPathImpl(path, PATH_ABS.matcher(path).matches());
+ return new RevisionAwareXPathImpl(path, isAbsoluteXPath(path));
+ }
+
+ public static boolean isAbsoluteXPath(final String path) {
+ return PATH_ABS.matcher(path).matches();
}
@SuppressWarnings("checkstyle:illegalCatch")
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.path;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.util.AbstractPathExpression;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
+
+final class ParsedPathExpression extends AbstractPathExpression {
+ private final @NonNull YangLocationPath location;
+
+ ParsedPathExpression(final YangLocationPath location, final String originalString) {
+ super(originalString);
+ this.location = requireNonNull(location);
+ }
+
+ @Override
+ public YangLocationPath getLocation() {
+ return location;
+ }
+
+ @Override
+ protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return super.addToStringAttributes(helper.add("location", location));
+ }
+}
import static com.google.common.base.Verify.verify;
import static com.google.common.base.Verify.verifyNotNull;
-import static java.util.Objects.requireNonNull;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
-import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathLexer;
import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser;
import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Absolute_pathContext;
import org.opendaylight.yangtools.antlrv4.code.gen.LeafRefPathParser.Relative_pathContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
-import org.opendaylight.yangtools.yang.model.api.PathExpression.WithLocation;
+import org.opendaylight.yangtools.yang.model.api.PathExpression;
import org.opendaylight.yangtools.yang.parser.rfc7950.antlr.SourceExceptionParser;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
import org.opendaylight.yangtools.yang.xpath.api.YangBinaryExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangPathExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class PathExpressionParser {
+ static final class Lenient extends PathExpressionParser {
+ private static final Logger LOG = LoggerFactory.getLogger(Lenient.class);
+
+ @Override
+ PathExpression parseExpression(final StmtContext<?, ?, ?> ctx, final String pathArg) {
+ try {
+ return super.parseExpression(ctx, pathArg);
+ } catch (IllegalStateException | SourceException e) {
+ LOG.warn("Failed to parse expression '{}'", pathArg, e);
+ return new UnparsedPathExpression(pathArg, e);
+ }
+ }
+ }
-final class AntlrPathExpression implements WithLocation {
private static final YangFunctionCallExpr CURRENT_CALL = YangFunctionCallExpr.of(
YangFunction.CURRENT.getIdentifier());
- private final @NonNull YangLocationPath location;
- private final @NonNull String originalString;
-
- private AntlrPathExpression(final YangLocationPath location, final String originalString) {
- this.location = requireNonNull(location);
- this.originalString = requireNonNull(originalString);
- }
-
- @Override
- public YangLocationPath getLocation() {
- return location;
- }
-
- @Override
- public String getOriginalString() {
- return originalString;
- }
-
- static AntlrPathExpression parse(final StmtContext<?, ?, ?> ctx, final String pathArg) {
+ PathExpression parseExpression(final StmtContext<?, ?, ?> ctx, final String pathArg) {
final LeafRefPathLexer lexer = new LeafRefPathLexer(CharStreams.fromString(pathArg));
final LeafRefPathParser parser = new LeafRefPathParser(new CommonTokenStream(lexer));
final Path_argContext path = SourceExceptionParser.parse(lexer, parser, parser::path_arg,
throw new IllegalStateException("Unsupported child " + childPath);
}
- return new AntlrPathExpression(location, pathArg);
+ return new ParsedPathExpression(location, pathArg);
}
private static Absolute parseAbsolute(final StmtContext<?, ?, ?> ctx, final String pathArg,
*/
package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.path;
+import static java.util.Objects.requireNonNull;
+
import org.opendaylight.yangtools.yang.model.api.PathExpression;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
public final class PathStatementSupport extends AbstractStatementSupport<PathExpression, PathStatement,
EffectiveStatement<PathExpression, PathStatement>> {
- private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
- .PATH)
- .build();
- private static final PathStatementSupport INSTANCE = new PathStatementSupport();
+ private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(
+ YangStmtMapping.PATH).build();
+ private static final PathStatementSupport LENIENT_INSTANCE = new PathStatementSupport(
+ new PathExpressionParser.Lenient());
+ private static final PathStatementSupport STRICT_INSTANCE = new PathStatementSupport(
+ new PathExpressionParser());
+
+ private final PathExpressionParser parser;
- private PathStatementSupport() {
+ private PathStatementSupport(final PathExpressionParser parser) {
super(YangStmtMapping.PATH);
+ this.parser = requireNonNull(parser);
+ }
+
+ public static PathStatementSupport lenientInstance() {
+ return LENIENT_INSTANCE;
}
- public static PathStatementSupport getInstance() {
- return INSTANCE;
+ public static PathStatementSupport strictInstance() {
+ return STRICT_INSTANCE;
}
@Override
public PathExpression parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
- return AntlrPathExpression.parse(ctx, value);
+ return parser.parseExpression(ctx, value);
}
@Override
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.path;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.opendaylight.yangtools.yang.model.util.AbstractPathExpression;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.ArgumentUtils;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
+
+final class UnparsedPathExpression extends AbstractPathExpression {
+ private final RuntimeException cause;
+ private final boolean absolute;
+
+ UnparsedPathExpression(final String originalString, final RuntimeException cause) {
+ super(originalString);
+ this.cause = requireNonNull(cause);
+ absolute = ArgumentUtils.isAbsoluteXPath(originalString);
+ }
+
+ @Override
+ public boolean isAbsolute() {
+ return absolute;
+ }
+
+ @Override
+ public YangLocationPath getLocation() {
+ throw new UnsupportedOperationException("Expression '" + getOriginalString() + "' was not parsed", cause);
+ }
+
+ @Override
+ protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return super.addToStringAttributes(helper.add("absolute", absolute)).add("cause", cause);
+ }
+}