import { Modes } from './../modes'; import { Types } from "./../../typeSystem/types"; import { StoreObject } from './storeObject'; export class Store { static canImplicitTypeCast (castType, sourceType) { if (castType.isCompatible(Types.INTEGER) || castType.isCompatible(Types.REAL)) { if (sourceType.isCompatible(Types.INTEGER) || sourceType.isCompatible(Types.REAL)) { return true; } } return false; } static doImplicitCasting (castType, stoObj) { if(!Store.canImplicitTypeCast(castType, stoObj.type)) { throw new Error("!!!Critical error: attempted to type cast invalid types"); } if(castType.isCompatible(Types.INTEGER)) { return new StoreObject(Types.INTEGER, stoObj.value.trunc()); } else { return new StoreObject(Types.REAL, stoObj.value); } } constructor(name) { this.name = name; this.store = new Map(); this.nextStore = null; this.mode = Modes.RUN; } extendStore (nextStore) { this.nextStore = nextStore; } applyStore (id) { if(!this.store.has(id)) { if (this.nextStore !== null) { return this.nextStore.applyStore(id); } else { throw new Error(`Variable ${id} not found.`); } } const val = this.store.get(id); if (val.isRef) { return val.getRefObj(); } return val; } updateStore (id, stoObj) { if(!this.store.has(id)) { if(this.nextStore !== null) { this.nextStore.updateStore(id, stoObj); return this; } else { // TODO: better error message throw new Error(`Variable ${id} not found.`); } } else { const oldObj = this.store.get(id); if(oldObj.readOnly) { // TODO: better error message throw new Error("Cannot change value of a read only variable: " + id); } if(oldObj.isRef) { oldObj.updateRef(stoObj); return this; } else if(oldObj.isCompatible(stoObj)) { const newObj = stoObj.copy(); stoObj.destroy(); newObj.setID(id); this.store.get(id).destroy(); this.store.set(id, newObj); return this; } else { const oldType = oldObj.type; const stoType = stoObj.type; // TODO: better error message throw new Error(`${oldType} is not compatible with type ${stoType} given`); } } } //In case of future use of ref, it needs to have a special function to update the storeRefObject // and no the StoreObject refferenced by it // updateStoreRef(id, stoObjAddress) {...} insertStore (id, stoObj) { if (this.store.has(id)) { // TODO: better error message throw new Error(`${id} is already defined`); } stoObj.setID(id); this.store.set(id, stoObj); return this; } /** * Helper function similar to applyStore. But it returns the actual object in the store be it ref or not * applyStore will return the refferenced object if the object in the store is a ref */ getStoreObject (id) { if(!this.store.has(id)) { if (this.nextStore !== null) { return this.nextStore.getStoreObject(id); } else { throw new Error(`Variable ${id} not found.`); } } return this.store.get(id); } }