| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 // TODO(jimhug): This should be an interface to work better with tools. | |
| 6 /** | |
| 7 * Represents a file of source code. | |
| 8 */ | |
| 9 class SourceFile implements Comparable<SourceFile> { | |
| 10 // TODO(terry): This filename for in memory buffer. May need to rework if | |
| 11 // filename is used for more than informational. | |
| 12 static String IN_MEMORY_FILE = '<buffer>'; | |
| 13 | |
| 14 /** The name of the file. */ | |
| 15 final String filename; | |
| 16 | |
| 17 /** The text content of the file. */ | |
| 18 String _text; | |
| 19 | |
| 20 /** | |
| 21 * The order of the source file in a given library. This is used while we're | |
| 22 * writing code for a library. A single source file can be used | |
| 23 */ | |
| 24 // TODO(jmesserly): I don't like having properties that are only valid | |
| 25 // sometimes. An alternative would be to store it in a Map that's used by | |
| 26 // WorldGenerator while it's emitting code. This seems simpler. | |
| 27 int orderInLibrary; | |
| 28 | |
| 29 List<int> _lineStarts; | |
| 30 | |
| 31 SourceFile(this.filename, this._text); | |
| 32 | |
| 33 String get text => _text; | |
| 34 | |
| 35 set text(String newText) { | |
| 36 if (newText != _text) { | |
| 37 _text = newText; | |
| 38 _lineStarts = null; | |
| 39 orderInLibrary = null; | |
| 40 } | |
| 41 } | |
| 42 | |
| 43 List<int> get lineStarts { | |
| 44 if (_lineStarts == null) { | |
| 45 var starts = [0]; | |
| 46 var index = 0; | |
| 47 while (index < text.length) { | |
| 48 index = text.indexOf('\n', index) + 1; | |
| 49 if (index <= 0) break; | |
| 50 starts.add(index); | |
| 51 } | |
| 52 starts.add(text.length + 1); | |
| 53 _lineStarts = starts; | |
| 54 } | |
| 55 return _lineStarts; | |
| 56 } | |
| 57 | |
| 58 int getLine(int position) { | |
| 59 // TODO(jimhug): Implement as binary search. | |
| 60 var starts = lineStarts; | |
| 61 for (int i=0; i < starts.length; i++) { | |
| 62 if (starts[i] > position) return i-1; | |
| 63 } | |
| 64 world.internalError('bad position'); | |
| 65 } | |
| 66 | |
| 67 int getColumn(int line, int position) { | |
| 68 return position - lineStarts[line]; | |
| 69 } | |
| 70 | |
| 71 /** | |
| 72 * Create a pretty string representation from a character position | |
| 73 * in the file. | |
| 74 */ | |
| 75 String getLocationMessage(String message, int start, | |
| 76 [int end, bool includeText=false]) { | |
| 77 var line = getLine(start); | |
| 78 var column = getColumn(line, start); | |
| 79 | |
| 80 var buf = new StringBuffer( | |
| 81 '${filename}:${line + 1}:${column + 1}: $message'); | |
| 82 if (includeText) { | |
| 83 buf.write('\n'); | |
| 84 var textLine; | |
| 85 // +1 for 0-indexing, +1 again to avoid the last line of the file | |
| 86 if ((line + 2) < _lineStarts.length) { | |
| 87 textLine = text.substring(_lineStarts[line], _lineStarts[line+1]); | |
| 88 } else { | |
| 89 textLine = text.substring(_lineStarts[line]) + '\n'; | |
| 90 } | |
| 91 | |
| 92 int toColumn = Math.min(column + (end-start), textLine.length); | |
| 93 if (options.useColors) { | |
| 94 buf.write(textLine.substring(0, column)); | |
| 95 buf.write(_RED_COLOR); | |
| 96 buf.write(textLine.substring(column, toColumn)); | |
| 97 buf.write(_NO_COLOR); | |
| 98 buf.write(textLine.substring(toColumn)); | |
| 99 } else { | |
| 100 buf.write(textLine); | |
| 101 } | |
| 102 | |
| 103 int i = 0; | |
| 104 for (; i < column; i++) { | |
| 105 buf.write(' '); | |
| 106 } | |
| 107 | |
| 108 if (options.useColors) buf.write(_RED_COLOR); | |
| 109 for (; i < toColumn; i++) { | |
| 110 buf.write('^'); | |
| 111 } | |
| 112 if (options.useColors) buf.write(_NO_COLOR); | |
| 113 } | |
| 114 | |
| 115 return buf.toString(); | |
| 116 } | |
| 117 | |
| 118 /** Compares two source files. */ | |
| 119 int compareTo(SourceFile other) { | |
| 120 if (orderInLibrary != null && other.orderInLibrary != null) { | |
| 121 return orderInLibrary - other.orderInLibrary; | |
| 122 } else { | |
| 123 return filename.compareTo(other.filename); | |
| 124 } | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 | |
| 129 /** | |
| 130 * A range of characters in a [SourceFile]. Used to represent the source | |
| 131 * positions of [Token]s and [Node]s for error reporting or other tooling | |
| 132 * work. | |
| 133 */ | |
| 134 // TODO(jmesserly): Rename to Span - but first write cool refactoring tool | |
| 135 class SourceSpan implements Comparable<SourceSpan> { | |
| 136 /** The [SourceFile] that contains this span. */ | |
| 137 final SourceFile file; | |
| 138 | |
| 139 /** The character position of the start of this span. */ | |
| 140 final int start; | |
| 141 | |
| 142 /** The character position of the end of this span. */ | |
| 143 final int end; | |
| 144 | |
| 145 SourceSpan(this.file, this.start, this.end); | |
| 146 | |
| 147 /** Returns the source text corresponding to this [Span]. */ | |
| 148 String get text { | |
| 149 return file.text.substring(start, end); | |
| 150 } | |
| 151 | |
| 152 toMessageString(String message) { | |
| 153 return file.getLocationMessage(message, start, end: end, includeText: true); | |
| 154 } | |
| 155 | |
| 156 int get line { | |
| 157 return file.getLine(start); | |
| 158 } | |
| 159 | |
| 160 int get column { | |
| 161 return file.getColumn(line, start); | |
| 162 } | |
| 163 | |
| 164 int get endLine { | |
| 165 return file.getLine(end); | |
| 166 } | |
| 167 | |
| 168 int get endColumn { | |
| 169 return file.getColumn(endLine, end); | |
| 170 } | |
| 171 | |
| 172 String get locationText { | |
| 173 var line = file.getLine(start); | |
| 174 var column = file.getColumn(line, start); | |
| 175 return '${file.filename}:${line + 1}:${column + 1}'; | |
| 176 } | |
| 177 | |
| 178 /** Compares two source spans by file and position. Handles nulls. */ | |
| 179 int compareTo(SourceSpan other) { | |
| 180 if (file == other.file) { | |
| 181 int d = start - other.start; | |
| 182 return d == 0 ? (end - other.end) : d; | |
| 183 } | |
| 184 return file.compareTo(other.file); | |
| 185 } | |
| 186 } | |
| OLD | NEW |