| 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]*://');
|
|
|