123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
- import { Modes } from '../modes';
- import { Types } from "../../typeSystem/types";
- import { StoreObject } from './storeObject';
- import { IType } from '../../typeSystem/itype';
- import { StoreObjectRef } from './storeObjectRef';
- import { ArrayType } from '../../typeSystem/array_type';
- import { ArrayStoreValue } from './value/array_store_value';
- import { Location } from '../../memory/location';
- import { StoreObjectArray } from './storeObjectArray';
- import { IStoreValue } from './value/istore_value';
- import { StoreValue } from './value/store_value';
- import { StoreValueAddress } from './value/store_value_address';
- import { StoreValueRef } from './value/store_value_ref';
- import { ArrayStoreValueRef } from './value/array_store_value_ref';
- import { StoreObjectArrayRef } from './store_object_array_ref';
- export class Store {
- static canImplicitTypeCast (castType: IType, sourceType: IType): boolean {
- 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: IType, stoObj: IStoreValue): IStoreValue {
- if(!Store.canImplicitTypeCast(castType, stoObj.type)) {
- throw new Error("!!!Critical error: attempted to type cast invalid types");
- }
- if(castType.isCompatible(Types.INTEGER)) {
- return new StoreValue(Types.INTEGER, stoObj.get().trunc());
- } else {
- return new StoreValue(Types.REAL, stoObj.get());
- }
- }
- private store: Map<string, StoreObject>;
- public nextStore?: Store
- public mode: symbol;
- constructor(public name: string) {
- this.store = new Map<string, StoreObject>();
- this.mode = Modes.RUN;
- }
- extendStore (nextStore: Store): void {
- this.nextStore = nextStore;
- }
- applyStore (id: string): IStoreValue {
- 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)!;
- let result = null
- if (val.type instanceof ArrayType) {
- const array = val as StoreObjectArray;
- const array_type = array.type as ArrayType;
- let l = 0, c = 0;
- const values = array.value.map( v => {
- if(array.isVector) {
- return new StoreValueAddress(array_type.innerType, v, l++, undefined, array.id, array.readOnly);
- } else {
- if(c >= array.columns) {
- c = 0;
- l += 1;
- }
- return new StoreValueAddress(array_type.innerType, v, l, c++, array.id, array.readOnly);
- }
- });
- result = new ArrayStoreValue(array_type, values, array.lines, array.columns, val.id, val.readOnly);
- } else {
- result = new StoreValue(val.type, val.value, val.id, val.readOnly);
- }
-
- return result;
- }
- updateStore (id: string, stoValue: IStoreValue): Store {
- if (!this.store.has(id)) {
- if (this.nextStore != null) {
- this.nextStore.updateStore(id, stoValue);
- 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 instanceof StoreObjectArray) {
- const array_value = stoValue as ArrayStoreValue;
- if(oldObj.isCompatible(array_value)) {
- if(oldObj.isVector) {
- array_value.get().forEach((val, index) => {
- oldObj.setAt(val, index, undefined);
- });
- } else {
- let line = 0;
- let column = 0;
- array_value.get().forEach((val) => {
- oldObj.setAt(val, line, column);
- column += 1;
- if(column >= oldObj.columns) {
- line += 1;
- column = 0;
- }
- });
- }
- return this;
- }
- } else if (oldObj.isCompatible(stoValue)) {
- const loc_address = oldObj.locAddress;
- Location.updateAddress(loc_address, stoValue.get());
- return this;
- }
- const oldType = oldObj.type;
- const stoType = stoValue.type;
- // TODO: better error message
- throw new Error(`${oldType.value} is not compatible with type ${stoType.value} given`);
-
- }
- }
- /**
- * Method used to update regions of an array (vector or matrix). The should only be used when update an specific
- * possition since it will only update the required addresses.
- * @param {string} id the variable id to be updated
- * @param {IStoreValue} sto_value the value to be used in the update process
- * @param {number} line the line address of the vector/matrix
- * @param {number} column the matrix column, which can be undefined
- */
- updateStoreArray (id: string, sto_value: IStoreValue, line: number, column?: number): Store {
- if (!this.store.has(id)) {
- if (this.nextStore != null) {
- this.nextStore.updateStoreArray(id, sto_value, line, column);
- 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 instanceof StoreObjectArray) {
- if(sto_value instanceof ArrayStoreValue) {
- // this must be a vector or matrix line update
- const actual_values = sto_value.get();
- if(oldObj.isVector && sto_value.isVector()) {
- for(let i = 0;i < sto_value.lines; i += 1) {
- const val = actual_values[i]
- oldObj.setAt(val, i, undefined);
- }
- } else if(!oldObj.isVector && column == null && sto_value.isVector()) {
- for(let i = 0;i < oldObj.columns; i += 1) {
- const val = actual_values[i]
- oldObj.setAt(val, line, i);
- }
- } else {
- // TODO: better error message
- throw new Error(`Attempting to assign an invalid value to array ${id}`);
- }
- } else {
- if(!oldObj.isVector && column == null) {
- // TODO: better error message
- throw new Error(`Attempting to assign an invalid value to array ${id}`);
- }
- oldObj.setAt(sto_value as StoreValue, line, column);
- }
- } else {
- throw new Error("Cannot update a non-array variable using updateStoreArray");
- }
- // const oldType = oldObj.type;
- // const stoType = sto_value.type;
- // // TODO: better error message
- // throw new Error(`${oldType.value} is not compatible with type ${stoType.value} given`);
- return this;
- }
- }
- /**
- * Inserts a new variable into the Store. This method should be used when declaring a new variable,
- * including the special return variable $.
- * @param id variable id
- * @param stoValue the value to be used as the initial value of id
- */
- insertStore (id: string, stoValue: IStoreValue): Store {
- if (this.store.has(id)) {
- // TODO: better error message
- throw new Error(`${id} is already defined`);
- }
- // TODO check for array....
- let newObj: StoreObject;
- if(stoValue instanceof StoreValueRef) {
- newObj = new StoreObjectRef(stoValue);
- } else if (stoValue instanceof ArrayStoreValueRef) {
- newObj = new StoreObjectArrayRef(stoValue, stoValue.lines, stoValue.columns);
- } else if (stoValue instanceof ArrayStoreValue) {
- const columns = stoValue.isVector() ? 0 : stoValue.columns!;
- const addresses: number[] = [];
- const all_values = stoValue.get();
- if(all_values.length > 0) {
- for(let i = 0; i < stoValue.get().length; i += 1) {
- const val = all_values[i].get();
- addresses.push(Location.allocate(val));
- }
- } else {
- let total = stoValue.lines;
- total = stoValue.isVector() ? total : total * columns;
- for(let i = 0; i < total; i += 1) {
- addresses.push(Location.allocate(null));
- }
- }
- newObj = new StoreObjectArray(stoValue.type as ArrayType, stoValue.lines, columns, addresses, stoValue.isConst);
- } else {
- const loc_address = Location.allocate(stoValue.get());
- newObj = new StoreObject(stoValue.type, loc_address, stoValue.isConst);
- }
- newObj.setID(id);
- this.store.set(id, newObj);
- 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: string): StoreObject {
- 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)!;
- }
- destroy (): void {
- this.store.forEach(sto => sto.destroy(), this);
- }
- isDefined (id: string): boolean {
- if (!this.store.has(id)) {
- if (this.nextStore != null) {
- return this.nextStore.isDefined(id);
- } else {
- return false;
- }
- }
- return true;
- }
- }
|