Populate parser/ hierarchy
[yangtools.git] / parser / yang-parser-spi / src / main / java / org / opendaylight / yangtools / yang / parser / spi / source / ExplicitStatement.java
diff --git a/parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/ExplicitStatement.java b/parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/ExplicitStatement.java
new file mode 100644 (file)
index 0000000..f043233
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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;
+    }
+}