blob: 3cb181950de2629673437a99163f18fde9896bc0 [file] [log] [blame]
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001// Copyright 2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000028"use strict";
29
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000030String.prototype.startsWith = function (str) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000031 if (str.length > this.length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000032 return false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000033 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000034 return this.substr(0, str.length) == str;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000035};
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000036
37function log10(num) {
38 return Math.log(num)/Math.log(10);
39}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000040
41function ToInspectableObject(obj) {
42 if (!obj && typeof obj === 'object') {
43 return void 0;
44 } else {
45 return Object(obj);
46 }
47}
48
49function GetCompletions(global, last, full) {
50 var full_tokens = full.split();
51 full = full_tokens.pop();
52 var parts = full.split('.');
53 parts.pop();
54 var current = global;
55 for (var i = 0; i < parts.length; i++) {
56 var part = parts[i];
57 var next = current[part];
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000058 if (!next) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000059 return [];
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000060 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000061 current = next;
62 }
63 var result = [];
64 current = ToInspectableObject(current);
65 while (typeof current !== 'undefined') {
66 var mirror = new $debug.ObjectMirror(current);
67 var properties = mirror.properties();
68 for (var i = 0; i < properties.length; i++) {
69 var name = properties[i].name();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000070 if (typeof name === 'string' && name.startsWith(last)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000071 result.push(name);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000072 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000073 }
74 current = ToInspectableObject(current.__proto__);
75 }
76 return result;
77}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000078
79
80// Global object holding debugger related constants and state.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000081var Debug = {};
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000082
83
84// Debug events which can occour in the V8 JavaScript engine. These originate
iposva@chromium.org245aa852009-02-10 00:49:54 +000085// from the API include file v8-debug.h.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000086Debug.DebugEvent = { Break: 1,
87 Exception: 2,
88 NewFunction: 3,
89 BeforeCompile: 4,
90 AfterCompile: 5 };
91
92
93// The different types of scripts matching enum ScriptType in objects.h.
94Debug.ScriptType = { Native: 0,
95 Extension: 1,
96 Normal: 2 };
97
98
ager@chromium.orge2902be2009-06-08 12:21:35 +000099// The different types of script compilations matching enum
100// Script::CompilationType in objects.h.
101Debug.ScriptCompilationType = { Host: 0,
102 Eval: 1,
103 JSON: 2 };
104
105
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000106// The different types of scopes matching constants runtime.cc.
107Debug.ScopeType = { Global: 0,
108 Local: 1,
109 With: 2,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000110 Closure: 3,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000111 Catch: 4,
112 Block: 5 };
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000113
114
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000115// Current debug state.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000116var kNoFrame = -1;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000117Debug.State = {
118 currentFrame: kNoFrame,
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000119 displaySourceStartLine: -1,
120 displaySourceEndLine: -1,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000121 currentSourceLine: -1
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000122};
iposva@chromium.org245aa852009-02-10 00:49:54 +0000123var trace_compile = false; // Tracing all compile events?
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000124var trace_debug_json = false; // Tracing all debug json packets?
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000125var last_cmd = '';
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000126var repeat_cmd_line = '';
127var is_running = true;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000128// Global variable used to store whether a handle was requested.
129var lookup_handle = null;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000130
131// Copied from debug-delay.js. This is needed below:
132function ScriptTypeFlag(type) {
133 return (1 << type);
134}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000135
136
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000137// Process a debugger JSON message into a display text and a running status.
138// This function returns an object with properties "text" and "running" holding
139// this information.
140function DebugMessageDetails(message) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000141 if (trace_debug_json) {
142 print("received: '" + message + "'");
143 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000144 // Convert the JSON string to an object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000145 var response = new ProtocolPackage(message);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000146 is_running = response.running();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000147
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000148 if (response.type() == 'event') {
149 return DebugEventDetails(response);
150 } else {
151 return DebugResponseDetails(response);
152 }
153}
154
155function DebugEventDetails(response) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000156 var details = {text:'', running:false};
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000157
158 // Get the running state.
159 details.running = response.running();
160
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000161 var body = response.body();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000162 var result = '';
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000163 switch (response.event()) {
164 case 'break':
165 if (body.breakpoints) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000166 result += 'breakpoint';
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000167 if (body.breakpoints.length > 1) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000168 result += 's';
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000169 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000170 result += ' #';
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000171 for (var i = 0; i < body.breakpoints.length; i++) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000172 if (i > 0) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000173 result += ', #';
iposva@chromium.org245aa852009-02-10 00:49:54 +0000174 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000175 result += body.breakpoints[i];
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000176 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000177 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000178 result += 'break';
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000179 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000180 result += ' in ';
181 result += body.invocationText;
182 result += ', ';
183 result += SourceInfo(body);
184 result += '\n';
185 result += SourceUnderline(body.sourceLineText, body.sourceColumn);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000186 Debug.State.currentSourceLine = body.sourceLine;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000187 Debug.State.displaySourceStartLine = -1;
188 Debug.State.displaySourceEndLine = -1;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000189 Debug.State.currentFrame = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000190 details.text = result;
191 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000192
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000193 case 'exception':
194 if (body.uncaught) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000195 result += 'Uncaught: ';
iposva@chromium.org245aa852009-02-10 00:49:54 +0000196 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000197 result += 'Exception: ';
iposva@chromium.org245aa852009-02-10 00:49:54 +0000198 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000199 result += '"';
200 result += body.exception.text;
201 result += '"';
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000202 if (body.sourceLine >= 0) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000203 result += ', ';
204 result += SourceInfo(body);
205 result += '\n';
206 result += SourceUnderline(body.sourceLineText, body.sourceColumn);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000207 Debug.State.currentSourceLine = body.sourceLine;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000208 Debug.State.displaySourceStartLine = -1;
209 Debug.State.displaySourceEndLine = -1;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000210 Debug.State.currentFrame = 0;
211 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000212 result += ' (empty stack)';
iposva@chromium.org245aa852009-02-10 00:49:54 +0000213 Debug.State.currentSourceLine = -1;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000214 Debug.State.displaySourceStartLine = -1;
215 Debug.State.displaySourceEndLine = -1;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000216 Debug.State.currentFrame = kNoFrame;
217 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000218 details.text = result;
219 break;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000220
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000221 case 'afterCompile':
iposva@chromium.org245aa852009-02-10 00:49:54 +0000222 if (trace_compile) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000223 result = 'Source ' + body.script.name + ' compiled:\n';
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000224 var source = body.script.source;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000225 if (!(source[source.length - 1] == '\n')) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000226 result += source;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000227 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000228 result += source.substring(0, source.length - 1);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000229 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000230 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000231 details.text = result;
232 break;
233
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000234 case 'scriptCollected':
235 details.text = result;
236 break;
237
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000238 default:
239 details.text = 'Unknown debug event ' + response.event();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000240 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000241
242 return details;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000243}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000244
245
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000246function SourceInfo(body) {
247 var result = '';
lrn@chromium.org25156de2010-04-06 13:10:27 +0000248
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000249 if (body.script) {
250 if (body.script.name) {
251 result += body.script.name;
252 } else {
253 result += '[unnamed]';
254 }
255 }
256 result += ' line ';
257 result += body.sourceLine + 1;
258 result += ' column ';
259 result += body.sourceColumn + 1;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000260
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000261 return result;
262}
263
264
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000265function SourceUnderline(source_text, position) {
266 if (!source_text) {
267 return;
268 }
269
270 // Create an underline with a caret pointing to the source position. If the
271 // source contains a tab character the underline will have a tab character in
272 // the same place otherwise the underline will have a space character.
273 var underline = '';
274 for (var i = 0; i < position; i++) {
275 if (source_text[i] == '\t') {
276 underline += '\t';
277 } else {
278 underline += ' ';
279 }
280 }
281 underline += '^';
282
283 // Return the source line text with the underline beneath.
284 return source_text + '\n' + underline;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000285}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000286
287
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000288// Converts a text command to a JSON request.
289function DebugCommandToJSONRequest(cmd_line) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000290 var result = new DebugRequest(cmd_line).JSONRequest();
291 if (trace_debug_json && result) {
292 print("sending: '" + result + "'");
293 }
294 return result;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000295}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000296
297
298function DebugRequest(cmd_line) {
299 // If the very first character is a { assume that a JSON request have been
300 // entered as a command. Converting that to a JSON request is trivial.
301 if (cmd_line && cmd_line.length > 0 && cmd_line.charAt(0) == '{') {
302 this.request_ = cmd_line;
303 return;
304 }
305
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000306 // Check for a simple carriage return to repeat the last command:
307 var is_repeating = false;
308 if (cmd_line == '\n') {
309 if (is_running) {
310 cmd_line = 'break'; // Not in debugger mode, break with a frame request.
311 } else {
312 cmd_line = repeat_cmd_line; // use command to repeat.
313 is_repeating = true;
314 }
315 }
316 if (!is_running) { // Only save the command if in debugger mode.
317 repeat_cmd_line = cmd_line; // save last command.
318 }
319
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000320 // Trim string for leading and trailing whitespace.
321 cmd_line = cmd_line.replace(/^\s+|\s+$/g, '');
322
323 // Find the command.
324 var pos = cmd_line.indexOf(' ');
325 var cmd;
326 var args;
327 if (pos == -1) {
328 cmd = cmd_line;
329 args = '';
330 } else {
331 cmd = cmd_line.slice(0, pos);
332 args = cmd_line.slice(pos).replace(/^\s+|\s+$/g, '');
333 }
334
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000335 if ((cmd === undefined) || !cmd) {
336 this.request_ = void 0;
337 return;
338 }
339
340 last_cmd = cmd;
341
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000342 // Switch on command.
343 switch (cmd) {
344 case 'continue':
345 case 'c':
346 this.request_ = this.continueCommandToJSONRequest_(args);
347 break;
348
349 case 'step':
350 case 's':
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000351 this.request_ = this.stepCommandToJSONRequest_(args, 'in');
352 break;
353
354 case 'stepi':
355 case 'si':
356 this.request_ = this.stepCommandToJSONRequest_(args, 'min');
357 break;
358
359 case 'next':
360 case 'n':
361 this.request_ = this.stepCommandToJSONRequest_(args, 'next');
362 break;
363
364 case 'finish':
365 case 'fin':
366 this.request_ = this.stepCommandToJSONRequest_(args, 'out');
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000367 break;
368
369 case 'backtrace':
370 case 'bt':
371 this.request_ = this.backtraceCommandToJSONRequest_(args);
372 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000373
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000374 case 'frame':
375 case 'f':
376 this.request_ = this.frameCommandToJSONRequest_(args);
377 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000378
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000379 case 'scopes':
380 this.request_ = this.scopesCommandToJSONRequest_(args);
381 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000382
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000383 case 'scope':
384 this.request_ = this.scopeCommandToJSONRequest_(args);
385 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000386
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000387 case 'disconnect':
388 case 'exit':
389 case 'quit':
390 this.request_ = this.disconnectCommandToJSONRequest_(args);
391 break;
392
393 case 'up':
394 this.request_ =
395 this.frameCommandToJSONRequest_('' +
396 (Debug.State.currentFrame + 1));
397 break;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000398
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000399 case 'down':
400 case 'do':
401 this.request_ =
402 this.frameCommandToJSONRequest_('' +
403 (Debug.State.currentFrame - 1));
404 break;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000405
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000406 case 'set':
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000407 case 'print':
408 case 'p':
409 this.request_ = this.printCommandToJSONRequest_(args);
410 break;
411
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000412 case 'dir':
413 this.request_ = this.dirCommandToJSONRequest_(args);
414 break;
415
iposva@chromium.org245aa852009-02-10 00:49:54 +0000416 case 'references':
417 this.request_ = this.referencesCommandToJSONRequest_(args);
418 break;
419
420 case 'instances':
421 this.request_ = this.instancesCommandToJSONRequest_(args);
422 break;
423
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000424 case 'list':
425 case 'l':
426 this.request_ = this.listCommandToJSONRequest_(args);
427 break;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000428 case 'source':
429 this.request_ = this.sourceCommandToJSONRequest_(args);
430 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000431
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000432 case 'scripts':
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000433 case 'script':
434 case 'scr':
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000435 this.request_ = this.scriptsCommandToJSONRequest_(args);
436 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000437
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000438 case 'break':
439 case 'b':
440 this.request_ = this.breakCommandToJSONRequest_(args);
441 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000442
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000443 case 'breakpoints':
444 case 'bb':
445 this.request_ = this.breakpointsCommandToJSONRequest_(args);
446 break;
447
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000448 case 'clear':
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000449 case 'delete':
450 case 'd':
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000451 this.request_ = this.clearCommandToJSONRequest_(args);
452 break;
453
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000454 case 'threads':
455 this.request_ = this.threadsCommandToJSONRequest_(args);
456 break;
457
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000458 case 'cond':
459 this.request_ = this.changeBreakpointCommandToJSONRequest_(args, 'cond');
460 break;
461
462 case 'enable':
463 case 'en':
464 this.request_ =
465 this.changeBreakpointCommandToJSONRequest_(args, 'enable');
466 break;
467
468 case 'disable':
469 case 'dis':
470 this.request_ =
471 this.changeBreakpointCommandToJSONRequest_(args, 'disable');
472 break;
473
474 case 'ignore':
475 this.request_ =
476 this.changeBreakpointCommandToJSONRequest_(args, 'ignore');
477 break;
478
479 case 'info':
480 case 'inf':
481 this.request_ = this.infoCommandToJSONRequest_(args);
482 break;
483
484 case 'flags':
485 this.request_ = this.v8FlagsToJSONRequest_(args);
486 break;
487
488 case 'gc':
489 this.request_ = this.gcToJSONRequest_(args);
490 break;
491
iposva@chromium.org245aa852009-02-10 00:49:54 +0000492 case 'trace':
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000493 case 'tr':
iposva@chromium.org245aa852009-02-10 00:49:54 +0000494 // Return undefined to indicate command handled internally (no JSON).
495 this.request_ = void 0;
496 this.traceCommand_(args);
497 break;
498
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000499 case 'help':
500 case '?':
501 this.helpCommand_(args);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000502 // Return undefined to indicate command handled internally (no JSON).
503 this.request_ = void 0;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000504 break;
505
506 default:
507 throw new Error('Unknown command "' + cmd + '"');
508 }
509}
510
511DebugRequest.prototype.JSONRequest = function() {
512 return this.request_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000513};
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000514
515
516function RequestPacket(command) {
517 this.seq = 0;
518 this.type = 'request';
519 this.command = command;
520}
521
522
523RequestPacket.prototype.toJSONProtocol = function() {
524 // Encode the protocol header.
525 var json = '{';
526 json += '"seq":' + this.seq;
527 json += ',"type":"' + this.type + '"';
528 if (this.command) {
529 json += ',"command":' + StringToJSON_(this.command);
530 }
531 if (this.arguments) {
532 json += ',"arguments":';
533 // Encode the arguments part.
534 if (this.arguments.toJSONProtocol) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000535 json += this.arguments.toJSONProtocol();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000536 } else {
537 json += SimpleObjectToJSON_(this.arguments);
538 }
539 }
540 json += '}';
541 return json;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000542};
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000543
544
545DebugRequest.prototype.createRequest = function(command) {
546 return new RequestPacket(command);
547};
548
549
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000550// Create a JSON request for the evaluation command.
551DebugRequest.prototype.makeEvaluateJSONRequest_ = function(expression) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000552 lookup_handle = null;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000553
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000554 // Check if the expression is a handle id in the form #<handle>#.
555 var handle_match = expression.match(/^#([0-9]*)#$/);
556 if (handle_match) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000557 // Remember the handle requested in a global variable.
558 lookup_handle = parseInt(handle_match[1]);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000559 // Build a lookup request.
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000560 var request = this.createRequest('lookup');
561 request.arguments = {};
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000562 request.arguments.handles = [ lookup_handle ];
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000563 return request.toJSONProtocol();
564 } else {
565 // Build an evaluate request.
566 var request = this.createRequest('evaluate');
567 request.arguments = {};
568 request.arguments.expression = expression;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000569 // Request a global evaluation if there is no current frame.
570 if (Debug.State.currentFrame == kNoFrame) {
571 request.arguments.global = true;
572 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000573 return request.toJSONProtocol();
574 }
575};
576
577
iposva@chromium.org245aa852009-02-10 00:49:54 +0000578// Create a JSON request for the references/instances command.
579DebugRequest.prototype.makeReferencesJSONRequest_ = function(handle, type) {
580 // Build a references request.
581 var handle_match = handle.match(/^#([0-9]*)#$/);
582 if (handle_match) {
583 var request = this.createRequest('references');
584 request.arguments = {};
585 request.arguments.type = type;
586 request.arguments.handle = parseInt(handle_match[1]);
587 return request.toJSONProtocol();
588 } else {
589 throw new Error('Invalid object id.');
590 }
591};
592
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000593
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000594// Create a JSON request for the continue command.
595DebugRequest.prototype.continueCommandToJSONRequest_ = function(args) {
596 var request = this.createRequest('continue');
597 return request.toJSONProtocol();
598};
599
600
601// Create a JSON request for the step command.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000602DebugRequest.prototype.stepCommandToJSONRequest_ = function(args, type) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000603 // Requesting a step is through the continue command with additional
604 // arguments.
605 var request = this.createRequest('continue');
606 request.arguments = {};
607
608 // Process arguments if any.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000609
610 // Only process args if the command is 'step' which is indicated by type being
611 // set to 'in'. For all other commands, ignore the args.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000612 if (args && args.length > 0) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000613 args = args.split(/\s+/g);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000614
615 if (args.length > 2) {
616 throw new Error('Invalid step arguments.');
617 }
618
619 if (args.length > 0) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000620 // Check if we have a gdb stype step command. If so, the 1st arg would
621 // be the step count. If it's not a number, then assume that we're
622 // parsing for the legacy v8 step command.
623 var stepcount = Number(args[0]);
624 if (stepcount == Number.NaN) {
625 // No step count at arg 1. Process as legacy d8 step command:
626 if (args.length == 2) {
627 var stepcount = parseInt(args[1]);
628 if (isNaN(stepcount) || stepcount <= 0) {
629 throw new Error('Invalid step count argument "' + args[0] + '".');
630 }
631 request.arguments.stepcount = stepcount;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000632 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000633
634 // Get the step action.
635 switch (args[0]) {
636 case 'in':
637 case 'i':
638 request.arguments.stepaction = 'in';
639 break;
640
641 case 'min':
642 case 'm':
643 request.arguments.stepaction = 'min';
644 break;
645
646 case 'next':
647 case 'n':
648 request.arguments.stepaction = 'next';
649 break;
650
651 case 'out':
652 case 'o':
653 request.arguments.stepaction = 'out';
654 break;
655
656 default:
657 throw new Error('Invalid step argument "' + args[0] + '".');
658 }
659
660 } else {
661 // gdb style step commands:
662 request.arguments.stepaction = type;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000663 request.arguments.stepcount = stepcount;
664 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000665 }
666 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000667 // Default is step of the specified type.
668 request.arguments.stepaction = type;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000669 }
670
671 return request.toJSONProtocol();
672};
673
674
675// Create a JSON request for the backtrace command.
676DebugRequest.prototype.backtraceCommandToJSONRequest_ = function(args) {
677 // Build a backtrace request from the text command.
678 var request = this.createRequest('backtrace');
lrn@chromium.org25156de2010-04-06 13:10:27 +0000679
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000680 // Default is to show top 10 frames.
681 request.arguments = {};
682 request.arguments.fromFrame = 0;
683 request.arguments.toFrame = 10;
684
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000685 args = args.split(/\s*[ ]+\s*/g);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000686 if (args.length == 1 && args[0].length > 0) {
687 var frameCount = parseInt(args[0]);
688 if (frameCount > 0) {
689 // Show top frames.
690 request.arguments.fromFrame = 0;
691 request.arguments.toFrame = frameCount;
692 } else {
693 // Show bottom frames.
694 request.arguments.fromFrame = 0;
695 request.arguments.toFrame = -frameCount;
696 request.arguments.bottom = true;
697 }
698 } else if (args.length == 2) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000699 var fromFrame = parseInt(args[0]);
700 var toFrame = parseInt(args[1]);
701 if (isNaN(fromFrame) || fromFrame < 0) {
702 throw new Error('Invalid start frame argument "' + args[0] + '".');
703 }
704 if (isNaN(toFrame) || toFrame < 0) {
705 throw new Error('Invalid end frame argument "' + args[1] + '".');
706 }
707 if (fromFrame > toFrame) {
708 throw new Error('Invalid arguments start frame cannot be larger ' +
709 'than end frame.');
710 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000711 // Show frame range.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000712 request.arguments.fromFrame = fromFrame;
713 request.arguments.toFrame = toFrame + 1;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000714 } else if (args.length > 2) {
715 throw new Error('Invalid backtrace arguments.');
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000716 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000717
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000718 return request.toJSONProtocol();
719};
720
721
722// Create a JSON request for the frame command.
723DebugRequest.prototype.frameCommandToJSONRequest_ = function(args) {
724 // Build a frame request from the text command.
725 var request = this.createRequest('frame');
726 args = args.split(/\s*[ ]+\s*/g);
727 if (args.length > 0 && args[0].length > 0) {
728 request.arguments = {};
729 request.arguments.number = args[0];
730 }
731 return request.toJSONProtocol();
732};
733
734
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000735// Create a JSON request for the scopes command.
736DebugRequest.prototype.scopesCommandToJSONRequest_ = function(args) {
737 // Build a scopes request from the text command.
738 var request = this.createRequest('scopes');
739 return request.toJSONProtocol();
740};
741
742
743// Create a JSON request for the scope command.
744DebugRequest.prototype.scopeCommandToJSONRequest_ = function(args) {
745 // Build a scope request from the text command.
746 var request = this.createRequest('scope');
747 args = args.split(/\s*[ ]+\s*/g);
748 if (args.length > 0 && args[0].length > 0) {
749 request.arguments = {};
750 request.arguments.number = args[0];
751 }
752 return request.toJSONProtocol();
753};
754
755
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000756// Create a JSON request for the print command.
757DebugRequest.prototype.printCommandToJSONRequest_ = function(args) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000758 // Build an evaluate request from the text command.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000759 if (args.length == 0) {
760 throw new Error('Missing expression.');
761 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000762 return this.makeEvaluateJSONRequest_(args);
763};
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000764
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000765
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000766// Create a JSON request for the dir command.
767DebugRequest.prototype.dirCommandToJSONRequest_ = function(args) {
768 // Build an evaluate request from the text command.
769 if (args.length == 0) {
770 throw new Error('Missing expression.');
771 }
772 return this.makeEvaluateJSONRequest_(args);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000773};
774
775
iposva@chromium.org245aa852009-02-10 00:49:54 +0000776// Create a JSON request for the references command.
777DebugRequest.prototype.referencesCommandToJSONRequest_ = function(args) {
778 // Build an evaluate request from the text command.
779 if (args.length == 0) {
780 throw new Error('Missing object id.');
781 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000782
iposva@chromium.org245aa852009-02-10 00:49:54 +0000783 return this.makeReferencesJSONRequest_(args, 'referencedBy');
784};
785
786
787// Create a JSON request for the instances command.
788DebugRequest.prototype.instancesCommandToJSONRequest_ = function(args) {
789 // Build an evaluate request from the text command.
790 if (args.length == 0) {
791 throw new Error('Missing object id.');
792 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000793
iposva@chromium.org245aa852009-02-10 00:49:54 +0000794 // Build a references request.
795 return this.makeReferencesJSONRequest_(args, 'constructedBy');
796};
797
798
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000799// Create a JSON request for the list command.
800DebugRequest.prototype.listCommandToJSONRequest_ = function(args) {
801
802 // Default is ten lines starting five lines before the current location.
803 if (Debug.State.displaySourceEndLine == -1) {
804 // If we list forwards, we will start listing after the last source end
805 // line. Set it to start from 5 lines before the current location.
806 Debug.State.displaySourceEndLine = Debug.State.currentSourceLine - 5;
807 // If we list backwards, we will start listing backwards from the last
808 // source start line. Set it to start from 1 lines before the current
809 // location.
810 Debug.State.displaySourceStartLine = Debug.State.currentSourceLine + 1;
811 }
812
813 var from = Debug.State.displaySourceEndLine + 1;
814 var lines = 10;
815
816 // Parse the arguments.
817 args = args.split(/\s*,\s*/g);
818 if (args == '') {
819 } else if ((args.length == 1) && (args[0] == '-')) {
820 from = Debug.State.displaySourceStartLine - lines;
821 } else if (args.length == 2) {
822 from = parseInt(args[0]);
823 lines = parseInt(args[1]) - from + 1; // inclusive of the ending line.
824 } else {
825 throw new Error('Invalid list arguments.');
826 }
827 Debug.State.displaySourceStartLine = from;
828 Debug.State.displaySourceEndLine = from + lines - 1;
829 var sourceArgs = '' + from + ' ' + lines;
830 return this.sourceCommandToJSONRequest_(sourceArgs);
831};
832
833
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000834// Create a JSON request for the source command.
835DebugRequest.prototype.sourceCommandToJSONRequest_ = function(args) {
836 // Build a evaluate request from the text command.
837 var request = this.createRequest('source');
838
839 // Default is ten lines starting five lines before the current location.
840 var from = Debug.State.currentSourceLine - 5;
841 var lines = 10;
842
843 // Parse the arguments.
844 args = args.split(/\s*[ ]+\s*/g);
845 if (args.length > 1 && args[0].length > 0 && args[1].length > 0) {
846 from = parseInt(args[0]) - 1;
847 lines = parseInt(args[1]);
848 } else if (args.length > 0 && args[0].length > 0) {
849 from = parseInt(args[0]) - 1;
850 }
851
852 if (from < 0) from = 0;
853 if (lines < 0) lines = 10;
854
855 // Request source arround current source location.
856 request.arguments = {};
857 request.arguments.fromLine = from;
858 request.arguments.toLine = from + lines;
859
860 return request.toJSONProtocol();
861};
862
863
864// Create a JSON request for the scripts command.
865DebugRequest.prototype.scriptsCommandToJSONRequest_ = function(args) {
866 // Build a evaluate request from the text command.
867 var request = this.createRequest('scripts');
868
869 // Process arguments if any.
870 if (args && args.length > 0) {
871 args = args.split(/\s*[ ]+\s*/g);
872
873 if (args.length > 1) {
874 throw new Error('Invalid scripts arguments.');
875 }
876
877 request.arguments = {};
878 switch (args[0]) {
879 case 'natives':
880 request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Native);
881 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000882
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000883 case 'extensions':
884 request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Extension);
885 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000886
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000887 case 'all':
888 request.arguments.types =
889 ScriptTypeFlag(Debug.ScriptType.Normal) |
890 ScriptTypeFlag(Debug.ScriptType.Native) |
891 ScriptTypeFlag(Debug.ScriptType.Extension);
892 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000893
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000894 default:
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000895 // If the arg is not one of the know one aboves, then it must be a
896 // filter used for filtering the results:
897 request.arguments.filter = args[0];
898 break;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000899 }
900 }
901
902 return request.toJSONProtocol();
903};
904
905
906// Create a JSON request for the break command.
907DebugRequest.prototype.breakCommandToJSONRequest_ = function(args) {
908 // Build a evaluate request from the text command.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000909 // Process arguments if any.
910 if (args && args.length > 0) {
911 var target = args;
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000912 var type = 'function';
913 var line;
914 var column;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000915 var condition;
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000916 var pos;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000917
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000918 var request = this.createRequest('setbreakpoint');
919
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000920 // Break the args into target spec and condition if appropriate.
921
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000922 // Check for breakpoint condition.
923 pos = args.indexOf(' ');
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000924 if (pos > 0) {
925 target = args.substring(0, pos);
926 condition = args.substring(pos + 1, args.length);
927 }
928
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000929 // Check for script breakpoint (name:line[:column]). If no ':' in break
930 // specification it is considered a function break point.
931 pos = target.indexOf(':');
932 if (pos > 0) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000933 var tmp = target.substring(pos + 1, target.length);
934 target = target.substring(0, pos);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000935 if (target[0] == '/' && target[target.length - 1] == '/') {
936 type = 'scriptRegExp';
937 target = target.substring(1, target.length - 1);
938 } else {
939 type = 'script';
940 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000941
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000942 // Check for both line and column.
943 pos = tmp.indexOf(':');
944 if (pos > 0) {
945 column = parseInt(tmp.substring(pos + 1, tmp.length)) - 1;
946 line = parseInt(tmp.substring(0, pos)) - 1;
947 } else {
948 line = parseInt(tmp) - 1;
949 }
950 } else if (target[0] == '#' && target[target.length - 1] == '#') {
951 type = 'handle';
952 target = target.substring(1, target.length - 1);
953 } else {
954 type = 'function';
955 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000956
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000957 request.arguments = {};
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000958 request.arguments.type = type;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000959 request.arguments.target = target;
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000960 request.arguments.line = line;
961 request.arguments.column = column;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000962 request.arguments.condition = condition;
963 } else {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000964 var request = this.createRequest('suspend');
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000965 }
966
967 return request.toJSONProtocol();
968};
969
970
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000971DebugRequest.prototype.breakpointsCommandToJSONRequest_ = function(args) {
972 if (args && args.length > 0) {
973 throw new Error('Unexpected arguments.');
974 }
975 var request = this.createRequest('listbreakpoints');
976 return request.toJSONProtocol();
977};
978
979
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000980// Create a JSON request for the clear command.
981DebugRequest.prototype.clearCommandToJSONRequest_ = function(args) {
982 // Build a evaluate request from the text command.
983 var request = this.createRequest('clearbreakpoint');
984
985 // Process arguments if any.
986 if (args && args.length > 0) {
987 request.arguments = {};
988 request.arguments.breakpoint = parseInt(args);
989 } else {
990 throw new Error('Invalid break arguments.');
991 }
992
993 return request.toJSONProtocol();
994};
995
996
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000997// Create a JSON request for the change breakpoint command.
998DebugRequest.prototype.changeBreakpointCommandToJSONRequest_ =
999 function(args, command) {
1000
1001 var request;
1002
1003 // Check for exception breaks first:
1004 // en[able] exc[eptions] [all|unc[aught]]
1005 // en[able] [all|unc[aught]] exc[eptions]
1006 // dis[able] exc[eptions] [all|unc[aught]]
1007 // dis[able] [all|unc[aught]] exc[eptions]
1008 if ((command == 'enable' || command == 'disable') &&
1009 args && args.length > 1) {
1010 var nextPos = args.indexOf(' ');
1011 var arg1 = (nextPos > 0) ? args.substring(0, nextPos) : args;
1012 var excType = null;
1013
1014 // Check for:
1015 // en[able] exc[eptions] [all|unc[aught]]
1016 // dis[able] exc[eptions] [all|unc[aught]]
1017 if (arg1 == 'exc' || arg1 == 'exception' || arg1 == 'exceptions') {
1018
1019 var arg2 = (nextPos > 0) ?
1020 args.substring(nextPos + 1, args.length) : 'all';
1021 if (!arg2) {
1022 arg2 = 'all'; // if unspecified, set for all.
1023 } if (arg2 == 'unc') { // check for short cut.
1024 arg2 = 'uncaught';
1025 }
1026 excType = arg2;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001027
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001028 // Check for:
1029 // en[able] [all|unc[aught]] exc[eptions]
1030 // dis[able] [all|unc[aught]] exc[eptions]
1031 } else if (arg1 == 'all' || arg1 == 'unc' || arg1 == 'uncaught') {
1032
1033 var arg2 = (nextPos > 0) ?
1034 args.substring(nextPos + 1, args.length) : null;
1035 if (arg2 == 'exc' || arg1 == 'exception' || arg1 == 'exceptions') {
1036 excType = arg1;
1037 if (excType == 'unc') {
1038 excType = 'uncaught';
1039 }
1040 }
1041 }
1042
1043 // If we matched one of the command formats, then excType will be non-null:
1044 if (excType) {
1045 // Build a evaluate request from the text command.
1046 request = this.createRequest('setexceptionbreak');
1047
1048 request.arguments = {};
1049 request.arguments.type = excType;
1050 request.arguments.enabled = (command == 'enable');
1051
1052 return request.toJSONProtocol();
1053 }
1054 }
1055
1056 // Build a evaluate request from the text command.
1057 request = this.createRequest('changebreakpoint');
1058
1059 // Process arguments if any.
1060 if (args && args.length > 0) {
1061 request.arguments = {};
1062 var pos = args.indexOf(' ');
1063 var breakpointArg = args;
1064 var otherArgs;
1065 if (pos > 0) {
1066 breakpointArg = args.substring(0, pos);
1067 otherArgs = args.substring(pos + 1, args.length);
1068 }
1069
1070 request.arguments.breakpoint = parseInt(breakpointArg);
1071
1072 switch(command) {
1073 case 'cond':
1074 request.arguments.condition = otherArgs ? otherArgs : null;
1075 break;
1076 case 'enable':
1077 request.arguments.enabled = true;
1078 break;
1079 case 'disable':
1080 request.arguments.enabled = false;
1081 break;
1082 case 'ignore':
1083 request.arguments.ignoreCount = parseInt(otherArgs);
1084 break;
1085 default:
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001086 throw new Error('Invalid arguments.');
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001087 }
1088 } else {
1089 throw new Error('Invalid arguments.');
1090 }
1091
1092 return request.toJSONProtocol();
1093};
1094
1095
1096// Create a JSON request for the disconnect command.
1097DebugRequest.prototype.disconnectCommandToJSONRequest_ = function(args) {
1098 var request;
1099 request = this.createRequest('disconnect');
1100 return request.toJSONProtocol();
1101};
1102
1103
1104// Create a JSON request for the info command.
1105DebugRequest.prototype.infoCommandToJSONRequest_ = function(args) {
1106 var request;
1107 if (args && (args == 'break' || args == 'br')) {
1108 // Build a evaluate request from the text command.
1109 request = this.createRequest('listbreakpoints');
1110 last_cmd = 'info break';
1111 } else if (args && (args == 'locals' || args == 'lo')) {
1112 // Build a evaluate request from the text command.
1113 request = this.createRequest('frame');
1114 last_cmd = 'info locals';
1115 } else if (args && (args == 'args' || args == 'ar')) {
1116 // Build a evaluate request from the text command.
1117 request = this.createRequest('frame');
1118 last_cmd = 'info args';
1119 } else {
1120 throw new Error('Invalid info arguments.');
1121 }
1122
1123 return request.toJSONProtocol();
1124};
1125
1126
1127DebugRequest.prototype.v8FlagsToJSONRequest_ = function(args) {
1128 var request;
1129 request = this.createRequest('v8flags');
1130 request.arguments = {};
1131 request.arguments.flags = args;
1132 return request.toJSONProtocol();
1133};
1134
1135
1136DebugRequest.prototype.gcToJSONRequest_ = function(args) {
1137 var request;
1138 if (!args) {
1139 args = 'all';
1140 }
1141 var args = args.split(/\s+/g);
1142 var cmd = args[0];
1143
1144 switch(cmd) {
1145 case 'all':
1146 case 'quick':
1147 case 'full':
1148 case 'young':
1149 case 'old':
1150 case 'compact':
1151 case 'sweep':
1152 case 'scavenge': {
1153 if (cmd == 'young') { cmd = 'quick'; }
1154 else if (cmd == 'old') { cmd = 'full'; }
1155
1156 request = this.createRequest('gc');
1157 request.arguments = {};
1158 request.arguments.type = cmd;
1159 break;
1160 }
1161 // Else fall thru to the default case below to report the error.
1162 default:
1163 throw new Error('Missing arguments after ' + cmd + '.');
1164 }
1165 return request.toJSONProtocol();
1166};
1167
1168
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001169// Create a JSON request for the threads command.
1170DebugRequest.prototype.threadsCommandToJSONRequest_ = function(args) {
1171 // Build a threads request from the text command.
1172 var request = this.createRequest('threads');
1173 return request.toJSONProtocol();
1174};
1175
1176
iposva@chromium.org245aa852009-02-10 00:49:54 +00001177// Handle the trace command.
1178DebugRequest.prototype.traceCommand_ = function(args) {
1179 // Process arguments.
1180 if (args && args.length > 0) {
1181 if (args == 'compile') {
1182 trace_compile = !trace_compile;
1183 print('Tracing of compiled scripts ' + (trace_compile ? 'on' : 'off'));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001184 } else if (args === 'debug json' || args === 'json' || args === 'packets') {
1185 trace_debug_json = !trace_debug_json;
1186 print('Tracing of debug json packets ' +
1187 (trace_debug_json ? 'on' : 'off'));
iposva@chromium.org245aa852009-02-10 00:49:54 +00001188 } else {
1189 throw new Error('Invalid trace arguments.');
1190 }
1191 } else {
1192 throw new Error('Invalid trace arguments.');
1193 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001194};
iposva@chromium.org245aa852009-02-10 00:49:54 +00001195
1196// Handle the help command.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001197DebugRequest.prototype.helpCommand_ = function(args) {
1198 // Help os quite simple.
1199 if (args && args.length > 0) {
1200 print('warning: arguments to \'help\' are ignored');
1201 }
1202
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001203 print('Note: <> denotes symbollic values to be replaced with real values.');
1204 print('Note: [] denotes optional parts of commands, or optional options / arguments.');
1205 print(' e.g. d[elete] - you get the same command if you type d or delete.');
1206 print('');
1207 print('[break] - break as soon as possible');
1208 print('b[reak] location [condition]');
1209 print(' - break on named function: location is a function name');
1210 print(' - break on function: location is #<id>#');
1211 print(' - break on script position: location is name:line[:column]');
1212 print('');
1213 print('clear <breakpoint #> - deletes the specified user defined breakpoint');
1214 print('d[elete] <breakpoint #> - deletes the specified user defined breakpoint');
1215 print('dis[able] <breakpoint #> - disables the specified user defined breakpoint');
1216 print('dis[able] exc[eptions] [[all] | unc[aught]]');
1217 print(' - disables breaking on exceptions');
1218 print('en[able] <breakpoint #> - enables the specified user defined breakpoint');
1219 print('en[able] exc[eptions] [[all] | unc[aught]]');
1220 print(' - enables breaking on exceptions');
1221 print('');
1222 print('b[ack]t[race] [n] | [-n] | [from to]');
1223 print(' - prints the stack back trace');
1224 print('f[rame] - prints info about the current frame context');
1225 print('f[rame] <frame #> - set context to specified frame #');
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001226 print('scopes');
1227 print('scope <scope #>');
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001228 print('');
1229 print('up - set context to caller of current frame');
1230 print('do[wn] - set context to callee of current frame');
1231 print('inf[o] br[eak] - prints info about breakpoints in use');
1232 print('inf[o] ar[gs] - prints info about arguments of the current function');
1233 print('inf[o] lo[cals] - prints info about locals in the current function');
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001234 print('');
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001235 print('step [in | next | out| min [step count]]');
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001236 print('c[ontinue] - continue executing after a breakpoint');
1237 print('s[tep] [<N>] - step into the next N callees (default N is 1)');
1238 print('s[tep]i [<N>] - step into the next N callees (default N is 1)');
1239 print('n[ext] [<N>] - step over the next N callees (default N is 1)');
1240 print('fin[ish] [<N>] - step out of N frames (default N is 1)');
1241 print('');
1242 print('p[rint] <expression> - prints the result of the specified expression');
1243 print('dir <expression> - prints the object structure of the result');
1244 print('set <var> = <expression> - executes the specified statement');
1245 print('');
1246 print('l[ist] - list the source code around for the current pc');
1247 print('l[ist] [- | <start>,<end>] - list the specified range of source code');
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001248 print('source [from line [num lines]]');
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001249 print('scr[ipts] [native|extensions|all]');
1250 print('scr[ipts] [<filter text>] - list scripts with the specified text in its description');
1251 print('');
1252 print('gc - runs the garbage collector');
1253 print('');
iposva@chromium.org245aa852009-02-10 00:49:54 +00001254 print('trace compile');
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001255 // hidden command: trace debug json - toggles tracing of debug json packets
1256 print('');
1257 print('disconnect|exit|quit - disconnects and quits the debugger');
1258 print('help - prints this help information');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001259};
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001260
1261
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001262function formatHandleReference_(value) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001263 if (value.handle() >= 0) {
1264 return '#' + value.handle() + '#';
1265 } else {
1266 return '#Transient#';
1267 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001268}
1269
1270
iposva@chromium.org245aa852009-02-10 00:49:54 +00001271function formatObject_(value, include_properties) {
1272 var result = '';
1273 result += formatHandleReference_(value);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001274 result += ', type: object';
iposva@chromium.org245aa852009-02-10 00:49:54 +00001275 result += ', constructor ';
1276 var ctor = value.constructorFunctionValue();
1277 result += formatHandleReference_(ctor);
1278 result += ', __proto__ ';
1279 var proto = value.protoObjectValue();
1280 result += formatHandleReference_(proto);
1281 result += ', ';
1282 result += value.propertyCount();
1283 result += ' properties.';
1284 if (include_properties) {
1285 result += '\n';
1286 for (var i = 0; i < value.propertyCount(); i++) {
1287 result += ' ';
1288 result += value.propertyName(i);
1289 result += ': ';
1290 var property_value = value.propertyValue(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001291 if (property_value instanceof ProtocolReference) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00001292 result += '<no type>';
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001293 } else {
1294 if (property_value && property_value.type()) {
1295 result += property_value.type();
1296 } else {
1297 result += '<no type>';
1298 }
iposva@chromium.org245aa852009-02-10 00:49:54 +00001299 }
1300 result += ' ';
1301 result += formatHandleReference_(property_value);
1302 result += '\n';
1303 }
1304 }
1305 return result;
1306}
1307
1308
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001309function formatScope_(scope) {
1310 var result = '';
1311 var index = scope.index;
1312 result += '#' + (index <= 9 ? '0' : '') + index;
1313 result += ' ';
1314 switch (scope.type) {
1315 case Debug.ScopeType.Global:
1316 result += 'Global, ';
1317 result += '#' + scope.object.ref + '#';
1318 break;
1319 case Debug.ScopeType.Local:
1320 result += 'Local';
1321 break;
1322 case Debug.ScopeType.With:
1323 result += 'With, ';
1324 result += '#' + scope.object.ref + '#';
1325 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001326 case Debug.ScopeType.Catch:
1327 result += 'Catch, ';
1328 result += '#' + scope.object.ref + '#';
1329 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001330 case Debug.ScopeType.Closure:
1331 result += 'Closure';
1332 break;
1333 default:
1334 result += 'UNKNOWN';
1335 }
1336 return result;
1337}
1338
1339
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001340function refObjectToString_(protocolPackage, handle) {
1341 var value = protocolPackage.lookup(handle);
1342 var result = '';
1343 if (value.isString()) {
1344 result = '"' + value.value() + '"';
1345 } else if (value.isPrimitive()) {
1346 result = value.valueString();
1347 } else if (value.isObject()) {
1348 result += formatObject_(value, true);
1349 }
1350 return result;
1351}
1352
1353
1354// Rounds number 'num' to 'length' decimal places.
1355function roundNumber(num, length) {
1356 var factor = Math.pow(10, length);
1357 return Math.round(num * factor) / factor;
1358}
1359
1360
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001361// Convert a JSON response to text for display in a text based debugger.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001362function DebugResponseDetails(response) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001363 var details = { text: '', running: false };
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001364
1365 try {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001366 if (!response.success()) {
1367 details.text = response.message();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001368 return details;
1369 }
1370
1371 // Get the running state.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001372 details.running = response.running();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001373
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001374 var body = response.body();
1375 var result = '';
1376 switch (response.command()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001377 case 'suspend':
1378 details.text = 'stopped';
1379 break;
vegorov@chromium.org42841962010-10-18 11:18:59 +00001380
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001381 case 'setbreakpoint':
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001382 result = 'set breakpoint #';
1383 result += body.breakpoint;
1384 details.text = result;
1385 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001386
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001387 case 'clearbreakpoint':
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001388 result = 'cleared breakpoint #';
1389 result += body.breakpoint;
1390 details.text = result;
1391 break;
vegorov@chromium.org42841962010-10-18 11:18:59 +00001392
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001393 case 'changebreakpoint':
1394 result = 'successfully changed breakpoint';
1395 details.text = result;
1396 break;
1397
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001398 case 'listbreakpoints':
1399 result = 'breakpoints: (' + body.breakpoints.length + ')';
1400 for (var i = 0; i < body.breakpoints.length; i++) {
1401 var breakpoint = body.breakpoints[i];
1402 result += '\n id=' + breakpoint.number;
1403 result += ' type=' + breakpoint.type;
1404 if (breakpoint.script_id) {
1405 result += ' script_id=' + breakpoint.script_id;
1406 }
1407 if (breakpoint.script_name) {
1408 result += ' script_name=' + breakpoint.script_name;
1409 }
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001410 if (breakpoint.script_regexp) {
1411 result += ' script_regexp=' + breakpoint.script_regexp;
1412 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001413 result += ' line=' + (breakpoint.line + 1);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001414 if (breakpoint.column != null) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001415 result += ' column=' + (breakpoint.column + 1);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001416 }
1417 if (breakpoint.groupId) {
1418 result += ' groupId=' + breakpoint.groupId;
1419 }
1420 if (breakpoint.ignoreCount) {
1421 result += ' ignoreCount=' + breakpoint.ignoreCount;
1422 }
1423 if (breakpoint.active === false) {
1424 result += ' inactive';
1425 }
1426 if (breakpoint.condition) {
1427 result += ' condition=' + breakpoint.condition;
1428 }
1429 result += ' hit_count=' + breakpoint.hit_count;
1430 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001431 if (body.breakpoints.length === 0) {
1432 result = "No user defined breakpoints\n";
1433 } else {
1434 result += '\n';
1435 }
1436 if (body.breakOnExceptions) {
1437 result += '* breaking on ALL exceptions is enabled\n';
1438 } else if (body.breakOnUncaughtExceptions) {
1439 result += '* breaking on UNCAUGHT exceptions is enabled\n';
1440 } else {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001441 result += '* all exception breakpoints are disabled\n';
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001442 }
1443 details.text = result;
1444 break;
1445
1446 case 'setexceptionbreak':
1447 result = 'Break on ' + body.type + ' exceptions: ';
1448 result += body.enabled ? 'enabled' : 'disabled';
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001449 details.text = result;
1450 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001451
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001452 case 'backtrace':
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001453 if (body.totalFrames == 0) {
1454 result = '(empty stack)';
1455 } else {
1456 var result = 'Frames #' + body.fromFrame + ' to #' +
1457 (body.toFrame - 1) + ' of ' + body.totalFrames + '\n';
1458 for (i = 0; i < body.frames.length; i++) {
1459 if (i != 0) result += '\n';
1460 result += body.frames[i].text;
1461 }
1462 }
1463 details.text = result;
1464 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001465
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001466 case 'frame':
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001467 if (last_cmd === 'info locals') {
1468 var locals = body.locals;
1469 if (locals.length === 0) {
1470 result = 'No locals';
1471 } else {
1472 for (var i = 0; i < locals.length; i++) {
1473 var local = locals[i];
1474 result += local.name + ' = ';
1475 result += refObjectToString_(response, local.value.ref);
1476 result += '\n';
1477 }
1478 }
1479 } else if (last_cmd === 'info args') {
1480 var args = body.arguments;
1481 if (args.length === 0) {
1482 result = 'No arguments';
1483 } else {
1484 for (var i = 0; i < args.length; i++) {
1485 var arg = args[i];
1486 result += arg.name + ' = ';
1487 result += refObjectToString_(response, arg.value.ref);
1488 result += '\n';
1489 }
1490 }
1491 } else {
1492 result = SourceUnderline(body.sourceLineText,
1493 body.column);
1494 Debug.State.currentSourceLine = body.line;
1495 Debug.State.currentFrame = body.index;
1496 Debug.State.displaySourceStartLine = -1;
1497 Debug.State.displaySourceEndLine = -1;
1498 }
1499 details.text = result;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001500 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001501
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001502 case 'scopes':
1503 if (body.totalScopes == 0) {
1504 result = '(no scopes)';
1505 } else {
1506 result = 'Scopes #' + body.fromScope + ' to #' +
1507 (body.toScope - 1) + ' of ' + body.totalScopes + '\n';
1508 for (i = 0; i < body.scopes.length; i++) {
1509 if (i != 0) {
1510 result += '\n';
1511 }
1512 result += formatScope_(body.scopes[i]);
1513 }
1514 }
1515 details.text = result;
1516 break;
1517
1518 case 'scope':
1519 result += formatScope_(body);
1520 result += '\n';
1521 var scope_object_value = response.lookup(body.object.ref);
1522 result += formatObject_(scope_object_value, true);
1523 details.text = result;
1524 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001525
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001526 case 'evaluate':
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001527 case 'lookup':
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001528 case 'getobj':
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001529 if (last_cmd == 'p' || last_cmd == 'print') {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001530 result = body.text;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001531 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001532 var value;
1533 if (lookup_handle) {
1534 value = response.bodyValue(lookup_handle);
1535 } else {
1536 value = response.bodyValue();
1537 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001538 if (value.isObject()) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00001539 result += formatObject_(value, true);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001540 } else {
1541 result += 'type: ';
1542 result += value.type();
1543 if (!value.isUndefined() && !value.isNull()) {
1544 result += ', ';
1545 if (value.isString()) {
1546 result += '"';
1547 }
1548 result += value.value();
1549 if (value.isString()) {
1550 result += '"';
1551 }
1552 }
1553 result += '\n';
1554 }
1555 }
1556 details.text = result;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001557 break;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001558
1559 case 'references':
1560 var count = body.length;
1561 result += 'found ' + count + ' objects';
1562 result += '\n';
1563 for (var i = 0; i < count; i++) {
1564 var value = response.bodyValue(i);
1565 result += formatObject_(value, false);
1566 result += '\n';
1567 }
1568 details.text = result;
1569 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001570
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001571 case 'source':
1572 // Get the source from the response.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001573 var source = body.source;
1574 var from_line = body.fromLine + 1;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001575 var lines = source.split('\n');
1576 var maxdigits = 1 + Math.floor(log10(from_line + lines.length));
1577 if (maxdigits < 3) {
1578 maxdigits = 3;
1579 }
1580 var result = '';
1581 for (var num = 0; num < lines.length; num++) {
1582 // Check if there's an extra newline at the end.
1583 if (num == (lines.length - 1) && lines[num].length == 0) {
1584 break;
1585 }
1586
1587 var current_line = from_line + num;
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001588 var spacer = maxdigits - (1 + Math.floor(log10(current_line)));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001589 if (current_line == Debug.State.currentSourceLine + 1) {
1590 for (var i = 0; i < maxdigits; i++) {
1591 result += '>';
1592 }
1593 result += ' ';
1594 } else {
1595 for (var i = 0; i < spacer; i++) {
1596 result += ' ';
1597 }
1598 result += current_line + ': ';
1599 }
1600 result += lines[num];
1601 result += '\n';
1602 }
1603 details.text = result;
1604 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001605
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001606 case 'scripts':
1607 var result = '';
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001608 for (i = 0; i < body.length; i++) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001609 if (i != 0) result += '\n';
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001610 if (body[i].id) {
1611 result += body[i].id;
1612 } else {
1613 result += '[no id]';
1614 }
1615 result += ', ';
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001616 if (body[i].name) {
1617 result += body[i].name;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001618 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001619 if (body[i].compilationType == Debug.ScriptCompilationType.Eval
1620 && body[i].evalFromScript
1621 ) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00001622 result += 'eval from ';
1623 var script_value = response.lookup(body[i].evalFromScript.ref);
1624 result += ' ' + script_value.field('name');
1625 result += ':' + (body[i].evalFromLocation.line + 1);
1626 result += ':' + body[i].evalFromLocation.column;
1627 } else if (body[i].compilationType ==
1628 Debug.ScriptCompilationType.JSON) {
1629 result += 'JSON ';
1630 } else { // body[i].compilation == Debug.ScriptCompilationType.Host
1631 result += '[unnamed] ';
1632 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001633 }
1634 result += ' (lines: ';
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 result += body[i].lineCount;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001636 result += ', length: ';
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001637 result += body[i].sourceLength;
1638 if (body[i].type == Debug.ScriptType.Native) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001639 result += ', native';
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 } else if (body[i].type == Debug.ScriptType.Extension) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001641 result += ', extension';
1642 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001643 result += '), [';
1644 var sourceStart = body[i].sourceStart;
1645 if (sourceStart.length > 40) {
1646 sourceStart = sourceStart.substring(0, 37) + '...';
1647 }
1648 result += sourceStart;
1649 result += ']';
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001650 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001651 if (body.length == 0) {
1652 result = "no matching scripts found";
1653 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001654 details.text = result;
1655 break;
1656
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001657 case 'threads':
1658 var result = 'Active V8 threads: ' + body.totalThreads + '\n';
1659 body.threads.sort(function(a, b) { return a.id - b.id; });
1660 for (i = 0; i < body.threads.length; i++) {
1661 result += body.threads[i].current ? '*' : ' ';
1662 result += ' ';
1663 result += body.threads[i].id;
1664 result += '\n';
1665 }
1666 details.text = result;
1667 break;
1668
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001669 case 'continue':
1670 details.text = "(running)";
1671 break;
lrn@chromium.org25156de2010-04-06 13:10:27 +00001672
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001673 case 'v8flags':
1674 details.text = "flags set";
1675 break;
1676
1677 case 'gc':
1678 details.text = "GC " + body.before + " => " + body.after;
1679 if (body.after > (1024*1024)) {
1680 details.text +=
1681 " (" + roundNumber(body.before/(1024*1024), 1) + "M => " +
1682 roundNumber(body.after/(1024*1024), 1) + "M)";
1683 } else if (body.after > 1024) {
1684 details.text +=
1685 " (" + roundNumber(body.before/1024, 1) + "K => " +
1686 roundNumber(body.after/1024, 1) + "K)";
1687 }
1688 break;
1689
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001690 default:
1691 details.text =
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001692 'Response for unknown command \'' + response.command() + '\'' +
1693 ' (' + response.raw_json() + ')';
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001694 }
1695 } catch (e) {
1696 details.text = 'Error: "' + e + '" formatting response';
1697 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001698
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001699 return details;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001700}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001701
1702
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001703/**
1704 * Protocol packages send from the debugger.
1705 * @param {string} json - raw protocol packet as JSON string.
1706 * @constructor
1707 */
1708function ProtocolPackage(json) {
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001709 this.raw_json_ = json;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001710 this.packet_ = JSON.parse(json);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001711 this.refs_ = [];
1712 if (this.packet_.refs) {
1713 for (var i = 0; i < this.packet_.refs.length; i++) {
1714 this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i];
1715 }
1716 }
1717}
1718
1719
1720/**
1721 * Get the packet type.
1722 * @return {String} the packet type
1723 */
1724ProtocolPackage.prototype.type = function() {
1725 return this.packet_.type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001726};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001727
1728
1729/**
1730 * Get the packet event.
1731 * @return {Object} the packet event
1732 */
1733ProtocolPackage.prototype.event = function() {
1734 return this.packet_.event;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001735};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001736
1737
1738/**
1739 * Get the packet request sequence.
1740 * @return {number} the packet request sequence
1741 */
1742ProtocolPackage.prototype.requestSeq = function() {
1743 return this.packet_.request_seq;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001744};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001745
1746
1747/**
1748 * Get the packet request sequence.
1749 * @return {number} the packet request sequence
1750 */
1751ProtocolPackage.prototype.running = function() {
1752 return this.packet_.running ? true : false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001753};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001754
1755
1756ProtocolPackage.prototype.success = function() {
1757 return this.packet_.success ? true : false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001758};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001759
1760
1761ProtocolPackage.prototype.message = function() {
1762 return this.packet_.message;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001763};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001764
1765
1766ProtocolPackage.prototype.command = function() {
1767 return this.packet_.command;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001768};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001769
1770
1771ProtocolPackage.prototype.body = function() {
1772 return this.packet_.body;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001773};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001774
1775
iposva@chromium.org245aa852009-02-10 00:49:54 +00001776ProtocolPackage.prototype.bodyValue = function(index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001777 if (index != null) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00001778 return new ProtocolValue(this.packet_.body[index], this);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001779 } else {
1780 return new ProtocolValue(this.packet_.body, this);
iposva@chromium.org245aa852009-02-10 00:49:54 +00001781 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001782};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001783
1784
1785ProtocolPackage.prototype.body = function() {
1786 return this.packet_.body;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001787};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001788
1789
1790ProtocolPackage.prototype.lookup = function(handle) {
1791 var value = this.refs_[handle];
1792 if (value) {
1793 return new ProtocolValue(value, this);
1794 } else {
1795 return new ProtocolReference(handle);
1796 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001797};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001798
1799
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001800ProtocolPackage.prototype.raw_json = function() {
1801 return this.raw_json_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001802};
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001803
1804
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001805function ProtocolValue(value, packet) {
1806 this.value_ = value;
1807 this.packet_ = packet;
1808}
1809
1810
1811/**
1812 * Get the value type.
1813 * @return {String} the value type
1814 */
1815ProtocolValue.prototype.type = function() {
1816 return this.value_.type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001817};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001818
1819
1820/**
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 * Get a metadata field from a protocol value.
ager@chromium.orge2902be2009-06-08 12:21:35 +00001822 * @return {Object} the metadata field value
1823 */
1824ProtocolValue.prototype.field = function(name) {
1825 return this.value_[name];
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001826};
ager@chromium.orge2902be2009-06-08 12:21:35 +00001827
1828
1829/**
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001830 * Check is the value is a primitive value.
1831 * @return {boolean} true if the value is primitive
1832 */
1833ProtocolValue.prototype.isPrimitive = function() {
1834 return this.isUndefined() || this.isNull() || this.isBoolean() ||
1835 this.isNumber() || this.isString();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001836};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001837
1838
1839/**
1840 * Get the object handle.
1841 * @return {number} the value handle
1842 */
1843ProtocolValue.prototype.handle = function() {
1844 return this.value_.handle;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001845};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001846
1847
1848/**
1849 * Check is the value is undefined.
1850 * @return {boolean} true if the value is undefined
1851 */
1852ProtocolValue.prototype.isUndefined = function() {
1853 return this.value_.type == 'undefined';
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001854};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001855
1856
1857/**
1858 * Check is the value is null.
1859 * @return {boolean} true if the value is null
1860 */
1861ProtocolValue.prototype.isNull = function() {
1862 return this.value_.type == 'null';
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001863};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001864
1865
1866/**
1867 * Check is the value is a boolean.
1868 * @return {boolean} true if the value is a boolean
1869 */
1870ProtocolValue.prototype.isBoolean = function() {
1871 return this.value_.type == 'boolean';
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001872};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001873
1874
1875/**
1876 * Check is the value is a number.
1877 * @return {boolean} true if the value is a number
1878 */
1879ProtocolValue.prototype.isNumber = function() {
1880 return this.value_.type == 'number';
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001881};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001882
1883
1884/**
1885 * Check is the value is a string.
1886 * @return {boolean} true if the value is a string
1887 */
1888ProtocolValue.prototype.isString = function() {
1889 return this.value_.type == 'string';
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001890};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001891
1892
1893/**
1894 * Check is the value is an object.
1895 * @return {boolean} true if the value is an object
1896 */
1897ProtocolValue.prototype.isObject = function() {
1898 return this.value_.type == 'object' || this.value_.type == 'function' ||
1899 this.value_.type == 'error' || this.value_.type == 'regexp';
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001900};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001901
1902
1903/**
1904 * Get the constructor function
1905 * @return {ProtocolValue} constructor function
1906 */
1907ProtocolValue.prototype.constructorFunctionValue = function() {
1908 var ctor = this.value_.constructorFunction;
1909 return this.packet_.lookup(ctor.ref);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001910};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001911
1912
1913/**
1914 * Get the __proto__ value
1915 * @return {ProtocolValue} __proto__ value
1916 */
1917ProtocolValue.prototype.protoObjectValue = function() {
1918 var proto = this.value_.protoObject;
1919 return this.packet_.lookup(proto.ref);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001920};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001921
1922
1923/**
1924 * Get the number og properties.
1925 * @return {number} the number of properties
1926 */
1927ProtocolValue.prototype.propertyCount = function() {
1928 return this.value_.properties ? this.value_.properties.length : 0;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001929};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001930
1931
1932/**
1933 * Get the specified property name.
1934 * @return {string} property name
1935 */
1936ProtocolValue.prototype.propertyName = function(index) {
1937 var property = this.value_.properties[index];
1938 return property.name;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001939};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001940
1941
1942/**
1943 * Return index for the property name.
1944 * @param name The property name to look for
1945 * @return {number} index for the property name
1946 */
1947ProtocolValue.prototype.propertyIndex = function(name) {
1948 for (var i = 0; i < this.propertyCount(); i++) {
1949 if (this.value_.properties[i].name == name) {
1950 return i;
1951 }
1952 }
1953 return null;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001954};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001955
1956
1957/**
1958 * Get the specified property value.
1959 * @return {ProtocolValue} property value
1960 */
1961ProtocolValue.prototype.propertyValue = function(index) {
1962 var property = this.value_.properties[index];
1963 return this.packet_.lookup(property.ref);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001964};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001965
1966
1967/**
1968 * Check is the value is a string.
1969 * @return {boolean} true if the value is a string
1970 */
1971ProtocolValue.prototype.value = function() {
1972 return this.value_.value;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001973};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001974
1975
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001976ProtocolValue.prototype.valueString = function() {
1977 return this.value_.text;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001978};
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001979
1980
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001981function ProtocolReference(handle) {
1982 this.handle_ = handle;
1983}
1984
1985
1986ProtocolReference.prototype.handle = function() {
1987 return this.handle_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001988};
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001989
1990
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001991function MakeJSONPair_(name, value) {
1992 return '"' + name + '":' + value;
1993}
1994
1995
1996function ArrayToJSONObject_(content) {
1997 return '{' + content.join(',') + '}';
1998}
1999
2000
2001function ArrayToJSONArray_(content) {
2002 return '[' + content.join(',') + ']';
2003}
2004
2005
2006function BooleanToJSON_(value) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002007 return String(value);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002008}
2009
2010
2011function NumberToJSON_(value) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002012 return String(value);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002013}
2014
2015
2016// Mapping of some control characters to avoid the \uXXXX syntax for most
2017// commonly used control cahracters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002018var ctrlCharMap_ = {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002019 '\b': '\\b',
2020 '\t': '\\t',
2021 '\n': '\\n',
2022 '\f': '\\f',
2023 '\r': '\\r',
2024 '"' : '\\"',
2025 '\\': '\\\\'
2026};
2027
2028
2029// Regular expression testing for ", \ and control characters (0x00 - 0x1F).
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002030var ctrlCharTest_ = new RegExp('["\\\\\x00-\x1F]');
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002031
2032
2033// Regular expression matching ", \ and control characters (0x00 - 0x1F)
2034// globally.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002035var ctrlCharMatch_ = new RegExp('["\\\\\x00-\x1F]', 'g');
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002036
2037
2038/**
2039 * Convert a String to its JSON representation (see http://www.json.org/). To
2040 * avoid depending on the String object this method calls the functions in
2041 * string.js directly and not through the value.
2042 * @param {String} value The String value to format as JSON
2043 * @return {string} JSON formatted String value
2044 */
2045function StringToJSON_(value) {
2046 // Check for" , \ and control characters (0x00 - 0x1F). No need to call
2047 // RegExpTest as ctrlchar is constructed using RegExp.
2048 if (ctrlCharTest_.test(value)) {
2049 // Replace ", \ and control characters (0x00 - 0x1F).
2050 return '"' +
2051 value.replace(ctrlCharMatch_, function (char) {
2052 // Use charmap if possible.
2053 var mapped = ctrlCharMap_[char];
2054 if (mapped) return mapped;
2055 mapped = char.charCodeAt();
2056 // Convert control character to unicode escape sequence.
2057 return '\\u00' +
2058 '0' + // TODO %NumberToRadixString(Math.floor(mapped / 16), 16) +
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002059 '0'; // TODO %NumberToRadixString(mapped % 16, 16)
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002060 })
2061 + '"';
2062 }
2063
2064 // Simple string with no special characters.
2065 return '"' + value + '"';
2066}
2067
2068
2069/**
2070 * Convert a Date to ISO 8601 format. To avoid depending on the Date object
2071 * this method calls the functions in date.js directly and not through the
2072 * value.
2073 * @param {Date} value The Date value to format as JSON
2074 * @return {string} JSON formatted Date value
2075 */
2076function DateToISO8601_(value) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002077 var f = function(n) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002078 return n < 10 ? '0' + n : n;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002079 };
2080 var g = function(n) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002081 return n < 10 ? '00' + n : n < 100 ? '0' + n : n;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002082 };
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002083 return builtins.GetUTCFullYearFrom(value) + '-' +
2084 f(builtins.GetUTCMonthFrom(value) + 1) + '-' +
2085 f(builtins.GetUTCDateFrom(value)) + 'T' +
2086 f(builtins.GetUTCHoursFrom(value)) + ':' +
2087 f(builtins.GetUTCMinutesFrom(value)) + ':' +
2088 f(builtins.GetUTCSecondsFrom(value)) + '.' +
2089 g(builtins.GetUTCMillisecondsFrom(value)) + 'Z';
2090}
2091
2092
2093/**
2094 * Convert a Date to ISO 8601 format. To avoid depending on the Date object
2095 * this method calls the functions in date.js directly and not through the
2096 * value.
2097 * @param {Date} value The Date value to format as JSON
2098 * @return {string} JSON formatted Date value
2099 */
2100function DateToJSON_(value) {
2101 return '"' + DateToISO8601_(value) + '"';
2102}
2103
2104
2105/**
2106 * Convert an Object to its JSON representation (see http://www.json.org/).
2107 * This implementation simply runs through all string property names and adds
2108 * each property to the JSON representation for some predefined types. For type
2109 * "object" the function calls itself recursively unless the object has the
2110 * function property "toJSONProtocol" in which case that is used. This is not
2111 * a general implementation but sufficient for the debugger. Note that circular
2112 * structures will cause infinite recursion.
2113 * @param {Object} object The object to format as JSON
2114 * @return {string} JSON formatted object value
2115 */
2116function SimpleObjectToJSON_(object) {
2117 var content = [];
2118 for (var key in object) {
2119 // Only consider string keys.
2120 if (typeof key == 'string') {
2121 var property_value = object[key];
2122
2123 // Format the value based on its type.
2124 var property_value_json;
2125 switch (typeof property_value) {
2126 case 'object':
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002127 if (property_value === null) {
2128 property_value_json = 'null';
2129 } else if (typeof property_value.toJSONProtocol == 'function') {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002130 property_value_json = property_value.toJSONProtocol(true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002131 } else if (property_value.constructor.name == 'Array'){
2132 property_value_json = SimpleArrayToJSON_(property_value);
2133 } else {
2134 property_value_json = SimpleObjectToJSON_(property_value);
2135 }
2136 break;
2137
2138 case 'boolean':
2139 property_value_json = BooleanToJSON_(property_value);
2140 break;
2141
2142 case 'number':
2143 property_value_json = NumberToJSON_(property_value);
2144 break;
2145
2146 case 'string':
2147 property_value_json = StringToJSON_(property_value);
2148 break;
2149
2150 default:
2151 property_value_json = null;
2152 }
2153
2154 // Add the property if relevant.
2155 if (property_value_json) {
2156 content.push(StringToJSON_(key) + ':' + property_value_json);
2157 }
2158 }
2159 }
2160
2161 // Make JSON object representation.
2162 return '{' + content.join(',') + '}';
2163}
2164
2165
2166/**
2167 * Convert an array to its JSON representation. This is a VERY simple
2168 * implementation just to support what is needed for the debugger.
2169 * @param {Array} arrya The array to format as JSON
2170 * @return {string} JSON formatted array value
2171 */
2172function SimpleArrayToJSON_(array) {
2173 // Make JSON array representation.
2174 var json = '[';
2175 for (var i = 0; i < array.length; i++) {
2176 if (i != 0) {
2177 json += ',';
2178 }
2179 var elem = array[i];
2180 if (elem.toJSONProtocol) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002181 json += elem.toJSONProtocol(true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002182 } else if (typeof(elem) === 'object') {
2183 json += SimpleObjectToJSON_(elem);
2184 } else if (typeof(elem) === 'boolean') {
2185 json += BooleanToJSON_(elem);
2186 } else if (typeof(elem) === 'number') {
2187 json += NumberToJSON_(elem);
2188 } else if (typeof(elem) === 'string') {
2189 json += StringToJSON_(elem);
2190 } else {
2191 json += elem;
2192 }
2193 }
2194 json += ']';
2195 return json;
2196}