| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 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 | 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 library dart2js.util; | 5 library dart2js.util; |
| 6 | 6 |
| 7 import "dart:collection"; | |
| 8 import 'util_implementation.dart'; | 7 import 'util_implementation.dart'; |
| 9 import 'characters.dart'; | 8 import 'characters.dart'; |
| 10 | 9 |
| 11 export 'setlet.dart'; | 10 export 'setlet.dart'; |
| 12 | 11 |
| 13 part 'link.dart'; | 12 part 'link.dart'; |
| 14 part 'expensive_map.dart'; | |
| 15 part 'expensive_set.dart'; | |
| 16 | 13 |
| 17 /** | 14 /** |
| 18 * Tagging interface for classes from which source spans can be generated. | 15 * Tagging interface for classes from which source spans can be generated. |
| 19 */ | 16 */ |
| 20 // TODO(johnniwinther): Find a better name. | 17 // TODO(johnniwinther): Find a better name. |
| 21 // TODO(ahe): How about "Bolt"? | 18 // TODO(ahe): How about "Bolt"? |
| 22 abstract class Spannable {} | 19 abstract class Spannable {} |
| 23 | 20 |
| 24 class _SpannableSentinel implements Spannable { | 21 class _SpannableSentinel implements Spannable { |
| 25 final String name; | 22 final String name; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 44 class SpannableAssertionFailure { | 41 class SpannableAssertionFailure { |
| 45 final Spannable node; | 42 final Spannable node; |
| 46 final String message; | 43 final String message; |
| 47 SpannableAssertionFailure(this.node, this.message); | 44 SpannableAssertionFailure(this.node, this.message); |
| 48 | 45 |
| 49 String toString() => 'Assertion failure' | 46 String toString() => 'Assertion failure' |
| 50 '${message != null ? ': $message' : ''}'; | 47 '${message != null ? ': $message' : ''}'; |
| 51 } | 48 } |
| 52 | 49 |
| 53 /** | 50 /** |
| 54 * Helper method for printing stack traces for debugging. | |
| 55 * | |
| 56 * [message] is printed as the header of the stack trace. | |
| 57 * | |
| 58 * If [condition] is provided, the stack trace is only printed if [condition] | |
| 59 * returns [:true:] on the stack trace text. This can be used to filter the | |
| 60 * printed stack traces based on their content. For instance only print stack | |
| 61 * traces that contain specific paths. | |
| 62 */ | |
| 63 void trace(String message, [bool condition(String stackTrace)]) { | |
| 64 try { | |
| 65 throw ''; | |
| 66 } catch (e, s) { | |
| 67 String stackTrace = prettifyStackTrace( | |
| 68 s, rangeStart: 1, filePrefix: stackTraceFilePrefix); | |
| 69 if (condition != null) { | |
| 70 if (!condition(stackTrace)) return; | |
| 71 } | |
| 72 print('$message\n$stackTrace'); | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 /** | |
| 77 * File name prefix used to shorten the file name in stack traces printed by | 51 * File name prefix used to shorten the file name in stack traces printed by |
| 78 * [trace]. | 52 * [trace]. |
| 79 */ | 53 */ |
| 80 String stackTraceFilePrefix = null; | 54 String stackTraceFilePrefix = null; |
| 81 | 55 |
| 82 /// Helper class for the processing of stack traces in [prettifyStackTrace]. | |
| 83 class _StackTraceLine { | |
| 84 final int index; | |
| 85 final String file; | |
| 86 final String lineNo; | |
| 87 final String columnNo; | |
| 88 final String method; | |
| 89 | |
| 90 _StackTraceLine(this.index, this.file, this.lineNo, | |
| 91 this.columnNo, this.method); | |
| 92 | |
| 93 String toString() { | |
| 94 return 'index=$index, file=$file, ' | |
| 95 'lineNo=$lineNo, columnNo=$columnNo, method=$method'; | |
| 96 } | |
| 97 } | |
| 98 | |
| 99 // TODO(johnniwinther): Use this format for --throw-on-error. | |
| 100 /** | |
| 101 * Converts the normal VM stack trace into a more compact and readable format. | |
| 102 * | |
| 103 * The output format is [: <file> . . . <lineNo>:<columnNo> <method> :] where | |
| 104 * [: <file> :] is file name, [: <lineNo> :] is the line number, | |
| 105 * [: <columnNo> :] is the column number, and [: <method> :] is the method name. | |
| 106 * | |
| 107 * If [rangeStart] and/or [rangeEnd] are provided, only the lines within the | |
| 108 * range are included. | |
| 109 * If [showColumnNo] is [:false:], the [: :<columnNo> :] part is omitted. | |
| 110 * If [showDots] is [:true:], the space between [: <file> :] and [: <lineNo> :] | |
| 111 * is padded with dots on every other line. | |
| 112 * If [filePrefix] is provided, then for every file name thats starts with | |
| 113 * [filePrefix] only the remainder is printed. | |
| 114 * If [lambda] is non-null, anonymous closures are printed as [lambda]. | |
| 115 */ | |
| 116 String prettifyStackTrace(StackTrace s, | |
| 117 {int rangeStart, | |
| 118 int rangeEnd, | |
| 119 bool showColumnNo: false, | |
| 120 bool showDots: true, | |
| 121 String filePrefix, | |
| 122 String lambda: r'?'}) { | |
| 123 int index = -1; | |
| 124 int maxFileLength = 0; | |
| 125 int maxLineNoLength = 0; | |
| 126 int maxColumnNoLength = 0; | |
| 127 | |
| 128 String stackTrace = '$s'; | |
| 129 List<_StackTraceLine> lines = <_StackTraceLine>[]; | |
| 130 for (String line in stackTrace.split('\n')) { | |
| 131 try { | |
| 132 index++; | |
| 133 if (rangeStart != null && index < rangeStart) continue; | |
| 134 if (rangeEnd != null && index > rangeEnd) continue; | |
| 135 if (line.isEmpty) continue; | |
| 136 | |
| 137 // Strip index. | |
| 138 line = line.replaceFirst(new RegExp(r'#\d+\s*'), ''); | |
| 139 | |
| 140 int leftParenPos = line.indexOf('('); | |
| 141 int rightParenPos = line.indexOf(')', leftParenPos); | |
| 142 int lastColon = line.lastIndexOf(':', rightParenPos); | |
| 143 int nextToLastColon = line.lastIndexOf(':', lastColon-1); | |
| 144 | |
| 145 String lineNo; | |
| 146 String columnNo; | |
| 147 if (nextToLastColon != -1) { | |
| 148 lineNo = line.substring(nextToLastColon+1, lastColon); | |
| 149 columnNo = line.substring(lastColon+1, rightParenPos); | |
| 150 try { | |
| 151 int.parse(lineNo); | |
| 152 } on FormatException catch (e) { | |
| 153 lineNo = columnNo; | |
| 154 columnNo = ''; | |
| 155 nextToLastColon = lastColon; | |
| 156 } | |
| 157 } else { | |
| 158 lineNo = line.substring(lastColon+1, rightParenPos); | |
| 159 columnNo = ''; | |
| 160 nextToLastColon = lastColon; | |
| 161 } | |
| 162 | |
| 163 if (lineNo.length > maxLineNoLength) { | |
| 164 maxLineNoLength = lineNo.length; | |
| 165 } | |
| 166 if (columnNo.length > maxColumnNoLength) { | |
| 167 maxColumnNoLength = columnNo.length; | |
| 168 } | |
| 169 | |
| 170 String file = line.substring(leftParenPos+1, nextToLastColon); | |
| 171 if (filePrefix != null && file.startsWith(filePrefix)) { | |
| 172 file = file.substring(filePrefix.length); | |
| 173 } | |
| 174 if (file.length > maxFileLength) { | |
| 175 maxFileLength = file.length; | |
| 176 } | |
| 177 String method = line.substring(0, leftParenPos-1); | |
| 178 if (lambda != null) { | |
| 179 method = method.replaceAll('<anonymous closure>', lambda); | |
| 180 } | |
| 181 lines.add(new _StackTraceLine(index, file, lineNo, columnNo, method)); | |
| 182 } catch (e) { | |
| 183 print('Error prettifying "$line": $e'); | |
| 184 return stackTrace; | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 StringBuffer sb = new StringBuffer(); | |
| 189 bool dots = true; | |
| 190 for (_StackTraceLine line in lines) { | |
| 191 String file = pad('${line.file} ', maxFileLength, | |
| 192 dots: showDots && dots ? ' .' : ' '); | |
| 193 String lineNo = pad(line.lineNo, maxLineNoLength, padLeft: true); | |
| 194 String columnNo = | |
| 195 showColumnNo ? ':${pad(line.columnNo, maxColumnNoLength)}' : ''; | |
| 196 String method = line.method; | |
| 197 sb.write(' $file $lineNo$columnNo $method\n'); | |
| 198 dots = !dots; | |
| 199 } | |
| 200 return sb.toString(); | |
| 201 } | |
| 202 | |
| 203 /** | |
| 204 * Pads (or truncates) [text] to the [intendedLength]. | |
| 205 * | |
| 206 * If [padLeft] is [:true:] the text is padding inserted to the left of [text]. | |
| 207 * A repetition of the [dots] text is used for padding. | |
| 208 */ | |
| 209 String pad(String text, int intendedLength, | |
| 210 {bool padLeft: false, String dots: ' '}) { | |
| 211 if (text.length == intendedLength) return text; | |
| 212 if (text.length > intendedLength) return text.substring(0, intendedLength); | |
| 213 if (dots == null || dots.isEmpty) dots = ' '; | |
| 214 int dotsLength = dots.length; | |
| 215 StringBuffer sb = new StringBuffer(); | |
| 216 if (!padLeft) { | |
| 217 sb.write(text); | |
| 218 } | |
| 219 for (int index = text.length ; index < intendedLength ; index ++) { | |
| 220 int dotsIndex = index % dotsLength; | |
| 221 sb.write(dots.substring(dotsIndex, dotsIndex + 1)); | |
| 222 } | |
| 223 if (padLeft) { | |
| 224 sb.write(text); | |
| 225 } | |
| 226 return sb.toString(); | |
| 227 } | |
| 228 | |
| 229 /// Writes the characters of [string] on [buffer]. The characters | 56 /// Writes the characters of [string] on [buffer]. The characters |
| 230 /// are escaped as suitable for JavaScript and JSON. [buffer] is | 57 /// are escaped as suitable for JavaScript and JSON. [buffer] is |
| 231 /// anything which supports [:write:] and [:writeCharCode:], for example, | 58 /// anything which supports [:write:] and [:writeCharCode:], for example, |
| 232 /// [StringBuffer]. Note that JS supports \xnn and \unnnn whereas JSON only | 59 /// [StringBuffer]. Note that JS supports \xnn and \unnnn whereas JSON only |
| 233 /// supports the \unnnn notation. Therefore we use the \unnnn notation. | 60 /// supports the \unnnn notation. Therefore we use the \unnnn notation. |
| 234 void writeJsonEscapedCharsOn(String string, buffer) { | 61 void writeJsonEscapedCharsOn(String string, buffer) { |
| 235 void addCodeUnitEscaped(var buffer, int code) { | 62 void addCodeUnitEscaped(var buffer, int code) { |
| 236 assert(code < 0x10000); | 63 assert(code < 0x10000); |
| 237 buffer.write(r'\u'); | 64 buffer.write(r'\u'); |
| 238 if (code < 0x1000) { | 65 if (code < 0x1000) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 buffer.write(string); | 126 buffer.write(string); |
| 300 } | 127 } |
| 301 | 128 |
| 302 int computeHashCode(part1, [part2, part3, part4, part5]) { | 129 int computeHashCode(part1, [part2, part3, part4, part5]) { |
| 303 return (part1.hashCode | 130 return (part1.hashCode |
| 304 ^ part2.hashCode | 131 ^ part2.hashCode |
| 305 ^ part3.hashCode | 132 ^ part3.hashCode |
| 306 ^ part4.hashCode | 133 ^ part4.hashCode |
| 307 ^ part5.hashCode) & 0x3fffffff; | 134 ^ part5.hashCode) & 0x3fffffff; |
| 308 } | 135 } |
| OLD | NEW |