Skip to content

Commit b995657

Browse files
committed
Add support for loading a JSON file into an empty template
1 parent 85f5fb0 commit b995657

4 files changed

Lines changed: 107 additions & 35 deletions

File tree

html/src/App.svelte

Lines changed: 98 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,56 +12,123 @@
1212
1313
import { AccessInstance, type GenericInformation, MemoryRegionManager, type OutputJSON } from './lib/types';
1414
15-
import { Drawer, drawerStore } from '@skeletonlabs/skeleton';
15+
import { Drawer, drawerStore, FileDropzone } from '@skeletonlabs/skeleton';
1616
import { dummyData } from './lib/loadDummyData';
1717
import InspectDrawer from './components/InspectDrawer.svelte';
1818
import VisualizeMemoryRegion from './components/VisualizeMemoryRegion.svelte';
1919
import { pageState } from './lib/stores';
2020
import { currentMemoryRegion } from './lib/stores';
2121
22-
// Load the general data
23-
// We actually do a JSON.parse here, as it is faster using the JSON parser than for the browser to evaluate an existing JSON object in JavaScript
24-
// This is because the parser for the DOM needs to do more complex work.
25-
// Additionally this leaves us an easy entry point which will not get simplified away (which normally a comment might be)
22+
// Function to load a valid JSON file into the application as memory structure
23+
const loadJSON = (json: OutputJSON) => {
24+
const info = json.GlobalSettings;
2625
27-
// But actually for development mode load in a file
28-
const MemoryData: OutputJSON = JSON.parse(import.meta.env.DEV ? dummyData : `// JS_TEMPLATE`);
26+
// Generate AccessInstances from the pure data
27+
const data: AccessInstance[] = json.MemoryAccessLogs.map(
28+
([address, blockID, threadID, isRead]) => new AccessInstance(address, blockID, threadID, isRead, info)
29+
);
2930
30-
const info = MemoryData.GlobalSettings;
31+
// Generate MemoryRegionManagers
32+
const memoryRegions: MemoryRegionManager[] = json.MemoryRegions.map((region) => new MemoryRegionManager(region));
3133
32-
// Generate AccessInstances from the pure data
33-
const data: AccessInstance[] = MemoryData.MemoryAccessLogs.map(
34-
([address, blockID, threadID, isRead]) => new AccessInstance(address, blockID, threadID, isRead, info)
35-
);
36-
37-
// Generate MemoryRegionManagers
38-
const memoryRegions: MemoryRegionManager[] = MemoryData.MemoryRegions.map(
39-
(region) => new MemoryRegionManager(region)
40-
);
34+
// Store all our memory accesses in the memoryRegions
35+
// This is relatively slow as we need to iterate over all memory accesses and then again over all memory regions, maybe this can be optimized, but the number of memory Regions should be low, so this should not be a problem
36+
data.forEach((access) => {
37+
memoryRegions.forEach((region) => {
38+
region.addMemoryAccessIfInRegion(access);
39+
});
40+
});
4141
42-
// Store all our memory accesses in the memoryRegions
43-
// This is relatively slow as we need to iterate over all memory accesses and then again over all memory regions, maybe this can be optimized, but the number of memory Regions should be low, so this should not be a problem
44-
data.forEach((access) => {
42+
// For each memory region, bake all data which gets processed after the data is loaded
4543
memoryRegions.forEach((region) => {
46-
region.addMemoryAccessIfInRegion(access);
44+
region.bake();
4745
});
48-
});
4946
50-
// For each memory region, bake all data which gets processed after the data is loaded
51-
memoryRegions.forEach((region) => {
52-
region.bake();
53-
});
47+
// Add the loaded memory regions to the store so it can be selected
48+
$pageState.availableMemoryRegions = [...$pageState.availableMemoryRegions, ...memoryRegions];
49+
};
50+
51+
// To support errors and loading new files into the template without an export, create all necessary variables
52+
// Template which will be replaced
53+
const loadData = '// JS_TEMPLATE';
54+
let validTemplate = true;
55+
// Holds dragged in files
56+
let files: FileList;
57+
58+
// Check if we are not in development mode, but still no data was loaded
59+
if (loadData.startsWith('// JS_TEMPLAT') && !import.meta.env.DEV) {
60+
// Neither data, nor dev mode are enabled, so show error.
61+
validTemplate = false;
62+
} else {
63+
// Otherwise we might be in dev mode, or have data
64+
try {
65+
// For development mode load in a file
66+
// For production mode parse the existing data
67+
// Parsing JSON in a string is always faster than the JavaScript parser
68+
const MemoryData: OutputJSON = JSON.parse(import.meta.env.DEV ? dummyData : loadData);
69+
loadJSON(MemoryData);
70+
} catch (e) {
71+
// If we have an error, we are not in dev mode, but the data is invalid
72+
console.error(e);
73+
validTemplate = false;
74+
}
75+
}
76+
77+
// This is a reactive statement if files changes, this only changes, if files were dropped
78+
$: if (files) {
79+
// Log the files we got
80+
console.log(files);
81+
82+
// Now try to load the data instead of the static data included in the file
83+
for (const file of files) {
84+
// Check if it is a JSON file
85+
if (file.type === 'application/json') {
86+
// Read the file
87+
const reader = new FileReader();
88+
// Define the callback for when the file is read
89+
reader.onload = (e) => {
90+
// Parse the JSON
91+
const data: OutputJSON = JSON.parse(e.target.result as string) as OutputJSON;
92+
// Check if the data is valid
93+
if (data && data.GlobalSettings && data.MemoryRegions.length > 0 && data.MemoryAccessLogs.length > 0) {
94+
// Load the data
95+
loadJSON(data);
96+
97+
// To not cause an event loading the same data twice, clear the files
98+
files = null;
5499
55-
$pageState.availableMemoryRegions = memoryRegions;
100+
// Set the valid template to true
101+
validTemplate = true;
102+
}
103+
};
104+
// Start reading the file
105+
reader.readAsText(file);
106+
}
107+
}
108+
}
56109
</script>
57110

58111
<Layout>
59112
<div class="h-full mx-auto flex flex-row">
60-
{#if $currentMemoryRegion != null}
61-
<VisualizeMemoryRegion MemoryRegion={$currentMemoryRegion} />
113+
{#if validTemplate}
114+
{#if $currentMemoryRegion != null && !('isPlaceHolder' in $currentMemoryRegion)}
115+
<VisualizeMemoryRegion MemoryRegion={$currentMemoryRegion} />
116+
{:else}
117+
<div class="flex flex-col justify-center items-center w-full h-full">
118+
<h1 class="text-3xl font-bold opacity-30 ">Please select a memory region</h1>
119+
<div class="px-12 my-12 w-full">
120+
<FileDropzone bind:files title="You can upload additional .json files here." />
121+
</div>
122+
</div>
123+
{/if}
62124
{:else}
63-
<div class="flex flex-col justify-center items-center w-full h-full">
64-
<h1 class="text-3xl font-bold opacity-30 ">Please select a memory region</h1>
125+
<div class="flex flex-col justify-center items-center w-full h-full text-center">
126+
<h1 class="text-3xl font-bold opacity-30 ">
127+
Please load in valid data for this template.<br /> Without data this HTML file can't do anything.
128+
</h1>
129+
<div class="px-12 my-12 w-full">
130+
<FileDropzone bind:files title="You can alternatively drag in a valid .json as template here." />
131+
</div>
65132
</div>
66133
{/if}
67134
</div>

html/src/components/SideBar.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { pageState } from '../lib/stores';
3-
import { currentMemoryRegion } from '../lib/stores.js';
3+
import { currentMemoryRegion, ListPlaceHolder } from '../lib/stores';
44
import { ListBox, ListBoxItem } from '@skeletonlabs/skeleton';
55
</script>
66

@@ -9,6 +9,7 @@
99
<p class="my-1">Select the data structure you want to view:</p>
1010

1111
<ListBox selected={currentMemoryRegion} class="my-1 border-gray-600/20 border-2 rounded-3xl">
12+
<ListBoxItem value={ListPlaceHolder} class="mb-2">None</ListBoxItem>
1213
{#each $pageState.availableMemoryRegions as region, index}
1314
<ListBoxItem value={region} class="mb-2">{region.name}</ListBoxItem>
1415
{/each}

html/src/lib/stores.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@ export interface DrawerState {
1313
export interface PageState {
1414
backGroundContrastBlack: boolean;
1515
showIndex: boolean;
16-
activeMemoryRegion?: MemoryRegionManager;
1716
availableMemoryRegions: MemoryRegionManager[];
1817
showGrid: boolean;
1918
customMemoryWidth: number;
2019
}
2120

21+
export const ListPlaceHolder = {
22+
// eslint-disable-next-line no-prototype-builtins,@typescript-eslint/ban-types
23+
includes: (object: {}) => object.hasOwnProperty('isPlaceHolder'),
24+
isPlaceHolder: true
25+
};
26+
2227
function createDrawerStateStore() {
2328
const { subscribe, set, update } = writable<DrawerState>({
2429
currentMemoryRegion: null,
@@ -57,4 +62,4 @@ export const pageState = writable<PageState>({
5762
customMemoryWidth: 0
5863
});
5964

60-
export const currentMemoryRegion = writable<MemoryRegionManager>(null);
65+
export const currentMemoryRegion = writable<MemoryRegionManager | typeof ListPlaceHolder>(ListPlaceHolder);

html/src/lib/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,6 @@ export class MemoryRegionManager {
311311
// This is because we use a list to be able to select the memory regions in the GUI
312312
// But this GUI element calls includes on the object for some reason
313313
includes(object: MemoryRegionManager): boolean {
314-
console.log(object);
315314
return object === this;
316315
}
317316
}

0 commit comments

Comments
 (0)