Add line table command to debugger

New command returns token information of a script. This will enable
the editor/debugger to translate token offsets to line numbers.
Review URL: https://codereview.chromium.org//13533016

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@21009 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
hausner@google.com 2013-04-05 23:45:14 +00:00
parent cbe8bd9a3a
commit ee69789e07
5 changed files with 138 additions and 1 deletions

View file

@ -479,6 +479,7 @@ static JSONDebuggerCommand debugger_commands[] = {
{ "getGlobalVariables", DbgMessage::HandleGetGlobalsCmd },
{ "getScriptURLs", DbgMessage::HandleGetScriptURLsCmd },
{ "getScriptSource", DbgMessage::HandleGetSourceCmd },
{ "getLineNumberTable", DbgMessage::HandleGetLineNumbersCmd },
{ "getStackTrace", DbgMessage::HandleGetStackTraceCmd },
{ "setBreakpoint", DbgMessage::HandleSetBpCmd },
{ "setPauseOnException", DbgMessage::HandlePauseOnExcCmd },
@ -788,6 +789,53 @@ bool DbgMessage::HandleGetSourceCmd(DbgMessage* in_msg) {
}
bool DbgMessage::HandleGetLineNumbersCmd(DbgMessage* in_msg) {
ASSERT(in_msg != NULL);
MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
int msg_id = msg_parser.MessageId();
dart::TextBuffer msg(64);
intptr_t lib_id = msg_parser.GetIntParam("libraryId");
char* url_chars = msg_parser.GetStringParam("url");
ASSERT(url_chars != NULL);
Dart_Handle url = DartUtils::NewString(url_chars);
ASSERT_NOT_ERROR(url);
free(url_chars);
url_chars = NULL;
Dart_Handle info = Dart_ScriptGetTokenInfo(lib_id, url);
if (Dart_IsError(info)) {
in_msg->SendErrorReply(msg_id, Dart_GetError(info));
return false;
}
ASSERT(Dart_IsList(info));
intptr_t info_len = 0;
Dart_Handle res = Dart_ListLength(info, &info_len);
ASSERT_NOT_ERROR(res);
msg.Printf("{ \"id\": %d, ", msg_id);
msg.Printf("\"result\": { \"lines\": [");
Dart_Handle elem;
bool num_elems = 0;
for (intptr_t i = 0; i < info_len; i++) {
elem = Dart_ListGetAt(info, i);
if (Dart_IsNull(elem)) {
msg.Printf((i == 0) ? "[" : "], [");
num_elems = 0;
} else {
ASSERT(Dart_IsInteger(elem));
int value = GetIntValue(elem);
if (num_elems == 0) {
msg.Printf("%d", value);
} else {
msg.Printf(",%d", value);
}
num_elems++;
}
}
msg.Printf("]]}}");
in_msg->SendReply(&msg);
return false;
}
bool DbgMessage::HandleGetStackTraceCmd(DbgMessage* in_msg) {
ASSERT(in_msg != NULL);
MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());

View file

@ -104,6 +104,7 @@ class DbgMessage {
static bool HandleGetListCmd(DbgMessage* msg);
static bool HandleGetScriptURLsCmd(DbgMessage* msg);
static bool HandleGetSourceCmd(DbgMessage* msg);
static bool HandleGetLineNumbersCmd(DbgMessage* msg);
static bool HandleGetStackTraceCmd(DbgMessage* msg);
static bool HandlePauseOnExcCmd(DbgMessage* msg);
static bool HandleSetBpCmd(DbgMessage* msg);

View file

@ -141,6 +141,28 @@ DART_EXPORT Dart_Handle Dart_ScriptGetSource(
Dart_Handle script_url_in);
/**
* Returns an array containing line number and token offset info
* for the given script.
*
* Returns an array of numbers. Null values indicate the beginning of
* a new line. The first number after null is the line number.
* The line number is followed by pairs of numbers, with the first value
* being the "token offset" and the second value being the character offset
* of the token relative to the beginning of the script.
* The "token offset" is a value that is used to indicate a location
* in code, similarly to a "PC" address.
* Source lines with no tokens are omitted.
*
* Requires there to be a current isolate.
*
* \return A handle to an array or an error object.
*/
DART_EXPORT Dart_Handle Dart_ScriptGetTokenInfo(
intptr_t library_id,
Dart_Handle script_url_in);
/**
* Returns a string containing a generated source code of the given script
* in the given library. This is essentially used to pretty print dart code

View file

@ -587,6 +587,57 @@ DART_EXPORT Dart_Handle Dart_ScriptGetSource(
}
DART_EXPORT Dart_Handle Dart_ScriptGetTokenInfo(
intptr_t library_id,
Dart_Handle script_url_in) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
const Library& lib = Library::Handle(Library::GetLibrary(library_id));
if (lib.IsNull()) {
return Api::NewError("%s: %"Pd" is not a valid library id",
CURRENT_FUNC, library_id);
}
UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
const Script& script = Script::Handle(lib.LookupScript(script_url));
if (script.IsNull()) {
return Api::NewError("%s: script '%s' not found in library '%s'",
CURRENT_FUNC, script_url.ToCString(),
String::Handle(lib.url()).ToCString());
}
const GrowableObjectArray& info =
GrowableObjectArray::Handle(GrowableObjectArray::New());
const String& source = String::Handle(script.Source());
const String& key = Symbols::Empty();
const Object& line_separator = Object::Handle();
const TokenStream& tkns = TokenStream::Handle(script.tokens());
ASSERT(!tkns.IsNull());
TokenStream::Iterator tkit(tkns, 0);
int current_line = -1;
Scanner s(source, key);
s.Scan();
while (s.current_token().kind != Token::kEOS) {
ASSERT(tkit.IsValid());
ASSERT(s.current_token().kind == tkit.CurrentTokenKind());
int token_line = s.current_token().position.line;
if (token_line != current_line) {
// emit line
info.Add(line_separator);
info.Add(Smi::Handle(Smi::New(token_line)));
current_line = token_line;
}
// TODO(hausner): Could optimize here by not reporting tokens
// that will never be a location used by the debugger, e.g.
// braces, semicolons, most keywords etc.
info.Add(Smi::Handle(Smi::New(tkit.CurrentPosition())));
info.Add(Smi::Handle(Smi::New(s.current_token().offset)));
s.Scan();
tkit.Advance();
}
return Api::NewHandle(isolate, Array::MakeArray(info));
}
DART_EXPORT Dart_Handle Dart_GenerateScriptSource(Dart_Handle library_url_in,
Dart_Handle script_url_in) {
Isolate* isolate = Isolate::Current();

View file

@ -48,6 +48,7 @@ void printHelp() {
pg <id> Print all global variables visible within given library id
ls <lib_id> List loaded scripts in library
gs <lib_id> <script_url> Get source text of script in library
tok <lib_id> <script_url> Get line and token table of script in library
epi <none|all|unhandled> Set exception pause info
i <id> Interrupt execution of given isolate id
h Print help
@ -181,6 +182,13 @@ void processCommand(String cmdLine) {
"libraryId": int.parse(args[1]),
"url": args[2] } };
sendCmd(cmd).then((result) => handleGetSourceResponse(result));
} else if (command == "tok" && args.length == 3) {
var cmd = { "id": seqNum,
"command": "getLineNumberTable",
"params": { "isolateId" : isolate_id,
"libraryId": int.parse(args[1]),
"url": args[2] } };
sendCmd(cmd).then((result) => handleGetLineTableResponse(result));
} else if (command == "epi" && args.length == 2) {
var cmd = { "id": seqNum,
"command": "setPauseOnException",
@ -324,6 +332,13 @@ handleGetSourceResponse(response) {
}
handleGetLineTableResponse(response) {
Map result = response["result"];
var info = result["lines"];
print("Line info table:\n$info");
}
void handleGetLibraryResponse(response) {
Map result = response["result"];
List libs = result["libraries"];
@ -391,7 +406,7 @@ void printStackTrace(List frames) {
void handlePausedEvent(msg) {
assert(msg["params"] != null);
var reason = msg["params"]["reason"];
isolate_id = msg["params"]["id"];
isolate_id = msg["params"]["isolateId"];
stackTrace = msg["params"]["callFrames"];
assert(stackTrace != null);
assert(stackTrace.length >= 1);