From 00887575ce056bcec09f9635738fb547fca80fce Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sat, 6 Apr 2024 03:21:22 -0700 Subject: [PATCH] fix lspWorker and attach App properties --- www/src/js/app/app.ts | 27 +- www/src/js/editor/index.ts | 8 +- www/src/js/editor/lspWorker.ts | 172 ++++--- www/src/js/index.ts | 21 - www/src/js/session.ts | 8 +- www/src/js/virtual_machine/index.ts | 737 +++++++++++++++------------- 6 files changed, 522 insertions(+), 451 deletions(-) diff --git a/www/src/js/app/app.ts b/www/src/js/app/app.ts index b29c4da..500d490 100644 --- a/www/src/js/app/app.ts +++ b/www/src/js/app/app.ts @@ -1,11 +1,16 @@ import { HTMLTemplateResult, html, css, CSSResultGroup } from "lit"; -import { customElement, property } from "lit/decorators.js"; +import { customElement, property, query } from "lit/decorators.js"; import { BaseElement, defaultCss } from "../components"; import "./nav.ts"; import "@shoelace-style/shoelace/dist/components/split-panel/split-panel.js"; import "../editor"; +import { IC10Editor } from "../editor"; +import { Session } from "../session"; +import { VirtualMachine } from "../virtual_machine"; + + @customElement("ic10emu-app") export class App extends BaseElement { @@ -34,8 +39,21 @@ export class App extends BaseElement { `, ]; + editorSettings: { fontSize: number; relativeLineNumbers: boolean }; + + get editor() { + return this.renderRoot.querySelector('ace-ic10') as IC10Editor; + } + + vm!: VirtualMachine; + session!: Session; + constructor() { super(); + window.App = this; + this.session = new Session(); + this.vm = new VirtualMachine(); + } protected render(): HTMLTemplateResult { @@ -57,3 +75,10 @@ export class App extends BaseElement { `; } } + +declare global { + interface Window { + App?: App; + } +} + diff --git a/www/src/js/editor/index.ts b/www/src/js/editor/index.ts index 2ccbcc8..2e4935d 100644 --- a/www/src/js/editor/index.ts +++ b/www/src/js/editor/index.ts @@ -7,7 +7,6 @@ import { LanguageProvider } from "ace-linters/types/language-provider"; import { IC10EditorUI } from "./ui"; import { Range } from "ace-builds"; -import { App } from "../index"; import { Session } from "../session"; // import { Mode as TextMode } from 'ace-code/src/mode/text'; @@ -341,7 +340,6 @@ export class IC10Editor extends BaseElement { // this.ui = new IC10EditorUI(this); - const that = this; } protected render() { @@ -427,7 +425,7 @@ export class IC10Editor extends BaseElement { this.initializeEditor(); - App.session.onLoad(((e: CustomEvent) => { + window.App!.session.onLoad(((e: CustomEvent) => { const session = e.detail; const updated_ids: number[] = []; for (const [id, _] of session.programs) { @@ -441,9 +439,9 @@ export class IC10Editor extends BaseElement { } } }) as EventListener); - App.session.loadFromFragment(); + window.App!.session.loadFromFragment(); - App.session.onActiveLine(((e: CustomEvent) => { + window.App!.session.onActiveLine(((e: CustomEvent) => { const session = e.detail; for (const id of session.programs.keys()) { const active_line = session.getActiveLine(id); diff --git a/www/src/js/editor/lspWorker.ts b/www/src/js/editor/lspWorker.ts index 60afa33..7204a37 100644 --- a/www/src/js/editor/lspWorker.ts +++ b/www/src/js/editor/lspWorker.ts @@ -12,10 +12,7 @@ export default class Bytes { return decoder.decode(input); } - static append( - constructor: Uint8ArrayConstructor, - ...arrays: Uint8Array[] - ) { + static append(constructor: Uint8ArrayConstructor, ...arrays: Uint8Array[]) { let totalLength = 0; for (const arr of arrays) { totalLength += arr.length; @@ -30,26 +27,37 @@ export default class Bytes { } } -export class AsyncStreamQueue implements AsyncIterator { - +export class AsyncStreamQueueUint8Array + implements AsyncIterator { promises: Promise[] = []; - resolvers: Promise[] = []; + resolvers: ((value: Uint8Array) => void)[] = []; observers: any = []; closed = false; tag = ""; stream: WritableStream; - static __add(promises: any[], resolvers: any[]) { - promises.push(new Promise((resolve) => { - resolvers.push(resolve); - })) + static __add( + promises: Promise[], + resolvers: ((value: Uint8Array) => void)[], + ) { + promises.push( + new Promise((resolve: (value: Uint8Array) => void) => { + resolvers.push(resolve); + }), + ); } - static __enqueue(closed: boolean, promises: any[], resolvers: any[], item: any) { + static __enqueue( + closed: boolean, + promises: Promise[], + resolvers: ((value: Uint8Array) => void)[], + item: Uint8Array, + ) { if (!closed) { - if (!resolvers.length) AsyncStreamQueue.__add(promises, resolvers); - const resolve = resolvers.shift(); + if (!resolvers.length) + AsyncStreamQueueUint8Array.__add(promises, resolvers); + const resolve = resolvers.shift()!; resolve(item); } } @@ -62,31 +70,37 @@ export class AsyncStreamQueue implements AsyncIterator any; params: { hasOwnProperty: (arg0: string) => any; rootUri: string; textDocument: { hasOwnProperty: (arg0: string) => any; uri: string; }; }; }) { - if (data.hasOwnProperty("params") && data.params.hasOwnProperty("rootUri") && data.params.rootUri === "") { - data.params.rootUri = null +function fixup(data: { + hasOwnProperty: (arg0: string) => any; + params: { + hasOwnProperty: (arg0: string) => any; + rootUri: string | null; + textDocument: { hasOwnProperty: (arg0: string) => any; uri: string }; + }; +}) { + if ( + data.hasOwnProperty("params") && + data.params.hasOwnProperty("rootUri") && + data.params.rootUri === "" + ) { + data.params.rootUri = null; } - if (data.hasOwnProperty("params") && data.params.hasOwnProperty("textDocument")) { + if ( + data.hasOwnProperty("params") && + data.params.hasOwnProperty("textDocument") + ) { if (data.params.textDocument.hasOwnProperty("uri")) { const match = data.params.textDocument.uri.match(/^file:\/\/\/(.*)/); if (null == match) { data.params.textDocument.uri = `file:///${data.params.textDocument.uri}`; } } - data.params.rootUri = null + data.params.rootUri = null; } - return data + return data; } function sendClient(data: any) { data = fixup(data); const data_j = JSON.stringify(data); - const msg = `Content-Length: ${data_j.length}\r\n\r\n${data_j}` + const msg = `Content-Length: ${data_j.length}\r\n\r\n${data_j}`; clientMsgStream.enqueue(encoder.encode(msg)); } async function listen() { - let contentLength = null; + let contentLength: number | null = null; let buffer = new Uint8Array(); console.log("Worker: listening for lsp messages..."); for await (const bytes of serverMsgStream) { buffer = Bytes.append(Uint8Array, buffer, bytes); + let waitingForFullContent = false; + let messagesThisLoop = 0; - // check if the content length is known - if (null == contentLength) { - // if not, try to match the prefixed headers - const match = Bytes.decode(buffer).match(/^Content-Length:\s*(\d+)\s*/); - if (null == match) continue; + // sometimes the buffer can get more than one message in it, loop untill we need to wait for more. + while (buffer.length > 0 && !waitingForFullContent) { + // check if the content length is known + if (null == contentLength) { + // if not, try to match the prefixed headers + const match = Bytes.decode(buffer).match(/^Content-Length:\s*(\d+)\s*/); + if (null == match) continue; - // try to parse the content-length from the headers - const length = parseInt(match[1]); - if (isNaN(length)) throw new Error("invalid content length"); + // try to parse the content-length from the headers + const length = parseInt(match[1]); + if (isNaN(length)) throw new Error("invalid content length"); - // slice the headers since we now have the content length - buffer = buffer.slice(match[0].length); + // slice the headers since we now have the content length + buffer = buffer.slice(match[0].length); - // set the content length - contentLength = length; + // set the content length + contentLength = length; + } + + // if the buffer doesn't contain a full message; await another iteration + if (buffer.length < contentLength) { + waitingForFullContent = true; + continue; + } + messagesThisLoop += 1; + + // decode buffer up to `contentLength` to a string (leave the rest for the next message) + const delimited = Bytes.decode(buffer.slice(0, contentLength)); + + // reset the buffer + buffer = buffer.slice(contentLength); + // reset the contentLength + contentLength = null; + + try { + const message = JSON.parse(delimited); + console.log( + "Lsp Message:", + `| This Loop: ${messagesThisLoop} |`, + message, + ); + postMessage(message); + } catch (e) { + console.log("Error parsing Lsp Message:", e); + } } - - // if the buffer doesn't contain a full message; await another iteration - if (buffer.length < contentLength) continue; - - // decode buffer to a string - const delimited = Bytes.decode(buffer); - - // reset the buffer - buffer = buffer.slice(contentLength); - // reset the contentLength - contentLength = null; - - const message = JSON.parse(delimited); - console.log("Lsp Message:", message); - postMessage(message) } console.log("Worker: lsp message queue done?"); } @@ -212,8 +256,8 @@ postMessage("ready"); onmessage = function (e) { console.log("Client Message:", e.data); - sendClient(e.data) -} + sendClient(e.data); +}; console.log("Starting LSP..."); start(); diff --git a/www/src/js/index.ts b/www/src/js/index.ts index 0031a83..0430df2 100644 --- a/www/src/js/index.ts +++ b/www/src/js/index.ts @@ -3,27 +3,6 @@ import { Session } from "./session"; import { VirtualMachine } from "./virtual_machine"; import { docReady, openFile, saveFile } from "./utils"; // import { makeRequest } from "./utils"; -declare global { - interface Window { - App: App; - } -} - -type App = { - editorSettings: { fontSize: number; relativeLineNumbers: boolean }; - editor: IC10Editor; - vm: VirtualMachine; - session: Session; -}; - -export const App: App = { - editor: null, - vm: null, - session: new Session(), - editorSettings: { fontSize: 16, relativeLineNumbers: false }, -}; - -window.App = App; // const dbPromise = makeRequest({ method: "GET", url: "/data/database.json"}); // const dbPromise = fetch("/data/database.json").then(resp => resp.json()); diff --git a/www/src/js/session.ts b/www/src/js/session.ts index e358de7..296dfba 100644 --- a/www/src/js/session.ts +++ b/www/src/js/session.ts @@ -60,10 +60,6 @@ j ra `; -interface CustomEvent extends Event { - detail: string -} - export class Session extends EventTarget { _programs: Map; _activeSession: number; @@ -142,8 +138,8 @@ export class Session extends EventTarget { if (this._save_timeout) clearTimeout(this._save_timeout); this._save_timeout = setTimeout(() => { this.saveToFragment(); - if (window.App.vm) { - window.App.vm.updateCode(); + if (window.App!.vm) { + window.App!.vm.updateCode(); } this._save_timeout = undefined; }, 1000); diff --git a/www/src/js/virtual_machine/index.ts b/www/src/js/virtual_machine/index.ts index f529d6c..b1b3a1e 100644 --- a/www/src/js/virtual_machine/index.ts +++ b/www/src/js/virtual_machine/index.ts @@ -1,417 +1,446 @@ import { DeviceRef, VM, init } from "ic10emu_wasm"; import { VMDeviceUI } from "./device"; +import { BaseElement } from "../components"; // import { Card } from 'bootstrap'; declare global { - interface Window { VM: VirtualMachine } + interface Window { + VM?: VirtualMachine; + } } type DeviceDB = { - logic_enabled: string[]; - slot_logic_enabled: string[]; - devices: string[]; - items: { - [key: string]: { - name: string, - hash: number, - desc: string, - logic?: { [key: string]: string }, - slots?: { name: string, type: string }[], - modes?: { [key: string]: string }, - conn?: { [key: string]: string[] }, - } - } -} + logic_enabled: string[]; + slot_logic_enabled: string[]; + devices: string[]; + items: { + [key: string]: { + name: string; + hash: number; + desc: string; + logic?: { [key: string]: string }; + slots?: { name: string; type: string }[]; + modes?: { [key: string]: string }; + conn?: { [key: string]: string[] }; + }; + }; +}; class VirtualMachine { - ic10vm: VM; - ui: VirtualMachineUI; - _devices: Map; - _ics: Map; - db: DeviceDB; + ic10vm: VM; + ui: VirtualMachineUI; + _devices: Map; + _ics: Map; + db: DeviceDB; - constructor() { - const vm = init(); + constructor() { + const vm = init(); - window.VM = this; + window.VM = this; - this.ic10vm = vm; - this.ui = new VirtualMachineUI(this); + this.ic10vm = vm; + // this.ui = new VirtualMachineUI(this); - this._devices = new Map(); - this._ics = new Map(); + this._devices = new Map(); + this._ics = new Map(); - this.updateDevices(); + this.updateDevices(); - this.updateCode() + this.updateCode(); + } + get devices() { + return this._devices; + } + + get ics() { + return this._ics; + } + + get activeIC() { + return this._ics.get(window.App!.session.activeSession); + } + + updateDevices() { + const device_ids = this.ic10vm.devices; + for (const id of device_ids) { + if (!this._devices.has(id)) { + this._devices.set(id, this.ic10vm.getDevice(id)!); + } + } + for (const id of this._devices.keys()) { + if (!device_ids.includes(id)) { + this._devices.get(id)!.free(); + this._devices.delete(id); + } } - get devices() { - return this._devices; + const ics = this.ic10vm.ics; + for (const id of ics) { + if (!this._ics.has(id)) { + this._ics.set(id, this._devices.get(id)!); + } } - - get ics() { - return this._ics; + for (const id of this._ics.keys()) { + if (!ics.includes(id)) { + this._ics.get(id)!.free(); + this._ics.delete(id); + } } + } - get activeIC() { - return this._ics.get(window.App.session.activeSession); - } - - updateDevices() { - - const device_ids = this.ic10vm.devices; - for (const id of device_ids) { - if (!this._devices.has(id)) { - this._devices.set(id, this.ic10vm.getDevice(id)); - } - } - for (const id of this._devices.keys()) { - if (!device_ids.includes(id)) { - this._devices.get(id).free(); - this._devices.delete(id); - } - } - - const ics = this.ic10vm.ics; - for (const id of ics) { - if (!this._ics.has(id)) { - this._ics.set(id, this._devices.get(id)); - } - } - for (const id of this._ics.keys()) { - if (!ics.includes(id)) { - this._ics.get(id).free(); - this._ics.delete(id); - } - } - - } - - updateCode() { - const progs = window.App.session.programs; - for (const id of progs.keys()) { - const attempt = Date.now().toString(16) - const ic = this._ics.get(id); - const prog = progs.get(id); - if (ic && prog) { - console.time(`CompileProgram_${id}_${attempt}`); - try { - this.ics.get(id).setCode(progs.get(id)); - } catch (e) { - console.log(e); - } - console.timeEnd(`CompileProgram_${id}_${attempt}`); - } - } - this.update(); - } - - step() { - const ic = this.activeIC; - if (ic) { - try { - ic.step(false); - } catch (e) { - console.log(e); - } - this.update(); - } - } - - run() { - const ic = this.activeIC; - if (ic) { - try { - ic.run(false); - } catch (e) { - console.log(e); - } - this.update(); - } - } - - reset() { - const ic = this.activeIC; - if (ic) { - ic.reset(); - this.update(); - } - } - - update() { - this.updateDevices(); - const ic = this.activeIC; - window.App.session.setActiveLine(window.App.session.activeSession, ic.ip); - this.ui.update(ic); - } - - setRegister(index: number, val: number) { - const ic = this.activeIC; + updateCode() { + const progs = window.App!.session.programs; + for (const id of progs.keys()) { + const attempt = Date.now().toString(16); + const ic = this._ics.get(id); + const prog = progs.get(id); + if (ic && prog) { + console.time(`CompileProgram_${id}_${attempt}`); try { - ic.setRegister(index, val); + this.ics.get(id)!.setCode(progs.get(id)!); } catch (e) { - console.log(e); + console.log(e); } + console.timeEnd(`CompileProgram_${id}_${attempt}`); + } } + this.update(); + } - setStack(addr: number, val: number) { - const ic = this.activeIC; - try { - ic.setStack(addr, val); - } catch (e) { - console.log(e); - } + step() { + const ic = this.activeIC; + if (ic) { + try { + ic.step(false); + } catch (e) { + console.log(e); + } + this.update(); } + } - setupDeviceDatabase(db: DeviceDB) { - this.db = db; - console.log("Loaded Device Database", this.db); + run() { + const ic = this.activeIC; + if (ic) { + try { + ic.run(false); + } catch (e) { + console.log(e); + } + this.update(); } + } + + reset() { + const ic = this.activeIC; + if (ic) { + ic.reset(); + this.update(); + } + } + + update() { + this.updateDevices(); + const ic = this.activeIC!; + window.App!.session.setActiveLine(window.App!.session.activeSession, ic.ip!); + // this.ui.update(ic); + } + + setRegister(index: number, val: number) { + const ic = this.activeIC!; + try { + ic.setRegister(index, val); + } catch (e) { + console.log(e); + } + } + + setStack(addr: number, val: number) { + const ic = this.activeIC; + try { + ic!.setStack(addr, val); + } catch (e) { + console.log(e); + } + } + + setupDeviceDatabase(db: DeviceDB) { + this.db = db; + console.log("Loaded Device Database", this.db); + } } - class VirtualMachineUI { - vm: VirtualMachine; - state: VMStateUI; - registers: VMRegistersUI; - stack: VMStackUI; - devices: VMDeviceUI; + vm: VirtualMachine; + state: VMStateUI; + registers: VMRegistersUI; + stack: VMStackUI; + devices: VMDeviceUI; - constructor(vm: VirtualMachine) { - this.vm = vm - this.state = new VMStateUI(this); - this.registers = new VMRegistersUI(this); - this.stack = new VMStackUI(this); - this.devices = new VMDeviceUI(this); + constructor(vm: VirtualMachine) { + this.vm = vm; + this.state = new VMStateUI(this); + this.registers = new VMRegistersUI(this); + this.stack = new VMStackUI(this); + this.devices = new VMDeviceUI(this); - const that = this; + const that = this; - document.getElementById("vmControlRun").addEventListener('click', (_event) => { - that.vm.run(); - }, { capture: true }); - document.getElementById("vmControlStep").addEventListener('click', (_event) => { - that.vm.step(); - }, { capture: true }); - document.getElementById("vmControlReset").addEventListener('click', (_event) => { - that.vm.reset(); - }, { capture: true }); - - } - - update(ic: DeviceRef) { - this.state.update(ic); - this.registers.update(ic); - this.stack.update(ic); - this.devices.update(ic); - } + document.getElementById("vmControlRun")!.addEventListener( + "click", + (_event) => { + that.vm.run(); + }, + { capture: true }, + ); + document.getElementById("vmControlStep")!.addEventListener( + "click", + (_event) => { + that.vm.step(); + }, + { capture: true }, + ); + document.getElementById("vmControlReset")!.addEventListener( + "click", + (_event) => { + that.vm.reset(); + }, + { capture: true }, + ); + } + update(ic: DeviceRef) { + this.state.update(ic); + this.registers.update(ic); + this.stack.update(ic); + this.devices.update(ic); + } } class VMStateUI { - ui: VirtualMachineUI; - instructionPointer: HTMLElement; - instructionCounter: HTMLElement; - lastState: HTMLElement; - constructor(ui: VirtualMachineUI) { - this.ui = ui; + ui: VirtualMachineUI; + instructionPointer: HTMLElement; + instructionCounter: HTMLElement; + lastState: HTMLElement; + constructor(ui: VirtualMachineUI) { + this.ui = ui; - this.instructionPointer = document.getElementById("vmActiveICStateIP"); - this.instructionCounter = document.getElementById("vmActiveICStateICount"); - this.lastState = document.getElementById("vmActiveICStateLastRun"); - } + this.instructionPointer = document.getElementById("vmActiveICStateIP")!; + this.instructionCounter = document.getElementById("vmActiveICStateICount")!; + this.lastState = document.getElementById("vmActiveICStateLastRun")!; + } - update(ic: { ip: { toString: () => string; }; instructionCount: { toString: () => string; }; state: { toString: () => string; }; }) { - if (ic) { - this.instructionPointer.innerText = ic.ip.toString(); - this.instructionCounter.innerText = ic.instructionCount.toString(); - this.lastState.innerText = ic.state.toString(); - } + update(ic: DeviceRef) { + if (ic) { + this.instructionPointer.innerText = ic.ip!.toString(); + this.instructionCounter.innerText = ic.instructionCount!.toString(); + this.lastState.innerText = ic.state!.toString(); } + } } class VMRegistersUI { - ui: VirtualMachineUI; - tbl: HTMLDivElement; - regCells: { - cell: HTMLDivElement, - nameLabel: HTMLSpanElement, - aliasesLabel: HTMLSpanElement, - input: HTMLInputElement - }[]; - default_aliases: Map; - ic_aliases: Map; - constructor(ui: VirtualMachineUI) { - const that = this; - this.ui = ui; - const regDom = document.getElementById("vmActiveRegisters"); - this.tbl = document.createElement("div"); - this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-end",); - this.regCells = []; - for (var i = 0; i < 18; i++) { - const container = document.createElement("div"); - container.classList.add("vm_reg_cel", "align-that-stretch"); - const cell = document.createElement("div"); - cell.classList.add("input-group", "input-group-sm") - // cell.style.width = "30%"; - const nameLabel = document.createElement("span"); - nameLabel.innerText = `r${i}`; - nameLabel.classList.add("input-group-text") - cell.appendChild(nameLabel); - const input = document.createElement("input"); - input.type = "text" - input.value = (0).toString(); - input.dataset.index = i.toString(); - cell.appendChild(input); - const aliasesLabel = document.createElement("span"); - aliasesLabel.classList.add("input-group-text", "reg_label") - cell.appendChild(aliasesLabel); - this.regCells.push({ - cell, - nameLabel, - aliasesLabel, - input, - }); - container.appendChild(cell); - this.tbl.appendChild(container); + ui: VirtualMachineUI; + tbl: HTMLDivElement; + regCells: { + cell: HTMLDivElement; + nameLabel: HTMLSpanElement; + aliasesLabel: HTMLSpanElement; + input: HTMLInputElement; + }[]; + default_aliases: Map; + ic_aliases: Map; + constructor(ui: VirtualMachineUI) { + const that = this; + this.ui = ui; + const regDom = document.getElementById("vmActiveRegisters")!; + this.tbl = document.createElement("div"); + this.tbl.classList.add( + "d-flex", + "flex-wrap", + "justify-content-start", + "align-items-end", + ); + this.regCells = []; + for (var i = 0; i < 18; i++) { + const container = document.createElement("div"); + container.classList.add("vm_reg_cel", "align-that-stretch"); + const cell = document.createElement("div"); + cell.classList.add("input-group", "input-group-sm"); + // cell.style.width = "30%"; + const nameLabel = document.createElement("span"); + nameLabel.innerText = `r${i}`; + nameLabel.classList.add("input-group-text"); + cell.appendChild(nameLabel); + const input = document.createElement("input"); + input.type = "text"; + input.value = (0).toString(); + input.dataset.index = i.toString(); + cell.appendChild(input); + const aliasesLabel = document.createElement("span"); + aliasesLabel.classList.add("input-group-text", "reg_label"); + cell.appendChild(aliasesLabel); + this.regCells.push({ + cell, + nameLabel, + aliasesLabel, + input, + }); + container.appendChild(cell); + this.tbl.appendChild(container); + } + this.regCells.forEach((cell) => { + cell.input.addEventListener("change", that.onCellUpdate); + }); + this.default_aliases = new Map([ + ["sp", 16], + ["ra", 17], + ]); + this.ic_aliases = new Map(); + regDom.appendChild(this.tbl); + } + + onCellUpdate(e: Event) { + let index: number; + let val: number; + let target = e.target as HTMLInputElement; + try { + index = parseInt(target.dataset.index!); + val = parseFloat(target.value); + } catch (e) { + // reset the edit + console.log(e); + window.VM!.update(); + return; + } + window.VM!.setRegister(index, val); + } + + update(ic: DeviceRef) { + if (ic) { + const registers = ic.registers; + if (registers) { + for (var i = 0; i < registers.length; i++) { + this.regCells[i].input.value = registers[i].toString(); } - this.regCells.forEach(cell => { - cell.input.addEventListener('change', that.onCellUpdate); - }); - this.default_aliases = new Map([["sp", 16], ["ra", 17]]); + } + const aliases = ic.aliases; + if (aliases) { this.ic_aliases = new Map(); - regDom.appendChild(this.tbl); + aliases.forEach((target, alias, _map) => { + if ( + "RegisterSpec" in target && + target.RegisterSpec.indirection == 0 + ) { + const index = target.RegisterSpec.target; + this.ic_aliases.set(alias, index); + } + }); + } + } + this.updateAliases(); + } + + updateAliases() { + const aliases = new Map([ + ...Array.from(this.default_aliases), + ...Array.from(this.ic_aliases), + ]); + const labels = new Map(); + for (const [alias, target] of aliases) { + if (labels.hasOwnProperty(target)) { + labels.get(target)!.push(alias); + } else { + labels.set(target, [alias]); + } } - onCellUpdate(e: Event) { - let index; - let val; - let target = (e.target as HTMLInputElement); - try { - index = parseInt(target.dataset.index); - val = parseFloat(target.value); - } catch (e) { - // reset the edit - console.log(e); - window.VM.update(); - return; - } - window.VM.setRegister(index, val); - } - - update(ic: DeviceRef) { - const that = this; - if (ic) { - const registers = ic.registers; - if (registers) { - for (var i = 0; i < registers.length; i++) { - this.regCells[i].input.value = registers[i].toString(); - } - } - const aliases = ic.aliases; - if (aliases) { - this.ic_aliases = new Map(); - aliases.forEach((target, alias, _map) => { - if (("RegisterSpec" in target) && target.RegisterSpec.indirection == 0) { - const index = target.RegisterSpec.target; - this.ic_aliases.set(alias, index); - } - }) - } - } - this.updateAliases(); - } - - updateAliases() { - const aliases = new Map([...Array.from(this.default_aliases), ...Array.from(this.ic_aliases)]); - const labels = new Map(); - for (const [alias, target] of aliases) { - if (labels.hasOwnProperty(target)) { - labels.get(target).push(alias) - } else { - labels.set(target, [alias]); - } - } - - for (const [index, label_list] of labels) { - this.regCells[index].aliasesLabel.innerText = label_list.join(", ") - } + for (const [index, label_list] of labels) { + this.regCells[index].aliasesLabel.innerText = label_list.join(", "); } + } } class VMStackUI { - ui: VirtualMachineUI; - tbl: HTMLDivElement; - stackCells: { cell: HTMLDivElement, nameLabel: HTMLSpanElement, input: HTMLInputElement }[]; - constructor(ui: VirtualMachineUI) { - this.ui = ui; - const stackDom = document.getElementById("vmActiveStack"); - this.tbl = document.createElement("div"); - this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-end",); - this.stackCells = []; - for (var i = 0; i < 512; i++) { - const container = document.createElement("div"); - container.classList.add("vm_stack_cel", "align-that-stretch"); - const cell = document.createElement("div"); - cell.classList.add("input-group", "input-group-sm") - const nameLabel = document.createElement("span"); - nameLabel.innerText = `${i}`; - nameLabel.classList.add("input-group-text") - cell.appendChild(nameLabel); - const input = document.createElement("input"); - input.type = "text" - input.value = (0).toString(); - input.dataset.index = i.toString(); - cell.appendChild(input); + ui: VirtualMachineUI; + tbl: HTMLDivElement; + stackCells: { + cell: HTMLDivElement; + nameLabel: HTMLSpanElement; + input: HTMLInputElement; + }[]; + constructor(ui: VirtualMachineUI) { + this.ui = ui; + const stackDom = document.getElementById("vmActiveStack")!; + this.tbl = document.createElement("div"); + this.tbl.classList.add( + "d-flex", + "flex-wrap", + "justify-content-start", + "align-items-end", + ); + this.stackCells = []; + for (var i = 0; i < 512; i++) { + const container = document.createElement("div"); + container.classList.add("vm_stack_cel", "align-that-stretch"); + const cell = document.createElement("div"); + cell.classList.add("input-group", "input-group-sm"); + const nameLabel = document.createElement("span"); + nameLabel.innerText = `${i}`; + nameLabel.classList.add("input-group-text"); + cell.appendChild(nameLabel); + const input = document.createElement("input"); + input.type = "text"; + input.value = (0).toString(); + input.dataset.index = i.toString(); + cell.appendChild(input); - this.stackCells.push({ - cell, - nameLabel, - input, - }); - container.appendChild(cell); - this.tbl.appendChild(container); - } - this.stackCells.forEach(cell => { - cell.input.addEventListener('change', this.onCellUpdate); - }); - stackDom.appendChild(this.tbl); + this.stackCells.push({ + cell, + nameLabel, + input, + }); + container.appendChild(cell); + this.tbl.appendChild(container); } + this.stackCells.forEach((cell) => { + cell.input.addEventListener("change", this.onCellUpdate); + }); + stackDom.appendChild(this.tbl); + } - onCellUpdate(e: Event) { - let index; - let val; - let target = e.target as HTMLInputElement; - try { - index = parseInt(target.dataset.index); - val = parseFloat(target.value); - } catch (e) { - // reset the edit - window.VM.update(); - return; - } - window.VM.setStack(index, val); + onCellUpdate(e: Event) { + let index: number; + let val: number; + let target = e.target as HTMLInputElement; + try { + index = parseInt(target.dataset.index!); + val = parseFloat(target.value); + } catch (e) { + // reset the edit + window.VM!.update(); + return; } + window.VM!.setStack(index, val); + } - update(ic: { stack: any; registers: any[]; }) { - const that = this; - if (ic) { - const stack = ic.stack; - const sp = ic.registers[16]; - if (stack) { - for (var i = 0; i < stack.length; i++) { - this.stackCells[i].input.value = stack[i]; - if (i == sp) { - this.stackCells[i].nameLabel.classList.add("stack_pointer"); - } else { - this.stackCells[i].nameLabel.classList.remove("stack_pointer"); - } - } - } + update(ic: DeviceRef) { + if (ic) { + const stack = ic.stack; + const sp = ic.registers![16]; + if (stack) { + for (var i = 0; i < stack.length; i++) { + this.stackCells[i].input.value = stack[i].toString(); + if (i == sp) { + this.stackCells[i].nameLabel.classList.add("stack_pointer"); + } else { + this.stackCells[i].nameLabel.classList.remove("stack_pointer"); + } } + } } - + } } -export { VirtualMachine, VirtualMachineUI , DeviceDB }; +export { VirtualMachine, VirtualMachineUI, DeviceDB };