|  | @@ -6,7 +6,10 @@ import { Operators } from './../ast/operators';
 | 
	
		
			
				|  |  |  import { LanguageDefinedFunction } from './definedFunctions';
 | 
	
		
			
				|  |  |  import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from './compatibilityTable';
 | 
	
		
			
				|  |  |  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/';
 | 
	
		
			
				|  |  | +import * as Utils from './../util/utils';
 | 
	
		
			
				|  |  |  import { ArrayType } from './../typeSystem/array_type';
 | 
	
		
			
				|  |  |  import { convertToString, toInt } from '../typeSystem/parsers';
 | 
	
		
			
				|  |  |  import { Config } from '../util/config';
 | 
	
	
		
			
				|  | @@ -85,21 +88,20 @@ export class IVProgProcessor {
 | 
	
		
			
				|  |  |      this.mode = Modes.RUN;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  interpretAST () {
 | 
	
		
			
				|  |  | +  async interpretAST () {
 | 
	
		
			
				|  |  |      this.prepareState();
 | 
	
		
			
				|  |  |      Location.clear();
 | 
	
		
			
				|  |  | -    return this.initGlobal().then( _ => {
 | 
	
		
			
				|  |  | -      const mainFunc = this.findMainFunction();
 | 
	
		
			
				|  |  | -      if(mainFunc === null) {
 | 
	
		
			
				|  |  | -        return Promise.reject(ProcessorErrorFactory.main_missing())
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      return this.runFunction(mainFunc, [], this.globalStore);
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | +    await this.initGlobal();
 | 
	
		
			
				|  |  | +    const mainFunc = this.findMainFunction();
 | 
	
		
			
				|  |  | +    if (mainFunc === null) {
 | 
	
		
			
				|  |  | +      throw ProcessorErrorFactory.main_missing();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return this.runFunction(mainFunc, [], this.globalStore);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  initGlobal () {
 | 
	
		
			
				|  |  | +  async initGlobal () {
 | 
	
		
			
				|  |  |      if(!this.checkContext(Context.BASE)) {
 | 
	
		
			
				|  |  | -      return Promise.reject(ProcessorErrorFactory.invalid_global_var())
 | 
	
		
			
				|  |  | +      return ProcessorErrorFactory.invalid_global_var();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      return this.executeCommands(this.globalStore, this.ast.global);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -127,154 +129,147 @@ export class IVProgProcessor {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  runFunction (func, actualParameters, store) {
 | 
	
		
			
				|  |  | +  async runFunction (func, actualParameters, store) {
 | 
	
		
			
				|  |  |      const funcName = func.isMain ? IVProgProcessor.MAIN_INTERNAL_ID : func.name;
 | 
	
		
			
				|  |  |      const funcStore = new Store(funcName);
 | 
	
		
			
				|  |  |      funcStore.extendStore(this.globalStore);
 | 
	
		
			
				|  |  | -    return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | -      const run_lambda = () => {
 | 
	
		
			
				|  |  | -        const newFuncStore$ = this.associateParameters(func.formalParameters, actualParameters, store, funcStore);
 | 
	
		
			
				|  |  | -        newFuncStore$.then(sto => {
 | 
	
		
			
				|  |  | -          this.context.push(Context.FUNCTION);
 | 
	
		
			
				|  |  | -          this.stores.push(sto);
 | 
	
		
			
				|  |  | -          return this.executeCommands(sto, func.variablesDeclarations)
 | 
	
		
			
				|  |  | -            .then(stoWithVars => this.executeCommands(stoWithVars, func.commands)).then(finalSto => {
 | 
	
		
			
				|  |  | -              this.stores.pop();
 | 
	
		
			
				|  |  | -              this.context.pop();
 | 
	
		
			
				|  |  | -              return finalSto;
 | 
	
		
			
				|  |  | -            });
 | 
	
		
			
				|  |  | -        }).then(resolve)
 | 
	
		
			
				|  |  | -        .catch(reject);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      run_lambda();
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +    await this.associateParameters(func.formalParameters, actualParameters, store, funcStore);
 | 
	
		
			
				|  |  | +    this.context.push(Context.FUNCTION);
 | 
	
		
			
				|  |  | +    this.stores.push(funcStore);
 | 
	
		
			
				|  |  | +    const stoWithVars = await this.executeCommands(funcStore, func.variablesDeclarations);
 | 
	
		
			
				|  |  | +    const finalSto = this.executeCommands(stoWithVars, func.commands);
 | 
	
		
			
				|  |  | +    this.stores.pop();
 | 
	
		
			
				|  |  | +    this.context.pop();
 | 
	
		
			
				|  |  | +    return finalSto;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  associateParameters (formal_params, effective_params, caller_store, callee_store) {
 | 
	
		
			
				|  |  | +  async associateParameters (formal_params, effective_params, caller_store, callee_store) {
 | 
	
		
			
				|  |  |      const funcName = callee_store.name === IVProgProcessor.MAIN_INTERNAL_ID ?
 | 
	
		
			
				|  |  |        LanguageDefinedFunction.getMainFunctionName() : callee_store.name;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (formal_params.length != effective_params.length) {
 | 
	
		
			
				|  |  | -      return Promise.reject(ProcessorErrorFactory.invalid_parameters_size(funcName, formal_params.length, effective_params.length))
 | 
	
		
			
				|  |  | +      throw ProcessorErrorFactory.invalid_parameters_size(funcName, formal_params.length, effective_params.length);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    const promises$ = effective_params.map(actual_param => this.evaluateExpression(caller_store, actual_param));
 | 
	
		
			
				|  |  | -    return Promise.all(promises$).then(values => {
 | 
	
		
			
				|  |  | -      for (let i = 0; i < values.length; i++) {
 | 
	
		
			
				|  |  | -        const sto_value = values[i];
 | 
	
		
			
				|  |  | -        // console.log(callee_store.name);
 | 
	
		
			
				|  |  | -        // console.log(sto_value);
 | 
	
		
			
				|  |  | -        const exp = effective_params[i];
 | 
	
		
			
				|  |  | -        let shouldTypeCast = false;
 | 
	
		
			
				|  |  | -        const formalParameter = formal_params[i];
 | 
	
		
			
				|  |  | -        if(!formalParameter.type.isCompatible(sto_value.type)) {
 | 
	
		
			
				|  |  | -          if (Config.enable_type_casting && !formalParameter.byRef
 | 
	
		
			
				|  |  | -            && Store.canImplicitTypeCast(formalParameter.type, sto_value.type)) {
 | 
	
		
			
				|  |  | -              shouldTypeCast =  true;
 | 
	
		
			
				|  |  | -          } else {
 | 
	
		
			
				|  |  | -            return Promise.reject(ProcessorErrorFactory.invalid_parameter_type(funcName, exp.toString()))
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | +    for (let i = 0; i < effective_params.length; i += 1) {
 | 
	
		
			
				|  |  | +      const actualParam = effective_params[i];
 | 
	
		
			
				|  |  | +      const actualValue = await this.evaluateExpression(caller_store, actualParam);
 | 
	
		
			
				|  |  | +      const exp = effective_params[i];
 | 
	
		
			
				|  |  | +      let shouldTypeCast = false;
 | 
	
		
			
				|  |  | +      const formalParameter = formal_params[i];
 | 
	
		
			
				|  |  | +      if(!formalParameter.type.isCompatible(actualValue.type)) {
 | 
	
		
			
				|  |  | +        if (Config.enable_type_casting && !formalParameter.byRef
 | 
	
		
			
				|  |  | +          && Store.canImplicitTypeCast(formalParameter.type, actualValue.type)) {
 | 
	
		
			
				|  |  | +            shouldTypeCast =  true;
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          throw ProcessorErrorFactory.invalid_parameter_type(funcName, exp.toString());
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if(formalParameter.byRef && !sto_value.inStore()) {
 | 
	
		
			
				|  |  | -          return Promise.reject(ProcessorErrorFactory.invalid_ref(funcName, exp.toString()))
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +      if(formalParameter.byRef && !actualValue.inStore()) {
 | 
	
		
			
				|  |  | +        throw ProcessorErrorFactory.invalid_ref(funcName, exp.toString());
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if(formalParameter.byRef) {
 | 
	
		
			
				|  |  | -          const realObj = caller_store.getStoreObject(sto_value.id);
 | 
	
		
			
				|  |  | -          let ref = null;
 | 
	
		
			
				|  |  | -          if(sto_value instanceof ArrayStoreValue) {
 | 
	
		
			
				|  |  | -            // it's a vector or matrix...
 | 
	
		
			
				|  |  | -            const values = sto_value.get();
 | 
	
		
			
				|  |  | -            const array_type = sto_value.type;
 | 
	
		
			
				|  |  | -            const addresses = values.map( v => realObj.getLocAddressOf(v.line, v.column));
 | 
	
		
			
				|  |  | -            const columns = sto_value.isVector() ? 0 : sto_value.columns;
 | 
	
		
			
				|  |  | -            ref = new ArrayStoreValueRef(array_type, values, addresses, sto_value.lines, columns, realObj.id);
 | 
	
		
			
				|  |  | -          } else {
 | 
	
		
			
				|  |  | -            if(sto_value instanceof StoreValueAddress) {
 | 
	
		
			
				|  |  | -              const line = sto_value.line;
 | 
	
		
			
				|  |  | -              const column = sto_value.column;
 | 
	
		
			
				|  |  | -              ref = new StoreValueRef(sto_value.type, sto_value.get(),
 | 
	
		
			
				|  |  | -                realObj.getLocAddressOf(line, column), realObj.id);
 | 
	
		
			
				|  |  | -              ref.setReferenceDimension(realObj.type.dimensions);
 | 
	
		
			
				|  |  | -            } else {
 | 
	
		
			
				|  |  | -              ref = new StoreValueRef(sto_value.type, sto_value.get(), realObj.locAddress, realObj.id);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          callee_store.insertStore(formalParameter.id, ref);
 | 
	
		
			
				|  |  | +      if(formalParameter.byRef) {
 | 
	
		
			
				|  |  | +        const realObj = caller_store.getStoreObject(actualValue.id);
 | 
	
		
			
				|  |  | +        let ref = null;
 | 
	
		
			
				|  |  | +        if(actualValue instanceof ArrayStoreValue) {
 | 
	
		
			
				|  |  | +          // it's a vector or matrix...
 | 
	
		
			
				|  |  | +          const values = actualValue.get();
 | 
	
		
			
				|  |  | +          const array_type = actualValue.type;
 | 
	
		
			
				|  |  | +          const addresses = values.map( v => realObj.getLocAddressOf(v.line, v.column));
 | 
	
		
			
				|  |  | +          const columns = actualValue.isVector() ? 0 : actualValue.columns;
 | 
	
		
			
				|  |  | +          ref = new ArrayStoreValueRef(array_type, values, addresses, actualValue.lines, columns, realObj.id);
 | 
	
		
			
				|  |  |          } else {
 | 
	
		
			
				|  |  | -          let realValue = sto_value;
 | 
	
		
			
				|  |  | -          if (shouldTypeCast) {
 | 
	
		
			
				|  |  | -            realValue = Store.doImplicitCasting(formalParameter.type, realValue);
 | 
	
		
			
				|  |  | +          if(actualValue instanceof StoreValueAddress) {
 | 
	
		
			
				|  |  | +            const line = actualValue.line;
 | 
	
		
			
				|  |  | +            const column = actualValue.column;
 | 
	
		
			
				|  |  | +            ref = new StoreValueRef(actualValue.type, actualValue.get(),
 | 
	
		
			
				|  |  | +              realObj.getLocAddressOf(line, column), realObj.id);
 | 
	
		
			
				|  |  | +            ref.setReferenceDimension(realObj.type.dimensions);
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            ref = new StoreValueRef(actualValue.type, actualValue.get(), realObj.locAddress, realObj.id);
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  | -          callee_store.insertStore(formalParameter.id, realValue);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        callee_store.insertStore(formalParameter.id, ref);
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        let realValue = actualValue;
 | 
	
		
			
				|  |  | +        if (shouldTypeCast) {
 | 
	
		
			
				|  |  | +          realValue = Store.doImplicitCasting(formalParameter.type, realValue);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        callee_store.insertStore(formalParameter.id, realValue);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      return callee_store;
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return callee_store;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  executeCommands (store, cmds) {
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 
 | 
	
		
			
				|  |  | +   * @param {Store} store 
 | 
	
		
			
				|  |  | +   * @param {Command[]} cmds 
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  async executeCommands (store, cmds) {
 | 
	
		
			
				|  |  |      // helper to partially apply a function, in this case executeCommand
 | 
	
		
			
				|  |  | -    const partial = (fun, cmd) => (sto) => fun(sto, cmd);
 | 
	
		
			
				|  |  | -    return cmds.reduce((lastCommand, next) => {
 | 
	
		
			
				|  |  | -      const nextCommand = partial(this.executeCommand.bind(this), next);
 | 
	
		
			
				|  |  | -      return lastCommand.then(nextCommand);
 | 
	
		
			
				|  |  | -    }, Promise.resolve(store));
 | 
	
		
			
				|  |  | +    let sto = store;
 | 
	
		
			
				|  |  | +    for (let i = 0; i < cmds.length; i += 1) {
 | 
	
		
			
				|  |  | +      sto = await this.executeCommand(sto, cmds[i]);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return sto;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  executeCommand (store, cmd) {
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 
 | 
	
		
			
				|  |  | +   * @param {Store} store 
 | 
	
		
			
				|  |  | +   * @param {Command} cmd
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  async executeCommand (store, cmd) {
 | 
	
		
			
				|  |  |      this.instruction_count += 1;
 | 
	
		
			
				|  |  | -    return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | -      const command_lambda = () => {
 | 
	
		
			
				|  |  | -        if(this.instruction_count >= Config.max_instruction_count) {
 | 
	
		
			
				|  |  | -          return reject(ProcessorErrorFactory.exceed_max_instructions());
 | 
	
		
			
				|  |  | -        } else if(this.forceKill) {
 | 
	
		
			
				|  |  | -          return reject("FORCED_KILL!");
 | 
	
		
			
				|  |  | -        } else if (store.mode === Modes.PAUSE) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeCommand(store, cmd));
 | 
	
		
			
				|  |  | -        } else if(store.mode === Modes.RETURN) {
 | 
	
		
			
				|  |  | -          return resolve(store);
 | 
	
		
			
				|  |  | -        } else if(this.checkContext(Context.BREAKABLE) && store.mode === Modes.BREAK) {
 | 
	
		
			
				|  |  | -          return resolve(store);
 | 
	
		
			
				|  |  | -        } else if (this.mode === Modes.ABORT) {
 | 
	
		
			
				|  |  | -          return reject(LocalizedStrings.getMessage('aborted_execution'));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if (cmd instanceof Commands.Declaration) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeDeclaration(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.ArrayIndexAssign) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeArrayIndexAssign(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.Assign) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeAssign(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.Break) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeBreak(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.Return) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeReturn(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.IfThenElse) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeIfThenElse(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.RepeatUntil) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeRepeatUntil(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.While) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeWhile(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.For) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeFor(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.Switch) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeSwitch(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Expressions.FunctionCall) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeFunctionCall(store, cmd));
 | 
	
		
			
				|  |  | -        } else if (cmd instanceof Commands.SysCall) {
 | 
	
		
			
				|  |  | -          return resolve(this.executeSysCall(store, cmd));
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          return reject(ProcessorErrorFactory.unknown_command(cmd.sourceInfo))
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      };
 | 
	
		
			
				|  |  | -      if(this.instruction_count % Config.suspend_threshold == 0) {
 | 
	
		
			
				|  |  | -        //every 100th command should briefly delay its execution in order to allow the browser to process other things
 | 
	
		
			
				|  |  | -        setTimeout(command_lambda, 5);
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        command_lambda();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    })
 | 
	
		
			
				|  |  | +    if(this.instruction_count % Config.suspend_threshold == 0) {
 | 
	
		
			
				|  |  | +      //every Config.suspend_threshold instruction should briefly delay its execution in order to allow the browser to process other things
 | 
	
		
			
				|  |  | +      await Utils.sleep(5)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Checks if it must interrupt the execution for some reason
 | 
	
		
			
				|  |  | +    if(this.instruction_count >= Config.max_instruction_count) {
 | 
	
		
			
				|  |  | +      throw ProcessorErrorFactory.exceed_max_instructions();
 | 
	
		
			
				|  |  | +    } else if(this.forceKill) {
 | 
	
		
			
				|  |  | +      throw "FORCED_KILL!";
 | 
	
		
			
				|  |  | +    } else if (store.mode === Modes.PAUSE) {
 | 
	
		
			
				|  |  | +      return this.executeCommand(store, cmd);
 | 
	
		
			
				|  |  | +    } else if(store.mode === Modes.RETURN) {
 | 
	
		
			
				|  |  | +      return store;
 | 
	
		
			
				|  |  | +    } else if (this.checkContext(Context.BREAKABLE) && store.mode === Modes.BREAK) {
 | 
	
		
			
				|  |  | +      return store;
 | 
	
		
			
				|  |  | +    } else if (this.mode === Modes.ABORT) {
 | 
	
		
			
				|  |  | +      throw LocalizedStrings.getMessage('aborted_execution');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    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) {
 | 
	
		
			
				|  |  | +      return this.executeBreak(store, cmd);
 | 
	
		
			
				|  |  | +    } else if (cmd instanceof Commands.Return) {
 | 
	
		
			
				|  |  | +      return this.executeReturn(store, cmd);
 | 
	
		
			
				|  |  | +    } else if (cmd instanceof Commands.IfThenElse) {
 | 
	
		
			
				|  |  | +      return this.executeIfThenElse(store, cmd);
 | 
	
		
			
				|  |  | +    } else if (cmd instanceof Commands.RepeatUntil) {
 | 
	
		
			
				|  |  | +      return this.executeRepeatUntil(store, cmd);
 | 
	
		
			
				|  |  | +    } else if (cmd instanceof Commands.While) {
 | 
	
		
			
				|  |  | +      return this.executeWhile(store, cmd);
 | 
	
		
			
				|  |  | +    } else if (cmd instanceof Commands.For) {
 | 
	
		
			
				|  |  | +      return this.executeFor(store, cmd);
 | 
	
		
			
				|  |  | +    } else if (cmd instanceof Commands.Switch) {
 | 
	
		
			
				|  |  | +      return this.executeSwitch(store, cmd);
 | 
	
		
			
				|  |  | +    } else if (cmd instanceof Expressions.FunctionCall) {
 | 
	
		
			
				|  |  | +      return this.executeFunctionCall(store, cmd);
 | 
	
		
			
				|  |  | +    } else if (cmd instanceof Commands.SysCall) {
 | 
	
		
			
				|  |  | +      return this.executeSysCall(store, cmd);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      throw ProcessorErrorFactory.unknown_command(cmd.sourceInfo);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    executeSysCall (store, cmd) {
 | 
	
	
		
			
				|  | @@ -282,29 +277,24 @@ export class IVProgProcessor {
 | 
	
		
			
				|  |  |      return func(store, cmd);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  executeFunctionCall (store, cmd) {
 | 
	
		
			
				|  |  | +  async executeFunctionCall (store, cmd) {
 | 
	
		
			
				|  |  |      let func = null;
 | 
	
		
			
				|  |  |      if(cmd.isMainCall) {
 | 
	
		
			
				|  |  |        func = this.findMainFunction();
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        func = this.findFunction(cmd.id);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    // if(this.function_call_stack.length >= Config.max_call_stack) {
 | 
	
		
			
				|  |  | -    //   return Promise.reject(ProcessorErrorFactory.exceeded_recursive_calls(cmd.sourceInfo));
 | 
	
		
			
				|  |  | -    // }
 | 
	
		
			
				|  |  |      this.function_call_stack.push(cmd.sourceInfo);
 | 
	
		
			
				|  |  | -    return this.runFunction(func, cmd.actualParameters, store)
 | 
	
		
			
				|  |  | -      .then(sto => {
 | 
	
		
			
				|  |  | -        sto.destroy();
 | 
	
		
			
				|  |  | -        if(!Types.VOID.isCompatible(func.returnType) && sto.mode !== Modes.RETURN) {
 | 
	
		
			
				|  |  | -          const funcName = func.name === IVProgProcessor.MAIN_INTERNAL_ID ?
 | 
	
		
			
				|  |  | -            LanguageDefinedFunction.getMainFunctionName() : func.name;
 | 
	
		
			
				|  |  | -          return Promise.reject(ProcessorErrorFactory.function_no_return(funcName));
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          this.function_call_stack.pop();
 | 
	
		
			
				|  |  | -          return store;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | +    const sto = await this.runFunction(func, cmd.actualParameters, store);
 | 
	
		
			
				|  |  | +    sto.destroy();
 | 
	
		
			
				|  |  | +    if(!Types.VOID.isCompatible(func.returnType) && sto.mode !== Modes.RETURN) {
 | 
	
		
			
				|  |  | +      const funcName = func.name === IVProgProcessor.MAIN_INTERNAL_ID ?
 | 
	
		
			
				|  |  | +        LanguageDefinedFunction.getMainFunctionName() : func.name;
 | 
	
		
			
				|  |  | +      throw ProcessorErrorFactory.function_no_return(funcName);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      this.function_call_stack.pop();
 | 
	
		
			
				|  |  | +      return store;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    executeSwitch (store, cmd) {
 | 
	
	
		
			
				|  | @@ -732,71 +722,62 @@ export class IVProgProcessor {
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  evaluateExpression (store, exp) {
 | 
	
		
			
				|  |  | +  async evaluateExpression (store, exp) {
 | 
	
		
			
				|  |  |      this.instruction_count += 1;
 | 
	
		
			
				|  |  | -    return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | -      const expression_lambda = () => {
 | 
	
		
			
				|  |  | -        if (this.mode === Modes.ABORT) {
 | 
	
		
			
				|  |  | -          return reject(LocalizedStrings.getMessage('aborted_execution'));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if(this.instruction_count >= Config.max_instruction_count) {
 | 
	
		
			
				|  |  | -          return reject(new Error("Número de instruções excedeu o limite definido. Verifique se seu código não possui laços infinitos ou muitas chamadas de funções recursivas."))
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if (exp instanceof Expressions.UnaryApp) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateUnaryApp(store, exp));
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.InfixApp) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateInfixApp(store, exp));
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.ArrayAccess) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateArrayAccess(store, exp));
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.VariableLiteral) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateVariableLiteral(store, exp));
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.IntLiteral) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateLiteral(store, exp));
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.RealLiteral) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateLiteral(store, exp));
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.BoolLiteral) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateLiteral(store, exp));
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.StringLiteral) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateLiteral(store, exp));
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.ArrayLiteral) {
 | 
	
		
			
				|  |  | -          return reject(new Error("Internal Error: The system should not eval an array literal."))
 | 
	
		
			
				|  |  | -        } else if (exp instanceof Expressions.FunctionCall) {
 | 
	
		
			
				|  |  | -          return resolve(this.evaluateFunctionCall(store, exp));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        return resolve(null);
 | 
	
		
			
				|  |  | -      };
 | 
	
		
			
				|  |  | -      if(this.instruction_count % Config.suspend_threshold == 0) {
 | 
	
		
			
				|  |  | -        //every 100th command should briefly delay its execution in order to allow the browser to process other things
 | 
	
		
			
				|  |  | -        setTimeout(expression_lambda, 5);
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        expression_lambda();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +    if(this.instruction_count % Config.suspend_threshold == 0) {
 | 
	
		
			
				|  |  | +      //every Config.suspend_threshold instruction should briefly delay its execution in order to allow the browser to process other things
 | 
	
		
			
				|  |  | +      await Utils.sleep(5);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (this.mode === Modes.ABORT) {
 | 
	
		
			
				|  |  | +      throw LocalizedStrings.getMessage('aborted_execution');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(this.instruction_count >= Config.max_instruction_count) {
 | 
	
		
			
				|  |  | +      throw new Error("Número de instruções excedeu o limite definido. Verifique se seu código não possui laços infinitos ou muitas chamadas de funções recursivas.");
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (exp instanceof Expressions.UnaryApp) {
 | 
	
		
			
				|  |  | +      return this.evaluateUnaryApp(store, exp);
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.InfixApp) {
 | 
	
		
			
				|  |  | +      return this.evaluateInfixApp(store, exp);
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.ArrayAccess) {
 | 
	
		
			
				|  |  | +      return this.evaluateArrayAccess(store, exp);
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.VariableLiteral) {
 | 
	
		
			
				|  |  | +      return this.evaluateVariableLiteral(store, exp);
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.IntLiteral) {
 | 
	
		
			
				|  |  | +      return this.evaluateLiteral(store, exp);
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.RealLiteral) {
 | 
	
		
			
				|  |  | +      return this.evaluateLiteral(store, exp);
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.BoolLiteral) {
 | 
	
		
			
				|  |  | +      return this.evaluateLiteral(store, exp);
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.StringLiteral) {
 | 
	
		
			
				|  |  | +      return this.evaluateLiteral(store, exp);
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.ArrayLiteral) {
 | 
	
		
			
				|  |  | +      throw new Error("Internal Error: The system should not eval an array literal.");
 | 
	
		
			
				|  |  | +    } else if (exp instanceof Expressions.FunctionCall) {
 | 
	
		
			
				|  |  | +      return this.evaluateFunctionCall(store, exp);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return null;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  evaluateFunctionCall (store, exp) {
 | 
	
		
			
				|  |  | +  async evaluateFunctionCall (store, exp) {
 | 
	
		
			
				|  |  |      if(exp.isMainCall) {
 | 
	
		
			
				|  |  | -      return Promise.reject(ProcessorErrorFactory.void_in_expression_full(LanguageDefinedFunction.getMainFunctionName(), exp.sourceInfo));
 | 
	
		
			
				|  |  | +      throw ProcessorErrorFactory.void_in_expression_full(LanguageDefinedFunction.getMainFunctionName(), exp.sourceInfo);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      const func = this.findFunction(exp.id);
 | 
	
		
			
				|  |  |      if(Types.VOID.isCompatible(func.returnType)) {
 | 
	
		
			
				|  |  | -      return Promise.reject(ProcessorErrorFactory.void_in_expression_full(exp.id, exp.sourceInfo));
 | 
	
		
			
				|  |  | +      throw ProcessorErrorFactory.void_in_expression_full(exp.id, exp.sourceInfo);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if(this.function_call_stack.length >= Config.max_call_stack) {
 | 
	
		
			
				|  |  | -      return Promise.reject(ProcessorErrorFactory.exceeded_recursive_calls(exp.sourceInfo));
 | 
	
		
			
				|  |  | +      throw ProcessorErrorFactory.exceeded_recursive_calls(exp.sourceInfo);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      this.function_call_stack.push(exp.sourceInfo);
 | 
	
		
			
				|  |  | -    const $newStore = this.runFunction(func, exp.actualParameters, store);
 | 
	
		
			
				|  |  | -    return $newStore.then( sto => {
 | 
	
		
			
				|  |  | -      if(sto.mode !== Modes.RETURN) {
 | 
	
		
			
				|  |  | -        return Promise.reject(new Error("!!!Internal error: the function that was called did not have a return command or did not set the store mode properly -> "+exp.id));
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      const val = sto.applyStore('$');
 | 
	
		
			
				|  |  | -      sto.destroy();
 | 
	
		
			
				|  |  | -      this.function_call_stack.pop();
 | 
	
		
			
				|  |  | -      return Promise.resolve(val);
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | +    const sto = await this.runFunction(func, exp.actualParameters, store);
 | 
	
		
			
				|  |  | +    if(sto.mode !== Modes.RETURN) {
 | 
	
		
			
				|  |  | +      throw new Error("!!!Internal error: the function that was called did not have a return command or did not set the store mode properly -> "+exp.id);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    const val = sto.applyStore('$');
 | 
	
		
			
				|  |  | +    sto.destroy();
 | 
	
		
			
				|  |  | +    this.function_call_stack.pop();
 | 
	
		
			
				|  |  | +    return val;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /**
 |