|
@@ -9,6 +9,8 @@ import * as Commands from './../ast/commands/';
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
import { Command } from './../ast/commands/command'
|
|
|
import * as Expressions from './../ast/expressions/';
|
|
|
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
+import { Expression } from './../ast/expressions/expression'
|
|
|
import * as Utils from './../util/utils';
|
|
|
import { ArrayType } from './../typeSystem/array_type';
|
|
|
import { convertToString, toInt } from '../typeSystem/parsers';
|
|
@@ -205,7 +207,9 @@ export class IVProgProcessor {
|
|
|
/**
|
|
|
*
|
|
|
* @param {Store} store
|
|
|
- * @param {Command[]} cmds
|
|
|
+ * @param {Command[]} cmds
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
*/
|
|
|
async executeCommands (store, cmds) {
|
|
|
// helper to partially apply a function, in this case executeCommand
|
|
@@ -219,7 +223,9 @@ export class IVProgProcessor {
|
|
|
/**
|
|
|
*
|
|
|
* @param {Store} store
|
|
|
- * @param {Command} cmd
|
|
|
+ * @param {Command} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
*/
|
|
|
async executeCommand (store, cmd) {
|
|
|
this.instruction_count += 1;
|
|
@@ -272,11 +278,25 @@ export class IVProgProcessor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.SysCall} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
executeSysCall (store, cmd) {
|
|
|
const func = cmd.langFunc.bind(this);
|
|
|
return func(store, cmd);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.FunctionCall} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
async executeFunctionCall (store, cmd) {
|
|
|
let func = null;
|
|
|
if(cmd.isMainCall) {
|
|
@@ -297,384 +317,375 @@ export class IVProgProcessor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- executeSwitch (store, cmd) {
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.Switch} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
+ async executeSwitch (store, cmd) {
|
|
|
this.context.push(Context.BREAKABLE);
|
|
|
- const caseSequence = cmd.cases.reduce( (prev,next) => {
|
|
|
- return prev.then( tuple => {
|
|
|
- if(this.ignoreSwitchCases(tuple[1])) {
|
|
|
- return Promise.resolve(tuple);
|
|
|
- } else if(tuple[0] || next.isDefault) {
|
|
|
- return this.executeCommands(tuple[1], next.commands)
|
|
|
- .then(nSto => Promise.resolve([true, nSto]));
|
|
|
- } else {
|
|
|
- const equalityInfixApp = new Expressions.InfixApp(Operators.EQ, cmd.expression, next.expression);
|
|
|
- equalityInfixApp.sourceInfo = next.sourceInfo;
|
|
|
- return this.evaluateExpression(tuple[1],equalityInfixApp).then(stoObj => stoObj.get())
|
|
|
- .then(isEqual => {
|
|
|
- if (isEqual) {
|
|
|
- return this.executeCommands(tuple[1], next.commands)
|
|
|
- .then(nSto => Promise.resolve([true, nSto]));
|
|
|
- } else {
|
|
|
- return Promise.resolve(tuple);
|
|
|
- }
|
|
|
- });
|
|
|
+ const switchCases = cmd.cases;
|
|
|
+ let lastStore = store;
|
|
|
+ let lastCaseCheckResult = false;
|
|
|
+ for (let i = 0; i < switchCases.length && !this.ignoreSwitchCases(lastStore); i += 1) {
|
|
|
+ const switchCase = switchCases[i];
|
|
|
+ if (lastCaseCheckResult || switchCase.isDefault) {
|
|
|
+ lastStore = await this.executeCommands(lastStore, switchCase.commands);
|
|
|
+ } else {
|
|
|
+ const equalityInfixApp = new Expressions.InfixApp(Operators.EQ, cmd.expression, switchCase.expression);
|
|
|
+ equalityInfixApp.sourceInfo = switchCase.sourceInfo;
|
|
|
+ const result = await this.evaluateExpression(lastStore, equalityInfixApp);
|
|
|
+ if (result.get()) {
|
|
|
+ lastStore = await this.executeCommands(lastStore, switchCase.commands);
|
|
|
}
|
|
|
- });
|
|
|
- }, Promise.resolve([false, store]));
|
|
|
- return caseSequence.then(tuple => {
|
|
|
- this.context.pop();
|
|
|
- const newStore = tuple[1];
|
|
|
- if (newStore.mode === Modes.BREAK) {
|
|
|
- newStore.mode = Modes.RUN;
|
|
|
+ lastCaseCheckResult = result.get();
|
|
|
}
|
|
|
- return newStore;
|
|
|
- });
|
|
|
+ }
|
|
|
+ this.context.pop();
|
|
|
+ if (lastStore.mode === Modes.BREAK) {
|
|
|
+ lastStore.mode = Modes.RUN;
|
|
|
+ }
|
|
|
+ return lastStore;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
*
|
|
|
* @param {Store} store
|
|
|
* @param {Commands.For} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
*/
|
|
|
- executeFor (store, cmd) {
|
|
|
+ async executeFor (store, cmd) {
|
|
|
//BEGIN for -> while rewrite
|
|
|
const initCmd = new Commands.Assign(cmd.for_id.id, cmd.for_from);
|
|
|
initCmd.sourceInfo = cmd.sourceInfo;
|
|
|
- const expression_tuple = []; //(for conditional, is for increasing)
|
|
|
+ // Assume for is iterating forward and that pass is not missing
|
|
|
+ let passValue = cmd.for_pass;
|
|
|
+ let condition = new Expressions.InfixApp(Operators.LE, cmd.for_id, cmd.for_to);
|
|
|
+
|
|
|
if(cmd.for_pass == null) {
|
|
|
- expression_tuple.push(Promise.resolve(null));
|
|
|
- expression_tuple.push(this.evaluateExpression(store, new Expressions.InfixApp(Operators.GE, cmd.for_to, cmd.for_from)));
|
|
|
+ passValue = new Expressions.IntLiteral(toInt(1));
|
|
|
+ const checkEndGTBegin = await this.evaluateExpression(store,
|
|
|
+ new Expressions.InfixApp(Operators.GE, cmd.for_to, cmd.for_from));
|
|
|
+ if (!checkEndGTBegin.get()) {
|
|
|
+ passValue = new Expressions.IntLiteral(toInt(-1));
|
|
|
+ condition = new Expressions.InfixApp(Operators.GE, cmd.for_id, cmd.for_to);
|
|
|
+ }
|
|
|
} else {
|
|
|
- expression_tuple.push(this.evaluateExpression(store, new Expressions.InfixApp(Operators.GE, cmd.for_pass, new Expressions.IntLiteral(toInt(0)))));
|
|
|
- expression_tuple.push(Promise.resolve(null));
|
|
|
- }
|
|
|
-
|
|
|
- return Promise.all(expression_tuple).then (results => {
|
|
|
- // console.log(results);
|
|
|
- let is_forward = true;
|
|
|
- let is_end_gt_init = undefined;
|
|
|
- let condition = null;
|
|
|
- let pass_value = cmd.for_pass;
|
|
|
- if (results[0] == null) {
|
|
|
- // pass is null, we need to deduce a value for it
|
|
|
- is_end_gt_init = results[1].value;
|
|
|
- } else {
|
|
|
- is_forward = results[0].value
|
|
|
+ const isForward = await this.evaluateExpression(store, new Expressions.InfixApp(Operators.GE,
|
|
|
+ cmd.for_pass, new Expressions.IntLiteral(toInt(0))));
|
|
|
+ if (!isForward.get()) {
|
|
|
+ condition = new Expressions.InfixApp(Operators.GE, cmd.for_id, cmd.for_to)
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if(is_end_gt_init == null) {
|
|
|
- // console.log("pass is not null and is forward? ", is_forward);
|
|
|
- if(is_forward) {
|
|
|
- condition = new Expressions.InfixApp(Operators.LE, cmd.for_id, cmd.for_to);
|
|
|
- } else {
|
|
|
- condition = new Expressions.InfixApp(Operators.GE, cmd.for_id, cmd.for_to);
|
|
|
- }
|
|
|
- // console.log("Cond", condition);
|
|
|
- } else if(is_end_gt_init) {
|
|
|
- pass_value = new Expressions.IntLiteral(toInt(1));
|
|
|
- condition = new Expressions.InfixApp(Operators.LE, cmd.for_id, cmd.for_to);
|
|
|
- } else {
|
|
|
- pass_value = new Expressions.IntLiteral(toInt(-1));
|
|
|
- condition = new Expressions.InfixApp(Operators.GE, cmd.for_id, cmd.for_to);
|
|
|
- }
|
|
|
- condition.sourceInfo = cmd.sourceInfo;
|
|
|
- const increment = new Commands.Assign(cmd.for_id.id,
|
|
|
- new Expressions.InfixApp(Operators.ADD, cmd.for_id, pass_value));
|
|
|
- increment.sourceInfo = cmd.sourceInfo;
|
|
|
- const whileBlock = new Commands.CommandBlock([],
|
|
|
- cmd.commands.concat(increment));
|
|
|
- const forAsWhile = new Commands.While(condition, whileBlock);
|
|
|
- forAsWhile.sourceInfo = cmd.sourceInfo;
|
|
|
- //END for -> while rewrite
|
|
|
- const newCmdList = [initCmd,forAsWhile];
|
|
|
- return this.executeCommands(store, newCmdList);
|
|
|
- }).catch(error => Promise.reject(error));
|
|
|
+ condition.sourceInfo = cmd.sourceInfo;
|
|
|
+ const increment = new Commands.Assign(cmd.for_id.id,
|
|
|
+ new Expressions.InfixApp(Operators.ADD, cmd.for_id, passValue));
|
|
|
+ increment.sourceInfo = cmd.sourceInfo;
|
|
|
+ const whileBlock = new Commands.CommandBlock([],
|
|
|
+ cmd.commands.concat(increment));
|
|
|
+ const forAsWhile = new Commands.While(condition, whileBlock);
|
|
|
+ forAsWhile.sourceInfo = cmd.sourceInfo;
|
|
|
+ //END for -> while rewrite
|
|
|
+ const newCmdList = [initCmd,forAsWhile];
|
|
|
+ return this.executeCommands(store, newCmdList);
|
|
|
}
|
|
|
|
|
|
- executeRepeatUntil (store, cmd) {
|
|
|
- try {
|
|
|
- this.context.push(Context.BREAKABLE);
|
|
|
- const $newStore = this.executeCommands(store, cmd.commands);
|
|
|
- return $newStore.then(sto => {
|
|
|
- if(sto.mode === Modes.BREAK) {
|
|
|
- this.context.pop();
|
|
|
- sto.mode = Modes.RUN;
|
|
|
- return sto;
|
|
|
- }
|
|
|
- const $value = this.evaluateExpression(sto, cmd.expression);
|
|
|
- return $value.then(vl => {
|
|
|
- if (!vl.type.isCompatible(Types.BOOLEAN)) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.loop_condition_type_full(cmd.sourceInfo));
|
|
|
- }
|
|
|
- if (!vl.get()) {
|
|
|
- this.context.pop();
|
|
|
- return this.executeCommand(sto, cmd);
|
|
|
- } else {
|
|
|
- this.context.pop();
|
|
|
- return sto;
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- } catch (error) {
|
|
|
- return Promise.reject(error);
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.RepeatUntil} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
+ async executeRepeatUntil (store, cmd) {
|
|
|
+ this.context.push(Context.BREAKABLE);
|
|
|
+ const sto = await this.executeCommands(store, cmd.commands);
|
|
|
+ if(sto.mode === Modes.BREAK) {
|
|
|
+ this.context.pop();
|
|
|
+ sto.mode = Modes.RUN;
|
|
|
+ return sto;
|
|
|
+ }
|
|
|
+ const checkCondition = await this.evaluateExpression(sto, cmd.expression);
|
|
|
+ if (!checkCondition.type.isCompatible(Types.BOOLEAN)) {
|
|
|
+ throw ProcessorErrorFactory.loop_condition_type_full(cmd.sourceInfo);
|
|
|
+ }
|
|
|
+ this.context.pop();
|
|
|
+ if (checkCondition.get()) {
|
|
|
+ return sto;
|
|
|
+ } else {
|
|
|
+ return this.executeCommand(sto, cmd);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- executeWhile (store, cmd) {
|
|
|
- try {
|
|
|
- this.context.push(Context.BREAKABLE);
|
|
|
- const $value = this.evaluateExpression(store, cmd.expression);
|
|
|
- return $value.then(vl => {
|
|
|
- if(vl.type.isCompatible(Types.BOOLEAN)) {
|
|
|
- if(vl.get()) {
|
|
|
- const $newStore = this.executeCommands(store, cmd.commands);
|
|
|
- return $newStore.then(sto => {
|
|
|
- this.context.pop();
|
|
|
- if (sto.mode === Modes.BREAK) {
|
|
|
- sto.mode = Modes.RUN;
|
|
|
- return sto;
|
|
|
- }
|
|
|
- return this.executeCommand(sto, cmd);
|
|
|
- });
|
|
|
- } else {
|
|
|
- this.context.pop();
|
|
|
- return store;
|
|
|
- }
|
|
|
- } else {
|
|
|
- return Promise.reject(ProcessorErrorFactory.loop_condition_type_full(cmd.expression.toString(), cmd.sourceInfo));
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- } catch (error) {
|
|
|
- return Promise.reject(error);
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.While} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
+ async executeWhile (store, cmd) {
|
|
|
+ this.context.push(Context.BREAKABLE);
|
|
|
+ const checkCondition = await this.evaluateExpression(store, cmd.expression);
|
|
|
+ if(!checkCondition.type.isCompatible(Types.BOOLEAN)) {
|
|
|
+ throw ProcessorErrorFactory.loop_condition_type_full(cmd.expression.toString(), cmd.sourceInfo);
|
|
|
+ }
|
|
|
+ if(checkCondition.get()) {
|
|
|
+ const sto = await this.executeCommands(store, cmd.commands);
|
|
|
+ this.context.pop();
|
|
|
+ if (sto.mode === Modes.BREAK) {
|
|
|
+ sto.mode = Modes.RUN;
|
|
|
+ return sto;
|
|
|
+ }
|
|
|
+ return this.executeCommand(sto, cmd);
|
|
|
+ } else {
|
|
|
+ this.context.pop();
|
|
|
+ return store;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- executeIfThenElse (store, cmd) {
|
|
|
- try {
|
|
|
- const $value = this.evaluateExpression(store, cmd.condition);
|
|
|
- return $value.then(vl => {
|
|
|
- if(vl.type.isCompatible(Types.BOOLEAN)) {
|
|
|
- if(vl.get()) {
|
|
|
- return this.executeCommands(store, cmd.ifTrue.commands);
|
|
|
- } else if( cmd.ifFalse !== null){
|
|
|
- if(cmd.ifFalse instanceof Commands.IfThenElse) {
|
|
|
- return this.executeCommand(store, cmd.ifFalse);
|
|
|
- } else {
|
|
|
- return this.executeCommands(store, cmd.ifFalse.commands);
|
|
|
- }
|
|
|
- } else {
|
|
|
- return Promise.resolve(store);
|
|
|
- }
|
|
|
- } else {
|
|
|
- return Promise.reject(ProcessorErrorFactory.if_condition_type_full(cmd.condition.toString(), cmd.sourceInfo));
|
|
|
- }
|
|
|
- });
|
|
|
- } catch (error) {
|
|
|
- return Promise.reject(error);
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.IfThenElse} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
+ async executeIfThenElse (store, cmd) {
|
|
|
+ const isTrue = await this.evaluateExpression(store, cmd.condition);
|
|
|
+ if (!isTrue.type.isCompatible(Types.BOOLEAN)) {
|
|
|
+ throw ProcessorErrorFactory.if_condition_type_full(cmd.condition.toString(), cmd.sourceInfo);
|
|
|
+ }
|
|
|
+ if (isTrue.get()) {
|
|
|
+ return this.executeCommands(store, cmd.ifTrue.commands);
|
|
|
+ } else if (cmd.ifFalse !== null) {
|
|
|
+ if (cmd.ifFalse instanceof Commands.IfThenElse) {
|
|
|
+ return this.executeCommand(store, cmd.ifFalse);
|
|
|
+ } else {
|
|
|
+ return this.executeCommands(store, cmd.ifFalse.commands);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return store;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- executeReturn (store, cmd) {
|
|
|
- try {
|
|
|
- const funcName = store.name === IVProgProcessor.MAIN_INTERNAL_ID ?
|
|
|
- LanguageDefinedFunction.getMainFunctionName() : store.name;
|
|
|
- // console.log(funcName, store.name === IVProgProcessor.MAIN_INTERNAL_ID);
|
|
|
- const func = this.findFunction(store.name);
|
|
|
- const funcType = func.returnType;
|
|
|
- const $value = this.evaluateExpression(store, cmd.expression);
|
|
|
-
|
|
|
- return $value.then(value => {
|
|
|
-
|
|
|
- let real_value = value;
|
|
|
- if(value === null && funcType.isCompatible(Types.VOID)) {
|
|
|
- store.mode = Modes.RETURN;
|
|
|
- return Promise.resolve(store);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.Return} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
+ async executeReturn (store, cmd) {
|
|
|
+ const funcName = store.name === IVProgProcessor.MAIN_INTERNAL_ID ?
|
|
|
+ LanguageDefinedFunction.getMainFunctionName() : store.name;
|
|
|
+ // console.log(funcName, store.name === IVProgProcessor.MAIN_INTERNAL_ID);
|
|
|
+ const func = this.findFunction(store.name);
|
|
|
+ const funcType = func.returnType;
|
|
|
+ const value = await this.evaluateExpression(store, cmd.expression);
|
|
|
+ if(value === null && funcType.isCompatible(Types.VOID)) {
|
|
|
+ store.mode = Modes.RETURN;
|
|
|
+ return store;
|
|
|
+ }
|
|
|
|
|
|
- if (value === null || !funcType.isCompatible(value.type)) {
|
|
|
- if(!Config.enable_type_casting || !Store.canImplicitTypeCast(funcType, value.type)) {
|
|
|
- const stringInfo = funcType.stringInfo();
|
|
|
- const info = stringInfo[0];
|
|
|
- return Promise.reject(ProcessorErrorFactory.invalid_return_type_full(funcName, info.type, info.dim, cmd.sourceInfo));
|
|
|
- }
|
|
|
- real_value = Store.doImplicitCasting(funcType, value);
|
|
|
- } else {
|
|
|
- store.insertStore('$', real_value);
|
|
|
- store.mode = Modes.RETURN;
|
|
|
- return Promise.resolve(store);
|
|
|
- }
|
|
|
- });
|
|
|
- } catch (error) {
|
|
|
- return Promise.reject(error);
|
|
|
+ let real_value = value;
|
|
|
+ if (value === null || !funcType.isCompatible(value.type)) {
|
|
|
+ if (!Config.enable_type_casting || !Store.canImplicitTypeCast(funcType, value.type)) {
|
|
|
+ const stringInfo = funcType.stringInfo();
|
|
|
+ const info = stringInfo[0];
|
|
|
+ throw ProcessorErrorFactory.invalid_return_type_full(funcName, info.type, info.dim,
|
|
|
+ cmd.sourceInfo);
|
|
|
+ }
|
|
|
+ real_value = Store.doImplicitCasting(funcType, value);
|
|
|
}
|
|
|
+
|
|
|
+ store.insertStore('$', real_value);
|
|
|
+ store.mode = Modes.RETURN;
|
|
|
+ return store;
|
|
|
}
|
|
|
|
|
|
- executeBreak (store, cmd) {
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.Break} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
+ async executeBreak (store, cmd) {
|
|
|
if(this.checkContext(Context.BREAKABLE)) {
|
|
|
store.mode = Modes.BREAK;
|
|
|
- return Promise.resolve(store);
|
|
|
+ return store;
|
|
|
} else {
|
|
|
- return Promise.reject(ProcessorErrorFactory.unexpected_break_command_full(cmd.sourceInfo));
|
|
|
+ throw ProcessorErrorFactory.unexpected_break_command_full(cmd.sourceInfo);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- executeAssign (store, cmd) {
|
|
|
- try {
|
|
|
- const inStore = store.applyStore(cmd.id);
|
|
|
- if(inStore.isConst) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.invalid_const_assignment_full(cmd.id, cmd.sourceInfo))
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.Assign} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
+ async executeAssign (store, cmd) {
|
|
|
+ const inStore = store.applyStore(cmd.id);
|
|
|
+ if (inStore.isConst) {
|
|
|
+ throw ProcessorErrorFactory.invalid_const_assignment_full(cmd.id, cmd.sourceInfo);
|
|
|
+ }
|
|
|
+ const value = await this.evaluateExpression(store, cmd.expression);
|
|
|
+ let realValue = value;
|
|
|
+ if (!inStore.type.isCompatible(realValue.type)) {
|
|
|
+ if (Config.enable_type_casting && Store.canImplicitTypeCast(inStore.type, value.type)) {
|
|
|
+ realValue = Store.doImplicitCasting(inStore.type, realValue);
|
|
|
+ } else {
|
|
|
+ const stringInfo = inStore.type.stringInfo()
|
|
|
+ const info = stringInfo[0]
|
|
|
+ const exp_type_string_info = value.type.stringInfo();
|
|
|
+ const exp_type_info = exp_type_string_info[0];
|
|
|
+ const exp = cmd.expression.toString();
|
|
|
+ throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type,
|
|
|
+ exp_type_info.dim, exp, cmd.sourceInfo);
|
|
|
}
|
|
|
- const $value = this.evaluateExpression(store, cmd.expression);
|
|
|
- return $value.then( vl => {
|
|
|
- let realValue = vl;
|
|
|
- if(!inStore.type.isCompatible(realValue.type)) {
|
|
|
- if(Config.enable_type_casting && Store.canImplicitTypeCast(inStore.type, vl.type)) {
|
|
|
- realValue = Store.doImplicitCasting(inStore.type, realValue);
|
|
|
- } else {
|
|
|
- const stringInfo = inStore.type.stringInfo()
|
|
|
- const info = stringInfo[0]
|
|
|
- const exp_type_string_info = vl.type.stringInfo();
|
|
|
- const exp_type_info = exp_type_string_info[0];
|
|
|
- const exp = cmd.expression.toString();
|
|
|
- return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type, exp_type_info.dim, exp, cmd.sourceInfo));
|
|
|
- }
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- if(inStore instanceof ArrayStoreValue) {
|
|
|
- const columns = realValue.columns == null ? 0 : realValue.columns;
|
|
|
- if(inStore.lines !== realValue.lines || inStore.columns !== columns){
|
|
|
- const exp = cmd.expression.toString();
|
|
|
- if(inStore.isVector()) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.invalid_vector_assignment_full(cmd.id, inStore.lines, exp, realValue.lines, cmd.sourceInfo));
|
|
|
- } else {
|
|
|
- return Promise.reject(ProcessorErrorFactory.invalid_matrix_assignment_full(cmd.id, inStore.lines, inStore.columns, exp, realValue.lines, realValue.columns, cmd.sourceInfo));
|
|
|
- }
|
|
|
- }
|
|
|
+ if (inStore instanceof ArrayStoreValue) {
|
|
|
+ const columns = realValue.columns == null ? 0 : realValue.columns;
|
|
|
+ if (inStore.lines !== realValue.lines || inStore.columns !== columns){
|
|
|
+ const exp = cmd.expression.toString();
|
|
|
+ if (inStore.isVector()) {
|
|
|
+ throw ProcessorErrorFactory.invalid_vector_assignment_full(cmd.id, inStore.lines, exp,
|
|
|
+ realValue.lines, cmd.sourceInfo);
|
|
|
+ } else {
|
|
|
+ throw ProcessorErrorFactory.invalid_matrix_assignment_full(cmd.id, inStore.lines,
|
|
|
+ inStore.columns, exp, realValue.lines, realValue.columns, cmd.sourceInfo);
|
|
|
}
|
|
|
-
|
|
|
- store.updateStore(cmd.id, realValue)
|
|
|
- return store;
|
|
|
- });
|
|
|
- } catch (error) {
|
|
|
- return Promise.reject(error);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ store.updateStore(cmd.id, realValue)
|
|
|
+ return store;
|
|
|
}
|
|
|
|
|
|
- executeArrayIndexAssign (store, cmd) {
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Commands.ArrayIndexAssign} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
+ */
|
|
|
+ async executeArrayIndexAssign (store, cmd) {
|
|
|
const mustBeArray = store.applyStore(cmd.id);
|
|
|
let used_dims = 0;
|
|
|
- if(mustBeArray.isConst) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.invalid_const_assignment_full(cmd.id, cmd.sourceInfo))
|
|
|
+ if (mustBeArray.isConst) {
|
|
|
+ throw ProcessorErrorFactory.invalid_const_assignment_full(cmd.id, cmd.sourceInfo);
|
|
|
}
|
|
|
- if(!(mustBeArray.type instanceof ArrayType)) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo));
|
|
|
+ if (!(mustBeArray.type instanceof ArrayType)) {
|
|
|
+ throw ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo);
|
|
|
}
|
|
|
- const line$ = this.evaluateExpression(store, cmd.line);
|
|
|
- const column$ = this.evaluateExpression(store, cmd.column);
|
|
|
- const value$ = this.evaluateExpression(store, cmd.expression);
|
|
|
- return Promise.all([line$, column$, value$]).then(([line_sv, column_sv, value]) => {
|
|
|
- if(!Types.INTEGER.isCompatible(line_sv.type)) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
|
|
|
+ const lineSV = await this.evaluateExpression(store, cmd.line);
|
|
|
+ if (!Types.INTEGER.isCompatible(lineSV.type)) {
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
|
|
|
+ }
|
|
|
+ used_dims += 1;
|
|
|
+ const line = lineSV.get().toNumber();
|
|
|
+ const columnSV = await this.evaluateExpression(store, cmd.column);
|
|
|
+ let column = null;
|
|
|
+ if (columnSV != null) {
|
|
|
+ if(!Types.INTEGER.isCompatible(columnSV.type)) {
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
|
|
|
}
|
|
|
- const line = line_sv.get().toNumber();
|
|
|
+ column = columnSV.get().toNumber();
|
|
|
used_dims += 1;
|
|
|
- let column = undefined;
|
|
|
- if (column_sv != null) {
|
|
|
- if(!Types.INTEGER.isCompatible(column_sv.type)) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
|
|
|
- }
|
|
|
- column = column_sv.get().toNumber();
|
|
|
- used_dims += 1;
|
|
|
- }
|
|
|
- let actualValue = value;
|
|
|
+ }
|
|
|
+ const value = await this.evaluateExpression(store, cmd.expression);
|
|
|
+ let actualValue = value;
|
|
|
if (line >= mustBeArray.lines) {
|
|
|
- if(mustBeArray.isVector) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.vector_line_outbounds_full(cmd.id, line, mustBeArray.lines, cmd.sourceInfo));
|
|
|
+ if (mustBeArray.isVector) {
|
|
|
+ throw ProcessorErrorFactory.vector_line_outbounds_full(cmd.id, line, mustBeArray.lines,
|
|
|
+ cmd.sourceInfo);
|
|
|
} else {
|
|
|
- return Promise.reject(ProcessorErrorFactory.matrix_line_outbounds_full(cmd.id, line, mustBeArray.lines, cmd.sourceInfo));
|
|
|
+ throw ProcessorErrorFactory.matrix_line_outbounds_full(cmd.id, line, mustBeArray.lines,
|
|
|
+ cmd.sourceInfo);
|
|
|
}
|
|
|
} else if (line < 0) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo))
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
|
|
|
}
|
|
|
if (column != null && mustBeArray.columns === 0 ){
|
|
|
- return Promise.reject(ProcessorErrorFactory.vector_not_matrix_full(cmd.id, cmd.sourceInfo));
|
|
|
+ throw ProcessorErrorFactory.vector_not_matrix_full(cmd.id, cmd.sourceInfo);
|
|
|
}
|
|
|
- if(column != null ) {
|
|
|
+ if (column != null) {
|
|
|
if (column >= mustBeArray.columns) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.matrix_column_outbounds_full(cmd.id, column,mustBeArray.columns, cmd.sourceInfo));
|
|
|
+ throw ProcessorErrorFactory.matrix_column_outbounds_full(cmd.id, column,mustBeArray.columns,
|
|
|
+ cmd.sourceInfo);
|
|
|
} else if (column < 0) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo))
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!mustBeArray.type.canAccept(value.type, used_dims)) {
|
|
|
- if(!Config.enable_type_casting || !Store.canImplicitTypeCast(mustBeArray.type.innerType, value.type)) {
|
|
|
+ if (!Config.enable_type_casting || !Store.canImplicitTypeCast(mustBeArray.type.innerType,
|
|
|
+ value.type)) {
|
|
|
+
|
|
|
const type = mustBeArray.type.innerType;
|
|
|
const stringInfo = type.stringInfo();
|
|
|
const info = stringInfo[0];
|
|
|
const exp_type_string_info = value.type.stringInfo();
|
|
|
const exp_type_info = exp_type_string_info[0];
|
|
|
const exp = cmd.expression.toString();
|
|
|
- return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type, exp_type_info.dim, exp, cmd.sourceInfo));
|
|
|
+ throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type,
|
|
|
+ exp_type_info.dim, exp, cmd.sourceInfo);
|
|
|
}
|
|
|
actualValue = Store.doImplicitCasting(mustBeArray.type.innerType, value);
|
|
|
}
|
|
|
|
|
|
const current_value = mustBeArray.getAt(line, column);
|
|
|
- if(current_value instanceof ArrayStoreValue) {
|
|
|
- if(current_value.lines !== actualValue.lines || current_value.columns !== actualValue.columns){
|
|
|
+ if (current_value instanceof ArrayStoreValue) {
|
|
|
+ if (current_value.lines !== actualValue.lines || current_value.columns !== actualValue.columns){
|
|
|
const exp = cmd.expression.toString();
|
|
|
- return Promise.reject(ProcessorErrorFactory.invalid_matrix_index_assign_full(cmd.id, line, current_value.lines, exp, actualValue.lines, cmd.sourceInfo))
|
|
|
+ throw ProcessorErrorFactory.invalid_matrix_index_assign_full(cmd.id, line, current_value.lines,
|
|
|
+ exp, actualValue.lines, cmd.sourceInfo);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // mustBeArray.setAt(actualValue, line, column);
|
|
|
- // store.updateStore(cmd.id, mustBeArray);
|
|
|
- return store.updateStoreArray(cmd.id, actualValue, line, column);
|
|
|
- });
|
|
|
+ return store.updateStoreArray(cmd.id, actualValue, line, column);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
*
|
|
|
* @param {Store} store
|
|
|
* @param {Commands.Declaration} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
*/
|
|
|
- executeDeclaration (store, cmd) {
|
|
|
- try {
|
|
|
- let $value = Promise.resolve(null);
|
|
|
- if(cmd instanceof Commands.ArrayDeclaration) {
|
|
|
- return this.executeArrayDeclaration(store, cmd);
|
|
|
- } else {
|
|
|
- if(cmd.initial !== null) {
|
|
|
- $value = this.evaluateExpression(store, cmd.initial);
|
|
|
- }
|
|
|
- return $value.then(vl => {
|
|
|
- let realValue = vl;
|
|
|
- let temp = null;
|
|
|
- if (vl !== null) {
|
|
|
- if(!vl.type.isCompatible(cmd.type)) {
|
|
|
- if(Config.enable_type_casting && Store.canImplicitTypeCast(cmd.type, vl.type)) {
|
|
|
- realValue = Store.doImplicitCasting(cmd.type, realValue);
|
|
|
- } else {
|
|
|
- const stringInfo = vl.type.stringInfo();
|
|
|
- const info = stringInfo[0];
|
|
|
- const exp_type_string_info = vl.type.stringInfo();
|
|
|
- const exp_type_info = exp_type_string_info[0];
|
|
|
- const exp = cmd.expression.toString();
|
|
|
- return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type, exp_type_info.dim, exp, cmd.sourceInfo));
|
|
|
- }
|
|
|
- }
|
|
|
- temp = new StoreValue(cmd.type, realValue.get(), null, cmd.isConst);
|
|
|
+ async executeDeclaration (store, cmd) {
|
|
|
+ if (cmd instanceof Commands.ArrayDeclaration) {
|
|
|
+ return this.executeArrayDeclaration(store, cmd);
|
|
|
+ } else {
|
|
|
+ let temp = new StoreValue(cmd.type, null, null, cmd.isConst);
|
|
|
+ if(cmd.initial !== null) {
|
|
|
+ const value = await this.evaluateExpression(store, cmd.initial);
|
|
|
+ let realValue = value;
|
|
|
+ if (!value.type.isCompatible(cmd.type)) {
|
|
|
+ if(Config.enable_type_casting && Store.canImplicitTypeCast(cmd.type, value.type)) {
|
|
|
+ realValue = Store.doImplicitCasting(cmd.type, realValue);
|
|
|
} else {
|
|
|
- temp = new StoreValue(cmd.type, null, null, cmd.isConst);
|
|
|
+ const stringInfo = value.type.stringInfo();
|
|
|
+ const info = stringInfo[0];
|
|
|
+ const exp_type_string_info = value.type.stringInfo();
|
|
|
+ const exp_type_info = exp_type_string_info[0];
|
|
|
+ const exp = cmd.expression.toString();
|
|
|
+ throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type,
|
|
|
+ exp_type_info.dim, exp, cmd.sourceInfo);
|
|
|
}
|
|
|
- store.insertStore(cmd.id, temp);
|
|
|
- return store;
|
|
|
- });
|
|
|
+ }
|
|
|
+ temp = new StoreValue(cmd.type, realValue.get(), null, cmd.isConst);
|
|
|
}
|
|
|
- } catch (e) {
|
|
|
- return Promise.reject(e);
|
|
|
+ store.insertStore(cmd.id, temp);
|
|
|
+ return store;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -682,46 +693,43 @@ export class IVProgProcessor {
|
|
|
*
|
|
|
* @param {Store} store
|
|
|
* @param {Commands.ArrayDeclaration} cmd
|
|
|
+ *
|
|
|
+ * @returns {Promise<Store>}
|
|
|
*/
|
|
|
- executeArrayDeclaration (store, cmd) {
|
|
|
- const $lines = this.evaluateExpression(store, cmd.lines);
|
|
|
- const $columns = cmd.columns === null ? null: this.evaluateExpression(store, cmd.columns);
|
|
|
- return Promise.all([$lines, $columns]).then(([line_sv, column_sv]) => {
|
|
|
- if(!Types.INTEGER.isCompatible(line_sv.type)) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
|
|
|
- }
|
|
|
- const line = line_sv.get().toNumber();
|
|
|
- if(line < 0) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo));
|
|
|
- }
|
|
|
- let column = null
|
|
|
- if (column_sv !== null) {
|
|
|
- if(!Types.INTEGER.isCompatible(column_sv.type)) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
|
|
|
- }
|
|
|
- column = column_sv.get().toNumber();
|
|
|
- if(column < 0) {
|
|
|
- return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo));
|
|
|
- }
|
|
|
+ async executeArrayDeclaration (store, cmd) {
|
|
|
+ const linesSV = await this.evaluateExpression(store, cmd.lines);
|
|
|
+ if (!Types.INTEGER.isCompatible(linesSV.type)) {
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
|
|
|
+ }
|
|
|
+ const line = linesSV.get().toNumber();
|
|
|
+ const columnsSV = await this.evaluateExpression(store, cmd.columns);
|
|
|
+ let column = null
|
|
|
+ if (columnsSV !== null) {
|
|
|
+ if (!Types.INTEGER.isCompatible(columnsSV.type)) {
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
|
|
|
}
|
|
|
- let $value = Promise.resolve(null);
|
|
|
- if(cmd.initial !== null) {
|
|
|
- // array can only be initialized by a literal....
|
|
|
- $value = this.evaluateArrayLiteral(store, cmd.initial, cmd.type, line, column);
|
|
|
+ column = columnsSV.get().toNumber();
|
|
|
+ if(column < 0) {
|
|
|
+ throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
|
|
|
}
|
|
|
- return $value.then(vector_list => {
|
|
|
- let temp = null;
|
|
|
- if (vector_list !== null) {
|
|
|
- temp = new ArrayStoreValue(cmd.type, vector_list, line, column, null, cmd.isConst);
|
|
|
- } else {
|
|
|
- temp = new ArrayStoreValue(cmd.type, [], line, column, null, cmd.isConst);
|
|
|
- }
|
|
|
- store.insertStore(cmd.id, temp);
|
|
|
- return store;
|
|
|
- })
|
|
|
- });
|
|
|
+ }
|
|
|
+ let temp = new ArrayStoreValue(cmd.type, [], line, column, null, cmd.isConst);
|
|
|
+ if (cmd.initial !== null) {
|
|
|
+ // array can only be initialized by a literal....
|
|
|
+ const valueList = await this.evaluateArrayLiteral(store, cmd.initial, cmd.type, line, column);
|
|
|
+ temp = new ArrayStoreValue(cmd.type, valueList, line, column, null, cmd.isConst);
|
|
|
+ }
|
|
|
+ store.insertStore(cmd.id, temp);
|
|
|
+ return store;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {Store} store
|
|
|
+ * @param {Expression} exp
|
|
|
+ *
|
|
|
+ * @returns {Promise<import('./store/value/istore_value').IStoreValue>}
|
|
|
+ */
|
|
|
async evaluateExpression (store, exp) {
|
|
|
this.instruction_count += 1;
|
|
|
if(this.instruction_count % Config.suspend_threshold == 0) {
|