--- /dev/null
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. 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.api.meta;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * A {@link DeclarationReference} to something which resembles file.
+ */
+@Beta
+@NonNullByDefault
+public interface DeclarationInFile extends DeclarationReference {
+ /**
+ * Return the file where the declaration occurred. Returned is guaranteed to be non-empty and reference a file-like
+ * resource. No further guarantees on structure of the string are made.
+ *
+ * @return A non-empty file name.
+ */
+ String fileName();
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. 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.api.meta;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * A {@link DeclarationReference} to a position within a some text document.
+ */
+@Beta
+public interface DeclarationInText extends DeclarationReference {
+ /**
+ * Return the line where the declaration starts.
+ *
+ * @return A positive line number.
+ */
+ int startLine();
+
+ /**
+ * Return the column where the declaration starts.
+ *
+ * @return A positive column number.
+ */
+ int startColumn();
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. 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.api.meta;
+
+import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.concepts.Immutable;
+
+/**
+ * Reference to a statement declaration. This interface serves to provide additional information as to where a
+ * particular statement comes from. More accurate information may be available through further subclasses of this
+ * interface such as {@link DeclarationInText} and/or {@link DeclarationInFile}.
+ */
+@Beta
+public interface DeclarationReference extends Immutable {
+ /**
+ * Returns human readable representation of this reference. This method does not prescribe any format of the
+ * returned string.
+ *
+ * @return human readable representation of this reference.
+ */
+ @NonNull String toHumanReadable();
+}
return Collections2.transform(Collections2.filter(declaredSubstatements(), type::isInstance), type::cast);
}
+ /**
+ * Returns a {@link DeclarationReference} associated with this statement, if available.
+ *
+ * @apiNote
+ * This method does not contribute any semantic information and is provided purely as a conduit for
+ * implementation-specific information where a statement instance came from.
+ *
+ * @implSpec
+ * The default implementation returns {@link Optional#empty()}.
+ *
+ * @return A {@link DeclarationReference} associated with this statement or {@link Optional#empty()}.
+ */
+ @Beta
+ default @NonNull Optional<DeclarationReference> declarationReference() {
+ return Optional.empty();
+ }
+
/**
* Find the first effective substatement of specified type.
*
--- /dev/null
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. 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.spi.meta;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.Empty;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+
+/**
+ * Abstract base class for {@link DeclaredStatement} implementations which decorate a statement with a
+ * {@link DeclarationReference}.
+ *
+ * @param <A> Argument type ({@link Empty} if statement does not have argument.)
+ * @param <D> Class representing declared version of this statement.
+ */
+public abstract class AbstractRefStatement<A, D extends DeclaredStatement<A>>
+ extends ForwardingDeclaredStatement<A, D> {
+ private final @NonNull DeclarationReference ref;
+ private final @NonNull D delegate;
+
+ protected AbstractRefStatement(final D delegate, final DeclarationReference ref) {
+ this.delegate = requireNonNull(delegate);
+ this.ref = requireNonNull(ref);
+ }
+
+ @Override
+ public final Optional<DeclarationReference> declarationReference() {
+ return Optional.of(ref);
+ }
+
+ @Override
+ protected final D delegate() {
+ return delegate;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. 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.spi.meta;
+
+import com.google.common.annotations.Beta;
+import java.util.Collection;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+
+/**
+ * Common base class for forwarding implementations of {@link DeclaredStatement}.
+ */
+@Beta
+public abstract class ForwardingDeclaredStatement<A, D extends DeclaredStatement<A>>
+ extends ForwardingModelStatement<A, D> implements DeclaredStatement<A> {
+ @Override
+ public String rawArgument() {
+ return delegate().rawArgument();
+ }
+
+ @Override
+ public Collection<? extends DeclaredStatement<?>> declaredSubstatements() {
+ return delegate().declaredSubstatements();
+ }
+
+ @Override
+ public Optional<DeclarationReference> declarationReference() {
+ return delegate().declarationReference();
+ }
+
+ @Override
+ protected abstract @NonNull D delegate();
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. 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.spi.meta;
+
+import com.google.common.collect.ForwardingObject;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.meta.ModelStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementOrigin;
+
+/**
+ * Common base class for forwarding implementations of {@link ModelStatement}.
+ */
+public abstract class ForwardingModelStatement<A, S extends ModelStatement<A>> extends ForwardingObject
+ implements ModelStatement<A> {
+ @Override
+ public StatementDefinition statementDefinition() {
+ return delegate().statementDefinition();
+ }
+
+ @Override
+ public A argument() {
+ return delegate().argument();
+ }
+
+ @Override
+ public StatementOrigin statementOrigin() {
+ return delegate().statementOrigin();
+ }
+
+ @Override
+ protected abstract @NonNull S delegate();
+}
import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRKeyword;
import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRKeyword.Qualified;
import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRStatement;
-import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.ExplicitStatement;
import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
// Slow-path allocation of a new statement
private boolean processNewStatement(final int myOffset, final IRStatement stmt) {
- final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, stmt.startLine(),
- stmt.startColumn());
+ final StatementSourceReference ref = ExplicitStatement.atPosition(sourceName, stmt.startLine(),
+ stmt.startColumn() + 1);
final QName def = getValidStatementDefinition(stmt.keyword(), ref);
if (def == null) {
return false;
import java.util.ArrayDeque;
import java.util.Deque;
-import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.ExplicitStatement;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
el.setAttributeNS(attributes.getURI(i), attributes.getQName(i), attributes.getValue(i));
}
- final StatementSourceReference ref = DeclarationInTextSource.atPosition(file, documentLocator.getLineNumber(),
+ final StatementSourceReference ref = ExplicitStatement.atPosition(file, documentLocator.getLineNumber(),
documentLocator.getColumnNumber());
el.setUserData(USER_DATA_KEY, ref, null);
stack.push(el);
import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRKeyword.Unqualified;
import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRSchemaSource;
import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRStatement;
-import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.ExplicitStatement;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
/**
}
private static StatementSourceReference getReference(final SourceIdentifier source, final IRStatement stmt) {
- return DeclarationInTextSource.atPosition(source.getName(), stmt.startLine(), stmt.startColumn());
+ return ExplicitStatement.atPosition(source.getName(), stmt.startLine(), stmt.startColumn() + 1);
}
/**
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. 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.spi.source;
-
-import java.util.Objects;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.model.api.meta.StatementOrigin;
-
-/**
- * Reference of statement source present in textual source format. Utility implementation
- * of {@link StatementSourceReference} for textual sources, this is preferred {@link StatementSourceReference}
- * for implementations of YANG / YIN statement stream sources.
- *
- * <p>
- * To create source reference use one of this static factories:
- * <ul>
- * <li>{@link #atPosition(String, int, int)} - provides most specific reference of statement location, this is most
- * preferred since it provides most context to debug YANG model.</li>
- * <li>{@link #atLine(String, int)}- provides source and line of statement location.</li>
- * <li>{@link #inSource(String)} - least specific reference, should be used only if any of previous references are
- * unable to create / derive from source.</li>
- * </ul>
- */
-public abstract class DeclarationInTextSource implements StatementSourceReference {
- private static class InSource extends DeclarationInTextSource {
- InSource(final String sourceName) {
- super(sourceName);
- }
- }
-
- private static class AtLine extends InSource {
- private final int line;
-
- AtLine(final String sourceName, final int line) {
- super(sourceName);
- this.line = line;
- }
-
- @Override
- int hashCodeImpl() {
- return super.hashCodeImpl() * 31 + line;
- }
-
- @Override
- boolean equalsImpl(final DeclarationInTextSource obj) {
- return line == ((AtLine) obj).line && super.equalsImpl(obj);
- }
-
- @Override
- public String toString() {
- return super.toString() + ':' + line;
- }
- }
-
- private static final class AtPosition extends AtLine {
- private final int character;
-
- AtPosition(final String sourceName, final int line, final int character) {
- super(sourceName, line);
- this.character = character;
- }
-
- @Override
- int hashCodeImpl() {
- return super.hashCodeImpl() * 31 + character;
- }
-
- @Override
- boolean equalsImpl(final DeclarationInTextSource obj) {
- return character == ((AtPosition) obj).character && super.equalsImpl(obj);
- }
-
- @Override
- public String toString() {
- return super.toString() + ':' + character;
- }
- }
-
- private final String sourceName;
-
- DeclarationInTextSource(final String sourceName) {
- this.sourceName = sourceName;
- }
-
- public static @NonNull DeclarationInTextSource inSource(final String sourceName) {
- return new InSource(sourceName);
- }
-
- public static @NonNull DeclarationInTextSource atLine(final String sourceName, final int line) {
- return new AtLine(sourceName, line);
- }
-
- public static @NonNull DeclarationInTextSource atPosition(final String sourceName, final int line,
- final int position) {
- return new AtPosition(sourceName, line, position);
- }
-
- public final String getSourceName() {
- return sourceName;
- }
-
- @Override
- public final StatementOrigin statementOrigin() {
- return StatementOrigin.DECLARATION;
- }
-
- @Override
- public final int hashCode() {
- return hashCodeImpl();
- }
-
- @Override
- public final boolean equals(final Object obj) {
- return this == obj
- || obj != null && getClass().equals(obj.getClass()) && equalsImpl((DeclarationInTextSource) obj);
- }
-
- @Override
- public String toString() {
- return sourceName == null ? "null" : sourceName;
- }
-
- int hashCodeImpl() {
- return Objects.hashCode(sourceName);
- }
-
- boolean equalsImpl(final DeclarationInTextSource obj) {
- return Objects.equals(sourceName, obj.sourceName);
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o.
+ *
+ * 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.spi.source;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verifyNotNull;
+
+import com.google.common.annotations.Beta;
+import java.util.Objects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclarationInFile;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclarationInText;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementOrigin;
+
+/**
+ * Reference of statement source present in textual source format. Utility implementation
+ * of {@link StatementSourceReference} for textual sources, this is preferred {@link StatementSourceReference}
+ * for implementations of YANG / YIN statement stream sources.
+ *
+ * <p>
+ * To create source reference use one of this static factories:
+ * <ul>
+ * <li>{@link #atPosition(String, int, int)} - provides most specific reference of statement location, this is most
+ * preferred since it provides most context to debug YANG model.</li>
+ * <li>{@link #atPosition(int, int)}- provides location in text without knowing the name of the text file.</li>
+ * <li>{@link #inFile(String)}- provides a source name.</li>
+ * </ul>
+ */
+@Beta
+public abstract class ExplicitStatement extends StatementSourceReference implements DeclarationReference {
+ private static final class InFile extends ExplicitStatement implements DeclarationInFile {
+ InFile(final String fileName) {
+ super(fileName, -1, -1);
+ checkArgument(!fileName.isEmpty(), "Invalid empty file name");
+ }
+
+ @Override
+ public String fileName() {
+ return verifyNotNull(file());
+ }
+ }
+
+ private static class InText extends ExplicitStatement implements DeclarationInText {
+ InText(final String file, final int line, final int column) {
+ super(file, line, column);
+ checkArgument(line > 0, "Invalid start line %s", line);
+ checkArgument(column > 0, "Invalid start column %s", column);
+ }
+
+ @Override
+ public int startLine() {
+ return line();
+ }
+
+ @Override
+ public int startColumn() {
+ return column();
+ }
+ }
+
+ private static final class InTextFile extends InText implements DeclarationInFile {
+ InTextFile(final String fileName, final int line, final int column) {
+ super(fileName, line, column);
+ checkArgument(!fileName.isEmpty(), "Invalid empty file name");
+ }
+
+ @Override
+ public String fileName() {
+ return verifyNotNull(file());
+ }
+ }
+
+ private final String file;
+ private final int line;
+ private final int column;
+
+ ExplicitStatement(final String file, final int line, final int column) {
+ this.file = file;
+ this.line = line;
+ this.column = column;
+ }
+
+ public static @NonNull ExplicitStatement atPosition(final int line, final int column) {
+ return new InText(null, line, column);
+ }
+
+ public static @NonNull ExplicitStatement atPosition(final @Nullable String fileName, final int line,
+ final int column) {
+ return fileName == null ? atPosition(line, column) : new InTextFile(fileName, line, column);
+ }
+
+ public static @NonNull ExplicitStatement inFile(final @NonNull String fileName) {
+ return new InFile(fileName);
+ }
+
+ @Override
+ public final StatementOrigin statementOrigin() {
+ return StatementOrigin.DECLARATION;
+ }
+
+ @Override
+ public final DeclarationReference declarationReference() {
+ return this;
+ }
+
+ @Override
+ public final String toHumanReadable() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(file != null ? file : "<UNKNOWN>");
+ if (line > 0) {
+ sb.append(':').append(line);
+ }
+ if (column > 0) {
+ sb.append(':').append(column);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(file(), line(), column());
+ }
+
+ @Override
+ public final boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || !getClass().equals(obj.getClass())) {
+ return false;
+ }
+ final ExplicitStatement other = (ExplicitStatement) obj;
+ return line == other.line && column == other.column && Objects.equals(file, other.file);
+ }
+
+ @Override
+ public final String toString() {
+ return toHumanReadable();
+ }
+
+ final String file() {
+ return file;
+ }
+
+ final int line() {
+ return line;
+ }
+
+ final int column() {
+ return column;
+ }
+}
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
import org.opendaylight.yangtools.yang.model.api.meta.StatementOrigin;
/**
- * An implicit sub-statement, which is implied to be always present in its parent, even if it does not appear
- * in model source.
- *
- * @author Robert Varga
+ * An implicit sub-statement, which is implied to be always present in its parent, even if it does not appear in model
+ * source.
*/
@Beta
-public final class ImplicitSubstatement implements StatementSourceReference {
-
+public final class ImplicitSubstatement extends StatementSourceReference {
private final StatementSourceReference parentRef;
private ImplicitSubstatement(final StatementSourceReference parentRef) {
return StatementOrigin.CONTEXT;
}
+ @Override
+ public DeclarationReference declarationReference() {
+ return null;
+ }
+
@Override
public int hashCode() {
return parentRef.hashCode();
package org.opendaylight.yangtools.yang.parser.spi.source;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
import org.opendaylight.yangtools.yang.model.api.meta.StatementOrigin;
/**
*
* <p>
* Reasons for introduction of statement could be various, but most obvious one is explicit declaration in model source
- * text such as {@link DeclarationInTextSource}.
+ * text such as {@link ExplicitStatement}.
*/
-public interface StatementSourceReference {
+public abstract class StatementSourceReference implements Immutable {
/**
- * Returns source type.
+ * Returns the {@link StatementOrigin} associated with this reference.
*
* @return {@link StatementOrigin#DECLARATION} if statement was explicitly declared in YANG model source,
* {@link StatementOrigin#CONTEXT} if statement was inferred.
*/
- @NonNull StatementOrigin statementOrigin();
+ public abstract @NonNull StatementOrigin statementOrigin();
+
+ /**
+ * Returns the {@link DeclarationReference} associated with this reference, if available.
+ *
+ * @return A {@link DeclarationReference} or null.
+ */
+ public abstract @Nullable DeclarationReference declarationReference();
/**
* Returns human readable representation of statement source.
* @return human readable representation of statement source.
*/
@Override
- String toString();
+ public abstract @NonNull String toString();
}
import org.junit.Test;
import org.opendaylight.yangtools.yang.model.api.meta.StatementOrigin;
-public class DeclarationInTextSourceTest {
+public class ExplicitStatementTest {
@Test
public void testStatementSource() {
- assertEquals(StatementOrigin.DECLARATION, DeclarationInTextSource.atLine("foo", 5).statementOrigin());
+ assertEquals(StatementOrigin.DECLARATION, ExplicitStatement.inFile("foo").statementOrigin());
}
@Test
public void testToString() {
- assertEquals("foo", DeclarationInTextSource.inSource("foo").toString());
- assertEquals("foo:5", DeclarationInTextSource.atLine("foo", 5).toString());
- assertEquals("foo:5:10", DeclarationInTextSource.atPosition("foo", 5, 10).toString());
+ assertEquals("foo", ExplicitStatement.inFile("foo").toString());
+ assertEquals("<UNKNOWN>:5:10", ExplicitStatement.atPosition(5, 10).toString());
+ assertEquals("foo:5:10", ExplicitStatement.atPosition("foo", 5, 10).toString());
}
}