Prechádzať zdrojové kódy

Refactor type system

* Refactor language defined functions signature
* Refactor parser
* Refactor semantic analyser to handle MultiType
* Refactor compatibiity table to handl MultiType
* Refactor processor
* Implements new test cases
Lucas de Souza 5 rokov pred
rodič
commit
6b7c1f0d90
39 zmenil súbory, kde vykonal 441 pridanie a 383 odobranie
  1. 2 4
      js/ast/commands/arrayDeclaration.js
  2. 1 2
      js/ast/commands/formalParameter.js
  3. 2 2
      js/ast/commands/function.js
  4. 3 4
      js/ast/expressions/arrayLiteral.js
  5. 1 1
      js/ast/expressions/boolLiteral.js
  6. 1 1
      js/ast/expressions/intLiteral.js
  7. 1 1
      js/ast/expressions/realLiteral.js
  8. 1 1
      js/ast/expressions/stringLiteral.js
  9. 1 1
      js/ast/expressions/variableLiteral.js
  10. 22 4
      js/ast/ivprogParser.js
  11. 0 48
      js/ast/types.js
  12. 31 1
      js/processor/compatibilityTable.js
  13. 74 99
      js/processor/ivprogProcessor.js
  14. 6 4
      js/processor/lib/arrays.js
  15. 10 9
      js/processor/lib/io.js
  16. 30 13
      js/processor/lib/lang.js
  17. 31 26
      js/processor/lib/math.js
  18. 10 9
      js/processor/lib/strings.js
  19. 75 74
      js/processor/semantic/semanticAnalyser.js
  20. 4 2
      js/processor/store/store.js
  21. 1 1
      js/processor/store/storeObject.js
  22. 6 13
      js/processor/store/storeObjectArray.js
  23. 18 27
      js/processor/store/storeObjectArrayAddress.js
  24. 1 0
      js/processor/store/storeObjectArrayAddressRef.js
  25. 1 0
      js/processor/store/storeObjectRef.js
  26. 1 1
      js/typeSystem/baseTypes.js
  27. 10 1
      js/typeSystem/compoundType.js
  28. 2 3
      js/typeSystem/multiType.js
  29. 10 0
      js/typeSystem/parsers.js
  30. 21 0
      js/typeSystem/type.js
  31. 2 24
      js/typeSystem/types.js
  32. 1 1
      tests/test00.spec.js
  33. 1 1
      tests/test17.spec.js
  34. 1 1
      tests/test20.spec.js
  35. 1 1
      tests/test42.spec.js
  36. 4 3
      tests/test53.spec.js
  37. 11 0
      tests/test61.spec.js
  38. 11 0
      tests/test62.spec.js
  39. 32 0
      tests/testMinMax.spec.js

+ 2 - 4
js/ast/commands/arrayDeclaration.js

@@ -1,11 +1,9 @@
 import { Declaration } from './declaration';
-import { Types } from './../types';
 
 export class ArrayDeclaration extends Declaration {
 
-  constructor (id, subtype, lines, columns, initial, isConst)   {
-    super(id, Types.ARRAY, initial, isConst);
-    this.subtype = subtype;
+  constructor (id, type, lines, columns, initial, isConst)   {
+    super(id, type, initial, isConst);
     this.lines = lines;
     this.columns = columns;
   }

+ 1 - 2
js/ast/commands/formalParameter.js

@@ -1,9 +1,8 @@
 export class FormalParameter {
 
-  constructor (type, id, dimensions, byRef = false) {
+  constructor (type, id, byRef = false) {
     this.type = type;
     this.id = id;
-    this.dimensions = dimensions;
     this.byRef = byRef;
     this._sourceInfo = null;
   }

+ 2 - 2
js/ast/commands/function.js

@@ -1,4 +1,4 @@
-import { Types } from './../types';
+import { Types } from './../../typeSystem/types';
 
 export class Function {
 
@@ -11,7 +11,7 @@ export class Function {
   }
 
   get isMain () {
-    return this.name === null && this.returnType === Types.VOID;
+    return this.name === null && this.returnType.isCompatible(Types.VOID);
   }
 
   get commands () {

+ 3 - 4
js/ast/expressions/arrayLiteral.js

@@ -1,10 +1,9 @@
 import { Literal } from './literal';
-import { Types } from './../types';
 
 export class ArrayLiteral extends Literal {
   
-  constructor(value) {
-    super(Types.ARRAY);
+  constructor(type, value) {
+    super(type);
     this.value = value;
   }
 
@@ -80,4 +79,4 @@ export class ArrayLiteral extends Literal {
     }
     return valid;
   }
-}
+}

+ 1 - 1
js/ast/expressions/boolLiteral.js

@@ -1,5 +1,5 @@
 import { Literal } from './literal';
-import {Types} from './../types';
+import { Types } from './../../typeSystem/types';
 
 export class BoolLiteral extends Literal {
   

+ 1 - 1
js/ast/expressions/intLiteral.js

@@ -1,5 +1,5 @@
 import { Literal } from './literal';
-import {Types} from './../types';
+import { Types } from './../../typeSystem/types';
 
 export class IntLiteral extends Literal {
   

+ 1 - 1
js/ast/expressions/realLiteral.js

@@ -1,5 +1,5 @@
 import { Literal } from './literal';
-import {Types} from './../types';
+import { Types } from './../../typeSystem/types';
 
 export class RealLiteral extends Literal {
   

+ 1 - 1
js/ast/expressions/stringLiteral.js

@@ -1,5 +1,5 @@
 import { Literal } from './literal';
-import {Types} from './../types';
+import { Types } from './../../typeSystem/types';
 
 export class StringLiteral extends Literal {
   

+ 1 - 1
js/ast/expressions/variableLiteral.js

@@ -1,5 +1,5 @@
 import { Literal } from './literal';
-import { Types } from './../types';
+import { Types } from './../../typeSystem/types';
 
 export class VariableLiteral extends Literal {
   

+ 22 - 4
js/ast/ivprogParser.js

@@ -1,7 +1,9 @@
 import { CommonTokenStream, InputStream } from 'antlr4/index';
 import * as Expressions from './expressions/';
 import * as Commands from './commands/';
-import { Types, toInt, toString, toBool, toReal } from './types';
+import { toInt, toString, toBool, toReal } from './../typeSystem/parsers';
+import { Types } from "./../typeSystem/types";
+import { CompoundType } from "./../typeSystem/compoundType";
 import { SourceInfo } from './sourceInfo';
 import { convertFromString } from './operators';
 import { SyntaxErrorFactory } from './error/syntaxErrorFactory';
@@ -277,9 +279,14 @@ export class IVProgParser {
       initial = this.parseExpressionOR();
     }
     let declaration = null;
+    let dimensions = 0;
     if (dim1 !== null) {
+      dimensions++;
+      if(dim2 !== null) {
+        dimensions++;
+      }
       declaration = new Commands.ArrayDeclaration(idString,
-        typeString, dim1, dim2, initial, isConst);
+        new CompoundType(typeString, dimensions), dim1, dim2, initial, isConst);
     } else {
       declaration = new Commands.Declaration(idString, typeString, initial, isConst);
     }
@@ -385,7 +392,12 @@ export class IVProgParser {
       // }
     }
     const sourceInfo = SourceInfo.createSourceInfoFromList(beginArray, endArray);
-    const exp = new Expressions.ArrayLiteral(data);
+    let dataDim = 1;
+    if(data[0] instanceof Expressions.ArrayLiteral) {
+      dataDim++;
+    }
+    const type = new CompoundType(Types.UNDEFINED, dataDim);
+    const exp = new Expressions.ArrayLiteral(type, data);
     exp.sourceInfo = sourceInfo;
     return exp;
   }
@@ -463,7 +475,13 @@ export class IVProgParser {
           this.pos++;
         }
       }
-      list.push(new Commands.FormalParameter(typeString, idString, dimensions));
+      let type = null;
+      if(dimensions > 0) {
+        type = new CompoundType(typeString, dimensions);
+      } else {
+        type = typeString;
+      }
+      list.push(new Commands.FormalParameter(type, idString));
       const commaToken = this.getToken();
       if (commaToken.type !== this.lexerClass.COMMA)
         break;

+ 0 - 48
js/ast/types.js

@@ -1,48 +0,0 @@
-import { LanguageService } from "../services/languageService";
-import { BigNumber } from 'bignumber.js'
-
-export const Types = Object.freeze({
-  INTEGER: {value: "int", ord: 0},
-  REAL: {value: "real", ord: 1},
-  STRING: {value: "string", ord: 2},
-  BOOLEAN: {value: "bool", ord: 3},
-  VOID: {value: "void", ord: 4},
-  ARRAY: {value: 'array', ord: 5},
-  UNDEFINED: {value: 'undefined', ord: 6},
-  ALL: {value: 'all', ord: 7}
-});
-
-export function toInt (str) {
-  return new BigNumber(str);
-}
-
-export function toString (str) {
-  let value = str.replace(/^"/, '');
-  value = value.replace(/"$/, '');
-  value = value.replace(/\\b/g, "\b");
-  value = value.replace(/\\t/g, "\t");
-  value = value.replace(/\\n/g, "\n");
-  value = value.replace(/\\r/g, "\r");
-  value = value.replace(/\\\"/g, "\"");
-  value = value.replace(/\\\'/g, "\'");
-  value = value.replace(/\\\\/g, "\\");
-  return value;
-}
-
-export function toReal (value) {
-  return new BigNumber(value);
-}
-
-export function toBool (str) {
-  const val = "'" + str + "'";
-  const lexer = LanguageService.getCurrentLexer();
-  const instance = new lexer(null);
-  if (instance.literalNames[lexer.RK_TRUE] === val) {
-    return true;
-  } else if (instance.literalNames[lexer.RK_FALSE] === val) {
-    return false;
-  } else {
-    // TODO: better error message
-    throw new Error(str + "not a valid boolean");
-  }
-}

+ 31 - 1
js/processor/compatibilityTable.js

@@ -1,5 +1,6 @@
-import { Types } from './../ast/types';
+import { Types } from './../typeSystem/types';
 import { Operators } from './../ast/operators';
+import { MultiType } from '../typeSystem/multiType';
 
 function buildInfixAddTable () {
   const table = [[], [], [], []];
@@ -123,6 +124,32 @@ const unaryMap = buildUnaryCompatibilityTable();
 
 export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpressionType) {
   try {
+    if(leftExpressionType instanceof MultiType && rightExpressionType instanceof MultiType) {
+      let newMulti = [];
+      for (let i = 0; i < leftExpressionType.types.length; i++) {
+        const element = leftExpressionType.types[i];
+        if(rightExpressionType.types.indexOf(element) !== -1) {
+          newMulti.push(element);
+        }
+      }
+      if(newMulti.length <= 0) {
+        return Types.UNDEFINED;
+      } else {
+        return new MultiType(newMulti)
+      }
+    } else if(leftExpressionType instanceof MultiType) {
+      if(leftExpressionType.isCompatible(rightExpressionType)) {
+        return rightExpressionType;
+      } else {
+        return Types.UNDEFINED;
+      }
+    } else if(rightExpressionType instanceof MultiType) {
+      if(rightExpressionType.isCompatible(leftExpressionType)) {
+        return leftExpressionType;
+      } else {
+        return Types.UNDEFINED;
+      }
+    }
     const resultType = infixMap.get(operator)[leftExpressionType.ord][rightExpressionType.ord];
     if (resultType === null || resultType === undefined) {
       return Types.UNDEFINED
@@ -139,6 +166,9 @@ export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpre
 
 export function resultTypeAfterUnaryOp (operator, leftExpressionType) {
   try {
+    if(leftExpressionType instanceof MultiType){
+      return leftExpressionType;
+    }
     return unaryMap.get(operator)[leftExpressionType.ord];
   } catch (e) {
     if (e instanceof TypeError) {

+ 74 - 99
js/processor/ivprogProcessor.js

@@ -4,7 +4,7 @@ import { StoreObjectArray } from './store/storeObjectArray';
 import { StoreObjectRef } from './store/storeObjectRef';
 import { Modes } from './modes';
 import { Context } from './context';
-import { Types } from './../ast/types';
+import { Types } from './../typeSystem/types';
 import { Operators } from './../ast/operators';
 import { LanguageDefinedFunction } from './definedFunctions';
 import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from './compatibilityTable';
@@ -12,6 +12,7 @@ import * as Commands from './../ast/commands/';
 import * as Expressions from './../ast/expressions/';
 import { StoreObjectArrayAddress } from './store/storeObjectArrayAddress';
 import { StoreObjectArrayAddressRef } from './store/storeObjectArrayAddressRef';
+import { CompoundType } from './../typeSystem/compoundType';
 
 export class IVProgProcessor {
 
@@ -117,73 +118,24 @@ export class IVProgProcessor {
       for (let i = 0; i < values.length; i++) {
         const stoObj = values[i];
         const formalParameter = formalList[i];
-        switch (formalParameter.dimensions) {
-          case 1: {
-            if (stoObj.lines > 0 && stoObj.columns === null
-              && stoObj.subtype === formalParameter.type) {
-
-              if(formalParameter.byRef && !stoObj.inStore) {
-                throw new Error('You must inform a variable as parameter');
-              }
-
-              if(formalParameter.byRef) {
-                const ref = new StoreObjectArrayAddressRef(stoObj);
-                calleeStore.insertStore(formalParameter.id, ref);
-              } else {
-                calleeStore.insertStore(formalParameter.id, stoObj);
-              }
-
-            } else {
-              // TODO: Better error message
-              throw new Error(`Parameter ${formalParameter.id} is not compatible with the value given.`);
-            }
-            break;
-          }
-          case 2: {
-            if (stoObj.lines > 0 && stoObj.columns > 0
-              && stoObj.subtype === formalParameter.type) {
-
-              if(formalParameter.byRef && !stoObj.inStore) {
-                throw new Error('You must inform a variable as parameter');
-              }
-
-              if(formalParameter.byRef) {
-                const ref = new StoreObjectArrayAddressRef(stoObj);
-                calleeStore.insertStore(formalParameter.id, ref);
-              } else {
-                calleeStore.insertStore(formalParameter.id, stoObj);
-              }
-
-            } else {
-              // TODO: Better error message
-              throw new Error(`Parameter ${formalParameter.id} is not compatible with the value given.`);
-            }
-            break;
+        if(formalParameter.type.isCompatible(stoObj.type)) {
+          if(formalParameter.byRef && !stoObj.inStore) {
+            throw new Error('You must inform a variable as parameter');
           }
-          case 0: {
-            if(formalParameter.byRef && !stoObj.inStore) {
-
-              throw new Error('You must inform a variable as parameter');
-            } else if (formalParameter.type !== Types.ALL && stoObj.type !== formalParameter.type) {
 
-              // TODO: Better error message
-              throw new Error(`Parameter ${formalParameter.id} is not compatible with ${stoObj.type}.`);
+          if(formalParameter.byRef) {
+            let ref = null;
+            if (stoObj instanceof StoreObjectArrayAddress) {
+              ref = new StoreObjectArrayAddressRef(stoObj);
             } else {
-
-              if(formalParameter.byRef) {
-                let ref = null;
-                if (stoObj instanceof StoreObjectArrayAddress) {
-                  ref = new StoreObjectArrayAddressRef(stoObj);
-                } else {
-                  ref = new StoreObjectRef(stoObj.id, callerStore);
-                }
-                calleeStore.insertStore(formalParameter.id, ref);
-              } else {
-                calleeStore.insertStore(formalParameter.id, stoObj);
-              }
-
+              ref = new StoreObjectRef(stoObj.id, callerStore);
             }
+            calleeStore.insertStore(formalParameter.id, ref);
+          } else {
+            calleeStore.insertStore(formalParameter.id, stoObj);
           }
+        } else {
+          throw new Error(`Parameter ${formalParameter.id} is not compatible with the value given.`);
         }
       }
       return calleeStore;
@@ -332,7 +284,7 @@ export class IVProgProcessor {
         }
         const $value = this.evaluateExpression(sto, cmd.expression);
         return $value.then(vl => {
-          if (vl.type !== Types.BOOLEAN) {
+          if (!vl.type.isCompatible(Types.BOOLEAN)) {
             // TODO: Better error message -- Inform line and column from token!!!!
             // THIS IF SHOULD BE IN A SEMANTIC ANALYSER
             return Promise.reject(new Error(`DoWhile expression must be of type boolean`));
@@ -356,7 +308,7 @@ export class IVProgProcessor {
       this.context.push(Context.BREAKABLE);
       const $value = this.evaluateExpression(store, cmd.expression);
       return $value.then(vl => {
-        if(vl.type === Types.BOOLEAN) {
+        if(vl.type.isCompatible(Types.BOOLEAN)) {
           if(vl.value) {
             const $newStore = this.executeCommands(store, cmd.commands);
             return $newStore.then(sto => {
@@ -386,7 +338,7 @@ export class IVProgProcessor {
     try {
       const $value = this.evaluateExpression(store, cmd.condition);
       return $value.then(vl => {
-        if(vl.type === Types.BOOLEAN) {
+        if(vl.type.isCompatible(Types.BOOLEAN)) {
           if(vl.value) {
             return this.executeCommands(store, cmd.ifTrue.commands);
           } else if( cmd.ifFalse !== null){
@@ -416,11 +368,11 @@ export class IVProgProcessor {
       const funcName = store.applyStore('$name');
       return $value.then(vl => {
 
-        if(vl === null && funcType === Types.VOID) {
+        if(vl === null && funcType.isCompatible(Types.VOID)) {
           return Promise.resolve(store);
         }
 
-        if (vl === null || funcType.type !== vl.type) {
+        if (vl === null || !funcType.type.isCompatible(vl.type)) {
           // TODO: Better error message -- Inform line and column from token!!!!
           // THIS IF SHOULD BE IN A SEMANTIC ANALYSER
           return Promise.reject(new Error(`Function ${funcName.value} must return ${funcType.type} instead of ${vl.type}.`));
@@ -459,7 +411,7 @@ export class IVProgProcessor {
   executeArrayIndexAssign (store, cmd) {
     return new Promise((resolve, reject) => {
       const mustBeArray = store.applyStore(cmd.id);
-      if(mustBeArray.type !== Types.ARRAY) {
+      if(!(mustBeArray.type instanceof CompoundType)) {
         reject(new Error(cmd.id + " is not a vector/matrix"));
         return;
       }
@@ -468,7 +420,7 @@ export class IVProgProcessor {
       const value$ =  this.evaluateExpression(store, cmd.expression);
       Promise.all([line$, column$, value$]).then(results => {
         const lineSO = results[0];
-        if(lineSO.type !== Types.INTEGER) {
+        if(!Types.INTEGER.isCompatible(lineSO.type)) {
           // TODO: better error message
           //SHOULD NOT BE HERE. IT MUST HAVE A SEMANTIC ANALYSIS
           reject(new Error("Array dimension must be of type int"));
@@ -478,7 +430,7 @@ export class IVProgProcessor {
         const columnSO = results[1];
         let column = null
         if (columnSO !== null) {
-          if(columnSO.type !== Types.INTEGER) {
+          if(!Types.INTEGER.isCompatible(columnSO.type)) {
             // TODO: better error message
             //SHOULD NOT BE HERE. IT MUST HAVE A SEMANTIC ANALYSIS
             reject(new Error("Array dimension must be of type int"));
@@ -502,14 +454,14 @@ export class IVProgProcessor {
 
         const newArray = Object.assign(new StoreObjectArray(null,null,null), mustBeArray);
         if (column !== null) {
-         if (value.type === Types.ARRAY) {
+         if (value.type instanceof CompoundType) {
            reject(new Error("Invalid operation. This must be a value: line "+cmd.sourceInfo.line));
            return;
          }
          newArray.value[line].value[column] = value;
          store.updateStore(cmd.id, newArray);
         } else {
-         if(mustBeArray.columns !== null && value.type !== Types.ARRAY) {
+         if(mustBeArray.columns !== null && value.type instanceof CompoundType) {
           reject(new Error("Invalid operation. This must be a vector: line "+cmd.sourceInfo.line));
           return;
          }
@@ -529,7 +481,7 @@ export class IVProgProcessor {
         const $columns = cmd.columns === null ? null: this.evaluateExpression(store, cmd.columns);
         return Promise.all([$lines, $columns, $value]).then(values => {
           const lineSO = values[0];
-          if(lineSO.type !== Types.INTEGER) {
+          if(!Types.INTEGER.isCompatible(lineSO.type)) {
             // TODO: better error message
             //SHOULD NOT BE HERE. IT MUST HAVE A SEMANTIC ANALYSIS
             return Promise.reject(new Error("Array dimension must be of type int"));
@@ -538,7 +490,7 @@ export class IVProgProcessor {
           const columnSO = values[1];
           let column = null
           if (columnSO !== null) {
-            if(columnSO.type !== Types.INTEGER) {
+            if(!Types.INTEGER.isCompatible(columnSO.type)) {
               // TODO: better error message
               //SHOULD NOT BE HERE. IT MUST HAVE A SEMANTIC ANALYSIS
               return Promise.reject(new Error("Array dimension must be of type int"));
@@ -546,10 +498,18 @@ export class IVProgProcessor {
             column = columnSO.number;
           }
           const value = values[2];
-          const temp = new StoreObjectArray(cmd.subtype, line, column, null, cmd.isConst);
+          const temp = new StoreObjectArray(cmd.type, line, column, null, cmd.isConst);
           store.insertStore(cmd.id, temp);
-          if(value !== null) {
-            store.updateStore(cmd.id, value);
+          if (value !== null) {
+            let realValue = value;
+            if(value instanceof StoreObjectArrayAddress) {
+              if(value.type instanceof CompoundType) {
+                realValue = Object.assign(new StoreObjectArray(null,null,null), value.refValue);
+              } else {
+                realValue = Object.assign(new StoreObject(null,null), value.refValue);
+              }
+            }
+            store.updateStore(cmd.id, realValue)
           }
           return store;
         });
@@ -558,8 +518,17 @@ export class IVProgProcessor {
         const temp = new StoreObject(cmd.type, null, cmd.isConst);
         store.insertStore(cmd.id, temp);
         return $value.then(vl => {
-          if (vl !== null)
-            store.updateStore(cmd.id, vl)
+          if (vl !== null) {
+            let realValue = vl;
+            if(vl instanceof StoreObjectArrayAddress) {
+              if(vl.type instanceof CompoundType) {
+                realValue = Object.assign(new StoreObjectArray(null,null,null), vl.refValue);
+              } else {
+                realValue = Object.assign(new StoreObject(null,null), vl.refValue);
+              }
+            }
+            store.updateStore(cmd.id, realValue)
+          }
           return store;
         });
       }
@@ -597,14 +566,14 @@ export class IVProgProcessor {
 
   evaluateFunctionCall (store, exp) {
     const func = this.findFunction(exp.id);
-    if(func.returnType === Types.VOID) {
+    if(Types.VOID.isCompatible(func.returnType)) {
       // TODO: better error message
       return Promise.reject(new Error(`Function ${exp.id} cannot be used inside an expression`));
     }
     const $newStore = this.runFunction(func, exp.actualParameters, store);
     return $newStore.then( sto => {
       const val = sto.applyStore('$');
-      if (val.type === Types.ARRAY) {
+      if (val instanceof StoreObjectArray) {
         return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null,null), val));
       } else {
         return Promise.resolve(Object.assign(new StoreObject(null,null), val));
@@ -616,7 +585,8 @@ export class IVProgProcessor {
     if(!exp.isVector) {
       const $matrix = this.evaluateMatrix(store, exp.value);
       return $matrix.then(list => {
-        const arr = new StoreObjectArray(list[0].subtype, list.length, list[0].lines, list);
+        const type = new CompoundType(list[0].type.innerType, 2);
+        const arr = new StoreObjectArray(type, list.length, list[0].lines, list);
         if(arr.isValid)
           return Promise.resolve(arr);
         else
@@ -624,7 +594,8 @@ export class IVProgProcessor {
       });
     } else {
       return this.evaluateVector(store, exp.value).then(list => {
-        const stoArray = new StoreObjectArray(list[0].type, list.length, null, list);
+        const type = new CompoundType(list[0].type, 1);
+        const stoArray = new StoreObjectArray(type, list.length, null, list);
         if(stoArray.isValid)
           return Promise.resolve(stoArray);
         else
@@ -640,7 +611,10 @@ export class IVProgProcessor {
   evaluateMatrix (store, exps) {
     return Promise.all(exps.map( vector => {
       const $vector = this.evaluateVector(store, vector.value)
-      return $vector.then(list => new StoreObjectArray(list[0].type, list.length, null, list))
+      return $vector.then(list => {
+        const type = new CompoundType(list[0].type, 1);
+        return new StoreObjectArray(type, list.length, null, list)
+      });
     } ));
   }
 
@@ -651,7 +625,7 @@ export class IVProgProcessor {
   evaluateVariableLiteral (store, exp) {
     try {
       const val = store.applyStore(exp.id);
-      if (val.type === Types.ARRAY) {
+      if (val instanceof StoreObjectArray) {
         return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null), val));
       } else {
         return Promise.resolve(Object.assign(new StoreObject(null,null), val));
@@ -663,8 +637,9 @@ export class IVProgProcessor {
 
   evaluateArrayAccess (store, exp) {
     const mustBeArray = store.applyStore(exp.id);
-    if (mustBeArray.type !== Types.ARRAY) {
+    if (!(mustBeArray.type instanceof CompoundType)) {
       // TODO: better error message
+      console.log(mustBeArray.type);
       return Promise.reject(new Error(`${exp.id} is not of type array`));
     }
     const $line = this.evaluateExpression(store, exp.line);
@@ -672,7 +647,7 @@ export class IVProgProcessor {
     return Promise.all([$line, $column]).then(values => {
       const lineSO = values[0];
       const columnSO = values[1];
-      if(lineSO.type !== Types.INTEGER) {
+      if(!Types.INTEGER.isCompatible(lineSO.type)) {
         // TODO: better error message
         //SHOULD NOT BE HERE. IT MUST HAVE A SEMANTIC ANALYSIS
         return Promise.reject(new Error("Array dimension must be of type int"));
@@ -680,7 +655,7 @@ export class IVProgProcessor {
       const line = lineSO.number;
       let column = null;
       if(columnSO !== null) {
-        if(columnSO.type !== Types.INTEGER) {
+        if(!Types.INTEGER.isCompatible(columnSO.type)) {
           // TODO: better error message
           //SHOULD NOT BE HERE. IT MUST HAVE A SEMANTIC ANALYSIS
           return Promise.reject(new Error("Array dimension must be of type int"));
@@ -708,7 +683,7 @@ export class IVProgProcessor {
     const $left = this.evaluateExpression(store, unaryApp.left);
     return $left.then( left => {
       const resultType = resultTypeAfterUnaryOp(unaryApp.op, left.type);
-      if (resultType === Types.UNDEFINED) {
+      if (Types.UNDEFINED.isCompatible(resultType)) {
         // TODO: better urgent error message
         return Promise.reject(new Error(`Cannot use this op to ${left.type}`));
       }
@@ -732,9 +707,9 @@ export class IVProgProcessor {
       const left = values[0];
       const right = values[1];
       const resultType = resultTypeAfterInfixOp(infixApp.op, left.type, right.type);
-      if (resultType === Types.UNDEFINED) {
+      if (Types.UNDEFINED.isCompatible(resultType)) {
         // TODO: better urgent error message
-        return Promise.reject(new Error(`Cannot use this ${infixApp.op.value} to ${left.type.value} and ${right.type.value}`));
+        return Promise.reject(new Error(`Cannot use this ${infixApp.op} to ${left.type} and ${right.type}`));
       }
       let result = null;
       switch (infixApp.op.ord) {
@@ -746,7 +721,7 @@ export class IVProgProcessor {
           return new StoreObject(resultType, left.value.times(right.value));
         case Operators.DIV.ord: {
           result = left.value / right.value;
-          if (resultType === Types.INTEGER)
+          if (Types.INTEGER.isCompatible(resultType))
             result = left.value.idiv(right.value);
           else
             result = left.value.div(right.value);
@@ -755,7 +730,7 @@ export class IVProgProcessor {
         case Operators.MOD.ord:
           return new StoreObject(resultType, left.value.modulo(right.value));
         case Operators.GT.ord: {
-          if (left.type === Types.STRING) {
+          if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length > right.value.length;
           } else {
             result = left.value.gt(right.value);
@@ -763,7 +738,7 @@ export class IVProgProcessor {
           return new StoreObject(resultType, result);
         }
         case Operators.GE.ord: {
-          if (left.type === Types.STRING) {
+          if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length >= right.value.length;
           } else {
             result = left.value.gte(right.value);
@@ -771,7 +746,7 @@ export class IVProgProcessor {
           return new StoreObject(resultType, result);
         }
         case Operators.LT.ord: {
-          if (left.type === Types.STRING) {
+          if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length < right.value.length;
           } else {
             result = left.value.lt(right.value);
@@ -779,7 +754,7 @@ export class IVProgProcessor {
           return new StoreObject(resultType, result);
         }
         case Operators.LE.ord: {
-          if (left.type === Types.STRING) {
+          if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length <= right.value.length;
           } else {
             result = left.value.lte(right.value);
@@ -787,7 +762,7 @@ export class IVProgProcessor {
           return new StoreObject(resultType, result);
         }
         case Operators.EQ.ord: {
-          if (left.type === Types.INTEGER || left.type === Types.REAL) {
+          if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
             result = left.value.eq(right.value);
           } else {
             result = left.value === right.value;
@@ -795,7 +770,7 @@ export class IVProgProcessor {
           return new StoreObject(resultType, result);
         }
         case Operators.NEQ.ord: {
-          if (left.type === Types.INTEGER || left.type === Types.REAL) {
+          if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
             result = !left.value.eq(right.value);
           } else {
             result = left.value !== right.value;

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

@@ -1,6 +1,8 @@
 import { StoreObject } from '../store/storeObject';
 import * as Commands from './../../ast/commands';
-import { Types, toInt } from './../../ast/types';
+import { Types } from './../../typeSystem/types';
+import { toInt } from "./../../typeSystem/parsers";
+import { CompoundType } from '../../typeSystem/compoundType';
 
 /**
  * num_elements
@@ -17,7 +19,7 @@ export function createNumElementsFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(numElementsFun)]);
   const func = new Commands.Function('$numElements', Types.INTEGER,
-    [new Commands.FormalParameter(Types.ALL, 'vector', 1, false)],
+    [new Commands.FormalParameter(new CompoundType(Types.ALL, 1), 'vector', false)],
     block);
   return func;
  }
@@ -31,7 +33,7 @@ export function createMatrixLinesFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(matrixLinesFun)]);
   const func = new Commands.Function('$matrixLines', Types.INTEGER,
-    [new Commands.FormalParameter(Types.ALL, 'matrix', 2, false)],
+    [new Commands.FormalParameter(new CompoundType(Types.ALL, 2), 'matrix', false)],
     block);
   return func;
  }
@@ -45,7 +47,7 @@ export function createMatrixColumnsFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(matrixColumnsFun)]);
   const func = new Commands.Function('$matrixColumns', Types.INTEGER,
-    [new Commands.FormalParameter(Types.ALL, 'matrix', 2, false)],
+    [new Commands.FormalParameter(new CompoundType(Types.ALL, 2), 'matrix', false)],
     block);
   return func;
  }

+ 10 - 9
js/processor/lib/io.js

@@ -1,13 +1,14 @@
 import { StoreObject } from './../store/storeObject';
 import * as Commands from './../../ast/commands';
-import {Types, toInt, toString, toBool, toReal} from './../../ast/types';
+import {toInt, toString, toBool, toReal} from './../../typeSystem/parsers';
+import { Types } from './../../typeSystem/types';
 
 export function createOutputFun () {
   const writeFunction = function (store, _) {
     const val = store.applyStore('p1');
-    if(val.type === Types.INTEGER) {
+    if(val.type.isCompatible(Types.INTEGER)) {
       this.output.sendOutput(val.value.toString());
-    } else if (val.type === Types.REAL) {
+    } else if (val.type.isCompatible(Types.REAL)) {
       if (val.value.dp() <= 0) {
         this.output.sendOutput(val.value.toFixed(1));  
       } else {
@@ -20,7 +21,7 @@ export function createOutputFun () {
   }
   const block = new Commands.CommandBlock([], [new Commands.SysCall(writeFunction)]);
   const func = new Commands.Function('$write', Types.VOID,
-    [new Commands.FormalParameter(Types.ALL, 'p1', 0, false)],
+    [new Commands.FormalParameter(Types.ALL, 'p1', false)],
     block);
   return func;
 }
@@ -33,14 +34,14 @@ export function createInputFun () {
     return request.then(text => {
       const typeToConvert = store.applyStore('p1').type;
       let stoObj = null;
-      if (typeToConvert === Types.INTEGER) {
+      if (typeToConvert.isCompatible(Types.INTEGER)) {
         const val = toInt(text);
         stoObj = new StoreObject(Types.INTEGER, val);
-      } else if (typeToConvert === Types.REAL) {
+      } else if (typeToConvert.isCompatible(Types.REAL)) {
         stoObj = new StoreObject(Types.REAL, toReal(text));
-      } else if (typeToConvert === Types.BOOLEAN) {
+      } else if (typeToConvert.isCompatible(Types.BOOLEAN)) {
         stoObj = new StoreObject(Types.BOOLEAN, toBool(text));
-      } else if (typeToConvert === Types.STRING) {
+      } else if (typeToConvert.isCompatible(Types.STRING)) {
         stoObj = new StoreObject(Types.STRING, toString(text));
       }
       store.updateStore('p1', stoObj);
@@ -49,7 +50,7 @@ export function createInputFun () {
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(readFunction)]);
   const func = new Commands.Function('$read', Types.VOID,
-    [new Commands.FormalParameter(Types.ALL, 'p1', 0, true)],
+    [new Commands.FormalParameter(Types.ALL, 'p1', true)],
     block);
   return func;
 }

+ 30 - 13
js/processor/lib/lang.js

@@ -1,6 +1,7 @@
 import { StoreObject } from '../store/storeObject';
 import * as Commands from './../../ast/commands';
-import { Types, toReal } from './../../ast/types';
+import { Types } from './../../typeSystem/types';
+import { toReal, convertBoolToString } from "./../../typeSystem/parsers";
 import { IVProgParser } from '../../ast/ivprogParser';
 import { RealLiteral, IntLiteral, BoolLiteral } from '../../ast/expressions';
 
@@ -32,7 +33,7 @@ export function createIsRealFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(isRealFun)]);
   const func = new Commands.Function('$isReal', Types.BOOLEAN,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
     block);
   return func;
 }
@@ -54,7 +55,7 @@ export function createIsIntFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(isIntFun)]);
   const func = new Commands.Function('$isInt', Types.BOOLEAN,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
     block);
   return func;
 }
@@ -76,7 +77,7 @@ export function createIsBoolFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(isBoolFun)]);
   const func = new Commands.Function('$isBool', Types.BOOLEAN,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
     block);
   return func;
 }
@@ -106,7 +107,7 @@ export function createCastRealFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(castRealFun)]);
   const func = new Commands.Function('$castReal', Types.REAL,
-    [new Commands.FormalParameter(Types.ALL, 'val', 0, false)],
+    [new Commands.FormalParameter(Types.ALL, 'val', false)],
     block);
   return func;
 }
@@ -136,7 +137,7 @@ export function createCastIntFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(castIntFun)]);
   const func = new Commands.Function('$castInt', Types.INTEGER,
-    [new Commands.FormalParameter(Types.ALL, 'val', 0, false)],
+    [new Commands.FormalParameter(Types.ALL, 'val', false)],
     block);
   return func;
 }
@@ -157,7 +158,7 @@ export function createCastBoolFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(castBoolFun)]);
   const func = new Commands.Function('$castBool', Types.BOOLEAN,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
     block);
   return func;
 }
@@ -165,27 +166,43 @@ export function createCastBoolFun () {
 export function createCastStringFun () {
   const castStringFun = function (store, _) {
     const val = store.applyStore('str');
+    if(val.type.isCompatible(Types.INTEGER)) {
+      this.output.sendOutput(val.value.toString());
+    } else if (val.type.isCompatible(Types.REAL)) {
+      if (val.value.dp() <= 0) {
+        this.output.sendOutput(val.value.toFixed(1));  
+      } else {
+        this.output.sendOutput(val.value.toString());
+      }
+    } else {
+      this.output.sendOutput(val.value);
+    }
+    let result = null;
     switch (val.type.ord) {
       case Types.INTEGER.ord:
-        this.output.sendOutput(val.number);  
+        result = val.value.toString();  
         break;
       case Types.REAL.ord: {
         if (val.value.dp() <= 0) {
-          this.output.sendOutput(val.value.toFixed(1));  
+          result = val.value.toFixed(1);  
         } else {
-          this.output.sendOutput(val.number);
+          result = val.number;
         }
         break;
       }
+      case Types.BOOLEAN.ord:
+        result = convertBoolToString(val.value);
+        break;
       default:
-        this.output.sendOutput(val.value);
+        result = val.value;
         break;
     }
-    return Promise.resolve(store);
+    const temp = new StoreObject(Types.STRING, result);
+    return Promise.resolve(sto.updateStore("$", temp));
   }
   const block = new Commands.CommandBlock([], [new Commands.SysCall(castStringFun)]);
   const func = new Commands.Function('$castString', Types.STRING,
-    [new Commands.FormalParameter(Types.ALL, 'str', 0, false)],
+    [new Commands.FormalParameter(Types.ALL, 'str', false)],
     block);
   return func;
 }

+ 31 - 26
js/processor/lib/math.js

@@ -1,7 +1,10 @@
 import { StoreObject } from '../store/storeObject';
 import * as Commands from './../../ast/commands';
-import { Types, toReal } from './../../ast/types';
+import { Types } from './../../typeSystem/types';
+import { toReal } from "./../../typeSystem/parsers";
 import { BigNumber } from 'bignumber.js';
+import { MultiType } from '../../typeSystem/multiType';
+import { CompoundType } from '../../typeSystem/compoundType';
 
 /**
  * sin
@@ -27,7 +30,7 @@ export function createSinFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(sinFun)]);
   const func = new Commands.Function('$sin', Types.REAL,
-    [new Commands.FormalParameter(Types.REAL, 'x', 0, false)],
+    [new Commands.FormalParameter(new MultiType([[Types.INTEGER, Types.REAL]]), 'x', false)],
     block);
   return func;
 }
@@ -42,7 +45,7 @@ export function createCosFun () {
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(cosFun)]);
  const func = new Commands.Function('$cos', Types.REAL,
-   [new Commands.FormalParameter(Types.REAL, 'x', 0, false)],
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
    block);
  return func;
 }
@@ -57,7 +60,7 @@ export function createTanFun () {
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(tanFun)]);
  const func = new Commands.Function('$tan', Types.REAL,
-   [new Commands.FormalParameter(Types.REAL, 'x', 0, false)],
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
    block);
  return func;
 }
@@ -72,14 +75,14 @@ export function createSqrtFun () {
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(sqrtFun)]);
  const func = new Commands.Function('$sqrt', Types.REAL,
-   [new Commands.FormalParameter(Types.REAL, 'x', 0, false)],
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
    block);
  return func;
 }
 
 export function createPowFun () {
   const powFun = (sto, _) => {
-    const x = sto.applyStore('x');
+    const x = sto.applyStore('x');f
     const y = sto.applyStore('y');
     const result = toReal(Math.pow(x.number, y.number));
     const temp = new StoreObject(Types.REAL, result);
@@ -88,8 +91,8 @@ export function createPowFun () {
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(powFun)]);
  const func = new Commands.Function('$pow', Types.REAL,
-   [new Commands.FormalParameter(Types.REAL, 'x', 0, false),
-    new Commands.FormalParameter(Types.REAL, 'y', 0, false)],
+   [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;
 }
@@ -107,7 +110,7 @@ export function createLogFun () {
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(logFun)]);
  const func = new Commands.Function('$log', Types.REAL,
-   [new Commands.FormalParameter(Types.REAL, 'x', 0, false)],
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
    block);
  return func;
 }
@@ -116,13 +119,13 @@ export function createAbsFun () {
   const absFun = (sto, _) => {
     const x = sto.applyStore('x');
     const result = x.value.abs();
-    const temp = new StoreObject(Types.REAL, result);
+    const temp = new StoreObject(x.type, result);
     return Promise.resolve(sto.updateStore('$', temp));
   };
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(absFun)]);
- const func = new Commands.Function('$abs', Types.REAL,
-   [new Commands.FormalParameter(Types.REAL, 'x', 0, false)],
+ 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;
 }
@@ -131,13 +134,13 @@ export function createNegateFun () {
   const negateFun = (sto, _) => {
     const x = sto.applyStore('x');
     const result = x.value.negated();
-    const temp = new StoreObject(Types.REAL, result);
+    const temp = new StoreObject(x.type, result);
     return Promise.resolve(sto.updateStore('$', temp));
   };
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(negateFun)]);
- const func = new Commands.Function('$negate', Types.REAL,
-   [new Commands.FormalParameter(Types.REAL, 'x', 0, false)],
+ 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;
 }
@@ -152,7 +155,7 @@ export function createInvertFun () {
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(invertFun)]);
  const func = new Commands.Function('$invert', Types.REAL,
-   [new Commands.FormalParameter(Types.REAL, 'x', 0, false)],
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
    block);
  return func;
 }
@@ -160,14 +163,15 @@ export function createInvertFun () {
 export function createMaxFun () {
   const maxFun = (sto, _) => {
     const x = sto.applyStore('x');
-    const result = BigNumber.max(x.value);
-    const temp = new StoreObject(x.subtype, result);
+    const numbers = x.value.map(stoObj => stoObj.number);
+    const result = BigNumber.max(numbers);
+    const temp = new StoreObject(x.type.innerType, result);
     return Promise.resolve(sto.updateStore('$', temp));
   };
-
+ const paramType = new CompoundType(new MultiType([Types.INTEGER, Types.REAL]), 1);
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(maxFun)]);
- const func = new Commands.Function('$max', Types.ALL,
-   [new Commands.FormalParameter(Types.ALL, 'x', 1, false)],
+ const func = new Commands.Function('$max', new MultiType([Types.INTEGER, Types.REAL]),
+   [new Commands.FormalParameter(paramType, 'x', false)],
    block);
  return func;
 }
@@ -175,14 +179,15 @@ export function createMaxFun () {
 export function createMinFun () {
   const minFun = (sto, _) => {
     const x = sto.applyStore('x');
-    const result = BigNumber.max(x.value);
-    const temp = new StoreObject(x.subtype, result);
+    const numbers = x.value.map(stoObj => stoObj.number);
+    const result = BigNumber.min(numbers);
+    const temp = new StoreObject(x.type.innerType, result);
     return Promise.resolve(sto.updateStore('$', temp));
   };
-
+ const paramType = new CompoundType(new MultiType([Types.INTEGER, Types.REAL]), 1);
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(minFun)]);
- const func = new Commands.Function('$min', Types.ALL,
-   [new Commands.FormalParameter(Types.ALL, 'x', 1, false)],
+ const func = new Commands.Function('$min', new MultiType([Types.INTEGER, Types.REAL]),
+   [new Commands.FormalParameter(paramType, 'x', false)],
    block);
  return func;
 }

+ 10 - 9
js/processor/lib/strings.js

@@ -1,6 +1,7 @@
 import { StoreObject } from '../store/storeObject';
 import * as Commands from './../../ast/commands';
-import { Types, toInt } from './../../ast/types';
+import { Types } from './../../typeSystem/types';
+import { toInt } from "./../../typeSystem/parsers";
 
 
 /*
@@ -23,9 +24,9 @@ export function createSubstringFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(substringFun)]);
   const func = new Commands.Function('$substring', Types.STRING,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false),
-    new Commands.FormalParameter(Types.INTEGER, 'start', 0, false),
-    new Commands.FormalParameter(Types.INTEGER, 'end', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false),
+    new Commands.FormalParameter(Types.INTEGER, 'start', false),
+    new Commands.FormalParameter(Types.INTEGER, 'end', false)],
     block);
   return func;
 }
@@ -38,7 +39,7 @@ export function createLengthFun () {
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(lengthFun)]);
   const func = new Commands.Function('$length', Types.INTEGER,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
     block);
   return func;
 }
@@ -51,7 +52,7 @@ export function createUppercaseFun () {
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(uppercaseFun)]);
   const func = new Commands.Function('$uppercase', Types.STRING,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
     block);
   return func;
 }
@@ -64,7 +65,7 @@ export function createLowercaseFun () {
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(lowercaseFun)]);
   const func = new Commands.Function('$lowercase', Types.STRING,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
     block);
   return func;
 }
@@ -81,8 +82,8 @@ export function createrCharAtFun () {
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(charAtFun)]);
   const func = new Commands.Function('$charAt', Types.STRING,
-    [new Commands.FormalParameter(Types.STRING, 'str', 0, false),
-    new Commands.FormalParameter(Types.INTEGER, 'index', 0, false)],
+    [new Commands.FormalParameter(Types.STRING, 'str', false),
+    new Commands.FormalParameter(Types.INTEGER, 'index', false)],
     block);
   return func;
 }

+ 75 - 74
js/processor/semantic/semanticAnalyser.js

@@ -5,7 +5,9 @@ import { ArrayDeclaration, While, For, Switch, Case, Declaration, Assign, Break,
 import { InfixApp, UnaryApp, FunctionCall, IntLiteral, RealLiteral, StringLiteral, BoolLiteral, VariableLiteral, ArrayLiteral, ArrayAccess } from '../../ast/expressions';
 import { Literal } from '../../ast/expressions/literal';
 import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from '../compatibilityTable';
-import { Types } from '../../ast/types';
+import { Types } from '../../typeSystem/types';
+import { CompoundType } from '../../typeSystem/compoundType';
+import { MultiType } from '../../typeSystem/multiType';
 
 export class SemanticAnalyser {
 
@@ -93,20 +95,20 @@ export class SemanticAnalyser {
     if (declaration instanceof ArrayDeclaration) {
       if(declaration.initial === null) {
         const lineType = this.evaluateExpressionType(declaration.lines);
-        if (lineType !== Types.INTEGER) {
+        if (!lineType.isCompatible(Types.INTEGER)) {
           throw new Error("dim must be int");
         }
         if (declaration.columns !== null) {
           const columnType = this.evaluateExpressionType(declaration.columns);
-          if (columnType !== Types.INTEGER) {
+          if (!columnType.isCompatible(Types.INTEGER)) {
             throw new Error("dim must be int");
           }
         }
-        this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type, subtype: declaration.subtype});
+        this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type});
         return;
       }
-      this.evaluateArrayLiteral(declaration.lines, declaration.columns, declaration.subtype, declaration.initial);
-      this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type, subtype: declaration.subtype});
+      this.evaluateArrayLiteral(declaration.lines, declaration.columns, declaration.type, declaration.initial);
+      this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type});
 
     } else {
       if(declaration.initial === null) {
@@ -114,7 +116,12 @@ export class SemanticAnalyser {
         return;
       }
       const resultType = this.evaluateExpressionType(declaration.initial);
-      if(declaration.type !== resultType) {
+      if(resultType instanceof MultiType) {
+        if(!resultType.isCompatible(declaration.type)) {
+          throw new Error('Invalid type');  
+        }
+        this.insertSymbol(declaration.id, {id: declaration.id, type: declaration.type})
+      } else if(!declaration.type.isCompatible(resultType)) {
         throw new Error('Invalid type');
       } else {
         this.insertSymbol(declaration.id, {id: declaration.id, type: declaration.type})
@@ -136,30 +143,39 @@ export class SemanticAnalyser {
       return this.evaluateLiteralType(expression);
     } else if (expression instanceof FunctionCall) {
       const fun = this.findFunction(expression.id);
-      if (fun.returnType === Types.VOID) {
+      if (fun.returnType.isCompatible(Types.VOID)) {
         throw new Error("void return");
       }
       this.assertParameters(fun, expression.actualParameters);
       return fun.returnType;
     } else if (expression instanceof ArrayAccess) {
       const arrayTypeInfo = this.findSymbol(expression.id, this.symbolMap);
-      if (arrayTypeInfo.type !== Types.ARRAY) {
+      if (!(arrayTypeInfo.type instanceof CompoundType)) {
         throw new Error("it's not an array");
       }
       const lineType = this.evaluateExpressionType(expression.line);
-      if (lineType !== Types.INTEGER) {
+      if (!lineType.isCompatible(Types.INTEGER)) {
         throw new Error("line must be integer");
       }
-      if (expression.column != null) {
+      if (expression.column !== null) {
         if (arrayTypeInfo.columns === null) {
           throw new Error("it's not a matrix");
         }
         const columnType = this.evaluateExpressionType(expression.column);
-        if(columnType !== Types.INTEGER) {
+        if(!columnType.isCompatible(Types.INTEGER)) {
           throw new Error("column must be integer");
         }
       }
-      return arrayTypeInfo.subtype;
+      const arrType = arrayTypeInfo.type;
+      if(expression.column !== null) {
+        // indexing matrix
+        return arrType.innerType;
+      } else {
+        if(arrayTypeInfo.columns === null) {
+          return arrType.innerType;
+        }
+        return new CompoundType(arrType.innerType, 1);
+      }
     }
   }
 
@@ -174,8 +190,8 @@ export class SemanticAnalyser {
       return literal.type;
     } else if (literal instanceof VariableLiteral) {
       const typeInfo = this.findSymbol(literal.id, this.symbolMap);
-      if (typeInfo.type === Types.ARRAY) {
-        return typeInfo;
+      if (typeInfo.type instanceof CompoundType) {
+        return typeInfo.type;
       }
       return typeInfo.type;
     } else {
@@ -184,12 +200,12 @@ export class SemanticAnalyser {
     }
   }
 
-  evaluateArrayLiteral (lines, columns, subtype, literal) {
+  evaluateArrayLiteral (lines, columns, type, literal) {
     if (literal instanceof ArrayLiteral) {
       if (columns === null) {
         // it's a vector...
         const dimType = this.evaluateExpressionType(lines);
-        if (dimType !== Types.INTEGER) {
+        if (!dimType.isCompatible(Types.INTEGER)) {
           throw new Error("dim must be int");
         }
         if ((lines instanceof IntLiteral) && !lines.value.eq(literal.value.length)) {
@@ -197,15 +213,17 @@ export class SemanticAnalyser {
         }
         literal.value.reduce((last, next) => {
           const eType = this.evaluateExpressionType(next);
-          if (eType !== last) {
-            throw new Error("invalid array type");
+          if (!last.canAccept(eType)) {
+            console.log(last);
+            console.log(eType);
+            throw new Error("invalid value type for array");
           }
-          return eType;
-        }, subtype);
+          return last;
+        }, type);
         return true;
       } else {
         const dimType = this.evaluateExpressionType(columns);
-        if (dimType !== Types.INTEGER) {
+        if (!dimType.isCompatible(Types.INTEGER)) {
           throw new Error("dim must be int");
         }
         if ((columns instanceof IntLiteral) && !columns.value.eq(literal.value.length)) {
@@ -213,22 +231,18 @@ export class SemanticAnalyser {
         }
         for (let i = 0; i < columns; i++) {
           const anotherArray = literal.value[i];
-          this.evaluateArrayLiteral(lines, null, subtype, anotherArray)
+          this.evaluateArrayLiteral(lines, null, type, anotherArray)
         }
       }
 
     } else {
 
       const resultType = this.evaluateExpressionType(literal);
-      if (!resultType.subtype) {
+      if (!(resultType.type instanceof CompoundType)) {
         throw new Error("initial must be of type array");
       }
-      if (resultType.subtype !== subtype) {
+      if (!type.isCompatible(resultType.type)) {
         throw new Error("invalid array type");
-      } else if (resultType.lines !== lines) {
-        throw new Error("invalid array size");
-      } else if (resultType.columns !== columns) {
-        throw new Error("invalid array size");
       }
       return true;
 
@@ -238,7 +252,7 @@ export class SemanticAnalyser {
   assertFunction (fun) {
     this.pushMap();
     this.assertDeclarations(fun.variablesDeclarations);
-    const optional = fun.returnType === Types.VOID;
+    const optional = fun.returnType.isCompatible(Types.VOID);
     const valid = this.assertReturn(fun, optional);
     if (!valid) {
       throw new Error("function has no accessible return");
@@ -255,7 +269,7 @@ export class SemanticAnalyser {
   checkCommand (type, cmd, optional) {
     if (cmd instanceof While) {
       const resultType = this.evaluateExpressionType(cmd.expression);
-      if (resultType !== Types.BOOLEAN) {
+      if (!resultType.isCompatible(Types.BOOLEAN)) {
         throw new Error("condition not boolean");
       }
       this.checkCommands(type, cmd.commands, optional);
@@ -263,7 +277,7 @@ export class SemanticAnalyser {
     } else if (cmd instanceof For) {
       this.checkCommand(type, cmd.assignment, optional);
       const resultType = this.evaluateExpressionType(cmd.condition);
-      if (resultType !== Types.BOOLEAN) {
+      if (!resultType.isCompatible(Types.BOOLEAN)) {
         throw new Error("condition not boolean");
       }
       this.checkCommand(type, cmd.increment, optional);
@@ -277,7 +291,7 @@ export class SemanticAnalyser {
         const aCase = cmd.cases[i];
         if (aCase.expression !== null) {
           const caseType = this.evaluateExpressionType(aCase.expression);
-          if (sType !== caseType) {
+          if (!sType.isCompatible(caseType)) {
             throw new Error("invalid type in case");
           }
         } else {
@@ -289,13 +303,13 @@ export class SemanticAnalyser {
 
     } else if (cmd instanceof ArrayIndexAssign) {
       const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
-      if(!typeInfo.subtype) {
+      if(!(typeInfo.type instanceof CompoundType)) {
         throw new Error(cmd.id + " is not an array.");
       }
       const exp = cmd.expression;
       const lineExp = cmd.line;
       const lineType = this.evaluateExpressionType(lineExp);
-      if (lineType !== Types.INTEGER) {
+      if (!lineType.isCompatible(Types.INTEGER)) {
         throw new Error("array dimension must be of type int");
       }
       const columnExp = cmd.column;
@@ -303,13 +317,13 @@ export class SemanticAnalyser {
         throw new Error(cmd.id + " is not a matrix");
       } else if (columnExp !== null) {
         const columnType = this.evaluateExpressionType(columnExp);
-        if (columnType !== Types.INTEGER) {
+        if (!columnType.isCompatible(Types.INTEGER)) {
           throw new Error("array dimension must be of type int");
         }
       }
       // exp can be a arrayLiteral, a single value exp or an array access
       if(exp instanceof ArrayLiteral) {
-        this.evaluateArrayLiteral(typeInfo.lines, (columnExp ? typeInfo.columns : null), typeInfo.subtype, exp);
+        this.evaluateArrayLiteral(typeInfo.lines, (columnExp ? typeInfo.columns : null), typeInfo.type, exp);
       } else {
         // cannot properly evaluate since type system is poorly constructed
       }
@@ -318,16 +332,13 @@ export class SemanticAnalyser {
       const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
       const exp = cmd.expression;
       if(exp instanceof ArrayLiteral) {
-        if(!typeInfo.subtype) {
+        if(!(typeInfo.type instanceof CompoundType)) {
           throw new Error("type not compatible");
         }
-        this.evaluateArrayLiteral(typeInfo.lines, typeInfo.columns, typeInfo.subtype, exp);
+        this.evaluateArrayLiteral(typeInfo.lines, typeInfo.columns, typeInfo.type, exp);
       } else {
-        if(typeInfo.subtype) {
-          throw new Error("type not compatible");
-        }
         const resultType = this.evaluateExpressionType(exp);
-        if(resultType !== typeInfo.type) {
+        if(!resultType.isCompatible(typeInfo.type)) {
           throw new Error("type not compatible");
         }
       }
@@ -336,10 +347,9 @@ export class SemanticAnalyser {
       return optional;
     } else if (cmd instanceof IfThenElse) {
       const resultType = this.evaluateExpressionType(cmd.condition);
-      if (resultType !== Types.BOOLEAN) {
+      if (!resultType.isCompatible(Types.BOOLEAN)) {
         throw new Error("condition not boolean");
       }
-      console.log(cmd);
       if(cmd.ifFalse instanceof IfThenElse) {
         return this.checkCommands(type, cmd.ifTrue.commands, optional) && this.checkCommand(type, cmd.ifFalse, optional);
       } else {
@@ -351,11 +361,11 @@ export class SemanticAnalyser {
       this.assertParameters(fun, cmd.actualParameters);
       return optional;
     } else if (cmd instanceof Return) {
-      if (cmd.expression === null && type !== Types.VOID) {
+      if (cmd.expression === null && !type.isCompatible(Types.VOID)) {
         throw new Error('invalid return type');
       } else if (cmd.expression !== null) {
         const resultType = this.evaluateExpressionType(cmd.expression);
-        if (resultType !== type) {
+        if (!resultType.isCompatible(type)) {
           throw new Error('invalid return type');
         } else {
           return true;
@@ -381,40 +391,31 @@ export class SemanticAnalyser {
       const formalParam = fun.formalParameters[i];
       if(formalParam.byRef) {
         if (!(param instanceof VariableLiteral || param instanceof ArrayAccess)) {
-          throw new Error("Invalid param type");
+          throw new Error("Invalid param type for ref");
         }
       }
       const resultType = this.evaluateExpressionType(param);
-      switch (formalParam.dimensions) {
-        case 1: {
-          if (!resultType.subtype) {
-            throw new Error("invalid param type");   
-          } else if (resultType.subtype !== formalParam.type) {
-            throw new Error("invalid param type");   
-          } else if (resultType.lines === null || resultType.columns !== null) {
-            throw new Error("invalid param type");
+      if(resultType instanceof MultiType && formalParam.type instanceof MultiType) {
+        let shared = 0
+        for (let j = 0; j < resultType.types.length; j++) {
+          const element = resultType.types[j];
+          if(formalParam.type.types.indexOf(element) !== -1) {
+            shared++;
           }
-          break;
         }
-        case 2: {
-          if (!resultType.subtype) {
-            throw new Error("invalid param type");   
-          } else if (resultType.subtype !== formalParam.type) {
-            throw new Error("invalid param type");   
-          } else if (resultType.lines === null || resultType.columns === null) {
-            throw new Error("invalid param type");
-          }
-          break;
+        if(shared <= 0) {
+          throw new Error(`Parameter ${formalParam.id} is not compatible with the value given.`);
         }
-        default: {
-          if (resultType.subtype) {
-            throw new Error("invalid param type");
-          }
-          if (formalParam.type !== Types.ALL && resultType !== formalParam.type) {
-            throw new Error("invalid param type");
-          }
-          break;
+      } else if (resultType instanceof MultiType) {
+        if(!resultType.isCompatible(formalParam.type)) {
+          throw new Error(`Parameter ${formalParam.id} is not compatible with the value given.`);
         }
+      } else if(!formalParam.type.isCompatible(resultType)) {
+        console.log("####");
+        console.log(resultType);
+        console.log("####");
+        console.log(formalParam.type);
+        throw new Error(`Parameter ${formalParam.id} is not compatible with the value given.`);
       }
     }
   }

+ 4 - 2
js/processor/store/store.js

@@ -51,9 +51,11 @@ export class Store {
         this.store[id] = Object.freeze(stoObj);
         return this;
       } else {
-        const oldType = oldObj.subtype ? oldObj.subtype.value : oldObj.type.value;
-        const stoType = stoObj.subtype ? stoObj.subtype.value : stoObj.type.value;
+        const oldType = oldObj.type;
+        const stoType = stoObj.type;
         // TODO: better error message
+        console.log(oldObj);
+        console.log(stoObj);
         throw new Error(`${oldType} is not compatible with type ${stoType} given`);
       }
     }

+ 1 - 1
js/processor/store/storeObject.js

@@ -43,7 +43,7 @@ export class StoreObject {
 
   isCompatible (another) {
     if( another instanceof StoreObject) {
-      return this.type === another.type;
+      return this.type.isCompatible(another.type);
     }
     return false;
   }

+ 6 - 13
js/processor/store/storeObjectArray.js

@@ -1,13 +1,11 @@
-import { Types } from './../../ast/types';
 import { StoreObject } from './storeObject';
 
 export class StoreObjectArray extends StoreObject {
 
-  constructor (subtype, lines, columns, value = null, readOnly = false) {
-    super(Types.ARRAY, value, readOnly);
+  constructor (type, lines, columns, value = null, readOnly = false) {
+    super(type, value, readOnly);
     this._lines = lines;
     this._columns = columns;
-    this._subtype = subtype;
   }
 
   get lines () {
@@ -18,15 +16,10 @@ export class StoreObjectArray extends StoreObject {
     return this._columns;
   }
 
-  get subtype () {
-    return this._subtype;
-  }
-
   isCompatible (another) {
     if(another instanceof StoreObject) {
       if(this.lines === another.lines &&
-        this.columns === another.columns &&
-        this.subtype === another.subtype) {
+        this.columns === another.columns) {
           return super.isCompatible(another);
         }
     }
@@ -34,7 +27,7 @@ export class StoreObjectArray extends StoreObject {
   }
 
   get isVector () {
-    return this.columns === null;
+    return this.type.dimensions === 1;
   }
 
   get isValid () {
@@ -43,7 +36,7 @@ export class StoreObjectArray extends StoreObject {
         if(this.value.length !== this.lines) {
           return false;
         }
-        const mustBeNull = this.value.find(v => v.type !== this.subtype);
+        const mustBeNull = this.value.find(v => !this.type.canAccept(v.type) );
         if(!!mustBeNull) {
           return false;
         }
@@ -59,7 +52,7 @@ export class StoreObjectArray extends StoreObject {
         if(arr.length !== this.columns) {
           return false;
         }
-        const mustBeNull = arr.find(v => v.type !== this.subtype);
+        const mustBeNull = arr.find(v => !this.type.canAccept(v.type) );
         if(!!mustBeNull) {
           return false;
         }            

+ 18 - 27
js/processor/store/storeObjectArrayAddress.js

@@ -1,6 +1,7 @@
 import { StoreObject } from './storeObject';
 import { StoreObjectArray } from './storeObjectArray';
-import { Types } from '../../ast/types';
+import { Types } from '../../typeSystem/types';
+import { CompoundType } from '../../typeSystem/compoundType';
 
 export class StoreObjectArrayAddress extends StoreObject {
 
@@ -44,18 +45,12 @@ export class StoreObjectArrayAddress extends StoreObject {
   }
 
   get columns () {
-    if(this.lines <= 0) {
-      return null;
-    } else if (this.refValue.value[0].type !== Types.ARRAY) {
-      return null;
+    switch (this.type.dimensions) {
+      case 2:
+        return this.refValue.value[0].value.length;
+      default:
+        return null;
     }
-    // this.refValue is StoreObject
-    //this.refValue.value[0] is another StoreObject
-    return this.refValue.value[0].value.length;
-  }
-
-  get subtype () {
-    return this.refValue.subtype;
   }
 
   getArrayObject () {
@@ -65,31 +60,27 @@ export class StoreObjectArrayAddress extends StoreObject {
   updateArrayObject (stoObj) {
     const anArray =  this.getArrayObject();
     const newArray = Object.assign(new StoreObjectArray(null,null,null), anArray);
+    if(!stoObj.type.isCompatible(this.type)) {
+      throw new Error(`Invalid operation: cannot assign the value given to ${this.refID}`);
+    } else if (this.type instanceof CompoundType && this.type.canAccept(stoObj.type)) {
+      throw new Error(`Invalid operation: cannot assign the value given to ${this.refID}`);
+    }
     if (this.column !== null) {
-     if (stoObj.type === Types.ARRAY) {
-       throw new Error(`Invalid operation: cannot assign the value given to ${this.refID}`);
-     }
      newArray.value[this.line].value[this.column] = stoObj;
      return newArray;
     } else {
-     if(anArray.columns !== null && stoObj.type !== Types.ARRAY) {
-      throw new Error(`Invalid operation: cannot assign the value given to ${this.refID}`);
-     }
      newArray.value[this.line] = stoObj;
      return newArray;
     }
   }
 
   isCompatible (another) {
-    if(this.type === Types.ARRAY) {
-      if(another.type !== Types.ARRAY) {
-        return false;
-      }
-      if(another.subtype !== this.subtype) {
-        return false;
+    if(this.type.isCompatible(another.type)) {
+      if(another.type instanceof CompoundType) {
+        return this.lines === another.lines && this.columns === another.columns;
+      } else {
+        this.refValue.isCompatible(another);
       }
-      return this.lines === another.lines && this.columns === another.columns;
     }
-    return this.refValue.isCompatible(another);
   }
-}
+}

+ 1 - 0
js/processor/store/storeObjectArrayAddressRef.js

@@ -1,4 +1,5 @@
 import { StoreObject } from './storeObject';
+import { BigNumber } from "bignumber.js";
 
 export class StoreObjectArrayAddressRef extends StoreObject {
 

+ 1 - 0
js/processor/store/storeObjectRef.js

@@ -1,4 +1,5 @@
 import { StoreObject } from './storeObject';
+import { BigNumber } from "bignumber.js";
 
 export class StoreObjectRef extends StoreObject {
 

+ 1 - 1
js/typeSystem/baseTypes.js

@@ -22,5 +22,5 @@ export const BaseTypes = Object.freeze({
   STRING: new BaseType("string", 2),
   BOOLEAN: new BaseType("bool", 3),
   VOID: new BaseType("void", 4),
-  UNDEFINED: new BaseType('undefined', 5)
+  UNDEFINED: new BaseType("undefined", 5)
 })

+ 10 - 1
js/typeSystem/compoundType.js

@@ -1,4 +1,4 @@
-import { Type } from "./types";
+import { Type } from "./type";
 
 export class CompoundType extends Type {
 
@@ -17,4 +17,13 @@ export class CompoundType extends Type {
     }
     return false;
   }
+
+  canAccept (another) {
+    if(another instanceof CompoundType) {
+      console.log("canAccept: another is compound");
+      return this.dimensions >= another.dimensions && this.innerType.isCompatible(another.innerType);
+    } else {
+      return this.innerType.isCompatible(another);
+    }
+  }
 }

+ 2 - 3
js/typeSystem/multiType.js

@@ -1,8 +1,8 @@
-import { Type } from "./types";
+import { Type } from "./type";
 
 export class MultiType extends Type {
 
-  constructor (...types) {
+  constructor (types) {
     super(null);
     this.types = types;
   }
@@ -23,7 +23,6 @@ export class MultiType extends Type {
           return true;
         }
       }
-      return false;
     }
     return false;
   }

+ 10 - 0
js/typeSystem/parsers.js

@@ -34,4 +34,14 @@ export function toBool (str) {
     // TODO: better error message
     throw new Error(str + "not a valid boolean");
   }
+}
+
+export function convertBoolToString (bool) {
+  const lexer = LanguageService.getCurrentLexer();
+  const instance = new lexer(null);
+  if (bool) {
+    return instance.literalNames[lexer.RK_TRUE];
+  } else {
+    return instance.literalNames[lexer.RK_FALSE];
+  }
 }

+ 21 - 0
js/typeSystem/type.js

@@ -0,0 +1,21 @@
+export class Type {
+
+  constructor(baseType) {
+    this.baseType = baseType;
+  }
+
+  get value () {
+    return this.baseType.value;
+  }
+
+  get ord () {
+    return this.baseType.ord;
+  }
+
+  isCompatible (another) {
+    if(another instanceof Type) {
+      return this.baseType.isCompatible(another.baseType);
+    }
+    return false;
+  }
+}

+ 2 - 24
js/typeSystem/types.js

@@ -1,36 +1,14 @@
 import { BaseTypes } from './baseTypes';
+import { Type } from "./type";
 import { MultiType } from "./multiType";
 
-export class Type {
-
-  constructor(baseType) {
-    this.baseType = baseType;
-  }
-
-  get value () {
-    return this.baseType.value;
-  }
-
-  get ord () {
-    return this.baseType.ord;
-  }
-
-  isCompatible (another) {
-    if(another instanceof Type) {
-      return this.baseType.isCompatible(another.baseType);
-    }
-    return false;
-  }
-}
-
-
 const INTEGER = new Type(BaseTypes.INTEGER);
 const REAL = new Type(BaseTypes.REAL);
 const STRING = new Type(BaseTypes.STRING);
 const BOOLEAN = new Type(BaseTypes.BOOLEAN);
 const VOID = new Type(BaseTypes.VOID);
 const UNDEFINED = new Type(BaseTypes.UNDEFINED);
-const ALL = new MultiType(innerTypes.INTEGER, innerTypes.REAL, innerTypes.STRING, innerTypes.BOOLEAN);
+const ALL = new MultiType([INTEGER, REAL, STRING, BOOLEAN]);
 
 export const Types = Object.freeze({
   INTEGER: INTEGER,

+ 1 - 1
tests/test00.spec.js

@@ -4,7 +4,7 @@ import {
 import * as Expressions from './../js/ast/expressions/';
 import * as Commands from './../js/ast/commands/';
 import { LanguageService } from './../js/services/languageService';
-import { Types } from './../js/ast/types';
+import { Types } from './../js/typeSystem/types';
 
 describe("Testing Syntax Analysis for default", () => {
 

+ 1 - 1
tests/test17.spec.js

@@ -1,7 +1,7 @@
 import * as Expressions from './../js/ast/expressions/';
 import * as Commands from './../js/ast/commands/';
 import { Operators } from './../js/ast/operators';
-import {Types} from './../js/ast/types';
+import {Types} from './../js/typeSystem/types';
 import {
     IVProgParser
 } from './../js/ast/ivprogParser';

+ 1 - 1
tests/test20.spec.js

@@ -23,6 +23,6 @@ describe('An Array initialization with expressions', function () {
         sto.applyStore('a').value[1].number
       ]).toEqual(result);
       done();
-    });
+    }).catch(err => done(err));
   });
 });

+ 1 - 1
tests/test42.spec.js

@@ -1,6 +1,6 @@
 import { resultTypeAfterInfixOp } from './../js/processor/compatibilityTable';
 import { Operators } from './../js/ast/operators';
-import { Types } from '../js/ast/types';
+import { Types } from '../js/typeSystem/types';
 
 describe("The compatbility table", () => {
   it("should return the correct type for a given infix operator application", () => {

+ 4 - 3
tests/test53.spec.js

@@ -9,8 +9,9 @@ describe('Math lib modulo function ', function () {
   const code = `programa {
 
     funcao inicio() {
-      real a = -1.0
-      escreva(Matematica.modulo(a))
+      inteiro a = -1
+      inteiro b = Matematica.modulo(a)
+      escreva(b)
     }
   }`;
 
@@ -25,7 +26,7 @@ describe('Math lib modulo function ', function () {
     const exec = new IVProgProcessor(sem.analyseTree());
     exec.registerOutput(out);
     exec.interpretAST().then(_ => {
-      expect(out.list).toEqual(['1.0']);
+      expect(out.list).toEqual(['1']);
       done();
     }).catch(err => done(err));
   });

+ 11 - 0
tests/test61.spec.js

@@ -0,0 +1,11 @@
+import { CompoundType } from "./../js/typeSystem/compoundType";
+import { Types } from "./../js/typeSystem/types";
+
+describe("Two CompoundType of an Int and dimension 1", () => {
+
+  it("should be compatible", () => {
+    const t1 = new CompoundType(Types.INTEGER, 1);
+    const t2 = new CompoundType(Types.INTEGER, 1);
+    expect(t1.isCompatible(t2)).toBeTruthy();
+  });
+});

+ 11 - 0
tests/test62.spec.js

@@ -0,0 +1,11 @@
+import { CompoundType } from "./../js/typeSystem/compoundType";
+import { Types } from "./../js/typeSystem/types";
+
+describe("A CompoundType of an Int and dimension 1", () => {
+
+  it("should accept an int ", () => {
+    const t1 = new CompoundType(Types.INTEGER, 1);
+    const t2 = Types.INTEGER;
+    expect(t1.canAccept(t2)).toBeTruthy();
+  });
+});

+ 32 - 0
tests/testMinMax.spec.js

@@ -0,0 +1,32 @@
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { SemanticAnalyser } from './../js/processor/semantic/semanticAnalyser';
+import { LanguageService } from '../js/services/languageService';
+import { OutputTest } from '../js/util/outputTest';
+import { IVProgProcessor } from '../js/processor/ivprogProcessor';
+
+describe('Math max function applied to an int vector', function () {
+
+  const code = `programa {
+
+    funcao inicio() {
+      inteiro a[3] = {1,8,3}
+      escreva(Matematica.maximo(a))
+    }
+  }`;
+
+  localStorage.setItem('ivprog.lang', 'pt');
+
+  const lexer = LanguageService.getCurrentLexer();
+  const out = new OutputTest();
+
+  it(`should return an int`, function (done) {
+    const parser = new IVProgParser(code, lexer);
+    const sem = new SemanticAnalyser(parser.parseTree());
+    const exec = new IVProgProcessor(sem.analyseTree());
+    exec.registerOutput(out);
+    exec.interpretAST().then(_ => {
+      expect(out.list).toEqual(['8']);
+      done();
+    }).catch(err => done(err));
+  });
+});