| Index: test/debugger/test-api.js
|
| diff --git a/test/debugger/test-api.js b/test/debugger/test-api.js
|
| index 69c7c5d21937feace158cef15452dcaeb2c4ebbc..05acbbb8aa80f63aaa7ee7846efc24f983384ba8 100644
|
| --- a/test/debugger/test-api.js
|
| +++ b/test/debugger/test-api.js
|
| @@ -155,18 +155,22 @@ class DebugWrapper {
|
| this.takeReplyChecked(msgid);
|
| }
|
|
|
| - // Returns the serialized result of the given expression. For example:
|
| - // {"type":"number", "value":33, "description":"33"}.
|
| - evaluate(frameid, expression) {
|
| + debuggerFlags() {
|
| + return { breakPointsActive :
|
| + { setValue : (enabled) => this.setBreakPointsActive(enabled) }
|
| + };
|
| + }
|
| +
|
| + scripts() {
|
| + // Collect all scripts in the heap.
|
| + return %DebugGetLoadedScripts();
|
| + }
|
| +
|
| + setBreakPointsActive(enabled) {
|
| const {msgid, msg} = this.createMessage(
|
| - "Debugger.evaluateOnCallFrame",
|
| - { callFrameId : frameid,
|
| - expression : expression
|
| - });
|
| + "Debugger.setBreakpointsActive", { active : enabled });
|
| this.sendMessage(msg);
|
| -
|
| - const reply = this.takeReplyChecked(msgid);
|
| - return reply.result.result;
|
| + this.takeReplyChecked(msgid);
|
| }
|
|
|
| // --- Internal methods. -----------------------------------------------------
|
| @@ -236,13 +240,64 @@ class DebugWrapper {
|
| }
|
| }
|
|
|
| + execStateScopeObjectProperty(serialized_scope, prop) {
|
| + let found = null;
|
| + for (let i = 0; i < serialized_scope.length; i++) {
|
| + const elem = serialized_scope[i];
|
| + if (elem.name == prop) {
|
| + found = elem;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (found == null) return { isUndefined : true }
|
| +
|
| + const val = { value : () => found.value.value };
|
| + return { value : () => val,
|
| + isUndefined : () => found.value.type == "undefined"
|
| + };
|
| + }
|
| +
|
| // Returns an array of property descriptors of the scope object.
|
| // This is in contrast to the original API, which simply passed object
|
| // mirrors.
|
| execStateScopeObject(obj) {
|
| const serialized_scope = this.getProperties(obj.objectId);
|
| - const scope = {}
|
| - const scope_tuples = serialized_scope.forEach((elem) => {
|
| + const scope = this.propertiesToObject(serialized_scope);
|
| + return { value : () => scope,
|
| + property : (prop) =>
|
| + this.execStateScopeObjectProperty(serialized_scope, prop)
|
| + };
|
| + }
|
| +
|
| + setVariableValue(frame, scope_index, name, value) {
|
| + const frameid = frame.callFrameId;
|
| + const {msgid, msg} = this.createMessage(
|
| + "Debugger.setVariableValue",
|
| + { callFrameId : frameid,
|
| + scopeNumber : scope_index,
|
| + variableName : name,
|
| + newValue : { value : value }
|
| + });
|
| + this.sendMessage(msg);
|
| + this.takeReplyChecked(msgid);
|
| + }
|
| +
|
| + execStateScope(frame, scope_index) {
|
| + const scope = frame.scopeChain[scope_index];
|
| + return { scopeType : () => this.execStateScopeType(scope.type),
|
| + scopeObject : () => this.execStateScopeObject(scope.object),
|
| + setVariableValue :
|
| + (name, value) => this.setVariableValue(frame, scope_index,
|
| + name, value)
|
| + };
|
| + }
|
| +
|
| + // Takes a list of properties as produced by getProperties and turns them
|
| + // into an object.
|
| + propertiesToObject(props) {
|
| + const obj = {}
|
| + props.forEach((elem) => {
|
| const key = elem.name;
|
|
|
| let value;
|
| @@ -254,16 +309,10 @@ class DebugWrapper {
|
| }
|
| }
|
|
|
| - scope[key] = value;
|
| + obj[key] = value;
|
| })
|
|
|
| - return { value : () => scope };
|
| - }
|
| -
|
| - execStateScope(scope) {
|
| - return { scopeType : () => this.execStateScopeType(scope.type),
|
| - scopeObject : () => this.execStateScopeObject(scope.object)
|
| - };
|
| + return obj;
|
| }
|
|
|
| getProperties(objectId) {
|
| @@ -312,7 +361,38 @@ class DebugWrapper {
|
| return { value : () => localValue };
|
| }
|
|
|
| - execStateFrameEvaluate(frame, expr) {
|
| + reconstructRemoteObject(obj) {
|
| + let value = obj.value;
|
| + if (obj.type == "object") {
|
| + if (obj.subtype == "error") {
|
| + const desc = obj.description;
|
| + switch (obj.className) {
|
| + case "EvalError": throw new EvalError(desc);
|
| + case "RangeError": throw new RangeError(desc);
|
| + case "ReferenceError": throw new ReferenceError(desc);
|
| + case "SyntaxError": throw new SyntaxError(desc);
|
| + case "TypeError": throw new TypeError(desc);
|
| + case "URIError": throw new URIError(desc);
|
| + default: throw new Error(desc);
|
| + }
|
| + } else if (obj.subtype == "array") {
|
| + const array = [];
|
| + const props = this.propertiesToObject(
|
| + this.getProperties(obj.objectId));
|
| + for (let i = 0; i < props.length; i++) {
|
| + array[i] = props[i];
|
| + }
|
| + value = array;
|
| + }
|
| + }
|
| +
|
| + return { value : () => value,
|
| + isUndefined : () => obj.type == "undefined"
|
| + };
|
| +
|
| + }
|
| +
|
| + evaluateOnCallFrame(frame, expr) {
|
| const frameid = frame.callFrameId;
|
| const {msgid, msg} = this.createMessage(
|
| "Debugger.evaluateOnCallFrame",
|
| @@ -323,11 +403,7 @@ class DebugWrapper {
|
| const reply = this.takeReplyChecked(msgid);
|
|
|
| const result = reply.result.result;
|
| - if (result.subtype == "error") {
|
| - throw new Error(result.description);
|
| - }
|
| -
|
| - return { value : () => result.value };
|
| + return this.reconstructRemoteObject(result);
|
| }
|
|
|
| execStateFrame(frame) {
|
| @@ -336,17 +412,68 @@ class DebugWrapper {
|
| const column = frame.location.columnNumber;
|
| const loc = %ScriptLocationFromLine2(scriptid, line, column, 0);
|
| const func = { name : () => frame.functionName };
|
| - return { sourceLineText : () => loc.sourceText,
|
| - evaluate : (expr) => this.execStateFrameEvaluate(frame, expr),
|
| +
|
| + function allScopes() {
|
| + const scopes = [];
|
| + for (let i = 0; i < frame.scopeChain.length; i++) {
|
| + scopes.push(this.execStateScope(frame, i));
|
| + }
|
| + return scopes;
|
| + };
|
| +
|
| + return { sourceColumn : () => loc.column,
|
| + sourceLine : () => loc.line + 1,
|
| + sourceLineText : () => loc.sourceText,
|
| + evaluate : (expr) => this.evaluateOnCallFrame(frame, expr),
|
| functionName : () => frame.functionName,
|
| func : () => func,
|
| localCount : () => this.execStateFrameLocalCount(frame),
|
| localName : (ix) => this.execStateFrameLocalName(frame, ix),
|
| localValue: (ix) => this.execStateFrameLocalValue(frame, ix),
|
| scopeCount : () => frame.scopeChain.length,
|
| - scope : (index) => this.execStateScope(frame.scopeChain[index]),
|
| - allScopes : () => frame.scopeChain.map(
|
| - this.execStateScope.bind(this))
|
| + scope : (index) => this.execStateScope(frame, index),
|
| + allScopes : allScopes.bind(this)
|
| + };
|
| + }
|
| +
|
| + eventDataException(params) {
|
| + switch (params.data.type) {
|
| + case "string": {
|
| + return params.data.value;
|
| + }
|
| + case "object": {
|
| + const props = this.getProperties(params.data.objectId);
|
| + return this.propertiesToObject(props);
|
| + }
|
| + default: {
|
| + return undefined;
|
| + }
|
| + }
|
| + }
|
| +
|
| + eventDataScriptSource(id) {
|
| + const {msgid, msg} = this.createMessage(
|
| + "Debugger.getScriptSource", { scriptId : id });
|
| + this.sendMessage(msg);
|
| + const reply = this.takeReplyChecked(msgid);
|
| + return reply.result.scriptSource;
|
| + }
|
| +
|
| + eventDataScriptSetSource(id, src) {
|
| + const {msgid, msg} = this.createMessage(
|
| + "Debugger.setScriptSource", { scriptId : id, scriptSource : src });
|
| + this.sendMessage(msg);
|
| + this.takeReplyChecked(msgid);
|
| + }
|
| +
|
| + eventDataScript(params) {
|
| + const id = params.scriptId;
|
| + const name = params.url ? params.url : undefined;
|
| +
|
| + return { id : () => id,
|
| + name : () => name,
|
| + source : () => this.eventDataScriptSource(id),
|
| + setSource : (src) => this.eventDataScriptSetSource(id, src)
|
| };
|
| }
|
|
|
| @@ -358,6 +485,8 @@ class DebugWrapper {
|
| this.handleDebuggerPaused(message);
|
| } else if (method == "Debugger.scriptParsed") {
|
| this.handleDebuggerScriptParsed(message);
|
| + } else if (method == "Debugger.scriptFailedToParse") {
|
| + this.handleDebuggerScriptFailedToParse(message);
|
| }
|
| }
|
|
|
| @@ -391,6 +520,7 @@ class DebugWrapper {
|
| let eventData = this.execStateFrame(params.callFrames[0]);
|
| if (debugEvent == this.DebugEvent.Exception) {
|
| eventData.uncaught = () => params.data.uncaught;
|
| + eventData.exception = () => this.eventDataException(params);
|
| }
|
|
|
| this.invokeListener(debugEvent, execState, eventData);
|
| @@ -399,6 +529,7 @@ class DebugWrapper {
|
| handleDebuggerScriptParsed(message) {
|
| const params = message.params;
|
| let eventData = { scriptId : params.scriptId,
|
| + script : () => this.eventDataScript(params),
|
| eventType : this.DebugEvent.AfterCompile
|
| }
|
|
|
| @@ -408,6 +539,19 @@ class DebugWrapper {
|
| undefined);
|
| }
|
|
|
| + handleDebuggerScriptFailedToParse(message) {
|
| + const params = message.params;
|
| + let eventData = { scriptId : params.scriptId,
|
| + script : () => this.eventDataScript(params),
|
| + eventType : this.DebugEvent.CompileError
|
| + }
|
| +
|
| + // TODO(jgruber): Arguments as needed. Still completely missing exec_state,
|
| + // and eventData used to contain the script mirror instead of its id.
|
| + this.invokeListener(this.DebugEvent.CompileError, undefined, eventData,
|
| + undefined);
|
| + }
|
| +
|
| invokeListener(event, exec_state, event_data, data) {
|
| if (this.listener) {
|
| this.listener(event, exec_state, event_data, data);
|
|
|