Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(254)

Unified Diff: compiler/java/com/google/dart/compiler/common/SourceInfo.java

Issue 9651004: Make SourceInfo a class, rename its menthods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Tweak for formatting, lazily create LainesInfo Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: compiler/java/com/google/dart/compiler/common/SourceInfo.java
diff --git a/compiler/java/com/google/dart/compiler/common/SourceInfo.java b/compiler/java/com/google/dart/compiler/common/SourceInfo.java
index 261e037f864fb01dc091ebbfcd19d388eb72f715..1b64e5bddbe6e9422dc9a1239ed4efb2fe919b97 100644
--- a/compiler/java/com/google/dart/compiler/common/SourceInfo.java
+++ b/compiler/java/com/google/dart/compiler/common/SourceInfo.java
@@ -4,56 +4,161 @@
package com.google.dart.compiler.common;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
import com.google.dart.compiler.Source;
+import java.io.BufferedReader;
import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
/**
- * Tracks file and line information for AST nodes.
+ * Contains {@link Source} and location information for AST nodes.
+ * <p>
+ * Each node in the subtree (other than the contrived nodes) carries source range(s) information
+ * relating back to positions in the given source (the given source itself is not remembered with
+ * the AST). The source range usually begins at the first character of the first token corresponding
+ * to the node; leading whitespace and comments are <b>not</b> included. The source range usually
+ * extends through the last character of the last token corresponding to the node; trailing
+ * whitespace and comments are <b>not</b> included. There are a handful of exceptions (including the
+ * various body declarations). Source ranges nest properly: the source range for a child is always
+ * within the source range of its parent, and the source ranges of sibling nodes never overlap.
*/
-public interface SourceInfo extends Serializable {
+public final class SourceInfo implements Serializable {
/**
- * The source code provider.
+ * The unknown {@link SourceInfo}.
*/
- Source getSource();
+ public static final SourceInfo UNKNOWN = new SourceInfo(null, 0, 0);
+
+ private static final Map<Source, LinesInfo> lines = new MapMaker().weakKeys().makeMap();
+
+ private final Source source;
+ private final int offset;
+ private final int length;
+
+ public SourceInfo(Source source, int offset, int length) {
+ Preconditions.checkArgument(offset != -1 && length >= 0 || offset == -1 && length == 0);
+ this.source = source;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * @return the {@link LinesInfo}, may be empty if some {@link Exception} happens, but not
+ * <code>null</code>.
+ */
+ private static LinesInfo getLinesInfo(Source source) {
+ LinesInfo linesInfo = lines.get(source);
+ if (linesInfo == null) {
+ linesInfo = createLinesInfo(source);
+ lines.put(source, linesInfo);
+ }
+ return linesInfo;
+ }
/**
- * @return A 1-based line number into the original source file indicating
- * where the source fragment begins.
+ * @return the new {@link LinesInfo}, may be empty if some {@link Exception} happens, but not
+ * <code>null</code>.
*/
- int getSourceLine();
+ private static LinesInfo createLinesInfo(Source source) {
+ try {
+ BufferedReader reader = new BufferedReader(source.getSourceReader());
+ int offset = 0;
+ boolean ignoreLF = false;
+ List<Integer> lineOffsets = Lists.newArrayList(0);
+ while (true) {
+ int charValue = reader.read();
+ if (charValue == -1) {
+ break;
+ }
+ offset++;
+ char c = (char) charValue;
+ ignoreLF = c == '\n';
+ if (c == '\n' || c == '\r' && !ignoreLF) {
+ lineOffsets.add(offset);
+ }
+ }
+ return new LinesInfo(lineOffsets);
+ } catch (Throwable e) {
+ return new LinesInfo(ImmutableList.of(0));
+ }
+ }
/**
- * @return A 1-based column number into the original source file indicating
- * where the source fragment begins.
+ * @return the {@link Source}.
*/
- int getSourceColumn();
+ public Source getSource() {
+ return source;
+ }
/**
- * Returns the character index into the original source file indicating
- * where the source fragment corresponding to this node begins.
- *
- * <p>
- * The parser supplies useful well-defined source ranges to the nodes it creates.
- *
- * @return the 0-based character index, or <code>-1</code>
- * if no source startPosition information is recorded for this node
- * @see #getSourceLength()
- * @see HasSourceInfo#setSourceLocation(Source, int, int, int, int)
+ * @return the 0-based character index in the {@link Source}, may <code>-1</code> if no source
+ * information is recorded.
*/
- int getSourceStart();
+ public int getOffset() {
+ return offset;
+ }
/**
- * Returns the length in characters of the original source file indicating
- * where the source fragment corresponding to this node ends.
- * <p>
- * The parser supplies useful well-defined source ranges to the nodes it creates.
- *
- * @return a (possibly 0) length, or <code>0</code>
- * if no source source position information is recorded for this node
- * @see #getSourceStart()
- * @see HasSourceInfo#setSourceLocation(Source, int, int, int, int)
+ * @return a (possibly 0) length of this node in the {@link Source}, may <code>0</code> if no
+ * source position information is recorded.
*/
- int getSourceLength();
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * @return a 1-based line number in the {@link Source} indicating where the source fragment
+ * begins. May be <code>0</code> if line not found.
+ */
+ public int getLine() {
+ if (source == null) {
+ return 0;
+ }
+ return 1 + getLinesInfo(source).getLineOfOffset(offset);
+ }
+
+ /**
+ * @return a 1-based column number in the {@link Source} indicating where the source fragment
+ * begins. May be <code>0</code> if column not found.
+ */
+ public int getColumn() {
+ if (source == null) {
+ return 0;
+ }
+ return 1 + getLinesInfo(source).getColumnOfOffset(offset);
+ }
+
+ /**
+ * Container for information about lines in some {@link Source}.
+ */
+ private static class LinesInfo {
+ private final List<Integer> lineOffsets;
+
+ public LinesInfo(List<Integer> lineOffsets) {
+ this.lineOffsets = lineOffsets;
+ }
+
+ int getLineOffset(int line) {
+ return lineOffsets.get(line);
+ }
+
+ int getLineOfOffset(int offset) {
+ int index = Collections.binarySearch(lineOffsets, offset);
+ if (index >= 0) {
+ return index;
+ }
+ return -(2 + index);
+ }
+
+ int getColumnOfOffset(int offset) {
+ int line = getLineOfOffset(offset);
+ return offset - getLineOffset(line);
+ }
+ }
}

Powered by Google App Engine
This is Rietveld 408576698