a92a52a4ff
R=rnystrom@google.com Review URL: https://codereview.chromium.org//17765004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@24502 260f80e4-7a28-3924-810f-c04153c831b5
151 lines
5.1 KiB
Dart
151 lines
5.1 KiB
Dart
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
// 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:pathos/path.dart' as path;
|
|
|
|
import 'trace.dart';
|
|
|
|
// #1 Foo._bar (file:///home/nweiz/code/stuff.dart:42:21)
|
|
final _vmFrame = new RegExp(
|
|
r'^#\d+\s+([^\s].*) \((.+):(\d+):(\d+)\)$');
|
|
|
|
// at VW.call$0 (http://pub.dartlang.org/stuff.dart.js:560:28)
|
|
// at http://pub.dartlang.org/stuff.dart.js:560:28
|
|
final _v8Frame = new RegExp(
|
|
r'^\s*at (?:([^\s].*) \((.+):(\d+):(\d+)\)|(.+):(\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
|
|
final _firefoxFrame = new RegExp(
|
|
r'^([^@(/]*)(?:\(.*\))?(/[^<]*<)?(?:\(.*\))?@(.*):(\d+)$');
|
|
|
|
final _initialDot = new RegExp(r"^\.");
|
|
|
|
/// A single stack frame. Each frame points to a precise location in Dart code.
|
|
class Frame {
|
|
/// The URI of the file in which the code is located.
|
|
///
|
|
/// This URI will usually have the scheme `dart`, `file`, `http`, or `https`.
|
|
final Uri uri;
|
|
|
|
/// The line number on which the code location is located.
|
|
///
|
|
/// This can be null, indicating that the line number is unknown or
|
|
/// unimportant.
|
|
final int line;
|
|
|
|
/// The column number of the code location.
|
|
///
|
|
/// This can be null, indicating that the column number is unknown or
|
|
/// unimportant.
|
|
final int column;
|
|
|
|
/// The name of the member in which the code location occurs.
|
|
///
|
|
/// Anonymous closures are represented as `<fn>` in this member string.
|
|
final String member;
|
|
|
|
/// Whether this stack frame comes from the Dart core libraries.
|
|
bool get isCore => uri.scheme == 'dart';
|
|
|
|
/// Returns a human-friendly description of the library that this stack frame
|
|
/// comes from.
|
|
///
|
|
/// This will usually be the string form of [uri], but a relative URI will be
|
|
/// used if possible.
|
|
String get library {
|
|
if (uri.scheme != 'file') return uri.toString();
|
|
return path.relative(path.fromUri(uri));
|
|
}
|
|
|
|
/// Returns the name of the package this stack frame comes from, or `null` if
|
|
/// this stack frame doesn't come from a `package:` URL.
|
|
String get package {
|
|
if (uri.scheme != 'package') return null;
|
|
return uri.path.split('/').first;
|
|
}
|
|
|
|
/// A human-friendly description of the code location.
|
|
String get location {
|
|
if (line == null || column == null) return library;
|
|
return '$library $line:$column';
|
|
}
|
|
|
|
/// Returns a single frame of the current stack.
|
|
///
|
|
/// 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]) {
|
|
if (level < 0) {
|
|
throw new ArgumentError("Argument [level] must be greater than or equal "
|
|
"to 0.");
|
|
}
|
|
|
|
return new Trace.current(level + 1).frames.first;
|
|
}
|
|
|
|
/// Parses a string representation of a Dart VM stack frame.
|
|
factory Frame.parseVM(String frame) {
|
|
var match = _vmFrame.firstMatch(frame);
|
|
if (match == null) {
|
|
throw new FormatException("Couldn't parse VM stack trace line '$frame'.");
|
|
}
|
|
|
|
var uri = Uri.parse(match[2]);
|
|
var member = match[1].replaceAll("<anonymous closure>", "<fn>");
|
|
return new Frame(uri, int.parse(match[3]), int.parse(match[4]), member);
|
|
}
|
|
|
|
/// Parses a string representation of a Chrome/V8 stack frame.
|
|
factory Frame.parseV8(String frame) {
|
|
var match = _v8Frame.firstMatch(frame);
|
|
if (match == null) {
|
|
throw new FormatException("Couldn't parse V8 stack trace line '$frame'.");
|
|
}
|
|
|
|
// V8 stack frames can be in two forms.
|
|
if (match[2] != null) {
|
|
// The first form looks like " at FUNCTION (URI:LINE:COL)"
|
|
var uri = Uri.parse(match[2]);
|
|
var member = match[1].replaceAll("<anonymous>", "<fn>");
|
|
return new Frame(uri, int.parse(match[3]), int.parse(match[4]), member);
|
|
} else {
|
|
// The second form looks like " at URI:LINE:COL", and is used for
|
|
// anonymous functions.
|
|
var uri = Uri.parse(match[5]);
|
|
return new Frame(uri, int.parse(match[6]), int.parse(match[7]), "<fn>");
|
|
}
|
|
}
|
|
|
|
/// Parses a string representation of a Firefox stack frame.
|
|
factory Frame.parseFirefox(String frame) {
|
|
var match = _firefoxFrame.firstMatch(frame);
|
|
if (match == null) {
|
|
throw new FormatException(
|
|
"Couldn't parse Firefox stack trace line '$frame'.");
|
|
}
|
|
|
|
var uri = Uri.parse(match[3]);
|
|
var member = match[1];
|
|
if (member == "") {
|
|
member = "<fn>";
|
|
} else if (match[2] != null) {
|
|
member = "$member.<fn>";
|
|
}
|
|
// Some Firefox members have initial dots. We remove them for consistency
|
|
// with other platforms.
|
|
member = member.replaceFirst(_initialDot, '');
|
|
return new Frame(uri, int.parse(match[4]), null, member);
|
|
}
|
|
|
|
Frame(this.uri, this.line, this.column, this.member);
|
|
|
|
String toString() => '$location in $member';
|
|
}
|