Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactored load.js to load.ts and added a new file loadScope.ts in types #460

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 296 additions & 0 deletions src/simulator/src/data/load.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
import { resetScopeList, newCircuit, switchCircuit } from '../circuit'
import { setProjectName } from './save'
import {
scheduleUpdate,
update,
updateSimulationSet,
updateCanvasSet,
gridUpdateSet,
} from '../engine'
import { updateRestrictedElementsInScope } from '../restrictedElementDiv'
import { simulationArea } from '../simulationArea'

import { loadSubCircuit } from '../subcircuit'
import { scheduleBackup } from './backupCircuit'
import { showProperties } from '../ux'
import { constructNodeConnections, loadNode, replace } from '../node'
import { generateId } from '../utils'
import modules from '../modules'
import { oppositeDirection } from '../canvasApi'
import plotArea from '../plotArea'
import { TestbenchData } from '#/simulator/src/testbench'
import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore'
import { toRefs } from 'vue'
import { moduleList } from '../metadata'
import { Scope, ProjectData, VerilogMetadata, Layout,TestbenchData, NodeData, CircuitElement, ModuleData } from '../types/loadScope'; // Import required interfaces


/**
* Backward compatibility - needs to be deprecated
* @param {CircuitElement} obj - the object to be rectified
* @category data
*/
function rectifyObjectType(obj: string): string {
const rectify: Record<string, string> = {
FlipFlop: 'DflipFlop',
Ram: 'Rom',
};
return rectify[obj] || obj;
}

/**
* Function to load CircuitElements
* @param {ModuleData} data - JSOn data
* @param {Scope} scope - circuit in which we want to load modules
* @category data
*/
function loadModule(data: ModuleData, scope: Scope): void {
// Create circuit element
const obj = new modules[rectifyObjectType(data.objectType)](

Check failure

Code scanning / CodeQL

Unvalidated dynamic method call High

Invocation of method with
user-controlled
name may dispatch to unexpected target and cause an exception.
data.x,
data.y,
scope,
...(data.customData.constructorParamaters || [])
);
// Sets directions
obj.label = data.label;
obj.labelDirection = data.labelDirection || oppositeDirection[fixDirection[obj.direction]];

// Sets delay
obj.propagationDelay = data.propagationDelay || obj.propagationDelay;
obj.fixDirection();

// Restore other values
if (data.customData.values) {
for (const prop in data.customData.values) {
if (Object.prototype.hasOwnProperty.call(data.customData.values, prop)) {
obj[prop] = data.customData.values[prop];
}
}
}

// Replace new nodes with the correct old nodes (with connections)
if (data.customData.nodes) {
for (const node in data.customData.nodes) {
if (Object.prototype.hasOwnProperty.call(data.customData.nodes, node)) {
const n = data.customData.nodes[node];
if (Array.isArray(n)) {
for (let i = 0; i < n.length; i++) {
obj[node][i] = replace(obj[node][i], n[i].id); // Pass the id of NodeConnection instead of the whole object
}
} else {
obj[node] = replace(obj[node], n.id); // Again, pass the id property of NodeConnection
}

}
}
}
if (data.subcircuitMetadata) obj.subcircuitMetadata = data.subcircuitMetadata;
}

/**
* This function shouldn't ideally exist. But temporary fix
* for some issues while loading nodes.
* @category data
*/
function removeBugNodes(scope: Scope = globalScope): void {
let x = scope.allNodes.length;
for (let i = 0; i < x; i++) {
if (
scope.allNodes[i].type !== 2 &&
scope.allNodes[i].parent.objectType === 'CircuitElement'
) {
scope.allNodes[i].delete?.(); //even if delete doesn't exist, it won't cause any errors
}
if (scope.allNodes.length !== x) {
i = 0;
x = scope.allNodes.length;
}
}
}
Comment on lines +96 to +110
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider removing 'removeBugNodes' or clarifying its usage.

The 'removeBugNodes' function is labelled as a “temporary fix” but still persists. If this logic is essential, consider documenting the exact cases it covers or incorporate a more robust long-term solution.


/**
* Function to load a full circuit
* @param {Scope} scope
* @param {ProjectData} data
* @category data
*/
export function loadScope(scope: Scope, data: ProjectData): void {
const ML = moduleList.slice(); // Module List copy
scope.restrictedCircuitElementsUsed = data.restrictedCircuitElementsUsed;

// Load all nodes
data.allNodes.forEach((x) => loadNode(x, scope));

// Make all connections
for (let i = 0; i < data.allNodes.length; i++) {
constructNodeConnections(scope.allNodes[i], data.allNodes[i]);
}

// Load all modules
for (let i = 0; i < ML.length; i++) {
if (data[ML[i]]) {
if (ML[i] === 'SubCircuit') {
// Load subcircuits differently
for (let j = 0; j < data[ML[i]].length; j++) {
loadSubCircuit(data[ML[i]][j], scope);
}
} else {
// Load everything else similarly
for (let j = 0; j < data[ML[i]].length; j++) {
loadModule(data[ML[i]][j], scope);
}
}
}
}

// Update wires accordingly
scope.wires.forEach((x) => {
x.updateData(scope);
});

removeBugNodes(scope); // To be deprecated

// If Verilog Circuit Metadata exists, then restore
if (data.verilogMetadata) {
scope.verilogMetadata = data.verilogMetadata;
}

// If Test exists, then restore
if (data.testbenchData) {
globalScope.testbenchData = new TestbenchData(
data.testbenchData.testData,
data.testbenchData.currentGroup,
data.testbenchData.currentCase
);
}

// If layout exists, then restore
if (data.layout) {
scope.layout = data.layout;
} else {
// Else generate new layout according to how it would have been otherwise (backward compatibility)
scope.layout = {};
scope.layout.width = 100;
scope.layout.height =
Math.max(scope.Input.length, scope.Output.length) * 20 + 20;
scope.layout.title_x = 50;
scope.layout.title_y = 13;
for (let i = 0; i < scope.Input.length; i++) {
scope.Input[i].layoutProperties = {
x: 0,
y:
scope.layout.height / 2 -
scope.Input.length * 10 +
20 * i +
10,
id: generateId(),
};
}
for (let i = 0; i < scope.Output.length; i++) {
scope.Output[i].layoutProperties = {
x: scope.layout.width,
y:
scope.layout.height / 2 -
scope.Output.length * 10 +
20 * i +
10,
id: generateId(),
};
}
}
// Backward compatibility
if (scope.layout.titleEnabled === undefined) {
scope.layout.titleEnabled = true;
}
}

// Function to load project from data
/**
* loads a saved project
* @param {ProjectData} data - the json data of the
* @category data
* @exports load
*/
export default function load(data: ProjectData | null): void {
// If project is new and no data is there, then just set project name
const simulatorStore = SimulatorStore();
const { circuit_list } = toRefs(simulatorStore);

if (!data) {
setProjectName(__projectName);
return;
}

const { projectId } = data;
setProjectName(data.name);

globalScope = undefined;
resetScopeList(); // Remove default scope

// Load all according to the dependency order
for (let i = 0; i < data.scopes.length; i++) {
let isVerilogCircuit = false;
let isMainCircuit = false;
if (data.scopes[i].verilogMetadata) {
isVerilogCircuit = data.scopes[i].verilogMetadata.isVerilogCircuit;
isMainCircuit = data.scopes[i].verilogMetadata.isMainCircuit;
}

// Create new circuit
const scope = newCircuit(
data.scopes[i].name || 'Untitled',
data.scopes[i].id,
isVerilogCircuit,
isMainCircuit
);

// Load circuit data
loadScope(scope, data.scopes[i]);

// Focus circuit
globalScope = scope;

// Center circuit
if (embed) {
globalScope.centerFocus(true);
} else {
globalScope.centerFocus(false);
}

// update and backup circuit once
update(globalScope, true);

// Updating restricted element list initially on loading
updateRestrictedElementsInScope();

scheduleBackup();
}

// Restore clock
simulationArea.changeClockTime(data.timePeriod || 500);
simulationArea.clockEnabled =
data.clockEnabled === undefined ? true : data.clockEnabled;

if (!embed) {
showProperties(simulationArea.lastSelected);
}

// Reorder tabs according to the saved order
if (data.orderedTabs?.length) {
circuit_list.value.sort((a, b) => {
return data.orderedTabs.indexOf(String(a.id)) - data.orderedTabs.indexOf(String(b.id));
});
}

// Switch to last focussedCircuit
if (data.focussedCircuit) switchCircuit(String(data.focussedCircuit));

updateSimulationSet(true);
updateCanvasSet(true);
gridUpdateSet(true);

// Reset Timing
if (!embed) plotArea.reset();
scheduleUpdate(1);
}
Loading
Loading