fix lspWorker and attach App properties
This commit is contained in:
@@ -1,11 +1,16 @@
|
|||||||
import { HTMLTemplateResult, html, css, CSSResultGroup } from "lit";
|
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 { BaseElement, defaultCss } from "../components";
|
||||||
import "./nav.ts";
|
import "./nav.ts";
|
||||||
|
|
||||||
import "@shoelace-style/shoelace/dist/components/split-panel/split-panel.js";
|
import "@shoelace-style/shoelace/dist/components/split-panel/split-panel.js";
|
||||||
|
|
||||||
import "../editor";
|
import "../editor";
|
||||||
|
import { IC10Editor } from "../editor";
|
||||||
|
import { Session } from "../session";
|
||||||
|
import { VirtualMachine } from "../virtual_machine";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@customElement("ic10emu-app")
|
@customElement("ic10emu-app")
|
||||||
export class App extends BaseElement {
|
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() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
window.App = this;
|
||||||
|
this.session = new Session();
|
||||||
|
this.vm = new VirtualMachine();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): HTMLTemplateResult {
|
protected render(): HTMLTemplateResult {
|
||||||
@@ -57,3 +75,10 @@ export class App extends BaseElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
App?: App;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { LanguageProvider } from "ace-linters/types/language-provider";
|
|||||||
import { IC10EditorUI } from "./ui";
|
import { IC10EditorUI } from "./ui";
|
||||||
import { Range } from "ace-builds";
|
import { Range } from "ace-builds";
|
||||||
|
|
||||||
import { App } from "../index";
|
|
||||||
import { Session } from "../session";
|
import { Session } from "../session";
|
||||||
|
|
||||||
// import { Mode as TextMode } from 'ace-code/src/mode/text';
|
// import { Mode as TextMode } from 'ace-code/src/mode/text';
|
||||||
@@ -341,7 +340,6 @@ export class IC10Editor extends BaseElement {
|
|||||||
|
|
||||||
// this.ui = new IC10EditorUI(this);
|
// this.ui = new IC10EditorUI(this);
|
||||||
|
|
||||||
const that = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
@@ -427,7 +425,7 @@ export class IC10Editor extends BaseElement {
|
|||||||
|
|
||||||
this.initializeEditor();
|
this.initializeEditor();
|
||||||
|
|
||||||
App.session.onLoad(((e: CustomEvent) => {
|
window.App!.session.onLoad(((e: CustomEvent) => {
|
||||||
const session = e.detail;
|
const session = e.detail;
|
||||||
const updated_ids: number[] = [];
|
const updated_ids: number[] = [];
|
||||||
for (const [id, _] of session.programs) {
|
for (const [id, _] of session.programs) {
|
||||||
@@ -441,9 +439,9 @@ export class IC10Editor extends BaseElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) as EventListener);
|
}) as EventListener);
|
||||||
App.session.loadFromFragment();
|
window.App!.session.loadFromFragment();
|
||||||
|
|
||||||
App.session.onActiveLine(((e: CustomEvent) => {
|
window.App!.session.onActiveLine(((e: CustomEvent) => {
|
||||||
const session = e.detail;
|
const session = e.detail;
|
||||||
for (const id of session.programs.keys()) {
|
for (const id of session.programs.keys()) {
|
||||||
const active_line = session.getActiveLine(id);
|
const active_line = session.getActiveLine(id);
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ export default class Bytes {
|
|||||||
return decoder.decode(input);
|
return decoder.decode(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
static append(
|
static append(constructor: Uint8ArrayConstructor, ...arrays: Uint8Array[]) {
|
||||||
constructor: Uint8ArrayConstructor,
|
|
||||||
...arrays: Uint8Array[]
|
|
||||||
) {
|
|
||||||
let totalLength = 0;
|
let totalLength = 0;
|
||||||
for (const arr of arrays) {
|
for (const arr of arrays) {
|
||||||
totalLength += arr.length;
|
totalLength += arr.length;
|
||||||
@@ -30,26 +27,37 @@ export default class Bytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AsyncStreamQueue implements AsyncIterator<Uint8Array, undefined, Uint8Array> {
|
export class AsyncStreamQueueUint8Array
|
||||||
|
implements AsyncIterator<Uint8Array, undefined, Uint8Array> {
|
||||||
promises: Promise<Uint8Array>[] = [];
|
promises: Promise<Uint8Array>[] = [];
|
||||||
resolvers: Promise<Uint8Array>[] = [];
|
resolvers: ((value: Uint8Array) => void)[] = [];
|
||||||
observers: any = [];
|
observers: any = [];
|
||||||
|
|
||||||
closed = false;
|
closed = false;
|
||||||
tag = "";
|
tag = "";
|
||||||
stream: WritableStream<Uint8Array>;
|
stream: WritableStream<Uint8Array>;
|
||||||
|
|
||||||
static __add(promises: any[], resolvers: any[]) {
|
static __add(
|
||||||
promises.push(new Promise((resolve) => {
|
promises: Promise<Uint8Array>[],
|
||||||
resolvers.push(resolve);
|
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<Uint8Array>[],
|
||||||
|
resolvers: ((value: Uint8Array) => void)[],
|
||||||
|
item: Uint8Array,
|
||||||
|
) {
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
if (!resolvers.length) AsyncStreamQueue.__add(promises, resolvers);
|
if (!resolvers.length)
|
||||||
const resolve = resolvers.shift();
|
AsyncStreamQueueUint8Array.__add(promises, resolvers);
|
||||||
|
const resolve = resolvers.shift()!;
|
||||||
resolve(item);
|
resolve(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,31 +70,37 @@ export class AsyncStreamQueue implements AsyncIterator<Uint8Array, undefined, Ui
|
|||||||
const resolvers = this.resolvers;
|
const resolvers = this.resolvers;
|
||||||
this.stream = new WritableStream({
|
this.stream = new WritableStream({
|
||||||
write(item) {
|
write(item) {
|
||||||
AsyncStreamQueue.__enqueue(closed, promises, resolvers, item)
|
AsyncStreamQueueUint8Array.__enqueue(closed, promises, resolvers, item);
|
||||||
|
},
|
||||||
}
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
_add() {
|
_add() {
|
||||||
return AsyncStreamQueue.__add(this.promises, this.resolvers);
|
return AsyncStreamQueueUint8Array.__add(this.promises, this.resolvers);
|
||||||
}
|
}
|
||||||
|
|
||||||
enqueue(item: Uint8Array) {
|
enqueue(item: Uint8Array) {
|
||||||
return AsyncStreamQueue.__enqueue(this.closed, this.promises, this.resolvers, item);
|
return AsyncStreamQueueUint8Array.__enqueue(
|
||||||
|
this.closed,
|
||||||
|
this.promises,
|
||||||
|
this.resolvers,
|
||||||
|
item,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
dequeue() {
|
dequeue() {
|
||||||
if (!this.promises.length) this._add();
|
if (!this.promises.length) this._add();
|
||||||
const item = this.promises.shift();
|
const item = this.promises.shift()!;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now some utilities:
|
// now some utilities:
|
||||||
isEmpty() { // there are no values available
|
isEmpty() {
|
||||||
|
// there are no values available
|
||||||
return !this.promises.length; // this.length <= 0
|
return !this.promises.length; // this.length <= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
isBlocked() { // it's waiting for values
|
isBlocked() {
|
||||||
|
// it's waiting for values
|
||||||
return !!this.resolvers.length; // this.length < 0
|
return !!this.resolvers.length; // this.length < 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +130,7 @@ export class AsyncStreamQueue implements AsyncIterator<Uint8Array, undefined, Ui
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
get locked() {
|
get locked() {
|
||||||
return this.stream.locked;
|
return this.stream.locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,77 +145,107 @@ export class AsyncStreamQueue implements AsyncIterator<Uint8Array, undefined, Ui
|
|||||||
getWriter() {
|
getWriter() {
|
||||||
return this.stream.getWriter();
|
return this.stream.getWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
let clientMsgStream = new AsyncStreamQueue("client");
|
let clientMsgStream = new AsyncStreamQueueUint8Array("client");
|
||||||
let serverMsgStream = new AsyncStreamQueue("server");
|
let serverMsgStream = new AsyncStreamQueueUint8Array("server");
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
let config = new ServerConfig(clientMsgStream, serverMsgStream);
|
let config = new ServerConfig(clientMsgStream, serverMsgStream);
|
||||||
await serve(config);
|
await serve(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fixup(data: { hasOwnProperty: (arg0: string) => any; params: { hasOwnProperty: (arg0: string) => any; rootUri: string; textDocument: { hasOwnProperty: (arg0: string) => any; uri: string; }; }; }) {
|
function fixup(data: {
|
||||||
if (data.hasOwnProperty("params") && data.params.hasOwnProperty("rootUri") && data.params.rootUri === "") {
|
hasOwnProperty: (arg0: string) => any;
|
||||||
data.params.rootUri = null
|
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")) {
|
if (data.params.textDocument.hasOwnProperty("uri")) {
|
||||||
const match = data.params.textDocument.uri.match(/^file:\/\/\/(.*)/);
|
const match = data.params.textDocument.uri.match(/^file:\/\/\/(.*)/);
|
||||||
if (null == match) {
|
if (null == match) {
|
||||||
data.params.textDocument.uri = `file:///${data.params.textDocument.uri}`;
|
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) {
|
function sendClient(data: any) {
|
||||||
data = fixup(data);
|
data = fixup(data);
|
||||||
const data_j = JSON.stringify(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));
|
clientMsgStream.enqueue(encoder.encode(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listen() {
|
async function listen() {
|
||||||
let contentLength = null;
|
let contentLength: number | null = null;
|
||||||
let buffer = new Uint8Array();
|
let buffer = new Uint8Array();
|
||||||
console.log("Worker: listening for lsp messages...");
|
console.log("Worker: listening for lsp messages...");
|
||||||
for await (const bytes of serverMsgStream) {
|
for await (const bytes of serverMsgStream) {
|
||||||
buffer = Bytes.append(Uint8Array, buffer, bytes);
|
buffer = Bytes.append(Uint8Array, buffer, bytes);
|
||||||
|
let waitingForFullContent = false;
|
||||||
|
let messagesThisLoop = 0;
|
||||||
|
|
||||||
// check if the content length is known
|
// sometimes the buffer can get more than one message in it, loop untill we need to wait for more.
|
||||||
if (null == contentLength) {
|
while (buffer.length > 0 && !waitingForFullContent) {
|
||||||
// if not, try to match the prefixed headers
|
// check if the content length is known
|
||||||
const match = Bytes.decode(buffer).match(/^Content-Length:\s*(\d+)\s*/);
|
if (null == contentLength) {
|
||||||
if (null == match) continue;
|
// 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
|
// try to parse the content-length from the headers
|
||||||
const length = parseInt(match[1]);
|
const length = parseInt(match[1]);
|
||||||
if (isNaN(length)) throw new Error("invalid content length");
|
if (isNaN(length)) throw new Error("invalid content length");
|
||||||
|
|
||||||
// slice the headers since we now have the content length
|
// slice the headers since we now have the content length
|
||||||
buffer = buffer.slice(match[0].length);
|
buffer = buffer.slice(match[0].length);
|
||||||
|
|
||||||
// set the content length
|
// set the content length
|
||||||
contentLength = 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?");
|
console.log("Worker: lsp message queue done?");
|
||||||
}
|
}
|
||||||
@@ -212,8 +256,8 @@ postMessage("ready");
|
|||||||
|
|
||||||
onmessage = function (e) {
|
onmessage = function (e) {
|
||||||
console.log("Client Message:", e.data);
|
console.log("Client Message:", e.data);
|
||||||
sendClient(e.data)
|
sendClient(e.data);
|
||||||
}
|
};
|
||||||
|
|
||||||
console.log("Starting LSP...");
|
console.log("Starting LSP...");
|
||||||
start();
|
start();
|
||||||
|
|||||||
@@ -3,27 +3,6 @@ import { Session } from "./session";
|
|||||||
import { VirtualMachine } from "./virtual_machine";
|
import { VirtualMachine } from "./virtual_machine";
|
||||||
import { docReady, openFile, saveFile } from "./utils";
|
import { docReady, openFile, saveFile } from "./utils";
|
||||||
// import { makeRequest } 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 = makeRequest({ method: "GET", url: "/data/database.json"});
|
||||||
// const dbPromise = fetch("/data/database.json").then(resp => resp.json());
|
// const dbPromise = fetch("/data/database.json").then(resp => resp.json());
|
||||||
|
|||||||
@@ -60,10 +60,6 @@ j ra
|
|||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface CustomEvent extends Event {
|
|
||||||
detail: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Session extends EventTarget {
|
export class Session extends EventTarget {
|
||||||
_programs: Map<number, string>;
|
_programs: Map<number, string>;
|
||||||
_activeSession: number;
|
_activeSession: number;
|
||||||
@@ -142,8 +138,8 @@ export class Session extends EventTarget {
|
|||||||
if (this._save_timeout) clearTimeout(this._save_timeout);
|
if (this._save_timeout) clearTimeout(this._save_timeout);
|
||||||
this._save_timeout = setTimeout(() => {
|
this._save_timeout = setTimeout(() => {
|
||||||
this.saveToFragment();
|
this.saveToFragment();
|
||||||
if (window.App.vm) {
|
if (window.App!.vm) {
|
||||||
window.App.vm.updateCode();
|
window.App!.vm.updateCode();
|
||||||
}
|
}
|
||||||
this._save_timeout = undefined;
|
this._save_timeout = undefined;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|||||||
@@ -1,417 +1,446 @@
|
|||||||
import { DeviceRef, VM, init } from "ic10emu_wasm";
|
import { DeviceRef, VM, init } from "ic10emu_wasm";
|
||||||
import { VMDeviceUI } from "./device";
|
import { VMDeviceUI } from "./device";
|
||||||
|
import { BaseElement } from "../components";
|
||||||
// import { Card } from 'bootstrap';
|
// import { Card } from 'bootstrap';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window { VM: VirtualMachine }
|
interface Window {
|
||||||
|
VM?: VirtualMachine;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeviceDB = {
|
type DeviceDB = {
|
||||||
logic_enabled: string[];
|
logic_enabled: string[];
|
||||||
slot_logic_enabled: string[];
|
slot_logic_enabled: string[];
|
||||||
devices: string[];
|
devices: string[];
|
||||||
items: {
|
items: {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
name: string,
|
name: string;
|
||||||
hash: number,
|
hash: number;
|
||||||
desc: string,
|
desc: string;
|
||||||
logic?: { [key: string]: string },
|
logic?: { [key: string]: string };
|
||||||
slots?: { name: string, type: string }[],
|
slots?: { name: string; type: string }[];
|
||||||
modes?: { [key: string]: string },
|
modes?: { [key: string]: string };
|
||||||
conn?: { [key: string]: string[] },
|
conn?: { [key: string]: string[] };
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
class VirtualMachine {
|
class VirtualMachine {
|
||||||
ic10vm: VM;
|
ic10vm: VM;
|
||||||
ui: VirtualMachineUI;
|
ui: VirtualMachineUI;
|
||||||
_devices: Map<number, DeviceRef>;
|
_devices: Map<number, DeviceRef>;
|
||||||
_ics: Map<number, DeviceRef>;
|
_ics: Map<number, DeviceRef>;
|
||||||
db: DeviceDB;
|
db: DeviceDB;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const vm = init();
|
const vm = init();
|
||||||
|
|
||||||
window.VM = this;
|
window.VM = this;
|
||||||
|
|
||||||
this.ic10vm = vm;
|
this.ic10vm = vm;
|
||||||
this.ui = new VirtualMachineUI(this);
|
// this.ui = new VirtualMachineUI(this);
|
||||||
|
|
||||||
this._devices = new Map();
|
this._devices = new Map();
|
||||||
this._ics = 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() {
|
const ics = this.ic10vm.ics;
|
||||||
return this._devices;
|
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()) {
|
||||||
get ics() {
|
if (!ics.includes(id)) {
|
||||||
return this._ics;
|
this._ics.get(id)!.free();
|
||||||
|
this._ics.delete(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get activeIC() {
|
updateCode() {
|
||||||
return this._ics.get(window.App.session.activeSession);
|
const progs = window.App!.session.programs;
|
||||||
}
|
for (const id of progs.keys()) {
|
||||||
|
const attempt = Date.now().toString(16);
|
||||||
updateDevices() {
|
const ic = this._ics.get(id);
|
||||||
|
const prog = progs.get(id);
|
||||||
const device_ids = this.ic10vm.devices;
|
if (ic && prog) {
|
||||||
for (const id of device_ids) {
|
console.time(`CompileProgram_${id}_${attempt}`);
|
||||||
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;
|
|
||||||
try {
|
try {
|
||||||
ic.setRegister(index, val);
|
this.ics.get(id)!.setCode(progs.get(id)!);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
|
console.timeEnd(`CompileProgram_${id}_${attempt}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
setStack(addr: number, val: number) {
|
step() {
|
||||||
const ic = this.activeIC;
|
const ic = this.activeIC;
|
||||||
try {
|
if (ic) {
|
||||||
ic.setStack(addr, val);
|
try {
|
||||||
} catch (e) {
|
ic.step(false);
|
||||||
console.log(e);
|
} catch (e) {
|
||||||
}
|
console.log(e);
|
||||||
|
}
|
||||||
|
this.update();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setupDeviceDatabase(db: DeviceDB) {
|
run() {
|
||||||
this.db = db;
|
const ic = this.activeIC;
|
||||||
console.log("Loaded Device Database", this.db);
|
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 {
|
class VirtualMachineUI {
|
||||||
vm: VirtualMachine;
|
vm: VirtualMachine;
|
||||||
state: VMStateUI;
|
state: VMStateUI;
|
||||||
registers: VMRegistersUI;
|
registers: VMRegistersUI;
|
||||||
stack: VMStackUI;
|
stack: VMStackUI;
|
||||||
devices: VMDeviceUI;
|
devices: VMDeviceUI;
|
||||||
|
|
||||||
constructor(vm: VirtualMachine) {
|
constructor(vm: VirtualMachine) {
|
||||||
this.vm = vm
|
this.vm = vm;
|
||||||
this.state = new VMStateUI(this);
|
this.state = new VMStateUI(this);
|
||||||
this.registers = new VMRegistersUI(this);
|
this.registers = new VMRegistersUI(this);
|
||||||
this.stack = new VMStackUI(this);
|
this.stack = new VMStackUI(this);
|
||||||
this.devices = new VMDeviceUI(this);
|
this.devices = new VMDeviceUI(this);
|
||||||
|
|
||||||
const that = this;
|
const that = this;
|
||||||
|
|
||||||
document.getElementById("vmControlRun").addEventListener('click', (_event) => {
|
document.getElementById("vmControlRun")!.addEventListener(
|
||||||
that.vm.run();
|
"click",
|
||||||
}, { capture: true });
|
(_event) => {
|
||||||
document.getElementById("vmControlStep").addEventListener('click', (_event) => {
|
that.vm.run();
|
||||||
that.vm.step();
|
},
|
||||||
}, { capture: true });
|
{ capture: true },
|
||||||
document.getElementById("vmControlReset").addEventListener('click', (_event) => {
|
);
|
||||||
that.vm.reset();
|
document.getElementById("vmControlStep")!.addEventListener(
|
||||||
}, { capture: true });
|
"click",
|
||||||
|
(_event) => {
|
||||||
}
|
that.vm.step();
|
||||||
|
},
|
||||||
update(ic: DeviceRef) {
|
{ capture: true },
|
||||||
this.state.update(ic);
|
);
|
||||||
this.registers.update(ic);
|
document.getElementById("vmControlReset")!.addEventListener(
|
||||||
this.stack.update(ic);
|
"click",
|
||||||
this.devices.update(ic);
|
(_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 {
|
class VMStateUI {
|
||||||
ui: VirtualMachineUI;
|
ui: VirtualMachineUI;
|
||||||
instructionPointer: HTMLElement;
|
instructionPointer: HTMLElement;
|
||||||
instructionCounter: HTMLElement;
|
instructionCounter: HTMLElement;
|
||||||
lastState: HTMLElement;
|
lastState: HTMLElement;
|
||||||
constructor(ui: VirtualMachineUI) {
|
constructor(ui: VirtualMachineUI) {
|
||||||
this.ui = ui;
|
this.ui = ui;
|
||||||
|
|
||||||
this.instructionPointer = document.getElementById("vmActiveICStateIP");
|
this.instructionPointer = document.getElementById("vmActiveICStateIP")!;
|
||||||
this.instructionCounter = document.getElementById("vmActiveICStateICount");
|
this.instructionCounter = document.getElementById("vmActiveICStateICount")!;
|
||||||
this.lastState = document.getElementById("vmActiveICStateLastRun");
|
this.lastState = document.getElementById("vmActiveICStateLastRun")!;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(ic: { ip: { toString: () => string; }; instructionCount: { toString: () => string; }; state: { toString: () => string; }; }) {
|
update(ic: DeviceRef) {
|
||||||
if (ic) {
|
if (ic) {
|
||||||
this.instructionPointer.innerText = ic.ip.toString();
|
this.instructionPointer.innerText = ic.ip!.toString();
|
||||||
this.instructionCounter.innerText = ic.instructionCount.toString();
|
this.instructionCounter.innerText = ic.instructionCount!.toString();
|
||||||
this.lastState.innerText = ic.state.toString();
|
this.lastState.innerText = ic.state!.toString();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VMRegistersUI {
|
class VMRegistersUI {
|
||||||
ui: VirtualMachineUI;
|
ui: VirtualMachineUI;
|
||||||
tbl: HTMLDivElement;
|
tbl: HTMLDivElement;
|
||||||
regCells: {
|
regCells: {
|
||||||
cell: HTMLDivElement,
|
cell: HTMLDivElement;
|
||||||
nameLabel: HTMLSpanElement,
|
nameLabel: HTMLSpanElement;
|
||||||
aliasesLabel: HTMLSpanElement,
|
aliasesLabel: HTMLSpanElement;
|
||||||
input: HTMLInputElement
|
input: HTMLInputElement;
|
||||||
}[];
|
}[];
|
||||||
default_aliases: Map<string, number>;
|
default_aliases: Map<string, number>;
|
||||||
ic_aliases: Map<string, number>;
|
ic_aliases: Map<string, number>;
|
||||||
constructor(ui: VirtualMachineUI) {
|
constructor(ui: VirtualMachineUI) {
|
||||||
const that = this;
|
const that = this;
|
||||||
this.ui = ui;
|
this.ui = ui;
|
||||||
const regDom = document.getElementById("vmActiveRegisters");
|
const regDom = document.getElementById("vmActiveRegisters")!;
|
||||||
this.tbl = document.createElement("div");
|
this.tbl = document.createElement("div");
|
||||||
this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-end",);
|
this.tbl.classList.add(
|
||||||
this.regCells = [];
|
"d-flex",
|
||||||
for (var i = 0; i < 18; i++) {
|
"flex-wrap",
|
||||||
const container = document.createElement("div");
|
"justify-content-start",
|
||||||
container.classList.add("vm_reg_cel", "align-that-stretch");
|
"align-items-end",
|
||||||
const cell = document.createElement("div");
|
);
|
||||||
cell.classList.add("input-group", "input-group-sm")
|
this.regCells = [];
|
||||||
// cell.style.width = "30%";
|
for (var i = 0; i < 18; i++) {
|
||||||
const nameLabel = document.createElement("span");
|
const container = document.createElement("div");
|
||||||
nameLabel.innerText = `r${i}`;
|
container.classList.add("vm_reg_cel", "align-that-stretch");
|
||||||
nameLabel.classList.add("input-group-text")
|
const cell = document.createElement("div");
|
||||||
cell.appendChild(nameLabel);
|
cell.classList.add("input-group", "input-group-sm");
|
||||||
const input = document.createElement("input");
|
// cell.style.width = "30%";
|
||||||
input.type = "text"
|
const nameLabel = document.createElement("span");
|
||||||
input.value = (0).toString();
|
nameLabel.innerText = `r${i}`;
|
||||||
input.dataset.index = i.toString();
|
nameLabel.classList.add("input-group-text");
|
||||||
cell.appendChild(input);
|
cell.appendChild(nameLabel);
|
||||||
const aliasesLabel = document.createElement("span");
|
const input = document.createElement("input");
|
||||||
aliasesLabel.classList.add("input-group-text", "reg_label")
|
input.type = "text";
|
||||||
cell.appendChild(aliasesLabel);
|
input.value = (0).toString();
|
||||||
this.regCells.push({
|
input.dataset.index = i.toString();
|
||||||
cell,
|
cell.appendChild(input);
|
||||||
nameLabel,
|
const aliasesLabel = document.createElement("span");
|
||||||
aliasesLabel,
|
aliasesLabel.classList.add("input-group-text", "reg_label");
|
||||||
input,
|
cell.appendChild(aliasesLabel);
|
||||||
});
|
this.regCells.push({
|
||||||
container.appendChild(cell);
|
cell,
|
||||||
this.tbl.appendChild(container);
|
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);
|
const aliases = ic.aliases;
|
||||||
});
|
if (aliases) {
|
||||||
this.default_aliases = new Map([["sp", 16], ["ra", 17]]);
|
|
||||||
this.ic_aliases = new Map();
|
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<number, string[]>();
|
||||||
|
for (const [alias, target] of aliases) {
|
||||||
|
if (labels.hasOwnProperty(target)) {
|
||||||
|
labels.get(target)!.push(alias);
|
||||||
|
} else {
|
||||||
|
labels.set(target, [alias]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onCellUpdate(e: Event) {
|
for (const [index, label_list] of labels) {
|
||||||
let index;
|
this.regCells[index].aliasesLabel.innerText = label_list.join(", ");
|
||||||
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<number, string[]>();
|
|
||||||
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(", ")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VMStackUI {
|
class VMStackUI {
|
||||||
ui: VirtualMachineUI;
|
ui: VirtualMachineUI;
|
||||||
tbl: HTMLDivElement;
|
tbl: HTMLDivElement;
|
||||||
stackCells: { cell: HTMLDivElement, nameLabel: HTMLSpanElement, input: HTMLInputElement }[];
|
stackCells: {
|
||||||
constructor(ui: VirtualMachineUI) {
|
cell: HTMLDivElement;
|
||||||
this.ui = ui;
|
nameLabel: HTMLSpanElement;
|
||||||
const stackDom = document.getElementById("vmActiveStack");
|
input: HTMLInputElement;
|
||||||
this.tbl = document.createElement("div");
|
}[];
|
||||||
this.tbl.classList.add("d-flex", "flex-wrap", "justify-content-start", "align-items-end",);
|
constructor(ui: VirtualMachineUI) {
|
||||||
this.stackCells = [];
|
this.ui = ui;
|
||||||
for (var i = 0; i < 512; i++) {
|
const stackDom = document.getElementById("vmActiveStack")!;
|
||||||
const container = document.createElement("div");
|
this.tbl = document.createElement("div");
|
||||||
container.classList.add("vm_stack_cel", "align-that-stretch");
|
this.tbl.classList.add(
|
||||||
const cell = document.createElement("div");
|
"d-flex",
|
||||||
cell.classList.add("input-group", "input-group-sm")
|
"flex-wrap",
|
||||||
const nameLabel = document.createElement("span");
|
"justify-content-start",
|
||||||
nameLabel.innerText = `${i}`;
|
"align-items-end",
|
||||||
nameLabel.classList.add("input-group-text")
|
);
|
||||||
cell.appendChild(nameLabel);
|
this.stackCells = [];
|
||||||
const input = document.createElement("input");
|
for (var i = 0; i < 512; i++) {
|
||||||
input.type = "text"
|
const container = document.createElement("div");
|
||||||
input.value = (0).toString();
|
container.classList.add("vm_stack_cel", "align-that-stretch");
|
||||||
input.dataset.index = i.toString();
|
const cell = document.createElement("div");
|
||||||
cell.appendChild(input);
|
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({
|
this.stackCells.push({
|
||||||
cell,
|
cell,
|
||||||
nameLabel,
|
nameLabel,
|
||||||
input,
|
input,
|
||||||
});
|
});
|
||||||
container.appendChild(cell);
|
container.appendChild(cell);
|
||||||
this.tbl.appendChild(container);
|
this.tbl.appendChild(container);
|
||||||
}
|
|
||||||
this.stackCells.forEach(cell => {
|
|
||||||
cell.input.addEventListener('change', this.onCellUpdate);
|
|
||||||
});
|
|
||||||
stackDom.appendChild(this.tbl);
|
|
||||||
}
|
}
|
||||||
|
this.stackCells.forEach((cell) => {
|
||||||
|
cell.input.addEventListener("change", this.onCellUpdate);
|
||||||
|
});
|
||||||
|
stackDom.appendChild(this.tbl);
|
||||||
|
}
|
||||||
|
|
||||||
onCellUpdate(e: Event) {
|
onCellUpdate(e: Event) {
|
||||||
let index;
|
let index: number;
|
||||||
let val;
|
let val: number;
|
||||||
let target = e.target as HTMLInputElement;
|
let target = e.target as HTMLInputElement;
|
||||||
try {
|
try {
|
||||||
index = parseInt(target.dataset.index);
|
index = parseInt(target.dataset.index!);
|
||||||
val = parseFloat(target.value);
|
val = parseFloat(target.value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// reset the edit
|
// reset the edit
|
||||||
window.VM.update();
|
window.VM!.update();
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
window.VM.setStack(index, val);
|
|
||||||
}
|
}
|
||||||
|
window.VM!.setStack(index, val);
|
||||||
|
}
|
||||||
|
|
||||||
update(ic: { stack: any; registers: any[]; }) {
|
update(ic: DeviceRef) {
|
||||||
const that = this;
|
if (ic) {
|
||||||
if (ic) {
|
const stack = ic.stack;
|
||||||
const stack = ic.stack;
|
const sp = ic.registers![16];
|
||||||
const sp = ic.registers[16];
|
if (stack) {
|
||||||
if (stack) {
|
for (var i = 0; i < stack.length; i++) {
|
||||||
for (var i = 0; i < stack.length; i++) {
|
this.stackCells[i].input.value = stack[i].toString();
|
||||||
this.stackCells[i].input.value = stack[i];
|
if (i == sp) {
|
||||||
if (i == sp) {
|
this.stackCells[i].nameLabel.classList.add("stack_pointer");
|
||||||
this.stackCells[i].nameLabel.classList.add("stack_pointer");
|
} else {
|
||||||
} else {
|
this.stackCells[i].nameLabel.classList.remove("stack_pointer");
|
||||||
this.stackCells[i].nameLabel.classList.remove("stack_pointer");
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { VirtualMachine, VirtualMachineUI , DeviceDB };
|
export { VirtualMachine, VirtualMachineUI, DeviceDB };
|
||||||
|
|||||||
Reference in New Issue
Block a user