Index: packages/stack_trace/lib/src/frame.dart |
diff --git a/packages/stack_trace/lib/src/frame.dart b/packages/stack_trace/lib/src/frame.dart |
index 4077c7cba54318863a6f6799daf5bac5c5f30fcb..bbe5c79e697722de7844c3b988a8744c8a07beb9 100644 |
--- a/packages/stack_trace/lib/src/frame.dart |
+++ b/packages/stack_trace/lib/src/frame.dart |
@@ -2,8 +2,6 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
-library frame; |
- |
import 'package:path/path.dart' as path; |
import 'trace.dart'; |
@@ -19,8 +17,8 @@ final _vmFrame = new RegExp(r'^#\d+\s+(\S.*) \((.+?)((?::\d+){0,2})\)$'); |
// at VW.call$0 (eval as fn |
// (http://pub.dartlang.org/stuff.dart.js:560:28), efn:3:28) |
// at http://pub.dartlang.org/stuff.dart.js:560:28 |
-final _v8Frame = new RegExp( |
- r'^\s*at (?:(\S.*?)(?: \[as [^\]]+\])? \((.*)\)|(.*))$'); |
+final _v8Frame = |
+ new RegExp(r'^\s*at (?:(\S.*?)(?: \[as [^\]]+\])? \((.*)\)|(.*))$'); |
// http://pub.dartlang.org/stuff.dart.js:560:28 |
final _v8UrlLocation = new RegExp(r'^(.*):(\d+):(\d+)|native$'); |
@@ -29,34 +27,34 @@ final _v8UrlLocation = new RegExp(r'^(.*):(\d+):(\d+)|native$'); |
// eval as function (http://pub.dartlang.org/stuff.dart.js:560:28) |
// eval as function (eval as otherFunction |
// (http://pub.dartlang.org/stuff.dart.js:560:28)) |
-final _v8EvalLocation = new RegExp( |
- r'^eval at (?:\S.*?) \((.*)\)(?:, .*?:\d+:\d+)?$'); |
+final _v8EvalLocation = |
+ new RegExp(r'^eval at (?:\S.*?) \((.*)\)(?:, .*?:\d+:\d+)?$'); |
// .VW.call$0@http://pub.dartlang.org/stuff.dart.js:560 |
// .VW.call$0("arg")@http://pub.dartlang.org/stuff.dart.js:560 |
// .VW.call$0/name<@http://pub.dartlang.org/stuff.dart.js:560 |
// .VW.call$0@http://pub.dartlang.org/stuff.dart.js:560:36 |
// http://pub.dartlang.org/stuff.dart.js:560 |
-final _firefoxSafariFrame = new RegExp( |
- r'^' |
+final _firefoxSafariFrame = new RegExp(r'^' |
r'(?:' // Member description. Not present in some Safari frames. |
- r'([^@(/]*)' // The actual name of the member. |
- r'(?:\(.*\))?' // Arguments to the member, sometimes captured by Firefox. |
- r'((?:/[^/]*)*)' // Extra characters indicating a nested closure. |
- r'(?:\(.*\))?' // Arguments to the closure. |
- r'@' |
+ r'([^@(/]*)' // The actual name of the member. |
+ r'(?:\(.*\))?' // Arguments to the member, sometimes captured by Firefox. |
+ r'((?:/[^/]*)*)' // Extra characters indicating a nested closure. |
+ r'(?:\(.*\))?' // Arguments to the closure. |
+ r'@' |
r')?' |
r'(.*?)' // The frame's URL. |
r':' |
r'(\d*)' // The line number. Empty in Safari if it's unknown. |
r'(?::(\d*))?' // The column number. Not present in older browsers and |
- // empty in Safari if it's unknown. |
+ // empty in Safari if it's unknown. |
r'$'); |
-// foo/bar.dart 10:11 in Foo._bar |
-// http://dartlang.org/foo/bar.dart in Foo._bar |
-final _friendlyFrame = new RegExp( |
- r'^(\S+)(?: (\d+)(?::(\d+))?)?\s+([^\d]\S*)$'); |
+// foo/bar.dart 10:11 Foo._bar |
+// foo/bar.dart 10:11 (anonymous function).dart.fn |
+// http://dartlang.org/foo/bar.dart Foo._bar |
+// data:... 10:11 Foo._bar |
+final _friendlyFrame = new RegExp(r'^(\S+)(?: (\d+)(?::(\d+))?)?\s+([^\d].*)$'); |
/// A regular expression that matches asynchronous member names generated by the |
/// VM. |
@@ -120,7 +118,7 @@ class Frame { |
/// By default, this will return the frame above the current method. If |
/// [level] is `0`, it will return the current method's frame; if [level] is |
/// higher than `1`, it will return higher frames. |
- factory Frame.caller([int level=1]) { |
+ factory Frame.caller([int level = 1]) { |
if (level < 0) { |
throw new ArgumentError("Argument [level] must be greater than or equal " |
"to 0."); |
@@ -131,70 +129,72 @@ class Frame { |
/// Parses a string representation of a Dart VM stack frame. |
factory Frame.parseVM(String frame) => _catchFormatException(frame, () { |
- // The VM sometimes folds multiple stack frames together and replaces them |
- // with "...". |
- if (frame == '...') { |
- return new Frame(new Uri(), null, null, '...'); |
- } |
- |
- var match = _vmFrame.firstMatch(frame); |
- if (match == null) return new UnparsedFrame(frame); |
- |
- // Get the pieces out of the regexp match. Function, URI and line should |
- // always be found. The column is optional. |
- var member = match[1] |
- .replaceAll(_asyncBody, "<async>") |
- .replaceAll("<anonymous closure>", "<fn>"); |
- var uri = Uri.parse(match[2]); |
- |
- var lineAndColumn = match[3].split(':'); |
- var line = lineAndColumn.length > 1 ? int.parse(lineAndColumn[1]) : null; |
- var column = lineAndColumn.length > 2 ? int.parse(lineAndColumn[2]) : null; |
- return new Frame(uri, line, column, member); |
- }); |
+ // The VM sometimes folds multiple stack frames together and replaces them |
+ // with "...". |
+ if (frame == '...') { |
+ return new Frame(new Uri(), null, null, '...'); |
+ } |
+ |
+ var match = _vmFrame.firstMatch(frame); |
+ if (match == null) return new UnparsedFrame(frame); |
+ |
+ // Get the pieces out of the regexp match. Function, URI and line should |
+ // always be found. The column is optional. |
+ var member = match[1] |
+ .replaceAll(_asyncBody, "<async>") |
+ .replaceAll("<anonymous closure>", "<fn>"); |
+ var uri = Uri.parse(match[2]); |
+ |
+ var lineAndColumn = match[3].split(':'); |
+ var line = |
+ lineAndColumn.length > 1 ? int.parse(lineAndColumn[1]) : null; |
+ var column = |
+ lineAndColumn.length > 2 ? int.parse(lineAndColumn[2]) : null; |
+ return new Frame(uri, line, column, member); |
+ }); |
/// Parses a string representation of a Chrome/V8 stack frame. |
factory Frame.parseV8(String frame) => _catchFormatException(frame, () { |
- var match = _v8Frame.firstMatch(frame); |
- if (match == null) return new UnparsedFrame(frame); |
- |
- // v8 location strings can be arbitrarily-nested, since it adds a layer of |
- // nesting for each eval performed on that line. |
- parseLocation(location, member) { |
- var evalMatch = _v8EvalLocation.firstMatch(location); |
- while (evalMatch != null) { |
- location = evalMatch[1]; |
- evalMatch = _v8EvalLocation.firstMatch(location); |
- } |
- |
- if (location == 'native') { |
- return new Frame(Uri.parse('native'), null, null, member); |
- } |
- |
- var urlMatch = _v8UrlLocation.firstMatch(location); |
- if (urlMatch == null) return new UnparsedFrame(frame); |
- |
- return new Frame( |
- _uriOrPathToUri(urlMatch[1]), |
- int.parse(urlMatch[2]), |
- int.parse(urlMatch[3]), |
- member); |
- } |
- |
- // V8 stack frames can be in two forms. |
- if (match[2] != null) { |
- // The first form looks like " at FUNCTION (LOCATION)". V8 proper lists |
- // anonymous functions within eval as "<anonymous>", while IE10 lists them |
- // as "Anonymous function". |
- return parseLocation(match[2], |
- match[1].replaceAll("<anonymous>", "<fn>") |
- .replaceAll("Anonymous function", "<fn>")); |
- } else { |
- // The second form looks like " at LOCATION", and is used for anonymous |
- // functions. |
- return parseLocation(match[3], "<fn>"); |
- } |
- }); |
+ var match = _v8Frame.firstMatch(frame); |
+ if (match == null) return new UnparsedFrame(frame); |
+ |
+ // v8 location strings can be arbitrarily-nested, since it adds a layer of |
+ // nesting for each eval performed on that line. |
+ parseLocation(location, member) { |
+ var evalMatch = _v8EvalLocation.firstMatch(location); |
+ while (evalMatch != null) { |
+ location = evalMatch[1]; |
+ evalMatch = _v8EvalLocation.firstMatch(location); |
+ } |
+ |
+ if (location == 'native') { |
+ return new Frame(Uri.parse('native'), null, null, member); |
+ } |
+ |
+ var urlMatch = _v8UrlLocation.firstMatch(location); |
+ if (urlMatch == null) return new UnparsedFrame(frame); |
+ |
+ return new Frame(_uriOrPathToUri(urlMatch[1]), int.parse(urlMatch[2]), |
+ int.parse(urlMatch[3]), member); |
+ } |
+ |
+ // V8 stack frames can be in two forms. |
+ if (match[2] != null) { |
+ // The first form looks like " at FUNCTION (LOCATION)". V8 proper lists |
+ // anonymous functions within eval as "<anonymous>", while IE10 lists them |
+ // as "Anonymous function". |
+ return parseLocation( |
+ match[2], |
+ match[1] |
+ .replaceAll("<anonymous>", "<fn>") |
+ .replaceAll("Anonymous function", "<fn>") |
+ .replaceAll("(anonymous function)", "<fn>")); |
+ } else { |
+ // The second form looks like " at LOCATION", and is used for anonymous |
+ // functions. |
+ return parseLocation(match[3], "<fn>"); |
+ } |
+ }); |
/// Parses a string representation of a JavaScriptCore stack trace. |
factory Frame.parseJSCore(String frame) => new Frame.parseV8(frame); |
@@ -207,31 +207,31 @@ class Frame { |
/// Parses a string representation of a Firefox stack frame. |
factory Frame.parseFirefox(String frame) => _catchFormatException(frame, () { |
- var match = _firefoxSafariFrame.firstMatch(frame); |
- if (match == null) return new UnparsedFrame(frame); |
- |
- // Normally this is a URI, but in a jsshell trace it can be a path. |
- var uri = _uriOrPathToUri(match[3]); |
- |
- var member; |
- if (match[1] != null) { |
- member = match[1]; |
- member += |
- new List.filled('/'.allMatches(match[2]).length, ".<fn>").join(); |
- if (member == '') member = '<fn>'; |
- |
- // Some Firefox members have initial dots. We remove them for consistency |
- // with other platforms. |
- member = member.replaceFirst(_initialDot, ''); |
- } else { |
- member = '<fn>'; |
- } |
- |
- var line = match[4] == '' ? null : int.parse(match[4]); |
- var column = match[5] == null || match[5] == '' ? |
- null : int.parse(match[5]); |
- return new Frame(uri, line, column, member); |
- }); |
+ var match = _firefoxSafariFrame.firstMatch(frame); |
+ if (match == null) return new UnparsedFrame(frame); |
+ |
+ // Normally this is a URI, but in a jsshell trace it can be a path. |
+ var uri = _uriOrPathToUri(match[3]); |
+ |
+ var member; |
+ if (match[1] != null) { |
+ member = match[1]; |
+ member += |
+ new List.filled('/'.allMatches(match[2]).length, ".<fn>").join(); |
+ if (member == '') member = '<fn>'; |
+ |
+ // Some Firefox members have initial dots. We remove them for consistency |
+ // with other platforms. |
+ member = member.replaceFirst(_initialDot, ''); |
+ } else { |
+ member = '<fn>'; |
+ } |
+ |
+ var line = match[4] == '' ? null : int.parse(match[4]); |
+ var column = |
+ match[5] == null || match[5] == '' ? null : int.parse(match[5]); |
+ return new Frame(uri, line, column, member); |
+ }); |
/// Parses a string representation of a Safari 6.0 stack frame. |
@Deprecated("Use Frame.parseSafari instead.") |
@@ -246,23 +246,26 @@ class Frame { |
/// Parses this package's string representation of a stack frame. |
factory Frame.parseFriendly(String frame) => _catchFormatException(frame, () { |
- var match = _friendlyFrame.firstMatch(frame); |
- if (match == null) { |
- throw new FormatException( |
- "Couldn't parse package:stack_trace stack trace line '$frame'."); |
- } |
- |
- var uri = Uri.parse(match[1]); |
- // If there's no scheme, this is a relative URI. We should interpret it as |
- // relative to the current working directory. |
- if (uri.scheme == '') { |
- uri = path.toUri(path.absolute(path.fromUri(uri))); |
- } |
- |
- var line = match[2] == null ? null : int.parse(match[2]); |
- var column = match[3] == null ? null : int.parse(match[3]); |
- return new Frame(uri, line, column, match[4]); |
- }); |
+ var match = _friendlyFrame.firstMatch(frame); |
+ if (match == null) { |
+ throw new FormatException( |
+ "Couldn't parse package:stack_trace stack trace line '$frame'."); |
+ } |
+ // Fake truncated data urls generated by the friendly stack trace format |
+ // cause Uri.parse to throw an exception so we have to special case them. |
+ var uri = match[1] == 'data:...' |
+ ? new Uri.dataFromString('') |
+ : Uri.parse(match[1]); |
+ // If there's no scheme, this is a relative URI. We should interpret it as |
+ // relative to the current working directory. |
+ if (uri.scheme == '') { |
+ uri = path.toUri(path.absolute(path.fromUri(uri))); |
+ } |
+ |
+ var line = match[2] == null ? null : int.parse(match[2]); |
+ var column = match[3] == null ? null : int.parse(match[3]); |
+ return new Frame(uri, line, column, match[4]); |
+ }); |
/// A regular expression matching an absolute URI. |
static final _uriRegExp = new RegExp(r'^[a-zA-Z][-+.a-zA-Z\d]*://'); |