summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/environment.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/actors/environment.js')
-rw-r--r--devtools/server/actors/environment.js199
1 files changed, 199 insertions, 0 deletions
diff --git a/devtools/server/actors/environment.js b/devtools/server/actors/environment.js
new file mode 100644
index 000000000..bd03586eb
--- /dev/null
+++ b/devtools/server/actors/environment.js
@@ -0,0 +1,199 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const { ActorClassWithSpec } = require("devtools/shared/protocol");
+const { createValueGrip } = require("devtools/server/actors/object");
+const { environmentSpec } = require("devtools/shared/specs/environment");
+
+/**
+ * Creates an EnvironmentActor. EnvironmentActors are responsible for listing
+ * the bindings introduced by a lexical environment and assigning new values to
+ * those identifier bindings.
+ *
+ * @param Debugger.Environment aEnvironment
+ * The lexical environment that will be used to create the actor.
+ * @param ThreadActor aThreadActor
+ * The parent thread actor that contains this environment.
+ */
+let EnvironmentActor = ActorClassWithSpec(environmentSpec, {
+ initialize: function (environment, threadActor) {
+ this.obj = environment;
+ this.threadActor = threadActor;
+ },
+
+ /**
+ * Return an environment form for use in a protocol message.
+ */
+ form: function () {
+ let form = { actor: this.actorID };
+
+ // What is this environment's type?
+ if (this.obj.type == "declarative") {
+ form.type = this.obj.callee ? "function" : "block";
+ } else {
+ form.type = this.obj.type;
+ }
+
+ // Does this environment have a parent?
+ if (this.obj.parent) {
+ form.parent = (this.threadActor
+ .createEnvironmentActor(this.obj.parent,
+ this.registeredPool)
+ .form());
+ }
+
+ // Does this environment reflect the properties of an object as variables?
+ if (this.obj.type == "object" || this.obj.type == "with") {
+ form.object = createValueGrip(this.obj.object,
+ this.registeredPool, this.threadActor.objectGrip);
+ }
+
+ // Is this the environment created for a function call?
+ if (this.obj.callee) {
+ form.function = createValueGrip(this.obj.callee,
+ this.registeredPool, this.threadActor.objectGrip);
+ }
+
+ // Shall we list this environment's bindings?
+ if (this.obj.type == "declarative") {
+ form.bindings = this.bindings();
+ }
+
+ return form;
+ },
+
+ /**
+ * Handle a protocol request to change the value of a variable bound in this
+ * lexical environment.
+ *
+ * @param string name
+ * The name of the variable to be changed.
+ * @param any value
+ * The value to be assigned.
+ */
+ assign: function (name, value) {
+ // TODO: enable the commented-out part when getVariableDescriptor lands
+ // (bug 725815).
+ /* let desc = this.obj.getVariableDescriptor(name);
+
+ if (!desc.writable) {
+ return { error: "immutableBinding",
+ message: "Changing the value of an immutable binding is not " +
+ "allowed" };
+ }*/
+
+ try {
+ this.obj.setVariable(name, value);
+ } catch (e) {
+ if (e instanceof Debugger.DebuggeeWouldRun) {
+ throw {
+ error: "threadWouldRun",
+ message: "Assigning a value would cause the debuggee to run"
+ };
+ } else {
+ throw e;
+ }
+ }
+ return { from: this.actorID };
+ },
+
+ /**
+ * Handle a protocol request to fully enumerate the bindings introduced by the
+ * lexical environment.
+ */
+ bindings: function () {
+ let bindings = { arguments: [], variables: {} };
+
+ // TODO: this part should be removed in favor of the commented-out part
+ // below when getVariableDescriptor lands (bug 725815).
+ if (typeof this.obj.getVariable != "function") {
+ // if (typeof this.obj.getVariableDescriptor != "function") {
+ return bindings;
+ }
+
+ let parameterNames;
+ if (this.obj.callee) {
+ parameterNames = this.obj.callee.parameterNames;
+ } else {
+ parameterNames = [];
+ }
+ for (let name of parameterNames) {
+ let arg = {};
+ let value = this.obj.getVariable(name);
+
+ // TODO: this part should be removed in favor of the commented-out part
+ // below when getVariableDescriptor lands (bug 725815).
+ let desc = {
+ value: value,
+ configurable: false,
+ writable: !(value && value.optimizedOut),
+ enumerable: true
+ };
+
+ // let desc = this.obj.getVariableDescriptor(name);
+ let descForm = {
+ enumerable: true,
+ configurable: desc.configurable
+ };
+ if ("value" in desc) {
+ descForm.value = createValueGrip(desc.value,
+ this.registeredPool, this.threadActor.objectGrip);
+ descForm.writable = desc.writable;
+ } else {
+ descForm.get = createValueGrip(desc.get, this.registeredPool,
+ this.threadActor.objectGrip);
+ descForm.set = createValueGrip(desc.set, this.registeredPool,
+ this.threadActor.objectGrip);
+ }
+ arg[name] = descForm;
+ bindings.arguments.push(arg);
+ }
+
+ for (let name of this.obj.names()) {
+ if (bindings.arguments.some(function exists(element) {
+ return !!element[name];
+ })) {
+ continue;
+ }
+
+ let value = this.obj.getVariable(name);
+
+ // TODO: this part should be removed in favor of the commented-out part
+ // below when getVariableDescriptor lands.
+ let desc = {
+ value: value,
+ configurable: false,
+ writable: !(value &&
+ (value.optimizedOut ||
+ value.uninitialized ||
+ value.missingArguments)),
+ enumerable: true
+ };
+
+ // let desc = this.obj.getVariableDescriptor(name);
+ let descForm = {
+ enumerable: true,
+ configurable: desc.configurable
+ };
+ if ("value" in desc) {
+ descForm.value = createValueGrip(desc.value,
+ this.registeredPool, this.threadActor.objectGrip);
+ descForm.writable = desc.writable;
+ } else {
+ descForm.get = createValueGrip(desc.get || undefined,
+ this.registeredPool, this.threadActor.objectGrip);
+ descForm.set = createValueGrip(desc.set || undefined,
+ this.registeredPool, this.threadActor.objectGrip);
+ }
+ bindings.variables[name] = descForm;
+ }
+
+ return bindings;
+ }
+});
+
+exports.EnvironmentActor = EnvironmentActor;