Browse Source

Merge branch 'refactor-processor' of LInE/iVProg into master

GitAdmin 4 years ago
parent
commit
e2125dc273

+ 3 - 0
.babelrc

@@ -0,0 +1,3 @@
+{
+  "plugins": ["@babel/plugin-transform-runtime"]
+}

+ 2 - 1
.eslintrc.json

@@ -1,7 +1,8 @@
 {
     "env": {
         "browser": true,
-        "es6": true
+        "es6": true,
+        "node": true
     },
     "parser": "@typescript-eslint/parser",
     "plugins": ["@typescript-eslint"],

+ 7 - 0
js/ast/commands/case.js

@@ -5,9 +5,16 @@ export class Case extends Command {
   constructor (expression) {
     super();
     this.expression = expression;
+    /**
+     * @type {Command[]}
+     */
     this.commands = [];
   }
 
+  /**
+   * 
+   * @param {Command[]} commands 
+   */
   setCommands (commands) {
     this.commands = commands;
   }

+ 9 - 0
js/ast/commands/switch.js

@@ -1,7 +1,16 @@
 import { Command } from './command';
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+import { Expression } from '../expressions/expression';
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+import { Case } from '.';
 
 export class Switch extends Command {
   
+  /**
+   * 
+   * @param {Expression} expression 
+   * @param {Case[]} cases 
+   */
   constructor (expression, cases) {
     super();
     this.expression = expression;

+ 5 - 0
js/ast/expressions/arrayLiteral.js

@@ -2,6 +2,11 @@ import { Literal } from './literal';
 
 export class ArrayLiteral extends Literal {
   
+  /**
+   * 
+   * @param {import('../../typeSystem/itype').IType} type 
+   * @param {import('./expression').Expression[]} value 
+   */
   constructor(type, value) {
     super(type);
     this.value = value;

+ 9 - 6
js/io/domConsole.js

@@ -315,12 +315,15 @@ export class DOMConsole {
     this.cursorInterval = null;
   }
 
-  requestInput (callback, anyKey = false) {
-    this.inputListeners.push(callback);
-    this.anyKey = anyKey;
-    if(this.idleInterval == null)
-      this.scheduleNotify();
-    this.showInput();
+  requestInput (anyKey = false) {
+    const promise = new Promise( (resolve, _) => {
+      this.inputListeners.push(resolve);
+      this.anyKey = anyKey;
+      if(this.idleInterval == null)
+        this.scheduleNotify();
+      this.showInput();
+    });
+    return promise;
   }
 
   sendOutput (text) {

+ 6 - 3
js/io/domInput.js

@@ -27,9 +27,12 @@ export class DOMInput extends Input{
     }
   }
 
-  requestInput (callback) {
-    this.listeners.push(callback);
-    this.el.focus();
+  requestInput () {
+    const promise = new Promise( (resolve, _) => {
+      this.listeners.push(resolve);
+      this.el.focus();
+    });
+    return promise;
   }
 
   notifyInput (text) {

+ 1 - 1
js/io/input.js

@@ -1,6 +1,6 @@
 export class Input {
 
-  requestInput (callback) {
+  requestInput () {
     throw new Error("Must be implemented");
   }
 

+ 3 - 3
js/memory/address.ts

@@ -1,14 +1,14 @@
 export class Address {
 
   public id: number;
-  public value: any;
+  public value: unknown;
 
   /**
    * 
    * @param {Number} id the address id
-   * @param {*} value the value stored at this address
+   * @param {never} value the value stored at this address
    */
-  constructor (id: number, value: any) {
+  constructor (id: number, value: unknown) {
     this.id = id;
     this.value = value;
   }

+ 11 - 11
js/memory/location.ts

@@ -13,10 +13,10 @@ class LocationHolder {
 
   /**
    * 
-   * @param {*} value the value to be allocated
-   * @returns {Number} - the address id
+   * @param {never} value the value to be allocated
+   * @returns {number} - the address id
    */
-  allocate (value:any) : number {
+  allocate (value: unknown): number {
     const id = this.address_id;
     // console.log("Allocation address "+ id);
     const address = new Address(id, value);
@@ -27,9 +27,9 @@ class LocationHolder {
 
   /**
    * 
-   * @param {Number} id 
+   * @param {number} id 
    */
-  deallocate (id: number) : boolean {
+  deallocate (id: number): boolean {
     const index = this.findIndex(id);
     // console.log("Deallocation address "+ id);
     if(index !== -1) {
@@ -41,7 +41,7 @@ class LocationHolder {
 
   /**
    * 
-   * @param {Number} id 
+   * @param {number} id 
    * @returns {Address} the address identified by id
    */
   find (id: number): Address | undefined {
@@ -68,10 +68,10 @@ class LocationHolder {
 
   /**
    * 
-   * @param {Number} id address id
-   * @returns {Number} the index of the address identified by id
+   * @param {number} id address id
+   * @returns {number} the index of the address identified by id
    */
-  findIndex (id: number) : number {
+  findIndex (id: number): number {
     let beg = 0
     let end = this.data.length;
     while (beg < end) {
@@ -88,7 +88,7 @@ class LocationHolder {
     return -1;
   }
 
-  updateAddress (id: number, value: any): void {
+  updateAddress (id: number, value: unknown): void {
     const index = this.findIndex(id);
     if(index === -1) {
       throw new Error("Invalid address..." + id);
@@ -96,7 +96,7 @@ class LocationHolder {
     this.data[index].value = value;
   }
 
-  clear () {
+  clear (): void {
     for (let i = 0; i < this.data.length; i += 1) {
       delete this.data[i];
     }

File diff suppressed because it is too large
+ 793 - 777
js/processor/ivprogProcessor.js


+ 6 - 6
js/processor/lib/arrays.js

@@ -12,12 +12,12 @@ import { StoreValue } from '../store/value/store_value';
  */
 
 export function createNumElementsFun () {
-  const numElementsFun = (sto, _) => {
+  const numElementsFun = async (sto, _) => {
     const vector  = sto.applyStore("vector");
     const temp = new StoreValue(Types.INTEGER, toInt(vector.lines));
     sto.mode = Modes.RETURN;
     sto.insertStore("$", temp);
-    return Promise.resolve(sto);
+    return sto;
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(numElementsFun)]);
@@ -28,12 +28,12 @@ export function createNumElementsFun () {
  }
 
 export function createMatrixLinesFun () {
-  const matrixLinesFun = (sto, _) => {
+  const matrixLinesFun = async (sto, _) => {
     const matrix  = sto.applyStore("matrix");
     const temp = new StoreValue(Types.INTEGER, toInt(matrix.lines));
     sto.mode = Modes.RETURN;
     sto.insertStore("$", temp);
-    return Promise.resolve(sto);
+    return sto;
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(matrixLinesFun)]);
@@ -44,12 +44,12 @@ export function createMatrixLinesFun () {
  }
 
 export function createMatrixColumnsFun () {
-  const matrixColumnsFun = (sto, _) => {
+  const matrixColumnsFun = async (sto, _) => {
     const matrix  = sto.applyStore("matrix");
     const temp = new StoreValue(Types.INTEGER, toInt(matrix.columns));
     sto.mode = Modes.RETURN;
     sto.insertStore("$", temp);
-    return Promise.resolve(sto);
+    return sto;
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(matrixColumnsFun)]);

+ 42 - 46
js/processor/lib/io.js

@@ -6,11 +6,11 @@ import { ProcessorErrorFactory } from "./../error/processorErrorFactory";
 import { StoreValue } from '../store/value/store_value';
 
 export function createOutputFun () {
-  const writeFunction = function (store, _) {
+  const writeFunction = async function (store, _) {
     const val = store.applyStore('p1');
     this.output.sendOutput(convertToString(val.get(), val.type));
     store.mode = Modes.RETURN;
-    return Promise.resolve(store);
+    return store;
   }
   const block = new Commands.CommandBlock([], [new Commands.SysCall(writeFunction)]);
   const func = new Commands.Function('$write', Types.VOID,
@@ -20,51 +20,47 @@ export function createOutputFun () {
 }
 
 export function createInputFun () {
-  const readFunction = function (store, _) {
-    const request = new Promise((resolve, _) => {
-      this.input.requestInput(resolve);
-    });
-    return request.then(text => {
-      const typeToConvert = store.applyStore('p1').type;
-      let type = null
-      let result = null;
-      try {
-        if (typeToConvert.isCompatible(Types.INTEGER)) {
-          result = toInt(text.trim()).trunc();
-          type = Types.INTEGER;
-        } else if (typeToConvert.isCompatible(Types.REAL)) {
-          result = toReal(text.trim())
-          type = Types.REAL;
-        } else if (typeToConvert.isCompatible(Types.BOOLEAN)) {
-          result = toBool(text.trim())
-          type = Types.BOOLEAN;
-        } else if (typeToConvert.isCompatible(Types.STRING)) {
-          result = toString(text)
-          type  = Types.STRING;
-        } else {
-          return Promise.reject(new Error("!!!!Critical error: Unknown type in readFunction!!!!"));
-        }
-      } catch (_) {
-        if(this.mode == Modes.ABORT) {
-          store.mode = Modes.RETURN;
-          return Promise.resolve(store);
-        }
-        const stringInfo = typeToConvert.stringInfo()[0]
-        const realObject = store.getStoreObject("p1");
-        if (realObject.getReferenceDimension() > 0) {
-          const arrayInfo = realObject.type.stringInfo()[0];
-          const dim = realObject.getReferenceDimension();
-          const error = ProcessorErrorFactory.invalid_read_type_array(text, stringInfo.type, stringInfo.dim, realObject.getRefObj(), arrayInfo.type, dim, this.function_call_stack.pop());
-          return Promise.reject(error);
-        }
-        const error = ProcessorErrorFactory.invalid_read_type(text, stringInfo.type, stringInfo.dim, realObject.getRefObj(), this.function_call_stack.pop());
-        return Promise.reject(error);
+  const readFunction = async function (store, _) {
+    const text = await this.input.requestInput();
+    const typeToConvert = store.applyStore('p1').type;
+    let type = null
+    let result = null;
+    try {
+      if (typeToConvert.isCompatible(Types.INTEGER)) {
+        result = toInt(text.trim()).trunc();
+        type = Types.INTEGER;
+      } else if (typeToConvert.isCompatible(Types.REAL)) {
+        result = toReal(text.trim())
+        type = Types.REAL;
+      } else if (typeToConvert.isCompatible(Types.BOOLEAN)) {
+        result = toBool(text.trim())
+        type = Types.BOOLEAN;
+      } else if (typeToConvert.isCompatible(Types.STRING)) {
+        result = toString(text)
+        type  = Types.STRING;
+      } else {
+        throw new Error("!!!!Critical error: Unknown type in readFunction!!!!");
       }
-      const stoValue = new StoreValue(type, result);
-      store.updateStore('p1', stoValue);
-      store.mode = Modes.RETURN;
-      return Promise.resolve(store);
-    });
+    } catch (_) {
+      if(this.mode == Modes.ABORT) {
+        store.mode = Modes.RETURN;
+        return store;
+      }
+      const stringInfo = typeToConvert.stringInfo()[0]
+      const realObject = store.getStoreObject("p1");
+      if (realObject.getReferenceDimension() > 0) {
+        const arrayInfo = realObject.type.stringInfo()[0];
+        const dim = realObject.getReferenceDimension();
+        throw ProcessorErrorFactory.invalid_read_type_array(text, stringInfo.type, stringInfo.dim,
+          realObject.getRefObj(), arrayInfo.type, dim, this.function_call_stack.pop());
+      }
+      throw ProcessorErrorFactory.invalid_read_type(text, stringInfo.type, stringInfo.dim,
+        realObject.getRefObj(), this.function_call_stack.pop());
+    }
+    const stoValue = new StoreValue(type, result);
+    store.updateStore('p1', stoValue);
+    store.mode = Modes.RETURN;
+    return store;
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(readFunction)]);
   const func = new Commands.Function('$read', Types.VOID,

+ 21 - 21
js/processor/lib/lang.js

@@ -1,6 +1,6 @@
 import * as Commands from './../../ast/commands';
 import { Types } from './../../typeSystem/types';
-import { toReal, convertToString } from "./../../typeSystem/parsers";
+import * as Parsers from "./../../typeSystem/parsers";
 import { IVProgParser } from '../../ast/ivprogParser';
 import { RealLiteral, IntLiteral, BoolLiteral } from '../../ast/expressions';
 import { Modes } from '../modes';
@@ -20,7 +20,7 @@ import { StoreValue } from '../store/value/store_value';
  */
 
 export function createIsRealFun () {
-  const isRealFun = (sto, _) => {
+  const isRealFun = async (sto, _) => {
     const str = sto.applyStore("str");
     const parser = IVProgParser.createParser(str.get());
     let result = false;
@@ -35,7 +35,7 @@ export function createIsRealFun () {
     const temp = new StoreValue(Types.BOOLEAN, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(isRealFun)]);
@@ -46,7 +46,7 @@ export function createIsRealFun () {
 }
 
 export function createIsIntFun () {
-  const isIntFun = (sto, _) => {
+  const isIntFun = async (sto, _) => {
     const str = sto.applyStore("str");
     const parser = IVProgParser.createParser(str.get());
     let result = false;
@@ -61,7 +61,7 @@ export function createIsIntFun () {
     const temp = new StoreValue(Types.BOOLEAN, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(isIntFun)]);
@@ -87,7 +87,7 @@ export function createIsBoolFun () {
     const temp = new StoreValue(Types.BOOLEAN, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(isBoolFun)]);
@@ -98,16 +98,16 @@ export function createIsBoolFun () {
 }
 
 export function createCastRealFun () {
-  const castRealFun = (sto, _) => {
+  const castRealFun = async (sto, _) => {
     const val = sto.applyStore("val");
     let value = val.get();
     switch (val.type.ord) {
       case Types.INTEGER.ord: {
         value = value.toNumber();
-        const temp = new StoreValue(Types.REAL, toReal(value));
+        const temp = new StoreValue(Types.REAL, Parsers.toReal(value));
         sto.insertStore("$", temp);
         sto.mode = Modes.RETURN;
-        return Promise.resolve(sto);
+        return sto;
       }
       case Types.STRING.ord: {
         const parser = IVProgParser.createParser(value);
@@ -117,7 +117,7 @@ export function createCastRealFun () {
             const temp = new StoreValue(Types.REAL, result.value);
             sto.insertStore("$", temp);
             sto.mode = Modes.RETURN;
-            return Promise.resolve(sto);
+            return sto;
           }
         } catch (error) {
           // ignore
@@ -126,7 +126,7 @@ export function createCastRealFun () {
     }
     const typeStringInfoArray = Types.REAL.stringInfo();
     const typeInfo = typeStringInfoArray[0];
-    return Promise.reject(ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim));
+    throw ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim);
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(castRealFun)]);
@@ -137,7 +137,7 @@ export function createCastRealFun () {
 }
 
 export function createCastIntFun () {
-  const castIntFun = (sto, _) => {
+  const castIntFun = async (sto, _) => {
     const val = sto.applyStore("val");
     let value = val.get();
     switch (val.type.ord) {
@@ -146,7 +146,7 @@ export function createCastIntFun () {
         const temp = new StoreValue(Types.INTEGER, Math.floor(value));
         sto.insertStore("$", temp);
         sto.mode = Modes.RETURN;
-        return Promise.resolve(sto);
+        return sto;
       }
       case Types.STRING.ord: {
         const parser = IVProgParser.createParser(value);
@@ -156,7 +156,7 @@ export function createCastIntFun () {
             const temp = new StoreValue(Types.INTEGER, result.value);
             sto.insertStore("$", temp);
             sto.mode = Modes.RETURN;
-            return Promise.resolve(sto);
+            return sto;
           }
         } catch (error) { 
           // ignore
@@ -165,7 +165,7 @@ export function createCastIntFun () {
     }
     const typeStringInfoArray = Types.INTEGER.stringInfo();
     const typeInfo = typeStringInfoArray[0];
-    return Promise.reject(ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim));
+    throw ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim);
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(castIntFun)]);
@@ -176,7 +176,7 @@ export function createCastIntFun () {
 }
 
 export function createCastBoolFun () {
-  const castBoolFun = (sto, _) => {
+  const castBoolFun = async (sto, _) => {
     const str = sto.applyStore("str");
     const value = str.get(); 
     const parser = IVProgParser.createParser(value);
@@ -186,14 +186,14 @@ export function createCastBoolFun () {
         const temp = new StoreValue(Types.BOOLEAN, val.value);
         sto.insertStore("$", temp);
         sto.mode = Modes.RETURN;
-        return Promise.resolve(sto);
+        return sto;
       }
     } catch (error) { 
       // ignore
     }
     const typeStringInfoArray = Types.BOOLEAN.stringInfo();
     const typeInfo = typeStringInfoArray[0];
-    return Promise.reject(ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim));
+    throw ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim);
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(castBoolFun)]);
@@ -204,13 +204,13 @@ export function createCastBoolFun () {
 }
 
 export function createCastStringFun () {
-  const castStringFun = function (store, _) {
+  const castStringFun = async function (store, _) {
     const val = store.applyStore('str');
-    const result = convertToString(val.get(), val.type);
+    const result = Parsers.convertToString(val.get(), val.type);
     const temp = new StoreValue(Types.STRING, result);
     store.insertStore("$", temp);
     store.mode = Modes.RETURN;
-    return Promise.resolve(store);
+    return store;
   }
   const block = new Commands.CommandBlock([], [new Commands.SysCall(castStringFun)]);
   const func = new Commands.Function('$castString', Types.STRING,

+ 224 - 93
js/processor/lib/math.js

@@ -1,6 +1,6 @@
 import * as Commands from './../../ast/commands';
 import { Types } from './../../typeSystem/types';
-import { toReal } from "./../../typeSystem/parsers";
+import * as Parsers from "./../../typeSystem/parsers";
 import { Decimal } from 'decimal.js';
 import { MultiType } from '../../typeSystem/multiType';
 import { ArrayType } from '../../typeSystem/array_type';
@@ -22,12 +22,12 @@ import { ProcessorErrorFactory } from '../error/processorErrorFactory';
  * min
  */
 
-function convertToRadians (degrees) {
+function convertToRadians(degrees) {
   return degrees.times(Decimal.acos(-1)).div(180);
 }
 
 export function createSinFun () {
-   const sinFun = (sto, _) => {
+   const sinFun = async (sto, _) => {
      const x = sto.applyStore('x');
      const angle = x.get().mod(360);
      let result = null;
@@ -43,65 +43,93 @@ export function createSinFun () {
      const temp = new StoreValue(Types.REAL, result);
      sto.insertStore("$", temp);
      sto.mode = Modes.RETURN;
-     return Promise.resolve(sto);
+     return sto;
    };
 
-  const block = new Commands.CommandBlock([],  [new Commands.SysCall(sinFun)]);
-  const func = new Commands.Function('$sin', Types.REAL,
-    [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
-    block);
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(sinFun)]);
+  const func = new Commands.Function(
+    "$sin",
+    Types.REAL,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      )
+    ],
+    block
+  );
   return func;
 }
 
 export function createCosFun () {
-  const cosFun = (sto, _) => {
+  const cosFun = async (sto, _) => {
     const x = sto.applyStore('x');
     const angle = x.get().mod(360);
     let result = null;
-    if(angle.eq(90)) {
+    if (angle.eq(90)) {
       result = new Decimal(0);
     } else if (angle.eq(180)) {
       result = new Decimal(-1);
     } else if (angle.eq(270)) {
-      result = new Decimal(0)
+      result = new Decimal(0);
     }
     result = Decimal.cos(convertToRadians(angle));
     const temp = new StoreValue(Types.REAL, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(cosFun)]);
- const func = new Commands.Function('$cos', Types.REAL,
-   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
-   block);
- return func;
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(cosFun)]);
+  const func = new Commands.Function(
+    "$cos",
+    Types.REAL,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      )
+    ],
+    block
+  );
+  return func;
 }
 
 export function createTanFun () {
-  const tanFun = function (sto, _) {
+  const tanFun = async function (sto, _) {
     const x = sto.applyStore('x');
     const angle = x.get().mod(360);
     if(angle.eq(90) || angle.eq(270)) {
-      return Promise.reject(ProcessorErrorFactory.undefined_tanget_value(x.get().toNumber(), this.function_call_stack.pop()));
+      throw ProcessorErrorFactory.undefined_tanget_value(x.get().toNumber(),
+        this.function_call_stack.pop());
     }
     const result = Decimal.tan(convertToRadians(angle));
     const temp = new StoreValue(Types.REAL, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(tanFun)]);
- const func = new Commands.Function('$tan', Types.REAL,
-   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
-   block);
- return func;
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(tanFun)]);
+  const func = new Commands.Function(
+    "$tan",
+    Types.REAL,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      )
+    ],
+    block
+  );
+  return func;
 }
 
 export function createSqrtFun () {
-  const sqrtFun = function (sto, _) {
+  const sqrtFun = async function (sto, _) {
     const x = sto.applyStore('x');
     if(x.get().isNeg()) {
       return Promise.reject(ProcessorErrorFactory.negative_sqrt_value(this.function_call_stack.pop()));
@@ -110,151 +138,254 @@ export function createSqrtFun () {
     const temp = new StoreValue(Types.REAL, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(sqrtFun)]);
- const func = new Commands.Function('$sqrt', Types.REAL,
-   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
-   block);
- return func;
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(sqrtFun)]);
+  const func = new Commands.Function(
+    "$sqrt",
+    Types.REAL,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      )
+    ],
+    block
+  );
+  return func;
 }
 
 export function createPowFun () {
-  const powFun = (sto, _) => {
+  const powFun = async (sto, _) => {
     const x = sto.applyStore('x');
     const y = sto.applyStore('y');
     const result = x.get().pow(y.get());
     const temp = new StoreValue(Types.REAL, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(powFun)]);
- const func = new Commands.Function('$pow', Types.REAL,
-   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false),
-    new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'y', false)],
-   block);
- return func;
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(powFun)]);
+  const func = new Commands.Function(
+    "$pow",
+    Types.REAL,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      ),
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "y",
+        false
+      )
+    ],
+    block
+  );
+  return func;
 }
 
 export function createLogFun () {
-  const logFun = function (sto, _) {
+  const logFun = async function (sto, _) {
     const x = sto.applyStore('x');
     if (x.get().isNegative()) {
-      return Promise.reject(ProcessorErrorFactory.negative_log_value(this.function_call_stack.pop()));
+      return Promise.reject(
+        ProcessorErrorFactory.negative_log_value(this.function_call_stack.pop())
+      );
     }
     const result = Decimal.log10(x.get());
     const temp = new StoreValue(Types.REAL, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(logFun)]);
- const func = new Commands.Function('$log', Types.REAL,
-   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
-   block);
- return func;
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(logFun)]);
+  const func = new Commands.Function(
+    "$log",
+    Types.REAL,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      )
+    ],
+    block
+  );
+  return func;
 }
 
 export function createAbsFun () {
-  const absFun = (sto, _) => {
+  const absFun = async (sto, _) => {
     const x = sto.applyStore('x');
     const result = x.get().abs();
     const temp = new StoreValue(x.type, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(absFun)]);
- const func = new Commands.Function('$abs', new MultiType([Types.INTEGER, Types.REAL]),
-   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
-   block);
- return func;
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(absFun)]);
+  const func = new Commands.Function(
+    "$abs",
+    new MultiType([Types.INTEGER, Types.REAL]),
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      )
+    ],
+    block
+  );
+  return func;
 }
 
 export function createNegateFun () {
-  const negateFun = (sto, _) => {
+  const negateFun = async (sto, _) => {
     const x = sto.applyStore('x');
     const result = x.get().negated();
     const temp = new StoreValue(x.type, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(negateFun)]);
- const func = new Commands.Function('$negate', new MultiType([Types.INTEGER, Types.REAL]),
-   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
-   block);
- return func;
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(negateFun)]
+  );
+  const func = new Commands.Function(
+    "$negate",
+    new MultiType([Types.INTEGER, Types.REAL]),
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      )
+    ],
+    block
+  );
+  return func;
 }
 
-export function createInvertFun () {
-  const invertFun = (sto, _) => {
+export function createInvertFun() {
+  const invertFun = async (sto, _) => {
     const x = sto.applyStore('x');
-    const result = toReal(1).dividedBy(x.get());
+    const result = Parsers.toReal(1).dividedBy(x.get());
     const temp = new StoreValue(Types.REAL, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(invertFun)]);
- const func = new Commands.Function('$invert', Types.REAL,
-   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
-   block);
- return func;
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(invertFun)]
+  );
+  const func = new Commands.Function(
+    "$invert",
+    Types.REAL,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.REAL]),
+        "x",
+        false
+      )
+    ],
+    block
+  );
+  return func;
 }
 
 export function createMaxFun () {
-  const maxFun = (sto, _) => {
+  const maxFun = async (sto, _) => {
     const x = sto.applyStore('x');
     const numbers = x.get().map(sto_addrs => sto_addrs.get());
     const result = Decimal.max(...numbers);
     const temp = new StoreValue(x.type.innerType, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
- const paramType = new ArrayType(new MultiType([Types.INTEGER, Types.REAL]), 1);
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(maxFun)]);
- const func = new Commands.Function('$max', new MultiType([Types.INTEGER, Types.REAL]),
-   [new Commands.FormalParameter(paramType, 'x', false)],
-   block);
- return func;
+  const paramType = new ArrayType(
+    new MultiType([Types.INTEGER, Types.REAL]),
+    1
+  );
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(maxFun)]);
+  const func = new Commands.Function(
+    "$max",
+    new MultiType([Types.INTEGER, Types.REAL]),
+    [new Commands.FormalParameter(paramType, "x", false)],
+    block
+  );
+  return func;
 }
 
 export function createMinFun () {
-  const minFun = (sto, _) => {
+  const minFun = async (sto, _) => {
     const x = sto.applyStore('x');
     const numbers = x.get().map(sto_addrs => sto_addrs.get());
     const result = Decimal.min(...numbers);
     const temp = new StoreValue(x.type.innerType, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
- const paramType = new ArrayType(new MultiType([Types.INTEGER, Types.REAL]), 1);
- const block = new Commands.CommandBlock([],  [new Commands.SysCall(minFun)]);
- const func = new Commands.Function('$min', new MultiType([Types.INTEGER, Types.REAL]),
-   [new Commands.FormalParameter(paramType, 'x', false)],
-   block);
- return func;
+  const paramType = new ArrayType(
+    new MultiType([Types.INTEGER, Types.REAL]),
+    1
+  );
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(minFun)]);
+  const func = new Commands.Function(
+    "$min",
+    new MultiType([Types.INTEGER, Types.REAL]),
+    [new Commands.FormalParameter(paramType, "x", false)],
+    block
+  );
+  return func;
 }
 
-export function createRandFun () {
-  const randFun = (sto, _) => {
-    const val = Math.random();
+let seed = Date.now();
+export function createRandFun() {
+  const a = 16807;
+  const m = 2147483647;
+  const c = 12345;
+  const randFun = async (sto, _) => {
+    seed = (a * seed + c) % m;
+    const val = seed / (m - 1);
     const temp = new StoreValue(Types.REAL, new Decimal(val));
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
+  };
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(randFun)]);
+  const func = new Commands.Function("$rand", Types.REAL, [], block);
+  return func;
+}
+
+export function createSetSeedFun() {
+  const setSeedFun = async (sto, _) => {
+    const value = sto.applyStore("x");
+    seed = value.get().toNumber();
+    sto.mode = Modes.RETURN;
+    return sto;
   };
-  const block = new Commands.CommandBlock([],  [new Commands.SysCall(randFun)]);
-  const func = new Commands.Function('$rand', Types.REAL, [], block);
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(setSeedFun)]
+  );
+  const func = new Commands.Function(
+    "$setSeed",
+    Types.VOID,
+    [new Commands.FormalParameter(Types.INTEGER, "x", false)],
+    block
+  );
   return func;
 }

+ 12 - 11
js/processor/lib/strings.js

@@ -14,7 +14,7 @@ import { ProcessorErrorFactory } from '../error/processorErrorFactory';
 **/
 
 export function createSubstringFun () {
-  const substringFun = (sto, _) => {
+  const substringFun = async (sto, _) => {
     const str = sto.applyStore("str");
     const start = sto.applyStore("start");
     const end = sto.applyStore("end");
@@ -22,7 +22,7 @@ export function createSubstringFun () {
     const temp = new StoreValue(Types.STRING, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   };
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(substringFun)]);
@@ -35,12 +35,12 @@ export function createSubstringFun () {
 }
 
 export function createLengthFun () {
-  const lengthFun = (sto, _) => {
+  const lengthFun = async (sto, _) => {
     const str = sto.applyStore("str");
     const temp = new StoreValue(Types.INTEGER, toInt(str.value.length));
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(lengthFun)]);
   const func = new Commands.Function('$length', Types.INTEGER,
@@ -50,12 +50,12 @@ export function createLengthFun () {
 }
 
 export function createUppercaseFun () {
-  const uppercaseFun = (sto, _) => {
+  const uppercaseFun = async (sto, _) => {
     const str = sto.applyStore("str");
     const temp = new StoreValue(Types.STRING, str.get().toUpperCase());
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(uppercaseFun)]);
   const func = new Commands.Function('$uppercase', Types.STRING,
@@ -65,12 +65,12 @@ export function createUppercaseFun () {
 }
 
 export function createLowercaseFun () {
-  const lowercaseFun = (sto, _) => {
+  const lowercaseFun = async (sto, _) => {
     const str = sto.applyStore("str");
     const temp = new StoreValue(Types.STRING, str.get().toLowerCase());
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(lowercaseFun)]);
   const func = new Commands.Function('$lowercase', Types.STRING,
@@ -80,16 +80,17 @@ export function createLowercaseFun () {
 }
 
 export function createrCharAtFun () {
-  const charAtFun = function (sto, _) {
+  const charAtFun = async function (sto, _) {
     const str = sto.applyStore("str");
     const idx = sto.applyStore("index");
     if (idx.get().toNumber() < 0 || idx.get().toNumber() >= str.get().length) {
-      return Promise.reject(ProcessorErrorFactory.invalid_string_index(idx.get().toNumber(), str.get(), this.function_call_stack.pop()));
+      throw ProcessorErrorFactory.invalid_string_index(idx.get().toNumber(), str.get(),
+        this.function_call_stack.pop());
     }
     const temp = new StoreValue(Types.STRING, str.get().charAt(idx.get().toNumber()));
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto);
+    return sto;
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(charAtFun)]);
   const func = new Commands.Function('$charAt', Types.STRING,

+ 6 - 5
js/processor/semantic/semanticAnalyser.js

@@ -511,12 +511,13 @@ export class SemanticAnalyser {
       } else if (cmd.expression !== null) {
         const resultType = this.evaluateExpressionType(cmd.expression);
         if (!type.isCompatible(resultType)) {
-          const stringInfo = type.stringInfo();
-          const info = stringInfo[0];
-          throw ProcessorErrorFactory.invalid_return_type_full(funcName, info.type, info.dim, cmd.sourceInfo);
-        } else {
-          return true;
+          if (!Config.enable_type_casting || !Store.canImplicitTypeCast(type, resultType)) {
+            const stringInfo = type.stringInfo();
+            const info = stringInfo[0];
+            throw ProcessorErrorFactory.invalid_return_type_full(funcName, info.type, info.dim, cmd.sourceInfo);
+          }
         }
+        return true;
       } else {
         return true;
       }

+ 10 - 7
js/util/inputTest.js

@@ -9,12 +9,15 @@ export class InputTest extends Input {
     this.inputList = inputList;
   }
 
-  requestInput (callback) {
-    if(this.index < this.inputList.length) {      
-      callback(this.inputList[this.index]);
-      this.index++;
-    } else {
-      throw new Error(LocalizedStrings.getError("exceeded_input_request"));
-    }
+  requestInput () {
+    const promise = new Promise( (resolve, reject) => {
+      if(this.index < this.inputList.length) {      
+        resolve(this.inputList[this.index]);
+        this.index++;
+      } else {
+        reject(new Error(LocalizedStrings.getError("exceeded_input_request")));
+      }
+    });
+    return promise
   }
 }

+ 12 - 9
js/util/input_assessment.js

@@ -11,15 +11,18 @@ export class InputAssessment extends Input {
     });
   }
 
-  requestInput (callback) {
-    if(this.index < this.input_list.length) {
-      const input = this.input_list[this.index];
-      input.read = true;
-      this.index += 1;
-      callback(input.value);
-    } else {
-      throw new Error(LocalizedStrings.getError("exceeded_input_request"));
-    }
+  requestInput () {
+    const promise = new Promise( (resolve, reject) => {
+      if(this.index < this.input_list.length) {
+        const input = this.input_list[this.index];
+        input.read = true;
+        this.index += 1;
+        resolve(input.value);
+      } else {
+        reject(new Error(LocalizedStrings.getError("exceeded_input_request")));
+      }
+    });
+    return promise
   }
 
   isInputAvailable () {

+ 14 - 14
js/util/maybe.ts

@@ -8,30 +8,30 @@
 export class Maybe<T> {
   private constructor(private value: T | null) {}
 
-  static some<T>(value: T) {
-      if (!value) {
-          throw Error("Provided value must not be empty");
-      }
-      return new Maybe(value);
+  static some<T> (value: T): Maybe<T> {
+    if (!value) {
+      throw Error("Provided value must not be empty");
+    }
+    return new Maybe(value);
   }
 
-  static none<T>() {
-      return new Maybe<T>(null);
+  static none<T> (): Maybe<T> {
+    return new Maybe<T>(null);
   }
 
-  static fromValue<T>(value: T) {
-      return value ? Maybe.some(value) : Maybe.none<T>();
+  static fromValue<T> (value: T): Maybe<T> {
+    return value ? Maybe.some(value) : Maybe.none<T>();
   }
 
-  getOrElse(defaultValue: T) {
-      return this.value === null ? defaultValue : this.value;
+  getOrElse(defaultValue: T): T {
+    return this.value === null ? defaultValue : this.value;
   }
 
   map<R>(f: (wrapped: T) => R): Maybe<R> {
     if (this.value === null) {
-        return Maybe.none<R>();
+      return Maybe.none<R>();
     } else {
-        return Maybe.fromValue(f(this.value));
+      return Maybe.fromValue(f(this.value));
     }
-}
+  }
 }

+ 10 - 7
js/util/testConsole.js

@@ -40,13 +40,16 @@ export class TestConsole {
     }
   }
 
-  requestInput (callback) {
-    if(this.index < this.inputList.length) {      
-      callback(this.inputList[this.index]);
-      this.index++;
-    } else {
-      throw new Error(LocalizedStrings.getError("exceeded_input_request"));
-    }
+  requestInput () {
+    const promise = new Promise( (resolve, reject) => {
+      if(this.index < this.inputList.length) {      
+        resolve(this.inputList[this.index]);
+        this.index++;
+      } else {
+        reject(new Error(LocalizedStrings.getError("exceeded_input_request")));
+      }
+    });
+    return promise
   }
 
   sendOutput (text) {

+ 8 - 0
js/util/utils.js

@@ -272,3 +272,11 @@ export function openAssessmentDetail (event) {
 export function range (size, startAt = 0) {
   return [...Array(size).keys()].map(i => i + startAt);
 }
+
+/**
+ * 
+ * @param {number} ms 
+ */
+export async function sleep (ms) {
+    return new Promise( (res, _) => setTimeout(res, ms));
+  }

+ 13 - 3
package-lock.json

@@ -748,6 +748,18 @@
         "@babel/helper-plugin-utils": "^7.8.3"
       }
     },
+    "@babel/plugin-transform-runtime": {
+      "version": "7.9.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz",
+      "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-module-imports": "^7.8.3",
+        "@babel/helper-plugin-utils": "^7.8.3",
+        "resolve": "^1.8.1",
+        "semver": "^5.5.1"
+      }
+    },
     "@babel/plugin-transform-shorthand-properties": {
       "version": "7.8.3",
       "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz",
@@ -890,7 +902,6 @@
       "version": "7.9.2",
       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz",
       "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==",
-      "dev": true,
       "requires": {
         "regenerator-runtime": "^0.13.4"
       }
@@ -7191,8 +7202,7 @@
     "regenerator-runtime": {
       "version": "0.13.5",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
-      "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
-      "dev": true
+      "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
     },
     "regenerator-transform": {
       "version": "0.14.4",

+ 2 - 0
package.json

@@ -27,6 +27,7 @@
   "homepage": "https://git.lcalion.com/ivprog#readme",
   "devDependencies": {
     "@babel/core": "^7.6.2",
+    "@babel/plugin-transform-runtime": "^7.9.0",
     "@babel/preset-env": "^7.6.2",
     "@typescript-eslint/eslint-plugin": "^2.3.2",
     "@typescript-eslint/parser": "^2.3.2",
@@ -43,6 +44,7 @@
     "webpack-cli": "3.x"
   },
   "dependencies": {
+    "@babel/runtime": "^7.9.2",
     "antlr4": "^4.7.2",
     "codemirror": "^5.49.0",
     "csv-parser": "^2.3.1",