diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 78174f6..a9846fa 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -7,5 +7,6 @@ module.exports = {
plugins: ["react-refresh"],
rules: {
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
+ "no-console": ["warn", { allow: ["warn", "error"] }],
},
};
diff --git a/package-lock.json b/package-lock.json
index ee4960c..c626235 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -39,6 +39,7 @@
"react-json-view-compare": "^2.0.2",
"react-katex": "^3.0.1",
"react-redux": "^9.1.2",
+ "react-toastify": "^10.0.6",
"scale-codec": "^0.13.0",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
@@ -6370,6 +6371,18 @@
}
}
},
+ "node_modules/react-toastify": {
+ "version": "10.0.6",
+ "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.6.tgz",
+ "integrity": "sha512-yYjp+omCDf9lhZcrZHKbSq7YMuK0zcYkDFTzfRFgTXkTFHZ1ToxwAonzA4JI5CxA91JpjFLmwEsZEgfYfOqI1A==",
+ "dependencies": {
+ "clsx": "^2.1.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
diff --git a/package.json b/package.json
index 2bacc46..ec7d436 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"react-json-view-compare": "^2.0.2",
"react-katex": "^3.0.1",
"react-redux": "^9.1.2",
+ "react-toastify": "^10.0.6",
"scale-codec": "^0.13.0",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
diff --git a/src/App.tsx b/src/App.tsx
index 418aeb9..cb7f935 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,4 +1,7 @@
import "./App.css";
+import { ToastContainer } from "react-toastify";
+import "react-toastify/dist/ReactToastify.css";
+
import { Button } from "@/components/ui/button";
import { useCallback, useEffect, useRef } from "react";
import { Instructions } from "./components/Instructions";
@@ -51,6 +54,7 @@ import {
setPvmInitialized,
} from "@/store/debugger/debuggerSlice.ts";
import { MemoryPreview } from "@/components/MemoryPreview";
+import { logger } from "./utils/loggerService";
function App() {
const {
@@ -131,12 +135,12 @@ function App() {
try {
const result = disassemblify(new Uint8Array(newProgram));
- console.info("Disassembly result:", result);
+ logger.info("Disassembly result:", result);
dispatch(setProgramPreviewResult(result));
dispatch(setAllWorkersCurrentInstruction(result?.[0]));
dispatch(setPvmInitialized(true));
} catch (e) {
- console.log("Error disassembling program", e);
+ console.error("Error disassembling program", e);
}
},
[dispatch],
@@ -206,7 +210,7 @@ function App() {
};
const handlePvmTypeChange = async (selectedPvms: SelectedPvmWithPayload[]) => {
- console.log("selectedPvms vs workers ", selectedPvms, workers);
+ logger.debug("selectedPvms vs workers ", selectedPvms, workers);
await Promise.all(
workers.map((worker: WorkerState) => {
@@ -216,13 +220,13 @@ function App() {
await Promise.all(
selectedPvms.map(async ({ id, type, params }) => {
- console.log("Selected PVM type", id, type, params);
+ logger.info("Selected PVM type", id, type, params);
if (workers.find((worker: WorkerState) => worker.id === id)) {
- console.log("Worker already initialized");
+ logger.info("Worker already initialized");
// TODO: for now just initialize the worker one more time
}
- console.log("Worker not initialized");
+ logger.info("Worker not initialized");
if (id === AvailablePvms.POLKAVM) {
await dispatch(createWorker(AvailablePvms.POLKAVM)).unwrap();
@@ -246,7 +250,6 @@ function App() {
}),
).unwrap();
} else if (type === AvailablePvms.WASM_FILE) {
- console.log("go wasm file!", id, type, params);
await dispatch(createWorker(id)).unwrap();
await dispatch(
loadWorker({
@@ -419,6 +422,7 @@ function App() {
+
>
);
}
diff --git a/src/components/KnowledgeBase/index.tsx b/src/components/KnowledgeBase/index.tsx
index b6c768d..50bca03 100644
--- a/src/components/KnowledgeBase/index.tsx
+++ b/src/components/KnowledgeBase/index.tsx
@@ -48,7 +48,7 @@ export const KnowledgeBase = ({ currentInstruction }: { currentInstruction: Curr
{instruction?.name}
-
+
{currentInstructionFromKnowledgeBase?.description}
diff --git a/src/components/ProgramLoader/Assembly.tsx b/src/components/ProgramLoader/Assembly.tsx
index 6e8a671..57e2e36 100644
--- a/src/components/ProgramLoader/Assembly.tsx
+++ b/src/components/ProgramLoader/Assembly.tsx
@@ -144,7 +144,7 @@ export const Assembly = ({
return;
}
}
- console.log(e);
+ console.error(e);
onProgramLoad(undefined);
setError(`${e}`);
}
diff --git a/src/components/ProgramTextLoader/index.tsx b/src/components/ProgramTextLoader/index.tsx
index 5e48361..83baf5b 100644
--- a/src/components/ProgramTextLoader/index.tsx
+++ b/src/components/ProgramTextLoader/index.tsx
@@ -27,7 +27,7 @@ export const ProgramTextLoader = ({
setProgram(Array.prototype.slice.call(parsedBlob.buffer));
} catch (e) {
console.warn(e);
- console.log("wrong binary file");
+ console.error("wrong binary file");
setIsInvalidProgram(true);
}
} else {
@@ -36,7 +36,8 @@ export const ProgramTextLoader = ({
setProgram(JSON.parse(newInput));
setIsInvalidProgram(false);
} catch (e) {
- console.log("wrong json");
+ // TODO only validate on submit
+ console.error("wrong json");
setIsInvalidProgram(true);
setProgram();
}
diff --git a/src/components/PvmSelect/index.tsx b/src/components/PvmSelect/index.tsx
index 99331f6..472e242 100644
--- a/src/components/PvmSelect/index.tsx
+++ b/src/components/PvmSelect/index.tsx
@@ -45,7 +45,7 @@ const fetchWasmMetadata = async (url: string): Promise
alert("Invalid URL");
}
} catch (error) {
- console.log(error);
+ console.error(error);
alert("Invalid URL");
}
return;
diff --git a/src/context/NumeralSystemProvider.tsx b/src/context/NumeralSystemProvider.tsx
index d318b09..0587a92 100644
--- a/src/context/NumeralSystemProvider.tsx
+++ b/src/context/NumeralSystemProvider.tsx
@@ -3,9 +3,8 @@ import { NumeralSystem } from "./NumeralSystem";
export const NumeralSystemContext = createContext({
numeralSystem: NumeralSystem.DECIMAL,
- setNumeralSystem: (numeralSystem: NumeralSystem) => {
- console.log(numeralSystem);
- },
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ setNumeralSystem: (_: NumeralSystem) => {},
});
export const NumeralSystemProvider = ({ children }: { children: ReactNode }) => {
diff --git a/src/globals.css b/src/globals.css
index d0863a9..1e610ae 100644
--- a/src/globals.css
+++ b/src/globals.css
@@ -29,6 +29,8 @@
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
+
+ --toastify-toast-width: 350px;
}
.dark {
diff --git a/src/packages/web-worker/command-handlers/index.ts b/src/packages/web-worker/command-handlers/index.ts
new file mode 100644
index 0000000..5440aed
--- /dev/null
+++ b/src/packages/web-worker/command-handlers/index.ts
@@ -0,0 +1,9 @@
+import { runInit } from "./init";
+import { runLoad } from "./load";
+import { runStep } from "./step";
+
+export default {
+ runInit,
+ runLoad,
+ runStep,
+};
diff --git a/src/packages/web-worker/command-handlers/init.ts b/src/packages/web-worker/command-handlers/init.ts
new file mode 100644
index 0000000..be157d3
--- /dev/null
+++ b/src/packages/web-worker/command-handlers/init.ts
@@ -0,0 +1,59 @@
+import { InitialState } from "@/types/pvm";
+import { initPvm } from "../pvm";
+import { getState, isInternalPvm, regsAsUint8 } from "../utils";
+import { CommandStatus, PvmApiInterface } from "../worker";
+import { Pvm as InternalPvmInstance } from "@typeberry/pvm-debugger-adapter";
+import { logger } from "@/utils/loggerService";
+
+export type InitParams = {
+ pvm: PvmApiInterface | null;
+ program: Uint8Array;
+ initialState: InitialState;
+};
+export type InitResponse = {
+ initialState: InitialState;
+ status: CommandStatus;
+ error?: unknown;
+};
+
+const init = async ({ pvm, program, initialState }: InitParams) => {
+ if (!pvm) {
+ throw new Error("PVM is uninitialized.");
+ }
+ if (isInternalPvm(pvm)) {
+ logger.info("PVM init internal", pvm);
+ // TODO Fix type guards
+ initPvm(pvm as InternalPvmInstance, program, initialState);
+ } else {
+ logger.info("PVM init external", pvm);
+ const gas = initialState.gas || 10000;
+ pvm.reset(program, regsAsUint8(initialState.regs), BigInt(gas));
+ pvm.setNextProgramCounter(initialState.pc ?? 0);
+ pvm.setGasLeft(BigInt(gas));
+ }
+};
+
+export const runInit = async ({ pvm, program, initialState }: InitParams): Promise => {
+ if (program.length === 0) {
+ console.warn("Skipping init, no program yet.");
+ return {
+ status: CommandStatus.SUCCESS,
+ initialState: {},
+ };
+ }
+
+ try {
+ await init({ pvm, program, initialState });
+
+ return {
+ status: CommandStatus.SUCCESS,
+ initialState: pvm ? getState(pvm) : {},
+ };
+ } catch (error) {
+ return {
+ status: CommandStatus.ERROR,
+ error,
+ initialState: pvm ? getState(pvm) : {},
+ };
+ }
+};
diff --git a/src/packages/web-worker/command-handlers/load.ts b/src/packages/web-worker/command-handlers/load.ts
new file mode 100644
index 0000000..2487b00
--- /dev/null
+++ b/src/packages/web-worker/command-handlers/load.ts
@@ -0,0 +1,50 @@
+import { logger } from "@/utils/loggerService";
+import { loadArrayBufferAsWasm, SupportedLangs } from "../utils";
+import { CommandStatus, PvmApiInterface, PvmTypes } from "../worker";
+import { Pvm as InternalPvmInstance } from "@typeberry/pvm-debugger-adapter";
+
+export type LoadParams = { type: PvmTypes; params: { url?: string; file?: Blob; lang?: SupportedLangs } };
+export type LoadResponse = { pvm: PvmApiInterface | null; status: CommandStatus; error?: unknown };
+
+const load = async (args: LoadParams): Promise => {
+ if (args.type === PvmTypes.BUILT_IN) {
+ return new InternalPvmInstance();
+ } else if (args.type === PvmTypes.WASM_FILE) {
+ const file = args.params.file;
+ if (!file) {
+ throw new Error("No PVM file");
+ }
+
+ logger.info("Load WASM from file", file);
+ const bytes = await file.arrayBuffer();
+ return await loadArrayBufferAsWasm(bytes);
+ } else if (args.type === PvmTypes.WASM_URL) {
+ const url = args.params.url ?? "";
+ const isValidUrl = Boolean(new URL(url));
+
+ if (!isValidUrl) {
+ throw new Error("Invalid PVM URL");
+ }
+
+ logger.info("Load WASM from URL", url);
+ const response = await fetch(url);
+ const bytes = await response.arrayBuffer();
+
+ return await loadArrayBufferAsWasm(bytes, args.params.lang);
+ }
+
+ return null;
+};
+
+export const runLoad = async (args: LoadParams): Promise => {
+ try {
+ const pvm = await load(args);
+ if (pvm) {
+ return { pvm, status: CommandStatus.SUCCESS };
+ }
+ } catch (error) {
+ return { pvm: null, status: CommandStatus.ERROR, error };
+ }
+
+ return { pvm: null, status: CommandStatus.ERROR, error: new Error("Unknown PVM type") };
+};
diff --git a/src/packages/web-worker/command-handlers/step.ts b/src/packages/web-worker/command-handlers/step.ts
new file mode 100644
index 0000000..37f4b41
--- /dev/null
+++ b/src/packages/web-worker/command-handlers/step.ts
@@ -0,0 +1,40 @@
+import { CurrentInstruction, ExpectedState, Status } from "@/types/pvm";
+import { nextInstruction } from "../pvm";
+import { isInternalPvm, getState } from "../utils";
+import { CommandStatus, PvmApiInterface } from "../worker";
+
+export type StepParams = { program: number[]; pvm: PvmApiInterface | null };
+export type StepResponse = {
+ status: CommandStatus;
+ error?: unknown;
+ result: CurrentInstruction | object;
+ state: ExpectedState;
+ isFinished: boolean;
+};
+
+const step = ({ pvm, program }: StepParams) => {
+ if (!pvm) {
+ throw new Error("PVM is uninitialized.");
+ }
+
+ let isFinished: boolean;
+ if (isInternalPvm(pvm)) {
+ isFinished = pvm.nextStep() !== Status.OK;
+ } else {
+ isFinished = !pvm.nextStep();
+ }
+
+ const state = getState(pvm);
+ const result = nextInstruction(state.pc ?? 0, program) as unknown as CurrentInstruction;
+
+ return { result, state, isFinished };
+};
+
+export const runStep = ({ pvm, program }: StepParams): StepResponse => {
+ try {
+ const data = step({ pvm, program });
+ return { status: CommandStatus.SUCCESS, ...data };
+ } catch (error) {
+ return { status: CommandStatus.ERROR, error, isFinished: true, result: {}, state: {} };
+ }
+};
diff --git a/src/packages/web-worker/pvm.ts b/src/packages/web-worker/pvm.ts
index 9f0bf21..f3282b9 100644
--- a/src/packages/web-worker/pvm.ts
+++ b/src/packages/web-worker/pvm.ts
@@ -3,7 +3,7 @@ import { createResults, instructionArgumentTypeMap, ProgramDecoder } from "@type
import { ArgsDecoder, Registers } from "@typeberry/pvm-debugger-adapter";
import { byteToOpCodeMap } from "../../packages/pvm/pvm/assemblify";
import { Pvm as InternalPvmInstance, MemoryBuilder as InternalPvmMemoryBuilder } from "@typeberry/pvm-debugger-adapter";
-export const initPvm = (pvm: InternalPvmInstance, program: number[], initialState: InitialState) => {
+export const initPvm = (pvm: InternalPvmInstance, program: Uint8Array, initialState: InitialState) => {
const initialMemory = initialState.memory ?? [];
const pageMap = initialState.pageMap ?? [];
@@ -32,7 +32,6 @@ export const initPvm = (pvm: InternalPvmInstance, program: number[], initialStat
const registers = new Registers();
registers.copyFrom(new Uint32Array(initialState.regs!));
pvm.reset(new Uint8Array(program), initialState.pc ?? 0, initialState.gas ?? 0, registers, memory);
- return pvm;
};
export const runAllInstructions = (pvm: InternalPvm, program: number[]) => {
diff --git a/src/packages/web-worker/utils.ts b/src/packages/web-worker/utils.ts
index 9f93588..d8b556a 100644
--- a/src/packages/web-worker/utils.ts
+++ b/src/packages/web-worker/utils.ts
@@ -5,6 +5,7 @@ import { createWasmPvmShell } from "@/packages/web-worker/wasmPvmShell.ts";
import "./goWasmExec.js";
import "./goWasmExec.d.ts";
import { createGoWasmPvmShell } from "@/packages/web-worker/wasmGoPvmShell.ts";
+import { logger } from "@/utils/loggerService.tsx";
export enum SupportedLangs {
Go = "Go",
@@ -66,13 +67,13 @@ export async function loadArrayBufferAsWasm(bytes: ArrayBuffer, lang?: Supported
const go = new Go();
const wasmModule = await WebAssembly.instantiate(bytes, go.importObject);
go.run(wasmModule.instance);
- console.log("Go WASM module loaded", wasmModule.instance.exports);
+ logger.info("Go WASM module loaded", wasmModule.instance.exports);
const wasmPvmShell = createGoWasmPvmShell();
wasmPvmShell.__wbg_set_wasm(wasmModule.instance.exports);
return wasmPvmShell;
} else {
const wasmModule = await WebAssembly.instantiate(bytes, {});
- console.log("Rust WASM module loaded", wasmModule.instance.exports);
+ logger.info("Rust WASM module loaded", wasmModule.instance.exports);
const wasmPvmShell = createWasmPvmShell();
wasmPvmShell.__wbg_set_wasm(wasmModule.instance.exports);
return wasmPvmShell;
@@ -80,7 +81,6 @@ export async function loadArrayBufferAsWasm(bytes: ArrayBuffer, lang?: Supported
}
export function getMemoryPage(pageNumber: number, pvm: PvmApiInterface | null) {
- console.log("getMemoryPage", pageNumber, pvm);
if (!pvm) {
return [];
}
@@ -88,6 +88,5 @@ export function getMemoryPage(pageNumber: number, pvm: PvmApiInterface | null) {
if (isInternalPvm(pvm)) {
return pvm.getMemoryPage(pageNumber) || [];
}
- console.log("getpagedump", pageNumber, pvm.getPageDump(pageNumber));
return pvm.getPageDump(pageNumber) || [];
}
diff --git a/src/packages/web-worker/worker.ts b/src/packages/web-worker/worker.ts
index 192a305..a668e92 100644
--- a/src/packages/web-worker/worker.ts
+++ b/src/packages/web-worker/worker.ts
@@ -1,15 +1,8 @@
-import { CurrentInstruction, ExpectedState, InitialState, Pvm as InternalPvm, Status } from "@/types/pvm";
-import { initPvm, nextInstruction } from "./pvm";
-import {
- getMemoryPage,
- getState,
- isInternalPvm,
- loadArrayBufferAsWasm,
- regsAsUint8,
- SupportedLangs,
-} from "@/packages/web-worker/utils.ts";
+import { CurrentInstruction, ExpectedState, InitialState, Pvm as InternalPvm } from "@/types/pvm";
+import { getMemoryPage, SupportedLangs } from "@/packages/web-worker/utils.ts";
import { WasmPvmShellInterface } from "@/packages/web-worker/wasmPvmShell.ts";
-import { Pvm as InternalPvmInstance } from "@typeberry/pvm-debugger-adapter";
+import commandHandlers from "./command-handlers";
+import { logger } from "@/utils/loggerService";
export enum Commands {
LOAD = "load",
@@ -28,7 +21,7 @@ export enum PvmTypes {
WASM_FILE = "wasm-file",
}
-export enum CommandResult {
+export enum CommandStatus {
SUCCESS = "success",
ERROR = "error",
}
@@ -39,11 +32,13 @@ let pvm: PvmApiInterface | null = null;
let isRunMode = false;
export type TargetOnMessageParams =
- | { command: Commands.LOAD; result: CommandResult }
- | { command: Commands.INIT; payload: { initialState: InitialState } }
+ | { command: Commands.LOAD; status: CommandStatus; error?: unknown }
+ | { command: Commands.INIT; status: CommandStatus; error?: unknown; payload: { initialState: InitialState } }
| {
command: Commands.STEP;
- payload: { state: ExpectedState; result: CurrentInstruction; isFinished: boolean; isRunMode: boolean };
+ status: CommandStatus;
+ error?: unknown;
+ payload: { state: ExpectedState; result: CurrentInstruction | object; isFinished: boolean; isRunMode: boolean };
}
| { command: Commands.RUN; payload: { state: ExpectedState; isFinished: boolean; isRunMode: boolean } }
| { command: Commands.STOP; payload: { isRunMode: boolean } }
@@ -56,7 +51,7 @@ export type WorkerOnMessageParams =
command: Commands.LOAD;
payload: { type: PvmTypes; params: { url?: string; file?: Blob; lang?: SupportedLangs } };
}
- | { command: Commands.INIT; payload: { program: number[]; initialState: InitialState } }
+ | { command: Commands.INIT; payload: { program: Uint8Array; initialState: InitialState } }
| { command: Commands.STEP; payload: { program: number[] } }
| { command: Commands.RUN }
| { command: Commands.STOP }
@@ -64,7 +59,7 @@ export type WorkerOnMessageParams =
| { command: Commands.MEMORY_RANGE; payload: { start: number; end: number } }
| { command: Commands.MEMORY_SIZE };
-function postTypedMessage(msg: TargetOnMessageParams) {
+export function postTypedMessage(msg: TargetOnMessageParams) {
postMessage(msg);
}
@@ -72,107 +67,38 @@ onmessage = async (e: MessageEvent) => {
if (!e.data?.command) {
return;
}
+ logger.info("Worker received message", e.data);
- let result;
let state;
// let program;
let isFinished;
if (e.data.command === Commands.LOAD) {
- if (e.data.payload.type === PvmTypes.BUILT_IN) {
- pvm = new InternalPvmInstance();
- postMessage({ command: Commands.LOAD, result: CommandResult.SUCCESS });
- }
- if (e.data.payload.type === PvmTypes.WASM_FILE) {
- try {
- const file = e.data.payload.params.file;
- if (!file) {
- throw new Error("No PVM file");
- }
-
- console.log("Load WASM from file", file);
- const bytes = await file.arrayBuffer();
- pvm = await loadArrayBufferAsWasm(bytes, e.data.payload.params.lang);
-
- postTypedMessage({ command: Commands.LOAD, result: CommandResult.SUCCESS });
- } catch (error) {
- console.error(error);
- postTypedMessage({ command: Commands.LOAD, result: CommandResult.ERROR });
- }
- }
- if (e.data.payload.type === PvmTypes.WASM_URL) {
- try {
- const url = e.data.payload.params.url ?? "";
- const isValidUrl = Boolean(new URL(url));
-
- if (!isValidUrl) {
- throw new Error("Invalid PVM URL");
- }
-
- console.log("Load WASM from URL", url);
- const response = await fetch(url);
- const bytes = await response.arrayBuffer();
- pvm = await loadArrayBufferAsWasm(bytes);
-
- postTypedMessage({ command: Commands.LOAD, result: CommandResult.SUCCESS });
- } catch (error) {
- console.error(error);
- postTypedMessage({ command: Commands.LOAD, result: CommandResult.ERROR });
- }
- }
+ const data = await commandHandlers.runLoad(e.data.payload);
+ pvm = data.pvm;
+ postTypedMessage({ command: Commands.LOAD, status: data.status, error: data.error });
} else if (e.data.command === Commands.INIT) {
- if (e.data.payload.program.length === 0) {
- console.warn("Skipping init, no program yet.");
- postTypedMessage({
- command: Commands.INIT,
- payload: {
- initialState: {},
- },
- });
- } else {
- if (!pvm) {
- throw new Error("PVM is uninitialized.");
- }
- if (isInternalPvm(pvm)) {
- console.log("PVM init", pvm);
- pvm = initPvm(pvm as InternalPvmInstance, e.data.payload.program, e.data.payload.initialState);
- } else {
- console.log("PVM reset", pvm);
- const gas = e.data.payload.initialState.gas || 10000;
- pvm.reset(
- // TODO: check root cause of this type error
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-expect-error
- e.data.payload.program,
- regsAsUint8(e.data.payload.initialState.regs),
- BigInt(gas),
- );
- pvm.setNextProgramCounter(e.data.payload.initialState.pc ?? 0);
- pvm.setGasLeft(BigInt(gas));
- }
+ const data = await commandHandlers.runInit({
+ pvm,
+ program: e.data.payload.program,
+ initialState: e.data.payload.initialState,
+ });
- postTypedMessage({
- command: Commands.INIT,
- payload: {
- initialState: pvm ? getState(pvm) : {},
- },
- });
- }
+ postTypedMessage({
+ command: Commands.INIT,
+ status: data.status,
+ error: data.error,
+ payload: {
+ initialState: data.initialState,
+ },
+ });
} else if (e.data.command === Commands.STEP) {
- if (!pvm) {
- throw new Error("PVM is uninitialized.");
- }
- if (isInternalPvm(pvm)) {
- isFinished = pvm.nextStep() !== Status.OK;
- } else {
- isFinished = !pvm.nextStep();
- }
- if (isFinished) {
- isRunMode = false;
- }
- state = getState(pvm);
- result = nextInstruction(state.pc ?? 0, e.data.payload.program) as unknown as CurrentInstruction;
+ const { result, state, isFinished, status, error } = commandHandlers.runStep({
+ pvm,
+ program: e.data.payload.program,
+ });
+ isRunMode = !isFinished;
- postTypedMessage({ command: Commands.STEP, payload: { result, state, isFinished, isRunMode } });
+ postTypedMessage({ command: Commands.STEP, status, error, payload: { result, state, isFinished, isRunMode } });
} else if (e.data.command === Commands.RUN) {
isRunMode = true;
postTypedMessage({ command: Commands.RUN, payload: { isRunMode, isFinished: true, state: state ?? {} } });
@@ -197,14 +123,13 @@ onmessage = async (e: MessageEvent) => {
// Get first page to check the memory size
const memoryPage = getMemoryPage(0, pvm);
- console.log("memoryPage", memoryPage);
postMessage({
command: Commands.MEMORY_SIZE,
// TODO fix types
payload: { pageNumber: 0, memorySize: (memoryPage as unknown as Array)?.length },
});
}
- // TODO uncomennet and finish implementation
+ // TODO uncomment and finish implementation
// else if (e.data.command === Commands.MEMORY_RANGE) {
// const memoryRange = Object.values(memory).flat().slice(e.data.payload.start, e.data.payload.end);
// postMessage({
diff --git a/src/store/workers/workersSlice.ts b/src/store/workers/workersSlice.ts
index d26bd35..5651190 100644
--- a/src/store/workers/workersSlice.ts
+++ b/src/store/workers/workersSlice.ts
@@ -6,6 +6,7 @@ import { Commands, PvmTypes, TargetOnMessageParams } from "@/packages/web-worker
import PvmWorker from "@/packages/web-worker/worker?worker&inline";
import { SupportedLangs } from "@/packages/web-worker/utils.ts";
import { virtualTrapInstruction } from "@/utils/virtualTrapInstruction.ts";
+import { logger } from "@/utils/loggerService";
// TODO: remove this when found a workaround for BigInt support in JSON.stringify
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -71,10 +72,20 @@ export const loadWorker = createAsyncThunk(
}
return new Promise((resolve) => {
- const messageHandler = (event: MessageEvent) => {
+ const messageHandler = (event: MessageEvent) => {
+ if ("status" in event.data && event.data.status === "error") {
+ logger.error(`An error occured on command ${event.data.command}`, { error: event.data.error });
+ }
+
if (event.data.command === Commands.LOAD) {
- resolve(true);
- worker.worker.removeEventListener("message", messageHandler);
+ if (event.data.status === "success") {
+ resolve(true);
+ worker.worker.removeEventListener("message", messageHandler);
+ } else if (event.data.status === "error") {
+ resolve(false);
+ logger.error("Error loading PVM worker", { error: event.data.error });
+ worker.worker.removeEventListener("message", messageHandler);
+ }
}
};
@@ -104,6 +115,10 @@ export const initAllWorkers = createAsyncThunk("workers/initAllWorkers", async (
});
globalMessageHandlers[worker.id] = (event: MessageEvent) => {
+ if ("status" in event.data && event.data.status === "error") {
+ logger.error(`An error occured on command ${event.data.command}`, { error: event.data.error });
+ }
+
if (event.data.command === Commands.STEP) {
const { state, isFinished } = event.data.payload;
@@ -131,6 +146,7 @@ export const initAllWorkers = createAsyncThunk("workers/initAllWorkers", async (
id: worker.id,
pageNumber: event.data.payload.pageNumber,
data: event.data.payload.memoryPage,
+
isLoading: false,
}),
);
@@ -142,6 +158,14 @@ export const initAllWorkers = createAsyncThunk("workers/initAllWorkers", async (
worker.worker.addEventListener("message", globalMessageHandlers[worker.id]);
+ worker.worker.postMessage({
+ command: Commands.INIT,
+ payload: {
+ initialState: debuggerState.initialState,
+ program: debuggerState.program,
+ },
+ });
+
worker.worker.postMessage({
command: Commands.MEMORY_SIZE,
});
@@ -207,6 +231,10 @@ export const continueAllWorkers = createAsyncThunk("workers/continueAllWorkers",
}) => void,
) => {
const messageHandler = (event: MessageEvent) => {
+ if ("status" in event.data && event.data.status === "error") {
+ logger.error(`An error occured on command ${event.data.command}`, { error: event.data.error });
+ }
+
if (event.data.command === Commands.STEP) {
const { state, isRunMode, isFinished } = event.data.payload;
const currentState = getState() as RootState;
@@ -227,7 +255,7 @@ export const continueAllWorkers = createAsyncThunk("workers/continueAllWorkers",
isBreakpoint: debuggerState.breakpointAddresses.includes(state.pc),
});
- console.log("Response from worker:", {
+ logger.info("Response from worker:", {
isFinished,
state,
isRunMode,
@@ -492,7 +520,7 @@ const workers = createSlice({
},
extraReducers: (builder) => {
builder.addCase(createWorker.fulfilled, (state, action) => {
- console.log("Worker created", action.payload);
+ logger.info("Worker created", action.payload);
state.push({
worker: action.payload.worker,
id: action.payload.id,
diff --git a/src/utils/loggerService.tsx b/src/utils/loggerService.tsx
new file mode 100644
index 0000000..1c3706c
--- /dev/null
+++ b/src/utils/loggerService.tsx
@@ -0,0 +1,40 @@
+import { throttle } from "lodash";
+import { toast } from "react-toastify";
+
+const errorToast = throttle((msg: string) => {
+ toast.error(
+
+ {msg}
+
+ Check console for more information
+
,
+ { autoClose: 3000 },
+ );
+}, 6000);
+class Logger {
+ error(msg: string, { error, hideToast }: { error: unknown; hideToast?: boolean }) {
+ if (!hideToast) {
+ errorToast(msg);
+ }
+
+ console.error("‼️‼️‼️‼️Catched error:", error);
+ }
+
+ warn(...msg: unknown[]) {
+ console.warn("⚠️⚠️⚠️⚠️⚠️⚠️", ...msg);
+ }
+
+ info(...msg: unknown[]) {
+ // eslint-disable-next-line no-console
+ console.info("🪵🪵🪵🪵🪵", ...msg);
+ }
+
+ debug(...msg: unknown[]) {
+ if (process.env.NODE_ENV === "development") {
+ // eslint-disable-next-line no-console
+ console.debug("💻💻💻💻💻 DEV LOG: \n", ...msg);
+ }
+ }
+}
+
+export const logger = new Logger();