|
@@ -14,8 +14,11 @@ module.exports = class Computer {
|
|
|
*
|
|
|
* @param {number[]} stack The initial memory to load into the computer
|
|
|
* @param {Object} options Options that can be enabled within the computer
|
|
|
- * @param {boolean} options.followPointer When true, the memory will be dumped every call to Execute with the current instruction highlighted
|
|
|
- * @param {number} options.tickRate The number of milliseconds between calls to Execute. Initializes to 0.
|
|
|
+ * @param {object} options.debug A set of debugging options
|
|
|
+ * @param {number} options.debug.tickRate The number of milliseconds between calls to Execute. Initializes to 0.
|
|
|
+ * @param {boolean} options.debug.followPointer When true, the memory will be dumped during every call to Execute with the current instruction highlighted
|
|
|
+ * @param {boolean} options.debug.followRuntimeInput When true, the runtime input array will be dumped during every call to Execute
|
|
|
+ * @param {boolean} options.debug.followOutputValues When true, the output values array will be dumped during every call to Execute
|
|
|
* @param {boolean} options.inputFromConsole When true, the computer will prompt for input on the console. If false, it will check for an linked computer and, if one exists, will wait for input from that computer.
|
|
|
* @param {boolean} options.outputToConsole When true, the computer will print the output of opcode 4 to the console. If false, it will check for an linked computer and, if one exists, pass the output to that computer.
|
|
|
* @param {number[]} options.inputModeMap Map calls to the INPUT opcode to user input or the input array
|
|
@@ -51,8 +54,12 @@ module.exports = class Computer {
|
|
|
this.skipNext = false;
|
|
|
|
|
|
this.options = {
|
|
|
- followPointer: options.followPointer ?? false,
|
|
|
- tickRate: options.tickRate ?? 0,
|
|
|
+ debug: {
|
|
|
+ followPointer: options?.debug?.followPointer ?? false,
|
|
|
+ followRuntimeInput: options?.debug?.followRuntimeInput ?? false,
|
|
|
+ followOutputValues: options?.debug?.followOutputValues ?? false,
|
|
|
+ tickRate: options?.debug?.tickRate ?? 0,
|
|
|
+ },
|
|
|
inputFromConsole: options.inputFromConsole ?? false,
|
|
|
outputToConsole: options.outputToConsole ?? false,
|
|
|
inputModeMap: options.inputModeMap ?? [],
|
|
@@ -102,10 +109,10 @@ module.exports = class Computer {
|
|
|
*/
|
|
|
async Run() {
|
|
|
while (this.Execute(this.stack.Get(ComputerParameterMode.IMMEDIATE_MODE)) === true) {
|
|
|
- if (this.options.tickRate) {
|
|
|
+ if (this.options.debug.tickRate) {
|
|
|
// Sleep
|
|
|
// eslint-disable-next-line no-await-in-loop, no-promise-executor-return, arrow-parens
|
|
|
- await new Promise(resolve => setTimeout(resolve, this.options.tickRate));
|
|
|
+ await new Promise(resolve => setTimeout(resolve, this.options.debug.tickRate));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -122,10 +129,10 @@ module.exports = class Computer {
|
|
|
async RunWithInput(input) {
|
|
|
this.runtimeInput = input;
|
|
|
while (this.Execute(this.stack.Get(ComputerParameterMode.IMMEDIATE_MODE)) === true) {
|
|
|
- if (this.options.tickRate) {
|
|
|
+ if (this.options.debug.tickRate) {
|
|
|
// Sleep
|
|
|
// eslint-disable-next-line no-await-in-loop, no-promise-executor-return, arrow-parens
|
|
|
- await new Promise(resolve => setTimeout(resolve, this.options.tickRate));
|
|
|
+ await new Promise(resolve => setTimeout(resolve, this.options.debug.tickRate));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -140,9 +147,7 @@ module.exports = class Computer {
|
|
|
let status = true;
|
|
|
this.skipNext = false;
|
|
|
|
|
|
- if (this.options.followPointer) {
|
|
|
- this.DumpMemory(true);
|
|
|
- }
|
|
|
+ this.FollowExecution();
|
|
|
|
|
|
const opcode = rawOpcode % 100;
|
|
|
|
|
@@ -380,6 +385,21 @@ module.exports = class Computer {
|
|
|
this.stack.Put(outputPosition, Number(testPassed));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Inspects various parts of the computer before every call to Execution
|
|
|
+ *
|
|
|
+ * Based on the debug options set at runtime, may output any combination of the
|
|
|
+ * computer's core memory, the runtime input stack, and or the output values
|
|
|
+ * array.
|
|
|
+ *
|
|
|
+ * @returns {void}
|
|
|
+ */
|
|
|
+ FollowExecution() {
|
|
|
+ if (this.options.debug.followPointer) { this.DumpMemory(true); }
|
|
|
+ if (this.options.debug.followRuntimeInput) { this.InspectProperty("Inputs", "runtimeInput"); }
|
|
|
+ if (this.options.debug.followOutputValues) { this.InspectProperty("Outputs", "outputValues"); }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Outputs the computer's stack to the console
|
|
|
*
|
|
@@ -393,7 +413,27 @@ module.exports = class Computer {
|
|
|
memory = memory.map((instruction, idx) => (idx == this.stack.pointer ? `{${instruction}}` : instruction));
|
|
|
}
|
|
|
|
|
|
- console.log(util.inspect(memory, { breakLength: Infinity, colors: true, compact: true }));
|
|
|
+ this.InspectProperty("Memory", null, memory);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Inspect a property of this object in the console
|
|
|
+ *
|
|
|
+ * @param {string} [outputMessage] An optional message to prepend the inspection with
|
|
|
+ * @param {?string} [propertyName] The name of the Computer class property to inspect
|
|
|
+ * @param {?unknown} [overrideValue] If provided, this value is inspected as-is instead of the class property
|
|
|
+ * @returns {void}
|
|
|
+ */
|
|
|
+ InspectProperty(outputMessage = "", propertyName = null, overrideValue = null) {
|
|
|
+ let toInspect;
|
|
|
+ if (overrideValue !== null) {
|
|
|
+ toInspect = overrideValue;
|
|
|
+ }
|
|
|
+ else if (this[propertyName] !== undefined) {
|
|
|
+ toInspect = this[propertyName];
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log(outputMessage, util.inspect(toInspect, { breakLength: Infinity, colors: true, compact: true }));
|
|
|
}
|
|
|
|
|
|
/**
|