summaryrefslogtreecommitdiffstats
path: root/src/scripttools/debugging/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'src/scripttools/debugging/scripts')
-rw-r--r--src/scripttools/debugging/scripts/commands/advance.qs41
-rw-r--r--src/scripttools/debugging/scripts/commands/backtrace.qs26
-rw-r--r--src/scripttools/debugging/scripts/commands/break.qs59
-rw-r--r--src/scripttools/debugging/scripts/commands/clear.qs59
-rw-r--r--src/scripttools/debugging/scripts/commands/complete.qs14
-rw-r--r--src/scripttools/debugging/scripts/commands/condition.qs52
-rw-r--r--src/scripttools/debugging/scripts/commands/continue.qs22
-rw-r--r--src/scripttools/debugging/scripts/commands/delete.qs36
-rw-r--r--src/scripttools/debugging/scripts/commands/disable.qs56
-rw-r--r--src/scripttools/debugging/scripts/commands/down.qs33
-rw-r--r--src/scripttools/debugging/scripts/commands/enable.qs56
-rw-r--r--src/scripttools/debugging/scripts/commands/eval.qs21
-rw-r--r--src/scripttools/debugging/scripts/commands/finish.qs16
-rw-r--r--src/scripttools/debugging/scripts/commands/frame.qs36
-rw-r--r--src/scripttools/debugging/scripts/commands/help.qs71
-rw-r--r--src/scripttools/debugging/scripts/commands/ignore.qs51
-rw-r--r--src/scripttools/debugging/scripts/commands/info.qs128
-rw-r--r--src/scripttools/debugging/scripts/commands/interrupt.qs14
-rw-r--r--src/scripttools/debugging/scripts/commands/list.qs90
-rw-r--r--src/scripttools/debugging/scripts/commands/next.qs27
-rw-r--r--src/scripttools/debugging/scripts/commands/print.qs23
-rw-r--r--src/scripttools/debugging/scripts/commands/return.qs20
-rw-r--r--src/scripttools/debugging/scripts/commands/step.qs26
-rw-r--r--src/scripttools/debugging/scripts/commands/tbreak.qs59
-rw-r--r--src/scripttools/debugging/scripts/commands/up.qs37
25 files changed, 1073 insertions, 0 deletions
diff --git a/src/scripttools/debugging/scripts/commands/advance.qs b/src/scripttools/debugging/scripts/commands/advance.qs
new file mode 100644
index 0000000..2647dc1
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/advance.qs
@@ -0,0 +1,41 @@
+name = "advance";
+
+group = "running";
+
+shortDescription = "Continue the program up to the given location";
+
+longDescription = "This command has the same syntax as the \"break\" command.";
+
+seeAlso = [ "break", "tbreak" ];
+
+argumentTypes = [ "script-filename" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ message("Missing argument(s).");
+ return;
+ }
+ var arg = arguments[0];
+ var colonIndex = arg.lastIndexOf(':');
+ if (colonIndex == -1) {
+ lineNumber = parseInt(arg);
+ if (isNaN(lineNumber)) {
+ message("Location must be of the form <file>:<line> or <line>.");
+ return;
+ }
+ var sid = getCurrentScriptId();
+ if (sid == -1) {
+ message("No script.");
+ return;
+ }
+ scheduleRunToLocation(sid, lineNumber);
+ } else {
+ fileName = arg.slice(0, colonIndex);
+ lineNumber = parseInt(arg.slice(colonIndex+1));
+ // ### resolve the script to see if it's loaded or not? (e.g. so we can issue a warning)
+ scheduleRunToLocation(fileName, lineNumber);
+ }
+}
+
+function handleResponse(resp) {
+}
diff --git a/src/scripttools/debugging/scripts/commands/backtrace.qs b/src/scripttools/debugging/scripts/commands/backtrace.qs
new file mode 100644
index 0000000..4e959fd
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/backtrace.qs
@@ -0,0 +1,26 @@
+name = "backtrace";
+
+group = "stack";
+
+shortDescription = "Print backtrace of stack frames";
+
+longDescription = "";
+
+aliases = [ "bt" ];
+
+seeAlso = [ "frame", "info" ];
+
+function execute() {
+ scheduleGetBacktrace();
+};
+
+function handleResponse(resp) {
+ var strings = resp.result;
+ var msg = "";
+ for (var i = 0; i < strings.length; ++i) {
+ if (i > 0)
+ msg += "\n";
+ msg += "#" + i + " " + strings[i];
+ }
+ message(msg);
+}
diff --git a/src/scripttools/debugging/scripts/commands/break.qs b/src/scripttools/debugging/scripts/commands/break.qs
new file mode 100644
index 0000000..8363685
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/break.qs
@@ -0,0 +1,59 @@
+name = "break";
+
+group = "breakpoints";
+
+shortDescription = "Set a breakpoint at specified location";
+
+longDescription = "break <file>:<line> : Sets a breakpoint at the given location.";
+longDescription += "\nbreak <line> : Sets a breakpoint at the given line of the current file.";
+
+argumentTypes = [ "script-filename" ];
+
+aliases = [ "b" ];
+
+seeAlso = [ "condition", "delete", "disable", "tbreak" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ message("Missing argument.");
+ return;
+ }
+ var arg = arguments[0];
+ var colonIndex = arg.lastIndexOf(':');
+ if (colonIndex == -1) {
+ lineNumber = parseInt(arg);
+ if (isNaN(lineNumber)) {
+ message("Breakpoint location must be of the form <file>:<line> or <line>.");
+ return;
+ }
+ var sid = getCurrentScriptId();
+ if (sid == -1) {
+ message("No script.");
+ return;
+ }
+ scheduleGetScriptData(sid);
+ scriptId = sid;
+ state = 1;
+ } else {
+ fileName = arg.slice(0, colonIndex);
+ lineNumber = parseInt(arg.slice(colonIndex+1));
+ // ### resolve the script to see if it's loaded or not? (e.g. so we can issue a warning)
+ scheduleSetBreakpoint({ fileName: fileName, lineNumber: lineNumber});
+ state = 2;
+ }
+}
+
+function handleResponse(resp) {
+ if (state == 1) {
+ fileName = resp.result.fileName;
+ if (fileName.length == 0)
+ fileName = "<anonymous script, id=" + scriptId + ">";
+ scheduleSetBreakpoint({ scriptId: scriptId, lineNumber: lineNumber});
+ state = 2;
+ } else if (state == 2) {
+ if (resp.error == 0) {
+ var id = resp.result;
+ message("Breakpoint " + id + ": " + fileName + ", line " + lineNumber + ".");
+ }
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/clear.qs b/src/scripttools/debugging/scripts/commands/clear.qs
new file mode 100644
index 0000000..3a22587
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/clear.qs
@@ -0,0 +1,59 @@
+name = "clear";
+
+group = "breakpoints";
+
+shortDescription = "Clear breakpoint at specified location";
+
+longDescription = "clear <file>:<line> : Clear breakpoints at the given location.";
+longDescription += "\nclear <line> : Clear breakpoints at the given line of the current script.";
+
+seeAlso = [ "delete" ];
+
+argumentTypes = [ "script-filename" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ message("Missing argument.");
+ return;
+ }
+ var arg = arguments[0];
+ var colonIndex = arg.lastIndexOf(':');
+ if (colonIndex == -1) {
+ lineNumber = parseInt(arg);
+ if (isNaN(lineNumber)) {
+ message("Breakpoint location must be of the form <file>:<line> or <line>.");
+ return;
+ }
+ var sid = getCurrentScriptId();
+ if (sid == -1) {
+ message("No script.");
+ return;
+ }
+ scriptId = sid;
+ } else {
+ fileName = arg.slice(0, colonIndex);
+ lineNumber = parseInt(arg.slice(colonIndex+1));
+ }
+ scheduleGetBreakpoints();
+ state = 1;
+}
+
+function handleResponse(resp) {
+ if (state == 1) {
+ var breakpoints = resp.result;
+ if (breakpoints == undefined)
+ return;
+ for (var id in breakpoints) {
+ var data = breakpoints[id];
+ if ((data.lineNumber == lineNumber)
+ && (data.fileName == fileName)
+ || ((data.scriptId != -1) && (data.scriptId = scriptId))) {
+ scheduleDeleteBreakpoint(id);
+ message("Deleted breakpoint " + id + ".");
+ }
+ }
+ state = 2;
+ } else if (state == 2) {
+
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/complete.qs b/src/scripttools/debugging/scripts/commands/complete.qs
new file mode 100644
index 0000000..9d60312
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/complete.qs
@@ -0,0 +1,14 @@
+name = "complete";
+
+group = "void";
+
+shortDescription = "List the completions for the rest of the line as a command";
+
+longDescription = "";
+
+function execute() {
+ var prefix = (arguments.length > 0) ? arguments[0] : "";
+ var completions = getCommandCompletions(prefix);
+ for (var i = 0; i < completions.length; ++i)
+ message(completions[i]);
+}
diff --git a/src/scripttools/debugging/scripts/commands/condition.qs b/src/scripttools/debugging/scripts/commands/condition.qs
new file mode 100644
index 0000000..9bf6ae2
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/condition.qs
@@ -0,0 +1,52 @@
+name = "condition";
+
+group = "breakpoints";
+
+shortDescription = "Specify breakpoint condition";
+
+longDescription = "condition <breakpoint-id> <expression> : Specify that the breakpoint with the given id should only be triggered if the given expression evaluates to true.";
+
+argumentTypes = [ "breakpoint-id", "script" ];
+
+seeAlso = [ "ignore" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ message("Missing arguments (breakpoint number and condition).");
+ return;
+ }
+ var arg = arguments[0];
+ var spaceIndex = arg.indexOf(' ');
+ if (spaceIndex == -1)
+ spaceIndex = arg.length;
+ var id = parseInt(arg.slice(0, spaceIndex));
+ if (isNaN(id)) {
+ message("First argument must be a number (breakpoint id).");
+ return;
+ }
+ var cond = arg.slice(spaceIndex+1);
+ if ((cond.length != 0) && !checkSyntax(cond)) {
+ message("The condition has a syntax error.");
+ return;
+ }
+ scheduleGetBreakpointData(id);
+ breakpointId = id;
+ condition = cond;
+ state = 1;
+}
+
+function handleResponse(resp) {
+ if (state == 1) {
+ var data = resp.result;
+ if (data == undefined) {
+ message("No breakpoint number " + breakpointId + ".");
+ return;
+ }
+ data.condition = condition;
+ scheduleSetBreakpointData(breakpointId, data);
+ state = 2;
+ } else if (state == 2) {
+ if (condition.length == 0)
+ message("Breakpoint " + breakpointId + " now unconditional.");
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/continue.qs b/src/scripttools/debugging/scripts/commands/continue.qs
new file mode 100644
index 0000000..a940f13
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/continue.qs
@@ -0,0 +1,22 @@
+name = "continue";
+
+group = "running";
+
+shortDescription = "Continue evaluation";
+
+longDescription = "Evaluation will continue until an uncaught exception occurs, "
+longDescription += "a breakpoint is hit or evaluation is explicitly interrupted.";
+
+aliases = [ "c", "fg" ];
+
+seeAlso = [ "step", "interrupt" ];
+
+function execute() {
+ scheduleContinue();
+};
+
+function handleResponse(resp) {
+ if (!resp.async) {
+ message("The target is not evaluating code.");
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/delete.qs b/src/scripttools/debugging/scripts/commands/delete.qs
new file mode 100644
index 0000000..84497a7
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/delete.qs
@@ -0,0 +1,36 @@
+name = "delete";
+
+group = "breakpoints";
+
+shortDescription = "Delete breakpoint(s)";
+
+longDescription = "delete <breakpoint-id> : Deletes the breakpoint with the given id.";
+
+seeAlso = [ "clear", "disable" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ // delete all breakpoints
+ scheduleClearBreakpoints();
+ state = 1;
+ } else {
+ var id = parseInt(arguments[0]);
+ if (isNaN(id)) {
+ message("Breakpoint id expected.");
+ return;
+ }
+ scheduleDeleteBreakpoint(id);
+ breakpointId = id;
+ state = 2;
+ }
+}
+
+function handleResponse(resp) {
+ if (state == 1) {
+ } else if (state == 2) {
+ if (resp.error != 0) {
+ message("No breakpoint number " + breakpointId + ".");
+ return;
+ }
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/disable.qs b/src/scripttools/debugging/scripts/commands/disable.qs
new file mode 100644
index 0000000..91bf44b
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/disable.qs
@@ -0,0 +1,56 @@
+name = "disable";
+
+group = "breakpoints";
+
+shortDescription = "Disable breakpoint(s)";
+
+longDescription = "disable <breakpoint-id> : Disables the breakpoint with the given id.";
+
+seeAlso = [ "enable", "delete", "ignore" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ // disable all breakpoints
+ state = 1;
+ scheduleGetBreakpoints();
+ } else {
+ var id = parseInt(arguments[0]);
+ if (isNaN(id)) {
+ message("Breakpoint id expected.");
+ return;
+ }
+ scheduleGetBreakpointData(id);
+ breakpointId = id;
+ state = 3;
+ }
+};
+
+function handleResponse(resp) {
+ if (state == 1) {
+ var breakpoints = resp.result;
+ if (breakpoints == undefined)
+ return;
+ for (var id in breakpoints) {
+ var data = breakpoints[id];
+ if (data.enabled) {
+ data.enabled = false;
+ scheduleSetBreakpointData(id, data);
+ }
+ }
+ state = 2;
+ } else if (state == 2) {
+ state = 0;
+ } else if (state == 3) {
+ var data = resp.result;
+ if (data == undefined) {
+ message("No breakpoint number " + breakpointId + ".");
+ return;
+ } else if (data.enabled) {
+ data.enabled = false;
+ scheduleSetBreakpointData(breakpointId, data);
+ state = 4;
+ }
+ } else if (state == 4) {
+ state = 0;
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/down.qs b/src/scripttools/debugging/scripts/commands/down.qs
new file mode 100644
index 0000000..dc0429b
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/down.qs
@@ -0,0 +1,33 @@
+name = "down";
+
+group = "stack";
+
+shortDescription = "Select and print the stack frame below the current one";
+
+longDescription = "";
+
+seeAlso = [ "up", "frame" ];
+
+function execute() {
+ var idx = getCurrentFrameIndex();
+ if (idx == 0) {
+ warning("Already at bottom (innermost) frame.");
+ return;
+ }
+ setCurrentFrameIndex(idx - 1);
+ scheduleGetContextInfo(idx - 1);
+ state = 1;
+}
+
+function handleResponse(resp, id) {
+ if (state == 1) {
+ var info = resp.result;
+ setCurrentScriptId(info.scriptId);
+ setCurrentLineNumber(info.lineNumber);
+ scheduleGetBacktrace();
+ state = 2;
+ } else if (state == 2) {
+ var backtrace = resp.result;
+ message("#" + getCurrentFrameIndex() + " " + backtrace[getCurrentFrameIndex()]);
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/enable.qs b/src/scripttools/debugging/scripts/commands/enable.qs
new file mode 100644
index 0000000..6468d0a
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/enable.qs
@@ -0,0 +1,56 @@
+name = "enable";
+
+group = "breakpoints";
+
+shortDescription = "Enable breakpoint(s)";
+
+longDescription = "enable <breakpoint-id> : Enable the breakpoint with the given id.";
+
+seeAlso = [ "disable" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ // enable all breakpoints
+ state = 1;
+ scheduleGetBreakpoints();
+ } else {
+ var id = parseInt(arguments[0]);
+ if (isNaN(id)) {
+ message("Breakpoint id expected.");
+ return;
+ }
+ scheduleGetBreakpointData(id);
+ breakpointId = id;
+ state = 3;
+ }
+};
+
+function handleResponse(resp) {
+ if (state == 1) {
+ var breakpoints = resp.result;
+ if (breakpoints == undefined)
+ return;
+ for (var id in breakpoints) {
+ var data = breakpoints[id];
+ if (!data.enabled) {
+ data.enabled = true;
+ scheduleSetBreakpointData(id, data);
+ }
+ }
+ state = 2;
+ } else if (state == 2) {
+ state = 0;
+ } else if (state == 3) {
+ var data = resp.result;
+ if (data == undefined) {
+ message("No breakpoint number " + breakpointId + ".");
+ return;
+ } else if (!data.enabled) {
+ data.enabled = true;
+ scheduleSetBreakpointData(breakpointId, data);
+ state = 4;
+ }
+ } else if (state == 4) {
+ state = 0;
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/eval.qs b/src/scripttools/debugging/scripts/commands/eval.qs
new file mode 100644
index 0000000..02a1b9f
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/eval.qs
@@ -0,0 +1,21 @@
+name = "eval";
+
+group = "running";
+
+shortDescription = "Evaluate program";
+
+longDescription = "";
+
+argumentTypes = [ "script" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ message("Missing argument (program).");
+ return;
+ }
+ setEvaluateAction(0);
+ scheduleEvaluate(getCurrentFrameIndex(), arguments[0], "console input (" + Date() + ")");
+};
+
+function handleResponse(resp, id) {
+}
diff --git a/src/scripttools/debugging/scripts/commands/finish.qs b/src/scripttools/debugging/scripts/commands/finish.qs
new file mode 100644
index 0000000..bf19fc0
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/finish.qs
@@ -0,0 +1,16 @@
+name = "finish";
+
+group = "running";
+
+shortDescription = "Execute until the current stack frame returns";
+
+longDescription = "Upon return, the value returned is printed.";
+
+seeAlso = [ "next", "continue" ];
+
+function execute() {
+ scheduleStepOut();
+};
+
+function handleResponse(resp) {
+}
diff --git a/src/scripttools/debugging/scripts/commands/frame.qs b/src/scripttools/debugging/scripts/commands/frame.qs
new file mode 100644
index 0000000..5dc4611
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/frame.qs
@@ -0,0 +1,36 @@
+name = "frame";
+
+group = "stack";
+
+shortDescription = "Select and print a stack frame";
+
+longDescription = "";
+
+aliases = [ "f" ];
+
+function execute() {
+ if (arguments.length == 0)
+ requestedFrameIndex = getCurrentFrameIndex();
+ else
+ requestedFrameIndex = parseInt(arguments[0]);
+ scheduleGetContextInfo(requestedFrameIndex);
+ state = 1;
+};
+
+function handleResponse(resp, id) {
+ if (state == 1) {
+ var info = resp.result;
+ if (info == undefined) {
+ message("Frame index out of range.");
+ return;
+ }
+ setCurrentFrameIndex(requestedFrameIndex);
+ setCurrentScriptId(info.scriptId);
+ setCurrentLineNumber(info.lineNumber);
+ scheduleGetBacktrace();
+ state = 2;
+ } else if (state == 2) {
+ var backtrace = resp.result;
+ message("#" + getCurrentFrameIndex() + " " + backtrace[getCurrentFrameIndex()]);
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/help.qs b/src/scripttools/debugging/scripts/commands/help.qs
new file mode 100644
index 0000000..121db11
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/help.qs
@@ -0,0 +1,71 @@
+name = "help";
+
+group = "void";
+
+shortDescription = "Print list of commands";
+
+longDescription = "";
+
+argumentTypes = [ "command-or-group-name" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ var groups = getCommandGroups();
+ message("List of command categories:");
+ message("");
+ for (var name in groups) {
+ if (name == "void")
+ continue;
+ var data = groups[name];
+ message(name + " :: " + data.shortDescription);
+ }
+ message("");
+ message("Type \"help\" followed by a category name for a list of commands in that category.");
+ message("Type \"help all\" for the list of all commands.");
+ message("Type \"help\" followed by a command name for full documentation.");
+ message("Command name abbreviations are allowed if they are unambiguous.");
+ } else {
+ var arg = arguments[0];
+ if (arg == "all") {
+ var groups = getCommandGroups();
+ for (var name in groups) {
+ if (name == "void")
+ continue;
+ message("Command category: " + name);
+ message("");
+ var commands = getCommandsInGroup(name);
+ for (var i = 0; i < commands.length; ++i) {
+ var data = commands[i];
+ message(data.name + " :: " + data.shortDescription);
+ }
+ message("");
+ }
+ } else {
+ var data = findCommand(arg);
+ if (data != undefined) {
+ message(data.shortDescription + ".");
+ if (data.longDescription.length != 0)
+ message(data.longDescription);
+ if (data.aliases.length != 0)
+ message("Aliases: " + data.aliases.join(", "));
+ if (data.seeAlso.length != 0)
+ message("See also: " + data.seeAlso.join(", "));
+ } else {
+ data = getCommandGroups()[arg];
+ if (data != undefined) {
+ message(data.shortDescription + ".");
+ message("");
+ message("List of commands:");
+ message("");
+ var commands = getCommandsInGroup(arg);
+ for (var i = 0; i < commands.length; ++i) {
+ var data = commands[i];
+ message(data.name + " :: " + data.shortDescription);
+ }
+ } else {
+ message("Undefined command \"" + arg + "\". Try \"help\".");
+ }
+ }
+ }
+ }
+};
diff --git a/src/scripttools/debugging/scripts/commands/ignore.qs b/src/scripttools/debugging/scripts/commands/ignore.qs
new file mode 100644
index 0000000..b625bae
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/ignore.qs
@@ -0,0 +1,51 @@
+name = "ignore";
+
+group = "breakpoints";
+
+shortDescription = "Set ignore-count of a breakpoint";
+
+longDescription = "ignore <breakpoint-id> <count> : Ignores the breakpoint with the given id the next count times it is hit.";
+
+seeAlso = [ "condition" ];
+
+function execute() {
+ if (arguments.length < 1) {
+ message("Missing arguments (breakpoing number and ignore-count).");
+ return;
+ }
+ if (arguments.length < 2) {
+ message("Missing argument (ignore-count).");
+ return;
+ }
+ var id = parseInt(arguments[0]);
+ if (isNaN(id)) {
+ message("First argument (breakpoint id) must be a number.");
+ return;
+ }
+ var count = parseInt(arguments[1]);
+ if (isNaN(count)) {
+ message("Second argument (ignore-count) must be a number.");
+ return;
+ }
+ scheduleGetBreakpointData(id);
+ breakpointId = id;
+ if (count < 0)
+ count = 0;
+ ignoreCount = count;
+ state = 1;
+}
+
+function handleResponse(resp) {
+ if (state == 1) {
+ var data = resp.result;
+ if (data == undefined) {
+ message("No breakpoint number " + breakpointId + ".");
+ return;
+ }
+ data.ignoreCount = ignoreCount;
+ scheduleSetBreakpointData(breakpointId, data);
+ state = 2;
+ } else if (state == 2) {
+ message("Breakpoint " + breakpointId + " will be ignored the next " + ignoreCount + " time(s).");
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/info.qs b/src/scripttools/debugging/scripts/commands/info.qs
new file mode 100644
index 0000000..2577e92
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/info.qs
@@ -0,0 +1,128 @@
+name = "info";
+
+group = "status";
+
+shortDescription = "Display information about something";
+
+longDescription = "info scripts : Names of scripts being debugged";
+longDescription += "\ninfo breakpoints : Status of breakpoints currently set";
+longDescription += "\ninfo locals : Local variables of current stack frame";
+
+argumentTypes = [ "subcommand-name" ];
+
+subCommands = [ "breakpoints", "locals", "scripts" ];
+
+function execute() {
+ var arg = arguments[0];
+ if (arg == undefined) {
+ message("\"info\" must be followed by the name of an info command.");
+ return;
+ } else if (arg == "scripts") {
+ scheduleGetScripts();
+ state = 1;
+ } else if (arg == "breakpoints") {
+ if (arguments.length > 1) {
+ var id = parseInt(arguments[1]);
+ if (isNaN(id)) {
+ message("Breakpoint id expected.");
+ return;
+ }
+ scheduleGetBreakpointData(id);
+ breakpointId = id;
+ state = 3;
+ } else {
+ scheduleGetBreakpoints();
+ state = 2;
+ }
+ } else if (arg == "locals") {
+ scheduleGetActivationObject(getCurrentFrameIndex());
+ state = 4;
+ } else {
+ warning("Undefined info command \"" + arg + "\". Try \"help info\".");
+ }
+}
+
+function breakpointString(id, data) {
+ var fn = data.fileName;
+ if (fn.length == 0)
+ fn = "<anonymous script, id=" + data.scriptId + ">";
+ var ret = id + "\t" + (data.enabled ? "yes" : "no")
+ + "\t" + fn + ":" + data.lineNumber;
+ if (data.condition.length != 0) {
+ ret += "\n\tstop only if " + data.condition;
+ }
+ return ret;
+}
+
+function handleResponse(resp) {
+ if (state == 1) {
+ // info scripts
+ var scripts = resp.result;
+ if (scripts == undefined) {
+ message("No scripts loaded.");
+ return;
+ }
+ for (var id in scripts) {
+ var fn = scripts[id].fileName;
+ if (fn.length == 0)
+ fn = "<anonymous script, id=" + id + ">";
+ message("\t" + fn);
+ }
+ }
+
+ else if (state == 2) {
+ // info breakpoints
+ var breakpoints = resp.result;
+ if (breakpoints == undefined) {
+ message("No breakpoints set.");
+ return;
+ }
+ message("Id\tEnabled\tWhere");
+ for (var id in breakpoints) {
+ var data = breakpoints[id];
+ message(breakpointString(id, data));
+ }
+ } else if (state == 3) {
+ // info breakpoints N
+ var data = resp.result;
+ if (data == undefined) {
+ message("No breakpoint number " + breakpointId + ".");
+ return;
+ }
+ message("Id\tEnabled\tWhere");
+ message(breakpointString(breakpointId, data));
+ }
+
+ else if (state == 4) {
+ // info locals
+ var act = resp.result;
+ scheduleNewScriptValueIterator(act);
+ state = 5;
+ } else if (state == 5) {
+ var id = resp.result;
+ scheduleGetPropertiesByIterator(id, 100);
+ iteratorId = id;
+ state = 6;
+ } else if (state == 6) {
+ var props = resp.result;
+ if (props.length == 0) {
+ scheduleDeleteScriptValueIterator(iteratorId);
+ state = 7;
+ return;
+ }
+ var maxLength = 0;
+ for (var i = 0; i < props.length; ++i)
+ maxLength = Math.max(props[i].name.length, maxLength);
+ for (var i = 0; i < props.length; ++i) {
+ var prop = props[i];
+ var msg = prop.name;
+ var pad = maxLength - prop.name.length;
+ for (var j = 0; j < pad; ++j)
+ msg += ' ';
+ message(msg + " : " + prop.valueAsString);
+ }
+ scheduleGetPropertiesByIterator(iteratorId, 100);
+ } else if (state == 7) {
+ // done
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/interrupt.qs b/src/scripttools/debugging/scripts/commands/interrupt.qs
new file mode 100644
index 0000000..d4b66cc
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/interrupt.qs
@@ -0,0 +1,14 @@
+name = "interrupt";
+
+group = "running";
+
+shortDescription = "Interrupt evaluation";
+
+longDescription = "Interruption will occur as soon as a new script statement is reached.";
+
+function execute() {
+ scheduleInterrupt();
+}
+
+function handleResponse(resp) {
+}
diff --git a/src/scripttools/debugging/scripts/commands/list.qs b/src/scripttools/debugging/scripts/commands/list.qs
new file mode 100644
index 0000000..312b123
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/list.qs
@@ -0,0 +1,90 @@
+name = "list";
+
+group = "files";
+
+shortDescription = "List lines of a script";
+
+longDescription = "list <file>:<line> : Lists lines around the given location.";
+longDescription += "\nlist <line> : Lists lines in the current file.";
+
+argumentTypes = [ "script-filename" ];
+
+listLineNumber = 1;
+listScriptId = -1;
+lastSessionId = -1;
+lastFrameIndex = -1;
+
+function execute() {
+ state = 0;
+ if (arguments.length > 0) {
+ var arg = arguments[0];
+ var colonIndex = arg.lastIndexOf(':');
+ var fileName;
+ var lineNumber;
+ if (colonIndex == -1) {
+ lineNumber = parseInt(arg);
+ if (isNaN(lineNumber)) {
+ fileName = arg;
+ lineNumber = 1;
+ }
+ } else if (colonIndex == 0) {
+ fileName = arg;
+ lineNumber = 1;
+ } else {
+ fileName = arg.slice(0, colonIndex);
+ lineNumber = parseInt(arg.slice(colonIndex+1));
+ }
+ listLineNumber = Math.max(lineNumber, 1);
+ if (fileName != undefined) {
+ scheduleResolveScript(fileName);
+ state = 1;
+ } else {
+ setCurrentLineNumber(listLineNumber);
+ execute();
+ }
+ } else {
+ if ((getSessionId() != lastSessionId)
+ || (getCurrentFrameIndex() != lastFrameIndex)
+ || (listScriptId == -1)) {
+ listScriptId = getCurrentScriptId();
+ listLineNumber = getCurrentLineNumber();
+ lastSessionId = getSessionId();
+ lastFrameIndex = getCurrentFrameIndex();
+ }
+ scheduleGetScriptData(listScriptId);
+ state = 2;
+ }
+};
+
+function handleResponse(resp) {
+ if (state == 1) {
+ var id = resp.result;
+ if (id == -1) {
+ message("That script isn't loaded.");
+ state = 0;
+ return;
+ }
+ listScriptId = id;
+ scheduleGetScriptData(listScriptId);
+ state = 2;
+ } else if (state == 2) {
+ var data = resp.result;
+ if (data == undefined) {
+ message("No script.");
+ state = 0;
+ return;
+ }
+ var base = data.baseLineNumber;
+ var lines = data.contents.split('\n');
+ var start = Math.max(listLineNumber - 5, base);
+ for (var i = start; i < start + 10; ++i) {
+ var ln = lines[i - base];
+ var msg = String(i);
+ if (ln != undefined)
+ msg += "\t" + ln;
+ message(msg);
+ }
+ listLineNumber += 10;
+ state = 0;
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/next.qs b/src/scripttools/debugging/scripts/commands/next.qs
new file mode 100644
index 0000000..bc37a01
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/next.qs
@@ -0,0 +1,27 @@
+name = "next";
+
+group = "running";
+
+shortDescription = "Step program, proceeding through subroutine calls";
+
+longDescription = "Like the \"step\" command as long as subroutine calls do not happen;";
+longDescription += "\nwhen they do, the call is treated as one instruction.";
+longDescription += "\nIf a number N is given as argument, this will be done N times before execution is stopped.";
+aliases = [ "n" ];
+
+seeAlso = [ "step", "continue", "finish", "advance" ];
+
+function execute() {
+ var count = 1;
+ if (arguments.length != 0) {
+ var arg = arguments[0];
+ // ### evaluate the expression in the current frame?
+ var num = parseInt(arg);
+ if (!isNaN(num) && (num >= 1))
+ count = num;
+ }
+ scheduleStepOver(count);
+};
+
+function handleResponse(resp) {
+}
diff --git a/src/scripttools/debugging/scripts/commands/print.qs b/src/scripttools/debugging/scripts/commands/print.qs
new file mode 100644
index 0000000..9b98d16
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/print.qs
@@ -0,0 +1,23 @@
+// ### exactly the same as eval, but provided for convenience
+
+name = "print";
+
+group = "status";
+
+shortDescription = "Print value of an expression";
+
+longDescription = "";
+
+argumentTypes = [ "script" ];
+
+function execute() {
+ if (arguments.length == 0) {
+ message("Missing argument (expression).");
+ return;
+ }
+ setEvaluateAction(0);
+ scheduleEvaluate(getCurrentFrameIndex(), arguments[0], "console input (" + Date() + ")");
+};
+
+function handleResponse(resp, id) {
+}
diff --git a/src/scripttools/debugging/scripts/commands/return.qs b/src/scripttools/debugging/scripts/commands/return.qs
new file mode 100644
index 0000000..372c818
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/return.qs
@@ -0,0 +1,20 @@
+name = "return";
+
+group = "running";
+
+shortDescription = "Make selected stack frame return to its caller";
+
+longDescription = "";
+
+argumentTypes = [ "script" ];
+
+function execute() {
+ // TODO:
+ // 1. schedule evaluate of the expression.
+ // 2. install event handler/filter, so that we're notified when the evaluate is done.
+ // - what if another event occurs while we evaluate? (e.g. an exception or breakpoint)
+ // - the event filter needs to uninstall itself, or the event needs to be consumed internally
+ // 3. in the event handler, schedule forced return with the result as argument.
+ setEvaluateAction(1);
+ scheduleEvaluate(getCurrentFrameIndex(), arguments[0], "console input (" + Date() + ")");
+};
diff --git a/src/scripttools/debugging/scripts/commands/step.qs b/src/scripttools/debugging/scripts/commands/step.qs
new file mode 100644
index 0000000..1aacec0
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/step.qs
@@ -0,0 +1,26 @@
+name = "step";
+
+group = "running";
+
+shortDescription = "Step program until a new statement is reached";
+
+longDescription = "If a number N is given as argument, this will be done N times before execution is stopped.";
+
+aliases = [ "s" ];
+
+seeAlso = [ "next" ];
+
+function execute() {
+ var count = 1;
+ if (arguments.length != 0) {
+ var arg = arguments[0];
+ // ### evaluate the expression in the current frame?
+ var num = parseInt(arg);
+ if (!isNaN(num) && (num >= 1))
+ count = num;
+ }
+ scheduleStepInto(count);
+};
+
+function handleResponse(resp) {
+}
diff --git a/src/scripttools/debugging/scripts/commands/tbreak.qs b/src/scripttools/debugging/scripts/commands/tbreak.qs
new file mode 100644
index 0000000..66a8224
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/tbreak.qs
@@ -0,0 +1,59 @@
+name = "tbreak";
+
+group = "breakpoints";
+
+shortDescription = "Set a temporary breakpoint";
+
+longDescription = "The same as the \"break\" command, except that the breakpoint is automatically deleted as soon as it is triggered.";
+
+seeAlso = [ "break", "ignore" ];
+
+argumentTypes = [ "script-filename" ];
+
+// ### merge with break.qs: only difference is the "singleShot: true" in call to scheduleSetBreakpoint()
+// ### maybe an include() function so commands can share code?
+
+function execute() {
+ if (arguments.length == 0) {
+ message("Missing argument.");
+ return;
+ }
+ var arg = arguments[0];
+ var colonIndex = arg.lastIndexOf(':');
+ if (colonIndex == -1) {
+ lineNumber = parseInt(arg);
+ if (isNaN(lineNumber)) {
+ message("Breakpoint location must be of the form <file>:<line> or <line>.");
+ return;
+ }
+ var sid = getCurrentScriptId();
+ if (sid == -1) {
+ message("No script.");
+ return;
+ }
+ scheduleGetScriptData(sid);
+ scriptId = sid;
+ state = 1;
+ } else {
+ fileName = arg.slice(0, colonIndex);
+ lineNumber = parseInt(arg.slice(colonIndex+1));
+ // ### resolve the script to see if it's loaded or not? (e.g. so we can issue a warning)
+ scheduleSetBreakpoint({ fileName: fileName, lineNumber: lineNumber, singleShot: true });
+ state = 2;
+ }
+}
+
+function handleResponse(resp) {
+ if (state == 1) {
+ fileName = resp.result.fileName;
+ if (fileName.length == 0)
+ fileName = "<anonymous script, id=" + scriptId + ">";
+ scheduleSetBreakpoint({ scriptId: scriptId, lineNumber: lineNumber, singleShot: true });
+ state = 2;
+ } else if (state == 2) {
+ if (resp.error == 0) {
+ var id = resp.result;
+ message("Breakpoint " + id + ": " + fileName + ", line " + lineNumber + ".");
+ }
+ }
+}
diff --git a/src/scripttools/debugging/scripts/commands/up.qs b/src/scripttools/debugging/scripts/commands/up.qs
new file mode 100644
index 0000000..2d49df3
--- /dev/null
+++ b/src/scripttools/debugging/scripts/commands/up.qs
@@ -0,0 +1,37 @@
+name = "up";
+
+group = "stack";
+
+shortDescription = "Select and print the stack frame above the current one";
+
+longDescription = "";
+
+seeAlso = [ "down", "frame" ];
+
+function execute() {
+ scheduleGetContextCount();
+ state = 1;
+}
+
+function handleResponse(resp) {
+ if (state == 1) {
+ var count = resp.result;
+ var idx = getCurrentFrameIndex() + 1;
+ if (idx == count) {
+ warning("Already at top (outermost) frame.");
+ return;
+ }
+ setCurrentFrameIndex(idx);
+ scheduleGetContextInfo(idx);
+ state = 2;
+ } else if (state == 2) {
+ var info = resp.result;
+ setCurrentScriptId(info.scriptId);
+ setCurrentLineNumber(info.lineNumber);
+ scheduleGetBacktrace();
+ state = 3;
+ } else if (state == 3) {
+ var backtrace = resp.result;
+ message("#" + getCurrentFrameIndex() + " " + backtrace[getCurrentFrameIndex()]);
+ }
+}