|
@@ -4,29 +4,37 @@ import { StoreObjectArray } from './store/storeObjectArray';
|
|
|
import { StoreObjectRef } from './store/storeObjectRef';
|
|
|
import { Modes } from './modes';
|
|
|
import { Context } from './context';
|
|
|
-import { Types, toInt } from './../ast/types';
|
|
|
+import { Types } from './../typeSystem/types';
|
|
|
import { Operators } from './../ast/operators';
|
|
|
-import { NAMES, LanguageDefinedFunction } from './definedFunctions';
|
|
|
+import { LanguageDefinedFunction } from './definedFunctions';
|
|
|
import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from './compatibilityTable';
|
|
|
import * as Commands from './../ast/commands/';
|
|
|
import * as Expressions from './../ast/expressions/';
|
|
|
+import { StoreObjectArrayAddress } from './store/storeObjectArrayAddress';
|
|
|
+import { StoreObjectArrayAddressRef } from './store/storeObjectArrayAddressRef';
|
|
|
+import { CompoundType } from './../typeSystem/compoundType';
|
|
|
+import { convertToString } from '../typeSystem/parsers';
|
|
|
|
|
|
export class IVProgProcessor {
|
|
|
|
|
|
constructor (ast) {
|
|
|
this.ast = ast;
|
|
|
- this.globalStore = new Store();
|
|
|
- this.stores = [this.globalStore];
|
|
|
- this.context = [Context.BASE];
|
|
|
+ this.globalStore = null;
|
|
|
+ this.stores = null;
|
|
|
+ this.context = null;
|
|
|
this.input = null;
|
|
|
this.output = null;
|
|
|
}
|
|
|
|
|
|
registerInput (input) {
|
|
|
+ if(this.input !== null)
|
|
|
+ this.input = null;
|
|
|
this.input = input;
|
|
|
}
|
|
|
|
|
|
registerOutput (output) {
|
|
|
+ if(this.output !== null)
|
|
|
+ this.output = null;
|
|
|
this.output = output;
|
|
|
}
|
|
|
|
|
@@ -44,7 +52,22 @@ export class IVProgProcessor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ prepareState () {
|
|
|
+ if(this.stores !== null) {
|
|
|
+ for (let i = 0; i < this.stores.length; i++) {
|
|
|
+ delete this.stores[i];
|
|
|
+ }
|
|
|
+ this.stores = null;
|
|
|
+ }
|
|
|
+ if(this.globalStore !== null)
|
|
|
+ this.globalStore = null;
|
|
|
+ this.globalStore = new Store();
|
|
|
+ this.stores = [this.globalStore];
|
|
|
+ this.context = [Context.BASE];
|
|
|
+ }
|
|
|
+
|
|
|
interpretAST () {
|
|
|
+ this.prepareState();
|
|
|
this.initGlobal();
|
|
|
const mainFunc = this.findMainFunction();
|
|
|
if(mainFunc === null) {
|
|
@@ -69,7 +92,7 @@ export class IVProgProcessor {
|
|
|
|
|
|
findFunction (name) {
|
|
|
if(name.match(/^\$.+$/)) {
|
|
|
- const fun = LanguageDefinedFunction[name];
|
|
|
+ const fun = LanguageDefinedFunction.getFunction(name);
|
|
|
if(!!!fun) {
|
|
|
throw new Error("!!!Internal Error. Language defined function not implemented -> " + name + "!!!");
|
|
|
}
|
|
@@ -87,7 +110,16 @@ export class IVProgProcessor {
|
|
|
runFunction (func, actualParameters, store) {
|
|
|
let funcStore = new Store();
|
|
|
funcStore.extendStore(this.globalStore);
|
|
|
- const returnStoreObject = new StoreObject(func.returnType, null);
|
|
|
+ let returnStoreObject = null;
|
|
|
+ if(func.returnType instanceof CompoundType) {
|
|
|
+ if(func.returnType.dimensions > 1) {
|
|
|
+ returnStoreObject = new StoreObjectArray(func.returnType,-1,-1,[[]]);
|
|
|
+ } else {
|
|
|
+ returnStoreObject = new StoreObjectArray(func.returnType,-1,null,[]);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ returnStoreObject = new StoreObject(func.returnType, null);
|
|
|
+ }
|
|
|
const funcName = func.isMain ? 'main' : func.name;
|
|
|
const funcNameStoreObject = new StoreObject(Types.STRING, funcName, true);
|
|
|
funcStore.insertStore('$', returnStoreObject);
|
|
@@ -115,68 +147,25 @@ export class IVProgProcessor {
|
|
|
for (let i = 0; i < values.length; i++) {
|
|
|
const stoObj = values[i];
|
|
|
const formalParameter = formalList[i];
|
|
|
- switch (formalParameter.dimensions) {
|
|
|
- case 1: {
|
|
|
- if (stoObj.lines > 0 && stoObj.columns === null
|
|
|
- && stoObj.subtype === formalParameter.type) {
|
|
|
-
|
|
|
- if(formalParameter.byRef && !stoObj.inStore) {
|
|
|
- throw new Error('You must inform a variable as parameter');
|
|
|
- }
|
|
|
-
|
|
|
- if(formalParameter.byRef) {
|
|
|
- const ref = new StoreObjectRef(stoObj.id, callerStore);
|
|
|
- calleeStore.insertStore(formalParameter.id, ref);
|
|
|
- } else {
|
|
|
- calleeStore.insertStore(formalParameter.id, stoObj);
|
|
|
- }
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- throw new Error(`Parameter ${formalParameter.id} is not compatible with the value given.`);
|
|
|
- }
|
|
|
- break;
|
|
|
+ if(formalParameter.type.isCompatible(stoObj.type)) {
|
|
|
+ if(formalParameter.byRef && !stoObj.inStore) {
|
|
|
+ throw new Error('You must inform a variable as parameter');
|
|
|
}
|
|
|
- case 2: {
|
|
|
- if (stoObj.lines > 0 && stoObj.columns > 0
|
|
|
- && stoObj.subtype === formalParameter.type) {
|
|
|
-
|
|
|
- if(formalParameter.byRef && !stoObj.inStore) {
|
|
|
- throw new Error('You must inform a variable as parameter');
|
|
|
- }
|
|
|
-
|
|
|
- if(formalParameter.byRef) {
|
|
|
- const ref = new StoreObjectRef(stoObj.id, callerStore);
|
|
|
- calleeStore.insertStore(formalParameter.id, ref);
|
|
|
- } else {
|
|
|
- calleeStore.insertStore(formalParameter.id, stoObj);
|
|
|
- }
|
|
|
|
|
|
+ if(formalParameter.byRef) {
|
|
|
+ let ref = null;
|
|
|
+ if (stoObj instanceof StoreObjectArrayAddress) {
|
|
|
+ ref = new StoreObjectArrayAddressRef(stoObj);
|
|
|
} else {
|
|
|
-
|
|
|
- throw new Error(`Parameter ${formalParameter.id} is not compatible with the value given.`);
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- case 0: {
|
|
|
- if(formalParameter.byRef && !stoObj.inStore) {
|
|
|
-
|
|
|
- throw new Error('You must inform a variable as parameter');
|
|
|
- } else if (formalParameter.type !== Types.ALL && stoObj.type !== formalParameter.type) {
|
|
|
-
|
|
|
-
|
|
|
- throw new Error(`Parameter ${formalParameter.id} is not compatible with ${stoObj.type}.`);
|
|
|
- } else {
|
|
|
-
|
|
|
- if(formalParameter.byRef) {
|
|
|
- const ref = new StoreObjectRef(stoObj.id, callerStore);
|
|
|
- calleeStore.insertStore(formalParameter.id, ref);
|
|
|
- } else {
|
|
|
- calleeStore.insertStore(formalParameter.id, stoObj);
|
|
|
- }
|
|
|
-
|
|
|
+ ref = new StoreObjectRef(stoObj.id, callerStore);
|
|
|
}
|
|
|
+ calleeStore.insertStore(formalParameter.id, ref);
|
|
|
+ } else {
|
|
|
+ let realValue = this.parseStoreObjectValue(stoObj);
|
|
|
+ calleeStore.insertStore(formalParameter.id, realValue);
|
|
|
}
|
|
|
+ } else {
|
|
|
+ throw new Error(`Parameter ${formalParameter.id} is not compatible with the value given.`);
|
|
|
}
|
|
|
}
|
|
|
return calleeStore;
|
|
@@ -206,6 +195,8 @@ export class IVProgProcessor {
|
|
|
|
|
|
if (cmd instanceof Commands.Declaration) {
|
|
|
return this.executeDeclaration(store, cmd);
|
|
|
+ } else if (cmd instanceof Commands.ArrayIndexAssign) {
|
|
|
+ return this.executeArrayIndexAssign(store, cmd);
|
|
|
} else if (cmd instanceof Commands.Assign) {
|
|
|
return this.executeAssign(store, cmd);
|
|
|
} else if (cmd instanceof Commands.Break) {
|
|
@@ -232,46 +223,22 @@ export class IVProgProcessor {
|
|
|
}
|
|
|
|
|
|
executeSysCall (store, cmd) {
|
|
|
- if (cmd.id === NAMES.WRITE) {
|
|
|
- return this.runWriteFunction(store)
|
|
|
- } else if (cmd.id === NAMES.READ) {
|
|
|
- return this.runReadFunction(store);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- runWriteFunction (store) {
|
|
|
- const val = store.applyStore('p1');
|
|
|
- this.output.sendOutput(''+val.value);
|
|
|
- return Promise.resolve(store);
|
|
|
- }
|
|
|
-
|
|
|
- runReadFunction (store) {
|
|
|
- const request = new Promise((resolve, _) => {
|
|
|
- this.input.requestInput(resolve);
|
|
|
- });
|
|
|
- return request.then(text => {
|
|
|
- const typeToConvert = store.applyStore('p1').type;
|
|
|
- let stoObj = null;
|
|
|
- if (typeToConvert === Types.INTEGER) {
|
|
|
- const val = toInt(text);
|
|
|
- stoObj = new StoreObject(Types.INTEGER, val);
|
|
|
- } else if (typeToConvert === Types.REAL) {
|
|
|
- stoObj = new StoreObject(Types.REAL, parseFloat(text));
|
|
|
- } else if (typeToConvert === Types.BOOLEAN) {
|
|
|
- stoObj = new StoreObject(Types.BOOLEAN, true);
|
|
|
- } else if (typeToConvert === Types.STRING) {
|
|
|
- stoObj = new StoreObject(Types.STRING, text);
|
|
|
- }
|
|
|
- store.updateStore('p1', stoObj);
|
|
|
- return Promise.resolve(store);
|
|
|
- });
|
|
|
+ const func = cmd.langFunc.bind(this);
|
|
|
+ return func(store, cmd);
|
|
|
}
|
|
|
|
|
|
executeFunctionCall (store, cmd) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const func = this.findFunction(cmd.id);
|
|
|
this.runFunction(func, cmd.actualParameters, store)
|
|
|
- .then(_ => resolve(store))
|
|
|
+ .then(sto => {
|
|
|
+ if(!Types.VOID.isCompatible(func.returnType) && sto.mode !== Modes.RETURN) {
|
|
|
+
|
|
|
+ reject(new Error(`Function ${func.name} must have a return command`));
|
|
|
+ } else {
|
|
|
+ resolve(store);
|
|
|
+ }
|
|
|
+ })
|
|
|
.catch(err => reject(err));
|
|
|
});
|
|
|
}
|
|
@@ -354,7 +321,7 @@ export class IVProgProcessor {
|
|
|
}
|
|
|
const $value = this.evaluateExpression(sto, cmd.expression);
|
|
|
return $value.then(vl => {
|
|
|
- if (vl.type !== Types.BOOLEAN) {
|
|
|
+ if (!vl.type.isCompatible(Types.BOOLEAN)) {
|
|
|
|
|
|
|
|
|
return Promise.reject(new Error(`DoWhile expression must be of type boolean`));
|
|
@@ -378,7 +345,7 @@ export class IVProgProcessor {
|
|
|
this.context.push(Context.BREAKABLE);
|
|
|
const $value = this.evaluateExpression(store, cmd.expression);
|
|
|
return $value.then(vl => {
|
|
|
- if(vl.type === Types.BOOLEAN) {
|
|
|
+ if(vl.type.isCompatible(Types.BOOLEAN)) {
|
|
|
if(vl.value) {
|
|
|
const $newStore = this.executeCommands(store, cmd.commands);
|
|
|
return $newStore.then(sto => {
|
|
@@ -408,7 +375,7 @@ export class IVProgProcessor {
|
|
|
try {
|
|
|
const $value = this.evaluateExpression(store, cmd.condition);
|
|
|
return $value.then(vl => {
|
|
|
- if(vl.type === Types.BOOLEAN) {
|
|
|
+ if(vl.type.isCompatible(Types.BOOLEAN)) {
|
|
|
if(vl.value) {
|
|
|
return this.executeCommands(store, cmd.ifTrue.commands);
|
|
|
} else if( cmd.ifFalse !== null){
|
|
@@ -438,16 +405,17 @@ export class IVProgProcessor {
|
|
|
const funcName = store.applyStore('$name');
|
|
|
return $value.then(vl => {
|
|
|
|
|
|
- if(vl === null && funcType === Types.VOID) {
|
|
|
+ if(vl === null && funcType.isCompatible(Types.VOID)) {
|
|
|
return Promise.resolve(store);
|
|
|
}
|
|
|
|
|
|
- if (vl === null || funcType.type !== vl.type) {
|
|
|
+ if (vl === null || !funcType.type.isCompatible(vl.type)) {
|
|
|
|
|
|
|
|
|
return Promise.reject(new Error(`Function ${funcName.value} must return ${funcType.type} instead of ${vl.type}.`));
|
|
|
} else {
|
|
|
- store.updateStore('$', vl);
|
|
|
+ let realValue = this.parseStoreObjectValue(vl);
|
|
|
+ store.updateStore('$', realValue);
|
|
|
store.mode = Modes.RETURN;
|
|
|
return Promise.resolve(store);
|
|
|
}
|
|
@@ -470,7 +438,8 @@ export class IVProgProcessor {
|
|
|
try {
|
|
|
const $value = this.evaluateExpression(store, cmd.expression);
|
|
|
return $value.then( vl => {
|
|
|
- store.updateStore(cmd.id, vl)
|
|
|
+ let realValue = this.parseStoreObjectValue(vl);
|
|
|
+ store.updateStore(cmd.id, realValue)
|
|
|
return store;
|
|
|
});
|
|
|
} catch (error) {
|
|
@@ -478,6 +447,71 @@ export class IVProgProcessor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ executeArrayIndexAssign (store, cmd) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const mustBeArray = store.applyStore(cmd.id);
|
|
|
+ if(!(mustBeArray.type instanceof CompoundType)) {
|
|
|
+ reject(new Error(cmd.id + " is not a vector/matrix"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const line$ = this.evaluateExpression(store, cmd.line);
|
|
|
+ const column$ = this.evaluateExpression(store, cmd.column);
|
|
|
+ const value$ = this.evaluateExpression(store, cmd.expression);
|
|
|
+ Promise.all([line$, column$, value$]).then(results => {
|
|
|
+ const lineSO = results[0];
|
|
|
+ if(!Types.INTEGER.isCompatible(lineSO.type)) {
|
|
|
+
|
|
|
+
|
|
|
+ reject(new Error("Array dimension must be of type int"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const line = lineSO.number;
|
|
|
+ const columnSO = results[1];
|
|
|
+ let column = null
|
|
|
+ if (columnSO !== null) {
|
|
|
+ if(!Types.INTEGER.isCompatible(columnSO.type)) {
|
|
|
+
|
|
|
+
|
|
|
+ reject(new Error("Array dimension must be of type int"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ column = columnSO.number;
|
|
|
+ }
|
|
|
+ const value = this.parseStoreObjectValue(results[2]);
|
|
|
+ if (line >= mustBeArray.lines) {
|
|
|
+
|
|
|
+ return Promise.reject(new Error(`${exp.id}: index out of bounds: ${lines}`));
|
|
|
+ }
|
|
|
+ if (column !== null && mustBeArray.columns === null ){
|
|
|
+
|
|
|
+ return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
|
|
|
+ }
|
|
|
+ if(column !== null && column >= mustBeArray.columns) {
|
|
|
+
|
|
|
+ return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
|
|
|
+ }
|
|
|
+
|
|
|
+ const newArray = Object.assign(new StoreObjectArray(null,null,null), mustBeArray);
|
|
|
+ if (column !== null) {
|
|
|
+ if (value.type instanceof CompoundType) {
|
|
|
+ reject(new Error("Invalid operation. This must be a value: line "+cmd.sourceInfo.line));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ newArray.value[line].value[column] = value;
|
|
|
+ store.updateStore(cmd.id, newArray);
|
|
|
+ } else {
|
|
|
+ if(mustBeArray.columns !== null && value.type instanceof CompoundType) {
|
|
|
+ reject(new Error("Invalid operation. This must be a vector: line "+cmd.sourceInfo.line));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ newArray.value[line] = value;
|
|
|
+ store.updateStore(cmd.id, newArray);
|
|
|
+ }
|
|
|
+ resolve(store);
|
|
|
+ }).catch(err => reject(err));
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
executeDeclaration (store, cmd) {
|
|
|
try {
|
|
|
const $value = this.evaluateExpression(store, cmd.initial);
|
|
@@ -486,37 +520,65 @@ export class IVProgProcessor {
|
|
|
const $columns = cmd.columns === null ? null: this.evaluateExpression(store, cmd.columns);
|
|
|
return Promise.all([$lines, $columns, $value]).then(values => {
|
|
|
const lineSO = values[0];
|
|
|
- if(lineSO.type !== Types.INTEGER) {
|
|
|
+ if(!Types.INTEGER.isCompatible(lineSO.type)) {
|
|
|
|
|
|
|
|
|
return Promise.reject(new Error("Array dimension must be of type int"));
|
|
|
}
|
|
|
- const line = lineSO.value;
|
|
|
+ const line = lineSO.number;
|
|
|
const columnSO = values[1];
|
|
|
let column = null
|
|
|
if (columnSO !== null) {
|
|
|
- if(columnSO.type !== Types.INTEGER) {
|
|
|
+ if(!Types.INTEGER.isCompatible(columnSO.type)) {
|
|
|
|
|
|
|
|
|
return Promise.reject(new Error("Array dimension must be of type int"));
|
|
|
}
|
|
|
- column = columnSO.value;
|
|
|
+ column = columnSO.number;
|
|
|
}
|
|
|
const value = values[2];
|
|
|
- const temp = new StoreObjectArray(cmd.subtype, line, column, null, cmd.isConst);
|
|
|
+ const temp = new StoreObjectArray(cmd.type, line, column, null);
|
|
|
store.insertStore(cmd.id, temp);
|
|
|
- if(value !== null) {
|
|
|
- store.updateStore(cmd.id, value);
|
|
|
+ let realValue = value;
|
|
|
+ if (value !== null) {
|
|
|
+ if(value instanceof StoreObjectArrayAddress) {
|
|
|
+ if(value.type instanceof CompoundType) {
|
|
|
+ realValue = Object.assign(new StoreObjectArray(null,null,null), value.refValue);
|
|
|
+ } else {
|
|
|
+ realValue = Object.assign(new StoreObject(null,null), value.refValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ realValue = new StoreObjectArray(cmd.type, line, column, [])
|
|
|
+ if(column !== null) {
|
|
|
+ for (let i = 0; i < line; i++) {
|
|
|
+ realValue.value.push(new StoreObjectArray(new CompoundType(cmd.type.innerType, 1), column, null, []));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+ realValue.readOnly = cmd.isConst;
|
|
|
+ store.updateStore(cmd.id, realValue);
|
|
|
return store;
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
- const temp = new StoreObject(cmd.type, null, cmd.isConst);
|
|
|
+ const temp = new StoreObject(cmd.type, null);
|
|
|
store.insertStore(cmd.id, temp);
|
|
|
return $value.then(vl => {
|
|
|
- if (vl !== null)
|
|
|
- store.updateStore(cmd.id, vl)
|
|
|
+ let realValue = vl;
|
|
|
+ if (vl !== null) {
|
|
|
+ if(vl instanceof StoreObjectArrayAddress) {
|
|
|
+ if(vl.type instanceof CompoundType) {
|
|
|
+ realValue = Object.assign(new StoreObjectArray(null,null,null), vl.refValue);
|
|
|
+ } else {
|
|
|
+ realValue = Object.assign(new StoreObject(null,null), vl.refValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ realValue = new StoreObject(cmd.type,0);
|
|
|
+ }
|
|
|
+ realValue.readOnly = cmd.isConst;
|
|
|
+ store.updateStore(cmd.id, realValue);
|
|
|
return store;
|
|
|
});
|
|
|
}
|
|
@@ -548,20 +610,22 @@ export class IVProgProcessor {
|
|
|
} else if (exp instanceof Expressions.FunctionCall) {
|
|
|
return this.evaluateFunctionCall(store, exp);
|
|
|
}
|
|
|
- console.log('null exp');
|
|
|
return Promise.resolve(null);
|
|
|
}
|
|
|
|
|
|
evaluateFunctionCall (store, exp) {
|
|
|
const func = this.findFunction(exp.id);
|
|
|
- if(func.returnType === Types.VOID) {
|
|
|
+ if(Types.VOID.isCompatible(func.returnType)) {
|
|
|
|
|
|
return Promise.reject(new Error(`Function ${exp.id} cannot be used inside an expression`));
|
|
|
}
|
|
|
const $newStore = this.runFunction(func, exp.actualParameters, store);
|
|
|
return $newStore.then( sto => {
|
|
|
+ if(sto.mode !== Modes.RETURN) {
|
|
|
+ return Promise.reject(new Error("The function that was called did not had a return command: "+exp.id));
|
|
|
+ }
|
|
|
const val = sto.applyStore('$');
|
|
|
- if (val.type === Types.ARRAY) {
|
|
|
+ if (val instanceof StoreObjectArray) {
|
|
|
return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null,null), val));
|
|
|
} else {
|
|
|
return Promise.resolve(Object.assign(new StoreObject(null,null), val));
|
|
@@ -573,7 +637,8 @@ export class IVProgProcessor {
|
|
|
if(!exp.isVector) {
|
|
|
const $matrix = this.evaluateMatrix(store, exp.value);
|
|
|
return $matrix.then(list => {
|
|
|
- const arr = new StoreObjectArray(list[0].subtype, list.length, list[0].lines, list);
|
|
|
+ const type = new CompoundType(list[0].type.innerType, 2);
|
|
|
+ const arr = new StoreObjectArray(type, list.length, list[0].lines, list);
|
|
|
if(arr.isValid)
|
|
|
return Promise.resolve(arr);
|
|
|
else
|
|
@@ -581,7 +646,8 @@ export class IVProgProcessor {
|
|
|
});
|
|
|
} else {
|
|
|
return this.evaluateVector(store, exp.value).then(list => {
|
|
|
- const stoArray = new StoreObjectArray(list[0].type, list.length, null, list);
|
|
|
+ const type = new CompoundType(list[0].type, 1);
|
|
|
+ const stoArray = new StoreObjectArray(type, list.length, null, list);
|
|
|
if(stoArray.isValid)
|
|
|
return Promise.resolve(stoArray);
|
|
|
else
|
|
@@ -597,7 +663,10 @@ export class IVProgProcessor {
|
|
|
evaluateMatrix (store, exps) {
|
|
|
return Promise.all(exps.map( vector => {
|
|
|
const $vector = this.evaluateVector(store, vector.value)
|
|
|
- return $vector.then(list => new StoreObjectArray(list[0].type, list.length, null, list))
|
|
|
+ return $vector.then(list => {
|
|
|
+ const type = new CompoundType(list[0].type, 1);
|
|
|
+ return new StoreObjectArray(type, list.length, null, list)
|
|
|
+ });
|
|
|
} ));
|
|
|
}
|
|
|
|
|
@@ -608,7 +677,7 @@ export class IVProgProcessor {
|
|
|
evaluateVariableLiteral (store, exp) {
|
|
|
try {
|
|
|
const val = store.applyStore(exp.id);
|
|
|
- if (val.type === Types.ARRAY) {
|
|
|
+ if (val instanceof StoreObjectArray) {
|
|
|
return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null), val));
|
|
|
} else {
|
|
|
return Promise.resolve(Object.assign(new StoreObject(null,null), val));
|
|
@@ -620,8 +689,9 @@ export class IVProgProcessor {
|
|
|
|
|
|
evaluateArrayAccess (store, exp) {
|
|
|
const mustBeArray = store.applyStore(exp.id);
|
|
|
- if (mustBeArray.type !== Types.ARRAY) {
|
|
|
+ if (!(mustBeArray.type instanceof CompoundType)) {
|
|
|
|
|
|
+ console.log(mustBeArray.type);
|
|
|
return Promise.reject(new Error(`${exp.id} is not of type array`));
|
|
|
}
|
|
|
const $line = this.evaluateExpression(store, exp.line);
|
|
@@ -629,20 +699,20 @@ export class IVProgProcessor {
|
|
|
return Promise.all([$line, $column]).then(values => {
|
|
|
const lineSO = values[0];
|
|
|
const columnSO = values[1];
|
|
|
- if(lineSO.type !== Types.INTEGER) {
|
|
|
+ if(!Types.INTEGER.isCompatible(lineSO.type)) {
|
|
|
|
|
|
|
|
|
return Promise.reject(new Error("Array dimension must be of type int"));
|
|
|
}
|
|
|
- const line = lineSO.value;
|
|
|
+ const line = lineSO.number;
|
|
|
let column = null;
|
|
|
if(columnSO !== null) {
|
|
|
- if(columnSO.type !== Types.INTEGER) {
|
|
|
+ if(!Types.INTEGER.isCompatible(columnSO.type)) {
|
|
|
|
|
|
|
|
|
return Promise.reject(new Error("Array dimension must be of type int"));
|
|
|
}
|
|
|
- column = columnSO.value;
|
|
|
+ column = columnSO.number;
|
|
|
}
|
|
|
|
|
|
if (line >= mustBeArray.lines) {
|
|
@@ -657,12 +727,7 @@ export class IVProgProcessor {
|
|
|
|
|
|
return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
|
|
|
}
|
|
|
-
|
|
|
- if (column !== null) {
|
|
|
- return Promise.resolve(mustBeArray.value[line].value[column]);
|
|
|
- } else {
|
|
|
- return Promise.resolve(mustBeArray.value[line]);
|
|
|
- }
|
|
|
+ return Promise.resolve(new StoreObjectArrayAddress(mustBeArray.id, line, column, store));
|
|
|
});
|
|
|
}
|
|
|
|
|
@@ -670,15 +735,15 @@ export class IVProgProcessor {
|
|
|
const $left = this.evaluateExpression(store, unaryApp.left);
|
|
|
return $left.then( left => {
|
|
|
const resultType = resultTypeAfterUnaryOp(unaryApp.op, left.type);
|
|
|
- if (resultType === Types.UNDEFINED) {
|
|
|
+ if (Types.UNDEFINED.isCompatible(resultType)) {
|
|
|
|
|
|
return Promise.reject(new Error(`Cannot use this op to ${left.type}`));
|
|
|
}
|
|
|
switch (unaryApp.op.ord) {
|
|
|
case Operators.ADD.ord:
|
|
|
- return new StoreObject(resultType, +left.value);
|
|
|
+ return new StoreObject(resultType, left.value);
|
|
|
case Operators.SUB.ord:
|
|
|
- return new StoreObject(resultType, -left.value);
|
|
|
+ return new StoreObject(resultType, left.value.negated());
|
|
|
case Operators.NOT.ord:
|
|
|
return new StoreObject(resultType, !left.value);
|
|
|
default:
|
|
@@ -694,42 +759,85 @@ export class IVProgProcessor {
|
|
|
const left = values[0];
|
|
|
const right = values[1];
|
|
|
const resultType = resultTypeAfterInfixOp(infixApp.op, left.type, right.type);
|
|
|
- if (resultType === Types.UNDEFINED) {
|
|
|
+ if (Types.UNDEFINED.isCompatible(resultType)) {
|
|
|
|
|
|
- return Promise.reject(new Error(`Cannot use this op to ${left.type} and ${right.type}`));
|
|
|
+ return Promise.reject(new Error(`Cannot use this ${infixApp.op} to ${left.type} and ${right.type}`));
|
|
|
}
|
|
|
let result = null;
|
|
|
switch (infixApp.op.ord) {
|
|
|
- case Operators.ADD.ord:
|
|
|
- return new StoreObject(resultType, left.value + right.value);
|
|
|
- case Operators.SUB.ord:
|
|
|
- return new StoreObject(resultType, left.value - right.value);
|
|
|
- case Operators.MULT.ord: {
|
|
|
- result = left.value * right.value;
|
|
|
- if (resultType === Types.INTEGER)
|
|
|
- result = Math.trunc(result);
|
|
|
- return new StoreObject(resultType, result);
|
|
|
+ case Operators.ADD.ord: {
|
|
|
+ if(Types.STRING.isCompatible(left.type)) {
|
|
|
+ const rightStr = convertToString(right.value, right.type);
|
|
|
+ return new StoreObject(resultType, left.value + rightStr);
|
|
|
+ } else if (Types.STRING.isCompatible(right.type)) {
|
|
|
+ const leftStr = convertToString(left.value, left.type);
|
|
|
+ return new StoreObject(resultType, leftStr + right.value);
|
|
|
+ } else {
|
|
|
+ return new StoreObject(resultType, left.value.plus(right.value));
|
|
|
+ }
|
|
|
}
|
|
|
+ case Operators.SUB.ord:
|
|
|
+ return new StoreObject(resultType, left.value.minus(right.value));
|
|
|
+ case Operators.MULT.ord:
|
|
|
+ return new StoreObject(resultType, left.value.times(right.value));
|
|
|
case Operators.DIV.ord: {
|
|
|
result = left.value / right.value;
|
|
|
- if (resultType === Types.INTEGER)
|
|
|
- result = Math.trunc(result);
|
|
|
+ if (Types.INTEGER.isCompatible(resultType))
|
|
|
+ result = left.value.idiv(right.value);
|
|
|
+ else
|
|
|
+ result = left.value.div(right.value);
|
|
|
return new StoreObject(resultType, result);
|
|
|
}
|
|
|
case Operators.MOD.ord:
|
|
|
- return new StoreObject(resultType, left.value % right.value);
|
|
|
- case Operators.GT.ord:
|
|
|
- return new StoreObject(resultType, left.value > right.value);
|
|
|
- case Operators.GE.ord:
|
|
|
- return new StoreObject(resultType, left.value >= right.value);
|
|
|
- case Operators.LT.ord:
|
|
|
- return new StoreObject(resultType, left.value < right.value);
|
|
|
- case Operators.LE.ord:
|
|
|
- return new StoreObject(resultType, left.value <= right.value);
|
|
|
- case Operators.EQ.ord:
|
|
|
- return new StoreObject(resultType, left.value === right.value);
|
|
|
- case Operators.NEQ.ord:
|
|
|
- return new StoreObject(resultType, left.value !== right.value);
|
|
|
+ return new StoreObject(resultType, left.value.modulo(right.value));
|
|
|
+ case Operators.GT.ord: {
|
|
|
+ if (Types.STRING.isCompatible(left.type)) {
|
|
|
+ result = left.value.length > right.value.length;
|
|
|
+ } else {
|
|
|
+ result = left.value.gt(right.value);
|
|
|
+ }
|
|
|
+ return new StoreObject(resultType, result);
|
|
|
+ }
|
|
|
+ case Operators.GE.ord: {
|
|
|
+ if (Types.STRING.isCompatible(left.type)) {
|
|
|
+ result = left.value.length >= right.value.length;
|
|
|
+ } else {
|
|
|
+ result = left.value.gte(right.value);
|
|
|
+ }
|
|
|
+ return new StoreObject(resultType, result);
|
|
|
+ }
|
|
|
+ case Operators.LT.ord: {
|
|
|
+ if (Types.STRING.isCompatible(left.type)) {
|
|
|
+ result = left.value.length < right.value.length;
|
|
|
+ } else {
|
|
|
+ result = left.value.lt(right.value);
|
|
|
+ }
|
|
|
+ return new StoreObject(resultType, result);
|
|
|
+ }
|
|
|
+ case Operators.LE.ord: {
|
|
|
+ if (Types.STRING.isCompatible(left.type)) {
|
|
|
+ result = left.value.length <= right.value.length;
|
|
|
+ } else {
|
|
|
+ result = left.value.lte(right.value);
|
|
|
+ }
|
|
|
+ return new StoreObject(resultType, result);
|
|
|
+ }
|
|
|
+ case Operators.EQ.ord: {
|
|
|
+ if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
|
|
|
+ result = left.value.eq(right.value);
|
|
|
+ } else {
|
|
|
+ result = left.value === right.value;
|
|
|
+ }
|
|
|
+ return new StoreObject(resultType, result);
|
|
|
+ }
|
|
|
+ case Operators.NEQ.ord: {
|
|
|
+ if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
|
|
|
+ result = !left.value.eq(right.value);
|
|
|
+ } else {
|
|
|
+ result = left.value !== right.value;
|
|
|
+ }
|
|
|
+ return new StoreObject(resultType, result);
|
|
|
+ }
|
|
|
case Operators.AND.ord:
|
|
|
return new StoreObject(resultType, left.value && right.value);
|
|
|
case Operators.OR.ord:
|
|
@@ -740,4 +848,24 @@ export class IVProgProcessor {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ parseStoreObjectValue (vl) {
|
|
|
+ let realValue = vl;
|
|
|
+ if(vl instanceof StoreObjectArrayAddress) {
|
|
|
+ if(vl.type instanceof CompoundType) {
|
|
|
+ switch(vl.type.dimensions) {
|
|
|
+ case 1: {
|
|
|
+ realValue = new StoreObjectArray(vl.type, vl.value);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ throw new Error("Three dimensional array address...");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ realValue = new StoreObject(vl.type, vl.value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return realValue;
|
|
|
+ }
|
|
|
+
|
|
|
}
|