/*
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function () {
var DebuggerScript = {};
DebuggerScript._breakpoints = {};
DebuggerScript.PauseOnExceptionsState = {
DontPauseOnExceptions : 0,
PauseOnAllExceptions : 1,
PauseOnUncaughtExceptions: 2
};
DebuggerScript.ScriptWorldType = {
MainWorld : 0,
ExtensionsWorld : 1
};
DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions;
Debug.clearBreakOnException();
Debug.clearBreakOnUncaughtException();
DebuggerScript.getAfterCompileScript = function(eventData)
{
return DebuggerScript._formatScript(eventData.script_.script_);
}
DebuggerScript.getScripts = function(contextData)
{
var result = [];
if (!contextData)
return result;
var comma = contextData.indexOf(",");
if (comma === -1)
return result;
// Context data is a string in the following format:
// ("page"|"injected")","<page id>
var idSuffix = contextData.substring(comma); // including the comma
var scripts = Debug.scripts();
for (var i = 0; i < scripts.length; ++i) {
var script = scripts[i];
if (script.context_data && script.context_data.lastIndexOf(idSuffix) != -1)
result.push(DebuggerScript._formatScript(script));
}
return result;
}
DebuggerScript._formatScript = function(script)
{
var scriptWorldType = DebuggerScript.ScriptWorldType.MainWorld;
if (script.context_data && script.context_data.indexOf("injected") == 0)
scriptWorldType = DebuggerScript.ScriptWorldType.ExtensionsWorld;
return {
id: script.id,
name: script.name,
source: script.source,
lineOffset: DebuggerScript._v8ToWebkitLineNumber(script.line_offset),
lineCount: script.lineCount(),
scriptWorldType: scriptWorldType
};
}
DebuggerScript.setBreakpoint = function(execState, args)
{
args.lineNumber = DebuggerScript._webkitToV8LineNumber(args.lineNumber);
var breakId = Debug.setScriptBreakPointById(args.scriptId, args.lineNumber, 0 /* column */, args.condition);
if (!args.enabled)
Debug.disableScriptBreakPoint(breakId);
var locations = Debug.findBreakPointActualLocations(breakId);
var actualLineNumber = locations.length ? locations[0].line : args.lineNumber;
var key = args.scriptId + ":" + actualLineNumber;
if (key in DebuggerScript._breakpoints) {
// Remove old breakpoint.
Debug.findBreakPoint(DebuggerScript._breakpoints[key], true);
}
DebuggerScript._breakpoints[key] = breakId;
return DebuggerScript._v8ToWebkitLineNumber(actualLineNumber);
}
DebuggerScript.removeBreakpoint = function(execState, args)
{
args.lineNumber = DebuggerScript._webkitToV8LineNumber(args.lineNumber);
var key = args.scriptId + ":" + args.lineNumber;
var breakId = DebuggerScript._breakpoints[key];
if (breakId)
Debug.findBreakPoint(breakId, true);
delete DebuggerScript._breakpoints[key];
}
DebuggerScript.pauseOnExceptionsState = function()
{
return DebuggerScript._pauseOnExceptionsState;
}
DebuggerScript.setPauseOnExceptionsState = function(newState)
{
DebuggerScript._pauseOnExceptionsState = newState;
if (DebuggerScript.PauseOnExceptionsState.PauseOnAllExceptions === newState)
Debug.setBreakOnException();
else
Debug.clearBreakOnException();
if (DebuggerScript.PauseOnExceptionsState.PauseOnUncaughtExceptions === newState)
Debug.setBreakOnUncaughtException();
else
Debug.clearBreakOnUncaughtException();
}
DebuggerScript.currentCallFrame = function(execState, args)
{
var frameCount = execState.frameCount();
if (frameCount === 0)
return undefined;
var topFrame;
for (var i = frameCount - 1; i >= 0; i--) {
var frameMirror = execState.frame(i);
topFrame = DebuggerScript._frameMirrorToJSCallFrame(frameMirror, topFrame);
}
return topFrame;
}
DebuggerScript.stepIntoStatement = function(execState)
{
execState.prepareStep(Debug.StepAction.StepIn, 1);
}
DebuggerScript.stepOverStatement = function(execState)
{
execState.prepareStep(Debug.StepAction.StepNext, 1);
}
DebuggerScript.stepOutOfFunction = function(execState)
{
execState.prepareStep(Debug.StepAction.StepOut, 1);
}
DebuggerScript.editScriptSource = function(scriptId, newSource)
{
var scripts = Debug.scripts();
var scriptToEdit = null;
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].id == scriptId) {
scriptToEdit = scripts[i];
break;
}
}
if (!scriptToEdit)
throw("Script not found");
var changeLog = [];
Debug.LiveEdit.SetScriptSource(scriptToEdit, newSource, false, changeLog);
return scriptToEdit.source;
}
DebuggerScript.clearBreakpoints = function(execState, args)
{
for (var key in DebuggerScript._breakpoints) {
var breakId = DebuggerScript._breakpoints[key];
Debug.findBreakPoint(breakId, true);
}
DebuggerScript._breakpoints = {};
}
DebuggerScript.setBreakpointsActivated = function(execState, args)
{
for (var key in DebuggerScript._breakpoints) {
var breakId = DebuggerScript._breakpoints[key];
if (args.enabled)
Debug.enableScriptBreakPoint(breakId);
else
Debug.disableScriptBreakPoint(breakId);
}
}
DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame)
{
// Get function name.
var func;
try {
func = frameMirror.func();
} catch(e) {
}
var functionName;
if (func)
functionName = func.name() || func.inferredName();
// Get script ID.
var script = func.script();
var sourceID = script && script.id();
// Get line number.
var line = DebuggerScript._v8ToWebkitLineNumber(frameMirror.sourceLine());
// Get this object.
var thisObject = frameMirror.details_.receiver();
// Get scope chain array in format: [<scope type>, <scope object>, <scope type>, <scope object>,...]
var scopeChain = [];
var scopeType = [];
for (var i = 0; i < frameMirror.scopeCount(); i++) {
var scopeMirror = frameMirror.scope(i);
var scopeObjectMirror = scopeMirror.scopeObject();
var properties = scopeObjectMirror.properties();
var scopeObject = {};
for (var j = 0; j < properties.length; j++)
scopeObject[properties[j].name()] = properties[j].value_;
// Reset scope object prototype to null so that the proto properties
// don't appear in th local scope section.
scopeObject.__proto__ = null;
scopeType.push(scopeMirror.scopeType());
scopeChain.push(scopeObject);
}
function evaluate(expression) {
return frameMirror.evaluate(expression, false).value();
}
return {
"sourceID": sourceID,
"line": line,
"functionName": functionName,
"type": "function",
"thisObject": thisObject,
"scopeChain": scopeChain,
"scopeType": scopeType,
"evaluate": evaluate,
"caller": callerFrame
};
}
DebuggerScript._webkitToV8LineNumber = function(line)
{
return line - 1;
};
DebuggerScript._v8ToWebkitLineNumber = function(line)
{
return line + 1;
};
return DebuggerScript;
})();