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 |