Browse Source

Overhaul debugging options

Added two new debugging options, `followRuntimeInputs` and
`followOutputValues`. These two are similar to `followPointer` but dump
their respective values, and can be used independent of `followPointer`
or each other.
Abstracted the printing of the memory dump to the InspectProperty
function.
Moved all debugging options from the main `options` keyspace to
`options.debug`.
ApisNecros 1 year ago
parent
commit
81a38d8a61
1 changed files with 52 additions and 12 deletions
  1. 52 12
      IntComp/Computer.js

+ 52 - 12
IntComp/Computer.js

@@ -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 }));
     }
 
     /**