| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(jimhug): This should be an interface to work better with tools. | 5 #library('source_file'); |
| 6 |
| 7 #import('../../frog/leg/colors.dart'); |
| 8 |
| 6 /** | 9 /** |
| 7 * Represents a file of source code. | 10 * Represents a file of source code. |
| 8 */ | 11 */ |
| 9 class SourceFile implements Comparable { | 12 class 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 | 13 |
| 14 /** The name of the file. */ | 14 /** The name of the file. */ |
| 15 final String filename; | 15 final String filename; |
| 16 | 16 |
| 17 /** The text content of the file. */ | 17 /** The text content of the file. */ |
| 18 String _text; | 18 final 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 | 19 |
| 29 List<int> _lineStarts; | 20 List<int> _lineStarts; |
| 30 | 21 |
| 31 SourceFile(this.filename, this._text); | 22 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 | 23 |
| 43 List<int> get lineStarts() { | 24 List<int> get lineStarts() { |
| 44 if (_lineStarts == null) { | 25 if (_lineStarts == null) { |
| 45 var starts = [0]; | 26 var starts = [0]; |
| 46 var index = 0; | 27 var index = 0; |
| 47 while (index < text.length) { | 28 while (index < text.length) { |
| 48 index = text.indexOf('\n', index) + 1; | 29 index = text.indexOf('\n', index) + 1; |
| 49 if (index <= 0) break; | 30 if (index <= 0) break; |
| 50 starts.add(index); | 31 starts.add(index); |
| 51 } | 32 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 66 | 47 |
| 67 int getColumn(int line, int position) { | 48 int getColumn(int line, int position) { |
| 68 return position - lineStarts[line]; | 49 return position - lineStarts[line]; |
| 69 } | 50 } |
| 70 | 51 |
| 71 /** | 52 /** |
| 72 * Create a pretty string representation from a character position | 53 * Create a pretty string representation from a character position |
| 73 * in the file. | 54 * in the file. |
| 74 */ | 55 */ |
| 75 String getLocationMessage(String message, int start, | 56 String getLocationMessage(String message, int start, |
| 76 [int end, bool includeText=false]) { | 57 [int end, bool includeText=false, bool useColors = true]) { |
| 77 var line = getLine(start); | 58 var line = getLine(start); |
| 78 var column = getColumn(line, start); | 59 var column = getColumn(line, start); |
| 79 | 60 |
| 80 var buf = new StringBuffer( | 61 var buf = new StringBuffer( |
| 81 '${filename}:${line + 1}:${column + 1}: $message'); | 62 '${filename}:${line + 1}:${column + 1}: $message'); |
| 82 if (includeText) { | 63 if (includeText) { |
| 83 buf.add('\n'); | 64 buf.add('\n'); |
| 84 var textLine; | 65 var textLine; |
| 85 // +1 for 0-indexing, +1 again to avoid the last line of the file | 66 // +1 for 0-indexing, +1 again to avoid the last line of the file |
| 86 if ((line + 2) < _lineStarts.length) { | 67 if ((line + 2) < _lineStarts.length) { |
| 87 textLine = text.substring(_lineStarts[line], _lineStarts[line+1]); | 68 textLine = text.substring(_lineStarts[line], _lineStarts[line+1]); |
| 88 } else { | 69 } else { |
| 89 textLine = text.substring(_lineStarts[line]) + '\n'; | 70 textLine = text.substring(_lineStarts[line]) + '\n'; |
| 90 } | 71 } |
| 91 | 72 |
| 92 int toColumn = Math.min(column + (end-start), textLine.length); | 73 int toColumn = Math.min(column + (end-start), textLine.length); |
| 93 if (options.useColors) { | 74 if (useColors) { |
| 94 buf.add(textLine.substring(0, column)); | 75 buf.add(textLine.substring(0, column)); |
| 95 buf.add(_RED_COLOR); | 76 buf.add(RED_COLOR); |
| 96 buf.add(textLine.substring(column, toColumn)); | 77 buf.add(textLine.substring(column, toColumn)); |
| 97 buf.add(_NO_COLOR); | 78 buf.add(NO_COLOR); |
| 98 buf.add(textLine.substring(toColumn)); | 79 buf.add(textLine.substring(toColumn)); |
| 99 } else { | 80 } else { |
| 100 buf.add(textLine); | 81 buf.add(textLine); |
| 101 } | 82 } |
| 102 | 83 |
| 103 int i = 0; | 84 int i = 0; |
| 104 for (; i < column; i++) { | 85 for (; i < column; i++) { |
| 105 buf.add(' '); | 86 buf.add(' '); |
| 106 } | 87 } |
| 107 | 88 |
| 108 if (options.useColors) buf.add(_RED_COLOR); | 89 if (useColors) buf.add(RED_COLOR); |
| 109 for (; i < toColumn; i++) { | 90 for (; i < toColumn; i++) { |
| 110 buf.add('^'); | 91 buf.add('^'); |
| 111 } | 92 } |
| 112 if (options.useColors) buf.add(_NO_COLOR); | 93 if (useColors) buf.add(NO_COLOR); |
| 113 } | 94 } |
| 114 | 95 |
| 115 return buf.toString(); | 96 return buf.toString(); |
| 116 } | 97 } |
| 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 } | 98 } |
| 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 { | |
| 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 |