Display application success in playground

This commit is contained in:
momo5502
2025-06-30 17:32:24 +02:00
parent 9abdae11cb
commit 415d2d2efe
13 changed files with 318 additions and 23 deletions

View File

@@ -10,6 +10,10 @@ function getStateName(state: State) {
return "Paused";
case State.Running:
return "Running";
case State.Failed:
return "Failed";
case State.Success:
return "Success";
default:
return "";
}
@@ -17,12 +21,16 @@ function getStateName(state: State) {
function getStateColor(state: State) {
switch (state) {
case State.Stopped:
case State.Failed:
return "bg-orange-600";
case State.Paused:
return "bg-amber-500";
case State.Running:
case State.Success:
return "bg-lime-600";
case State.Stopped:
return "bg-yellow-800";
case State.Running:
return "bg-sky-500";
default:
return "";
}
@@ -31,10 +39,14 @@ function getStateColor(state: State) {
function getStateEmoji(state: State) {
switch (state) {
case State.Stopped:
return "🔴";
return "🟤";
case State.Paused:
return "🟡";
case State.Running:
return "🔵";
case State.Failed:
return "🔴";
case State.Success:
return "🟢";
default:
return "";

View File

@@ -9,6 +9,20 @@ export enum EmulationState {
Stopped,
Paused,
Running,
Success,
Failed,
}
export function isFinalState(state: EmulationState) {
switch (state) {
case EmulationState.Stopped:
case EmulationState.Success:
case EmulationState.Failed:
return true;
default:
return false;
}
}
function base64Encode(uint8Array: Uint8Array): string {
@@ -50,6 +64,7 @@ export class Emulator {
terminateReject: (reason?: any) => void;
worker: Worker;
state: EmulationState = EmulationState.Stopped;
exit_status: number | null = null;
constructor(logHandler: LogHandler, stateChangeHandler: StateChangeHandler) {
this.logHandler = logHandler;
@@ -142,8 +157,10 @@ export class Emulator {
} else if (event.data.message == "event") {
this._onEvent(decodeEvent(event.data.data));
} else if (event.data.message == "end") {
this._setState(EmulationState.Stopped);
this.terminateResolve(0);
this._setState(
this.exit_status === 0 ? EmulationState.Success : EmulationState.Failed,
);
this.terminateResolve(this.exit_status);
}
}
@@ -154,6 +171,11 @@ export class Emulator {
event.event as fbDebugger.GetStateResponseT,
);
break;
case fbDebugger.Event.ApplicationExit:
this._handle_application_exit(
event.event as fbDebugger.ApplicationExitT,
);
break;
}
}
@@ -162,6 +184,10 @@ export class Emulator {
this.stateChangeHandler(this.state);
}
_handle_application_exit(info: fbDebugger.ApplicationExitT) {
this.exit_status = info.exitStatus;
}
_handle_state_response(response: fbDebugger.GetStateResponseT) {
switch (response.state) {
case fbDebugger.State.None:

View File

@@ -2,6 +2,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
export { ApplicationExit, ApplicationExitT } from './debugger/application-exit.js';
export { DebugEvent, DebugEventT } from './debugger/debug-event.js';
export { Event } from './debugger/event.js';
export { GetStateRequest, GetStateRequestT } from './debugger/get-state-request.js';

View File

@@ -0,0 +1,86 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ApplicationExit implements flatbuffers.IUnpackableObject<ApplicationExitT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ApplicationExit {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsApplicationExit(bb:flatbuffers.ByteBuffer, obj?:ApplicationExit):ApplicationExit {
return (obj || new ApplicationExit()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsApplicationExit(bb:flatbuffers.ByteBuffer, obj?:ApplicationExit):ApplicationExit {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ApplicationExit()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
exitStatus():number|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint32(this.bb_pos + offset) : null;
}
mutate_exit_status(value:number):boolean {
const offset = this.bb!.__offset(this.bb_pos, 4);
if (offset === 0) {
return false;
}
this.bb!.writeUint32(this.bb_pos + offset, value);
return true;
}
static startApplicationExit(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addExitStatus(builder:flatbuffers.Builder, exitStatus:number) {
builder.addFieldInt32(0, exitStatus, null);
}
static endApplicationExit(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createApplicationExit(builder:flatbuffers.Builder, exitStatus:number|null):flatbuffers.Offset {
ApplicationExit.startApplicationExit(builder);
if (exitStatus !== null)
ApplicationExit.addExitStatus(builder, exitStatus);
return ApplicationExit.endApplicationExit(builder);
}
unpack(): ApplicationExitT {
return new ApplicationExitT(
this.exitStatus()
);
}
unpackTo(_o: ApplicationExitT): void {
_o.exitStatus = this.exitStatus();
}
}
export class ApplicationExitT implements flatbuffers.IGeneratedObject {
constructor(
public exitStatus: number|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return ApplicationExit.createApplicationExit(builder,
this.exitStatus
);
}
}

View File

@@ -4,6 +4,7 @@
import * as flatbuffers from 'flatbuffers';
import { ApplicationExit, ApplicationExitT } from '../debugger/application-exit.js';
import { Event, unionToEvent, unionListToEvent } from '../debugger/event.js';
import { GetStateRequest, GetStateRequestT } from '../debugger/get-state-request.js';
import { GetStateResponse, GetStateResponseT } from '../debugger/get-state-response.js';
@@ -104,7 +105,7 @@ unpackTo(_o: DebugEventT): void {
export class DebugEventT implements flatbuffers.IGeneratedObject {
constructor(
public eventType: Event = Event.NONE,
public event: GetStateRequestT|GetStateResponseT|PauseRequestT|ReadMemoryRequestT|ReadMemoryResponseT|ReadRegisterRequestT|ReadRegisterResponseT|RunRequestT|WriteMemoryRequestT|WriteMemoryResponseT|WriteRegisterRequestT|WriteRegisterResponseT|null = null
public event: ApplicationExitT|GetStateRequestT|GetStateResponseT|PauseRequestT|ReadMemoryRequestT|ReadMemoryResponseT|ReadRegisterRequestT|ReadRegisterResponseT|RunRequestT|WriteMemoryRequestT|WriteMemoryResponseT|WriteRegisterRequestT|WriteRegisterResponseT|null = null
){}

View File

@@ -2,6 +2,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import { ApplicationExit, ApplicationExitT } from '../debugger/application-exit.js';
import { GetStateRequest, GetStateRequestT } from '../debugger/get-state-request.js';
import { GetStateResponse, GetStateResponseT } from '../debugger/get-state-response.js';
import { PauseRequest, PauseRequestT } from '../debugger/pause-request.js';
@@ -29,13 +30,14 @@ export enum Event {
WriteRegisterRequest = 9,
WriteRegisterResponse = 10,
ReadRegisterRequest = 11,
ReadRegisterResponse = 12
ReadRegisterResponse = 12,
ApplicationExit = 13
}
export function unionToEvent(
type: Event,
accessor: (obj:GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse) => GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null
): GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null {
accessor: (obj:ApplicationExit|GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse) => ApplicationExit|GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null
): ApplicationExit|GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null {
switch(Event[type]) {
case 'NONE': return null;
case 'PauseRequest': return accessor(new PauseRequest())! as PauseRequest;
@@ -50,15 +52,16 @@ export function unionToEvent(
case 'WriteRegisterResponse': return accessor(new WriteRegisterResponse())! as WriteRegisterResponse;
case 'ReadRegisterRequest': return accessor(new ReadRegisterRequest())! as ReadRegisterRequest;
case 'ReadRegisterResponse': return accessor(new ReadRegisterResponse())! as ReadRegisterResponse;
case 'ApplicationExit': return accessor(new ApplicationExit())! as ApplicationExit;
default: return null;
}
}
export function unionListToEvent(
type: Event,
accessor: (index: number, obj:GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse) => GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null,
accessor: (index: number, obj:ApplicationExit|GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse) => ApplicationExit|GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null,
index: number
): GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null {
): ApplicationExit|GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null {
switch(Event[type]) {
case 'NONE': return null;
case 'PauseRequest': return accessor(index, new PauseRequest())! as PauseRequest;
@@ -73,6 +76,7 @@ export function unionListToEvent(
case 'WriteRegisterResponse': return accessor(index, new WriteRegisterResponse())! as WriteRegisterResponse;
case 'ReadRegisterRequest': return accessor(index, new ReadRegisterRequest())! as ReadRegisterRequest;
case 'ReadRegisterResponse': return accessor(index, new ReadRegisterResponse())! as ReadRegisterResponse;
case 'ApplicationExit': return accessor(index, new ApplicationExit())! as ApplicationExit;
default: return null;
}
}

View File

@@ -2,7 +2,7 @@ import React from "react";
import { Output } from "@/components/output";
import { Emulator, EmulationState } from "./emulator";
import { Emulator, EmulationState, isFinalState } from "./emulator";
import { Filesystem, setupFilesystem } from "./filesystem";
import "./App.css";
@@ -108,7 +108,7 @@ export class Playground extends React.Component<
}
_onEmulatorStateChanged(s: EmulationState, persistFs: boolean) {
if (s == EmulationState.Stopped && persistFs) {
if (isFinalState(s) && persistFs) {
this.setState({ filesystemPromise: null, filesystem: null });
this.initFilesys(true);
} else {
@@ -192,7 +192,7 @@ export class Playground extends React.Component<
(l) => this.logLines(l),
(s) => this._onEmulatorStateChanged(s, persistFs),
);
new_emulator.onTerminate().then(() => this.setState({ emulator: null }));
//new_emulator.onTerminate().then(() => this.setState({ emulator: null }));
this.setState({ emulator: new_emulator, application: userFile });
@@ -213,7 +213,10 @@ export class Playground extends React.Component<
</Button>
<Button
disabled={!this.state.emulator}
disabled={
!this.state.emulator ||
isFinalState(this.state.emulator.getState())
}
size="sm"
variant="secondary"
className="fancy"
@@ -223,7 +226,10 @@ export class Playground extends React.Component<
</Button>
<Button
size="sm"
disabled={!this.state.emulator}
disabled={
!this.state.emulator ||
isFinalState(this.state.emulator.getState())
}
variant="secondary"
className="fancy"
onClick={this.toggleEmulatorState}