Sfoglia il codice sorgente

Merge branch 'processor' of igorfelix/ivprog into master

Lucas de Souza 6 anni fa
parent
commit
bdab44ee7e
50 ha cambiato i file con 1897 aggiunte e 112 eliminazioni
  1. 1 1
      .vscode/launch.json
  2. 3 1
      grammar/pt-br/ivprog.g4
  3. 2 1
      js/ast/commands/arrayDeclaration.js
  4. 2 2
      js/ast/commands/for.js
  5. 9 0
      js/ast/commands/formalParameter.js
  6. 7 1
      js/ast/commands/index.js
  7. 12 0
      js/ast/commands/sysCall.js
  8. 30 24
      js/ast/expressions/arrayLiteral.js
  9. 5 3
      js/ast/expressions/variableLiteral.js
  10. 33 40
      js/ast/ivprogParser.js
  11. 34 6
      js/ast/types.js
  12. 37 0
      js/io/domInput.js
  13. 15 0
      js/io/domOutput.js
  14. 6 0
      js/io/input.js
  15. 6 0
      js/io/output.js
  16. 25 31
      js/main.js
  17. 60 0
      js/processor/compatibilityTable.js
  18. 5 0
      js/processor/context.js
  19. 28 0
      js/processor/definedFunctions.js
  20. 745 0
      js/processor/ivprogProcessor.js
  21. 6 0
      js/processor/modes.js
  22. 73 0
      js/processor/store/store.js
  23. 40 0
      js/processor/store/storeObject.js
  24. 71 0
      js/processor/store/storeObjectArray.js
  25. 34 0
      js/processor/store/storeObjectRef.js
  26. 17 0
      js/util/inputTest.js
  27. 13 0
      js/util/outputTest.js
  28. 5 0
      package-lock.json
  29. 2 1
      package.json
  30. 5 1
      tests/test17.spec.js
  31. 26 0
      tests/test19.spec.js
  32. 26 0
      tests/test20.spec.js
  33. 31 0
      tests/test21.spec.js
  34. 25 0
      tests/test22.spec.js
  35. 24 0
      tests/test23.spec.js
  36. 27 0
      tests/test24.spec.js
  37. 26 0
      tests/test25.spec.js
  38. 26 0
      tests/test26.spec.js
  39. 30 0
      tests/test27.spec.js
  40. 32 0
      tests/test28.spec.js
  41. 28 0
      tests/test29.spec.js
  42. 38 0
      tests/test30.spec.js
  43. 37 0
      tests/test31.spec.js
  44. 19 0
      tests/test32.spec.js
  45. 37 0
      tests/test33.spec.js
  46. 31 0
      tests/test34.spec.js
  47. 34 0
      tests/test35.spec.js
  48. 11 0
      tests/test36.spec.js
  49. 29 0
      tests/test37.spec.js
  50. 29 0
      tests/test38.spec.js

+ 1 - 1
.vscode/launch.json

@@ -8,7 +8,7 @@
             "type": "node",
             "request": "launch",
             "name": "Launch Program",
-            "program": "${workspaceFolder}/js/main.js"
+            "program": "${workspaceFolder}/build/ivprog.bundle.js"
         }
     ]
 }

+ 3 - 1
grammar/pt-br/ivprog.g4

@@ -3,6 +3,8 @@ lexer grammar ivprog;
 @lexer::members{
   //Translate to fit your language
   ivprog.MAIN_FUNCTION_NAME = "inicio";
+  ivprog.READ_FUNCTION_NAME = "leia";
+  ivprog.WRITE_FUNCTION_NAME = "escreva";
 }
 
 // BEGIN i18n Lexical rules
@@ -154,7 +156,7 @@ OR_OPERATOR
   ;
 
 RELATIONAL_OPERATOR
-  : ('>='|'=='|'<='|'>'|'<')
+  : ('>='|'=='|'<='|'>'|'<'|'!=')
   ;
 
 COLON

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

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

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

@@ -1,6 +1,6 @@
 export class For {
-  constructor (attribution, condition, increment, commandBlock) {
-    this.attribution = attribution;
+  constructor (assignment, condition, increment, commandBlock) {
+    this.assignment = assignment;
     this.condition = condition;
     this.increment = increment;
     this.commandBlock = commandBlock;

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

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

+ 7 - 1
js/ast/commands/index.js

@@ -11,6 +11,9 @@ import { CommandBlock } from './commandBlock';
 import { DoWhile } from './doWhile';
 import { Switch } from './switch';
 import { Case } from './case';
+import { SysCall } from './sysCall';
+import { FormalParameter } from './formalParameter';
+import { FunctionCall } from './../expressions/functionCall'; //Proxy to expression since they do exatcly the same thing
 
 export {
   Break,
@@ -25,5 +28,8 @@ export {
   CommandBlock,
   DoWhile,
   Switch,
-  Case
+  Case,
+  SysCall,
+  FormalParameter,
+  FunctionCall
 };

+ 12 - 0
js/ast/commands/sysCall.js

@@ -0,0 +1,12 @@
+/**
+ * This class represents all the language defined functions.
+ * The language processor uses the id provided here to properly execute the desired function.
+ * The function is actually implemented inside the language processor.
+ * All the functions can be found at: js/processor/definedFunctions.js
+ */
+export class SysCall {
+
+  constructor (id) {
+    this.id = id;
+  }
+}

+ 30 - 24
js/ast/expressions/arrayLiteral.js

@@ -1,8 +1,10 @@
 import { Literal } from './literal';
+import { Types } from './../types';
+
 export class ArrayLiteral extends Literal {
   
   constructor(value) {
-    super('array');
+    super(Types.ARRAY);
     this.value = value;
   }
 
@@ -28,33 +30,37 @@ export class ArrayLiteral extends Literal {
     }
   }
 
+  get isVector () {
+    return this.columns === null;
+  }
+
   get isValid () {
-    return this.validateType() && this.validateSize();
+    return true;//this.validateType() && this.validateSize();
   }
 
   validateType () {
-    let valid = true;
-    if(this.columns !== null) {
-      const len = this.columns;
-      const len2 = this.lines;
-      for (let i = len - 1; i >= 0; i--) {
-        for (let j = len2 - 1; j >= 0; j--) {
-          if(this.value[i].value[j].type !== this.subtype) {
-            valid = false;
-            break;
-          }
-        }
-      }
-    } else {
-      const len = this.lines;
-      for (var i = len - 1; i >= 0; i--) {
-        if(this.value[i].type !== this.subtype) {
-          valid = false;
-          break;
-        }
-      }
-    }
-    return valid;
+    // let valid = true;
+    // if(this.columns !== null) {
+    //   const len = this.columns;
+    //   const len2 = this.lines;
+    //   for (let i = len - 1; i >= 0; i--) {
+    //     for (let j = len2 - 1; j >= 0; j--) {
+    //       if(this.value[i].value[j].type !== this.subtype) {
+    //         valid = false;
+    //         break;
+    //       }
+    //     }
+    //   }
+    // } else {
+    //   const len = this.lines;
+    //   for (var i = len - 1; i >= 0; i--) {
+    //     if(this.value[i].type !== this.subtype) {
+    //       valid = false;
+    //       break;
+    //     }
+    //   }
+    // }
+    return true;//valid;
   }
 
   validateSize () {

+ 5 - 3
js/ast/expressions/variableLiteral.js

@@ -1,8 +1,10 @@
 import { Literal } from './literal';
+import { Types } from './../types';
+
 export class VariableLiteral extends Literal {
   
-  constructor(value) {
-    super('variable');
-    this.value = value;
+  constructor(id) {
+    super(Types.UNDEFINED);
+    this.id = id;
   }
 }

+ 33 - 40
js/ast/ivprogParser.js

@@ -1,9 +1,10 @@
 import { CommonTokenStream, InputStream } from 'antlr4/index';
 import * as Expressions from './expressions/';
 import * as Commands from './commands/';
-import { Types } from './types';
+import { Types, toInt, toString } from './types';
 import { convertFromString } from './operators';
 import { SyntaxError } from './SyntaxError';
+import { NAMES } from './../processor/definedFunctions';
 
 export class IVProgParser {
 
@@ -319,15 +320,7 @@ export class IVProgParser {
   **/
   getIntLiteral (token) {
     const text = token.text;
-    let val = null;
-    if(text.match('^0b|^0B')) {
-      val = parseInt(text.substring(2), 2);
-    } else if (text.match('^0x|^0X')) {
-      val = parseInt(text.substring(2), 16);
-    } else {
-      val = parseInt(text);
-    }
-    return new Expressions.IntLiteral(val);
+    return new Expressions.IntLiteral(toInt(text));
   }
 
   getRealLiteral (token) {
@@ -336,14 +329,7 @@ export class IVProgParser {
 
   getStringLiteral (token) {
     const text = token.text;
-    let value = text.replace("\\b", "\b");
-    value = value.replace("\\t", "\t");
-    value = value.replace("\\n", "\n");
-    value = value.replace("\\r", "\r");
-    value = value.replace("\\\"", "\"");
-    value = value.replace("\\\'", "\'");
-    value = value.replace("\\\\", "\\");
-    return new Expressions.StringLiteral(value);
+    return new Expressions.StringLiteral(toString(text));
   }
 
   getBoolLiteral (token) {
@@ -367,11 +353,11 @@ export class IVProgParser {
     this.pos++;
     this.parsingArrayDimension--;
     if (this.parsingArrayDimension === 0) {
-      if (!data.isValid) {
-      // TODO: better error message
-      console.log('invalid array');
-      throw new Error(`Invalid array at line ${beginArray.line}`);
-    }
+      // if (!data.isValid) {
+      //   // TODO: better error message
+      //   console.log('invalid array');
+      //   throw new Error(`Invalid array at line ${beginArray.line}`);
+      // }
     }
     return new Expressions.ArrayLiteral(data);
   }
@@ -444,7 +430,7 @@ export class IVProgParser {
           this.pos++;
         }
       }
-      list.push({type: typeString, id: idString, dimensions: dimensions});
+      list.push(new Commands.FormalParameter(typeString, idString, dimensions));
       const commaToken = this.getToken();
       if (commaToken.type !== this.lexerClass.COMMA)
         break;
@@ -715,10 +701,10 @@ export class IVProgParser {
       this.pos++;
       return (new Commands.Assign(id, exp));
     } else if (equalOrParenthesis.type === this.lexerClass.OPEN_PARENTHESIS) {
-      const actualParameters = this.parseActualParameters();
+      const funcCall = this.parseFunctionCallCommand(id);
       this.checkEOS();
       this.pos++;
-      return (new Expressions.FunctionCall(id, actualParameters));
+      return funcCall;
     } else {
       throw SyntaxError.createError("= or (", equalOrParenthesis);
     }
@@ -919,31 +905,38 @@ export class IVProgParser {
         this.consumeNewLines();
         this.checkCloseBrace();
         this.pos++;
-      } else {
-        this.pos--;
       }
 
       return new Expressions.ArrayAccess(id, firstIndex, secondIndex);
 
     } else if (this.checkOpenParenthesis(true)) {
-      this.pos++;
-      this.consumeNewLines();
-      let actualParameters = [];
-      if(!this.checkCloseParenthesis(true)) {
-        actualParameters = this.parseActualParameters();
-        this.consumeNewLines();
-        this.checkCloseParenthesis();
-        this.pos++;
-      } else {
-        this.pos++;
-      }
-      return new Expressions.FunctionCall(id, actualParameters);
+      return this.parseFunctionCallExpression(id);
     } else {
       this.pos = last;
+      return new Expressions.VariableLiteral(id);
+    }
+  }
+
+  getFunctionName (id) {
+    if (id === this.lexerClass.READ_FUNCTION_NAME) {
+      return NAMES.READ;
+    } else if (id === this.lexerClass.WRITE_FUNCTION_NAME) {
+      return NAMES.WRITE;
+    } else {
       return id;
     }
   }
 
+  parseFunctionCallExpression (id) {
+    const actualParameters = this.parseActualParameters();
+    const funcName = this.getFunctionName(id);
+    return new Expressions.FunctionCall(funcName, actualParameters);
+  }
+
+  parseFunctionCallCommand (id) {
+    return this.parseFunctionCallExpression(id);
+  }
+
   parseParenthesisExp () {
     this.checkOpenParenthesis();
     this.pos++;

+ 34 - 6
js/ast/types.js

@@ -1,7 +1,35 @@
 export const Types = Object.freeze({
-  INTEGER: Symbol("int"),
-  REAL: Symbol("real"),
-  STRING: Symbol("string"),
-  BOOLEAN: Symbol("bool"),
-  VOID: Symbol("void")
-});
+  INTEGER: "int",
+  REAL: "real",
+  STRING: "string",
+  BOOLEAN: "bool",
+  VOID: "void",
+  ARRAY: 'array',
+  UNDEFINED: 'undefined',
+  ALL: 'all'
+});
+
+export function toInt (str) {
+  if(str.match('^0b|^0B')) {
+    return parseInt(str.substring(2), 2);
+  } else if (str.match('^0x|^0X')) {
+    return parseInt(str.substring(2), 16);
+  } else {
+    return parseInt(str);
+  }
+}
+
+export function toString (str) {
+  let value = str.replace("\\b", "\b");
+  value = value.replace("\\t", "\t");
+  value = value.replace("\\n", "\n");
+  value = value.replace("\\r", "\r");
+  value = value.replace("\\\"", "\"");
+  value = value.replace("\\\'", "\'");
+  value = value.replace("\\\\", "\\");
+  return value;
+}
+
+export function toBool (str) {
+  return true;
+}

+ 37 - 0
js/io/domInput.js

@@ -0,0 +1,37 @@
+import {Input} from './input';
+import $ from 'jquery';
+
+export class DOMInput extends Input{
+
+  constructor (element) {
+    super();
+    this.el = $(element);
+    this.listeners = [];
+    this.setupEvents();
+  }
+
+  setupEvents () {
+    this.el.on('keydown', (e) => {
+      const code = e.keyCode || e.which;
+      if (code === 13) {
+        let text = this.el.val();
+        text = text.replace('[\n\r]+', '');
+        this.notifyInput(text);
+        this.el.val('');
+      }
+    });
+  }
+
+  requestInput (callback) {
+    this.listeners.push(callback);
+    this.el.focus();
+  }
+
+  notifyInput (text) {
+    this.listeners.forEach(resolve => {
+      resolve(l);
+    })
+    this.listeners.splice(0, this.listeners.length);
+  }
+
+}

+ 15 - 0
js/io/domOutput.js

@@ -0,0 +1,15 @@
+import { Output } from './output';
+import $ from 'jquery';
+
+export class DOMOutput extends Output {
+
+  constructor (selector) {
+    super();
+    this.el = $(selector);
+  }
+
+  sendOutput (text) {
+    const line = $(`<span class='ivprog-io-output> ${text} </span>`);
+    this.el.append(line);
+  }
+}

+ 6 - 0
js/io/input.js

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

+ 6 - 0
js/io/output.js

@@ -0,0 +1,6 @@
+export class Output {
+
+  sendOutput (text) {
+    throw new Error("Must be implemented");
+  }
+}

+ 25 - 31
js/main.js

@@ -5,28 +5,18 @@ import {
 import * as Commands from './ast/commands';
 import { IVProgParser } from './ast/ivprogParser';
 import Lexers from '../grammar/';
+import { IVProgProcessor } from './processor/ivprogProcessor';
 
 const lang = 'pt_br';
 
 const ivprogLexer = Lexers[lang];
 
 const input = `programa {
-
-  const real C = 6.8-5.8+1
              
-  funcao abc() {
-     inteiro a = 8
-     se (a * C > 80) {
-        a = 0
-     } senao se(verdadeiro) {
-        a = -1
-       fun()
-     }
+  funcao inicio() {
+     inteiro a[2] = {1,2}
   }
 
-  funcao real fun() {
-    retorne 3
-  }
 }`;
 
 // const lexer = new ivprogLexer(new InputStream(input));
@@ -40,22 +30,26 @@ const input = `programa {
 //     i++;
 // }
 const anaSin = new IVProgParser(input, ivprogLexer);
-try {
-  const data = anaSin.parseTree();
-  console.log(data);
-  var editor = new JsonEditor('#json-renderer', data);
-  $('#btn').click( () => {
-    const input = $('#input').val();
-    const analiser = new IVProgParser(input, ivprogLexer);
-    try {
-      const data = analiser.parseTree();
-      console.log(data);
-      editor.load(data);  
-    } catch (error) {
-      alert(error);
-    }
+const proc = new IVProgProcessor(anaSin.parseTree());
+proc.interpretAST().then( sto => {
+  console.log(sto.applyStore('a'));
+}).catch(e => console.log(e));
+// try {
+//   const data = anaSin.parseTree();
+//   console.log(data);
+//   var editor = new JsonEditor('#json-renderer', data);
+//   $('#btn').click( () => {
+//     const input = $('#input').val();
+//     const analiser = new IVProgParser(input, ivprogLexer);
+//     try {
+//       const data = analiser.parseTree();
+//       console.log(data);
+//       editor.load(data);  
+//     } catch (error) {
+//       alert(error);
+//     }
     
-  });
-} catch(a) {
-  console.log(a);
-}
+//   });
+// } catch(a) {
+//   console.log(a);
+// }

+ 60 - 0
js/processor/compatibilityTable.js

@@ -0,0 +1,60 @@
+import { Types } from './../ast/types';
+import { Operators } from './../ast/operators';
+
+const InfixCompatibilityTable = Object.freeze([
+  /*Add*/[Types.INTEGER, Types.REAL, Types.STRING],
+  /*Sub*/[Types.INTEGER, Types.REAL],
+  /*Mult*/[Types.INTEGER, Types.REAL],
+  /*Div*/[Types.INTEGER, Types.REAL],
+  /*Mod*/[Types.INTEGER],
+  /*Gt*/[Types.INTEGER, Types.REAL],
+  /*Ge*/[Types.INTEGER, Types.REAL],
+  /*Lt*/[Types.INTEGER, Types.REAL],
+  /*Le*/[Types.INTEGER, Types.REAL],
+  /*Eq*/[Types.INTEGER, Types.REAL, Types.STRING, Types.BOOLEAN],
+  /*Neq*/[Types.INTEGER, Types.REAL, Types.STRING, Types.BOOLEAN],
+  /*And*/[Types.BOOLEAN],
+  /*Or*/[Types.BOOLEAN],
+  /*Not*/null,
+]);
+
+const UnaryCompatibilityTable = Object.freeze([
+  /*Add*/[Types.INTEGER, Types.REAL],
+  /*Sub*/[Types.INTEGER, Types.REAL],
+  /*Mult*/null,
+  /*Div*/null,
+  /*Mod*/null,
+  /*Gt*/null,
+  /*Ge*/null,
+  /*Lt*/null,
+  /*Le*/null,
+  /*Eq*/null,
+  /*Neq*/null,
+  /*And*/null,
+  /*Or*/null,
+  /*Not*/[Types.BOOLEAN],
+]);
+
+export function canApplyUnaryOp (op, a) {
+  const list = UnaryCompatibilityTable[op];
+  if (!!!list) {
+    return false;
+  }
+  const type = list.find(t => t === a.type);
+  if (!!!type) {
+    return false;
+  }
+  return true
+}
+
+export function canApplyInfixOp (op, a, b) {
+  const list = InfixCompatibilityTable[op];
+  if (!!!list) {
+    return false;
+  }
+  const type = list.find(t => t === a.type);
+  if (!!!type) {
+    return false;
+  }
+  return type === b.type;
+}

+ 5 - 0
js/processor/context.js

@@ -0,0 +1,5 @@
+export const Context = Object.freeze({
+  BASE: Symbol('context:base'),
+  BREAKABLE: Symbol('context:breakable'),
+  FUNCTION: Symbol('context:function')
+});

+ 28 - 0
js/processor/definedFunctions.js

@@ -0,0 +1,28 @@
+import * as Commands from './../ast/commands';
+import {Types} from './../ast/types';
+
+function createOutputFun () {
+  const block = new Commands.CommandBlock([], [new Commands.SysCall('$write')]);
+  const func = new Commands.Function('$write', Types.VOID,
+    [new Commands.FormalParameter(Types.ALL, 'p1', 0, true)],
+    block);
+  return func;
+}
+
+function createInputFun () {
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall('$read')]);
+  const func = new Commands.Function('$read', Types.VOID,
+    [new Commands.FormalParameter(Types.ALL, 'p1', 0, true)],
+    block);
+  return func;
+}
+
+export const LanguageDefinedFunction = Object.freeze({
+  $write: createOutputFun(),
+  $read: createInputFun()
+});
+
+export const NAMES = Object.freeze({
+  WRITE: '$write',
+  READ: '$read'
+});

+ 745 - 0
js/processor/ivprogProcessor.js

@@ -0,0 +1,745 @@
+import { Store } from './store/store';
+import { StoreObject } from './store/storeObject';
+import { StoreObjectArray } from './store/storeObjectArray';
+import { StoreObjectRef } from './store/storeObjectRef';
+import { Modes } from './modes';
+import { Context } from './context';
+import { Types, toInt } from './../ast/types';
+import { Operators } from './../ast/operators';
+import { NAMES, LanguageDefinedFunction } from './definedFunctions';
+import { canApplyInfixOp, canApplyUnaryOp } from './compatibilityTable';
+import * as Commands from './../ast/commands/';
+import * as Expressions from './../ast/expressions/';
+
+export class IVProgProcessor {
+
+  constructor(ast) {
+    this.ast = ast;
+    this.globalStore = new Store();
+    this.stores = [this.globalStore];
+    this.context = [Context.BASE];
+    this.input = null;
+    this.output = null;
+  }
+
+  registerInput (input) {
+    this.input = input;
+  }
+
+  registerOutput (output) {
+    this.output = output;
+  }
+
+  checkContext(context) {
+    return this.context[this.context.length - 1] === context;
+  }
+
+  ignoreSwitchCases (store) {
+    if (store.mode === Modes.RETURN) {
+      return true;
+    } else if (store.mode === Modes.BREAK) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  interpretAST () {
+    this.initGlobal();
+    const mainFunc = this.findMainFunction();
+    if(mainFunc === null) {
+      // TODO: Better error message
+      throw new Error("Missing main funciton.");
+    }
+    return this.runFunction(mainFunc, [], this.globalStore);
+  }
+
+  initGlobal () {
+    if(!this.checkContext(Context.BASE)) {
+      throw new Error("!!!CRITICAL: Invalid call to initGlobal outside BASE context!!!");
+    }
+    this.ast.global.forEach(decl => {
+      this.executeCommand(this.globalStore, decl).then(sto => this.globalStore = sto);
+    });
+  }
+
+  findMainFunction () {
+    return this.ast.functions.find(v => v.isMain);
+  }
+
+  findFunction (name) {
+    if(name.match(/^\$.+$/)) {
+      const fun = LanguageDefinedFunction[name];
+      if(!!!fun) {
+        throw new Error("!!!Internal Error. Language defined function not implemented -> " + name + "!!!");
+      }
+      return fun;
+    } else {
+      const val = this.ast.functions.find( v => v.name === name);
+      if (!!!val) {
+        // TODO: better error message;
+        throw new Error(`Function ${name} is not defined.`);
+      }
+      return val;
+    }
+  }
+
+  runFunction (func, actualParameters, store) {
+    let funcStore = new Store();
+    funcStore.extendStore(this.globalStore);
+    const returnStoreObject = new StoreObject(func.returnType, null);
+    const funcName = func.isMain ? 'main' : func.name;
+    const funcNameStoreObject = new StoreObject(Types.STRING, funcName, true);
+    funcStore.insertStore('$', returnStoreObject);
+    funcStore.insertStore('$name', funcNameStoreObject);
+    const newFuncStore$ = this.associateParameters(func.formalParameters, actualParameters, store, funcStore);
+    return newFuncStore$.then(sto => {
+      this.context.push(Context.FUNCTION);
+      this.stores.push(sto);
+      return this.executeCommands(sto, func.variablesDeclarations)
+        .then(stoWithVars => this.executeCommands(stoWithVars, func.commands)).then(finalSto => {
+          this.stores.pop();
+          this.context.pop();
+          return finalSto;
+        });
+    });
+  }
+
+  associateParameters (formalList, actualList, callerStore, calleeStore) {
+    if (formalList.length != actualList.length) {
+      // TODO: Better error message
+      throw new Error("Numbers of parameters doesn't match");
+    }
+    const promises$ = actualList.map(actualParameter => this.evaluateExpression(callerStore, actualParameter));
+    return Promise.all(promises$).then(values => {
+      for (let i = 0; i < values.length; i++) {
+        const stoObj = values[i];
+        const formalParameter = formalList[i];
+        switch (formalParameter.dimensions) {
+          case 1: {
+            if (stoObj.lines > 0 && stoObj.columns === null
+              && stoObj.subtype === formalParameter.type) {
+
+              if(formalParameter.byRef && !stoObj.inStore) {
+                throw new Error('You must inform a variable as parameter');
+              }
+
+              if(formalParameter.byRef) {
+                const ref = new StoreObjectRef(stoObj.id, callerStore);
+                calleeStore.insertStore(formalParameter.id, ref);
+              } else {
+                calleeStore.insertStore(formalParameter.id, stoObj);
+              }
+
+            } else {
+              // 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 StoreObjectRef(stoObj.id, callerStore);
+                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 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}.`);
+            } else {
+
+              if(formalParameter.byRef) {
+                const ref = new StoreObjectRef(stoObj.id, callerStore);
+                console.log('it\'s a ref...');
+                console.log(ref);
+                calleeStore.insertStore(formalParameter.id, ref);
+              } else {
+                calleeStore.insertStore(formalParameter.id, stoObj);
+              }
+
+            }
+          }
+        }
+      }
+      return calleeStore;
+    });
+  }
+
+  executeCommands (store, cmds) {
+    const auxExecCmdFun = (promise, cmd) => promise.then( sto => this.executeCommand(sto, cmd));
+    let breakLoop = false;
+    let $result = Promise.resolve(store);
+    for (let index = 0; index < cmds.length && !breakLoop; index++) {
+      const cmd = cmds[index];
+      $result = auxExecCmdFun($result, cmd);
+      $result.then(sto => {
+        if(sto.mode === Modes.RETURN) {
+          breakLoop = true;
+        } else if (this.checkContext(Context.BREAKABLE && 
+          sto.mode === Modes.BREAK)) {
+            breakLoop = true;
+        }
+        return sto;
+      });
+    }
+    return $result;
+  }
+
+  executeCommand (store, cmd) {
+
+    while (store.mode === Modes.PAUSE) {
+      continue;
+    }
+
+    if(store.mode === Modes.RETURN) {
+      return Promise.resolve(store);
+    } else if(this.checkContext(Context.BREAKABLE) && store.mode === Modes.BREAK) {
+      return Promise.resolve(store);
+    }
+
+    if (cmd instanceof Commands.Declaration) {
+      return this.executeDeclaration(store, cmd);
+    } else if (cmd instanceof Commands.Assign) {
+      return this.executeAssign(store, cmd);
+    } else if (cmd instanceof Commands.Break) {
+      return this.executeBreak(store, cmd);
+    } else if (cmd instanceof Commands.Return) {
+      return this.executeReturn(store, cmd);
+    } else if (cmd instanceof Commands.IfThenElse) {
+      return this.executeIfThenElse(store, cmd);
+    } else if (cmd instanceof Commands.While) {
+      return this.executeWhile(store, cmd);
+    } else if (cmd instanceof Commands.DoWhile) {
+      return this.executeDoWhile(store, cmd);
+    } else if (cmd instanceof Commands.For) {
+      return this.executeFor(store, cmd);
+    } else if (cmd instanceof Commands.Switch) {
+      return this.executeSwitch(store, cmd);
+    } else if (cmd instanceof Commands.FunctionCall) {
+      return this.executeFunctionCall(store, cmd);
+    } else if (cmd instanceof Commands.SysCall) {
+      return this.executeSysCall(store, cmd);
+    } else {
+      throw new Error("!!!CRITICAL A unknown command was found!!!\n" + cmd);
+    }
+  }
+
+  executeSysCall (store, cmd) {
+    if (cmd.id === NAMES.WRITE) {
+      return this.runWriteFunction(store)
+    } else if (cmd.id === NAMES.READ) {
+      return this.runReadFunction(store);
+    }
+  }
+
+  runWriteFunction (store) {
+    const val = store.applyStore('p1');
+    this.output.sendOutput(''+val.value);
+    return Promise.resolve(store);
+  }
+
+  runReadFunction (store) {
+    const request = new Promise((resolve, _) => {
+      this.input.requestInput(resolve);
+    });
+    return request.then(text => {
+      const typeToConvert = store.applyStore('p1').type;
+      let stoObj = null;
+      if (typeToConvert === Types.INTEGER) {
+        const val = toInt(text);
+        stoObj = new StoreObject(Types.INTEGER, val);
+      } else if (typeToConvert === Types.REAL) {
+        stoObj = new StoreObject(Types.REAL, parseFloat(text));
+      } else if (typeToConvert === Types.BOOLEAN) {
+        stoObj = new StoreObject(Types.BOOLEAN, true);
+      } else if (typeToConvert === Types.STRING) {
+        stoObj = new StoreObject(Types.STRING, text);
+      }
+      store.updateStore('p1', stoObj);
+      return Promise.resolve(store);
+    });
+  }
+
+  executeFunctionCall (store, cmd) {
+    return new Promise((resolve, reject) => {
+      const func = this.findFunction(cmd.id);
+      this.runFunction(func, cmd.actualParameters, store)
+        .then(_ => resolve(store))
+        .catch(err => reject(err));
+    }); 
+  }
+
+  executeSwitch (store, cmd) {
+    this.context.push(Context.BREAKABLE);
+    const auxCaseFun = (promise, switchExp, aCase) => {
+      return promise.then( result => {
+        const sto = result.sto;
+        if (this.ignoreSwitchCases(sto)) {
+          return Promise.resolve(result);
+        } else if (result.wasTrue || aCase.isDefault) {
+          const $newSto = this.executeCommands(result.sto,aCase.commands);
+          return $newSto.then(nSto => {
+            return Promise.resolve({wasTrue: true, sto: nSto});
+          });
+        } else {
+          const $value = this.evaluateExpression(sto,
+            new Expressions.InfixApp(Operators.EQ, switchExp, aCase.expression));
+          return $value.then(vl => {
+            if (vl.value) {
+              const $newSto = this.executeCommands(result.sto,aCase.commands);
+              return $newSto.then(nSto => {
+                return Promise.resolve({wasTrue: true, sto: nSto});
+              });
+            } else {
+              return Promise.resolve({wasTrue: false, sto: sto});
+            }
+          });
+        }
+      });
+    }
+
+    try {
+      let breakLoop = false;
+      let $result = Promise.resolve({wasTrue: false, sto: store});
+      for (let index = 0; index < cmd.cases.length && !breakLoop; index++) {
+        const aCase = cmd.cases[index];
+        $result = auxCaseFun($result, cmd.expression, aCase);
+        $result.then( r => breakLoop = this.ignoreSwitchCases(r.sto));
+      }
+      return $result.then(r => {
+        this.context.pop();
+        if(r.sto.mode === Modes.BREAK) {
+          r.sto.mode = Modes.RUN;
+        }
+        return r.sto;
+      });
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  }
+
+  executeFor (store, cmd) {
+    try {
+      //BEGIN for -> while rewrite
+      const initCmd = cmd.assignment;
+      const condition = cmd.condition;
+      const increment = cmd.increment;
+      const whileBlock = new Commands.CommandBlock([],
+        cmd.commands.concat(increment));
+      const forAsWhile = new Commands.While(condition, whileBlock);
+      //END for -> while rewrite
+      const newCmdList = [initCmd,forAsWhile];
+      return this.executeCommands(store, newCmdList);
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  }
+
+  executeDoWhile (store, cmd) {
+    try {
+      this.context.push(Context.BREAKABLE);
+      const $newStore = this.executeCommands(store, cmd.commands);
+      return $newStore.then(sto => {
+        if(sto.mode === Modes.BREAK) {
+          this.context.pop();
+          sto.mode = Modes.RUN;
+          return Promise.resolve(sto);
+        }
+        const $value = this.evaluateExpression(sto, cmd.expression);
+        return $value.then(vl => {
+          if (vl.type !== 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`));
+          }
+          if (vl.value) {
+            this.context.pop();
+            return this.executeCommand(sto, cmd);
+          } else {
+            this.context.pop();
+            return Promise.resolve(sto);
+          }
+        });
+      });
+    } catch (error) {
+      return Promise.reject(error)
+    }
+  }
+
+  executeWhile (store, cmd) {
+    try {
+      this.context.push(Context.BREAKABLE);
+      const $value = this.evaluateExpression(store, cmd.expression);
+      return $value.then(vl => {
+        if(vl.type === Types.BOOLEAN) {
+          if(vl.value) {
+            const $newStore = this.executeCommands(store, cmd.commands);
+            return $newStore.then(sto => {
+              this.context.pop();
+              if (sto.mode === Modes.BREAK) {
+                sto.mode = Modes.RUN;
+                return Promise.resolve(sto);
+              }
+              return this.executeCommand(sto, cmd);
+            });
+          } else {
+            this.context.pop();
+            return Promise.resolve(store);
+          }
+        } else {
+          // TODO: Better error message -- Inform line and column from token!!!!
+          // THIS IF SHOULD BE IN A SEMANTIC ANALYSER
+          return Promise.reject(new Error(`Loop condition must be of type boolean`));
+        }
+      });
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  }
+
+  executeIfThenElse (store, cmd) {
+    try {
+      const $value = this.evaluateExpression(store, cmd.condition);
+      return $value.then(vl => {
+        if(vl.type === Types.BOOLEAN) {
+          if(vl.value) {
+            return this.executeCommands(store, cmd.ifTrue.commands);
+          } else if( cmd.ifFalse !== null){
+            if(cmd.ifFalse instanceof Commands.IfThenElse) {
+              return this.executeCommand(store, cmd.ifFalse);
+            } else {
+              return this.executeCommands(store, cmd.ifFalse.commands);
+            }
+          } else {
+            return Promise.resolve(store);
+          }
+        } else {
+          // TODO: Better error message -- Inform line and column from token!!!!
+          // THIS IF SHOULD BE IN A SEMANTIC ANALYSER
+          return Promise.reject(new Error(`If expression must be of type boolean`));
+        }
+      });
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  }
+
+  executeReturn (store, cmd) {
+    try {
+      const funcType = store.applyStore('$');
+      const $value = this.evaluateExpression(store, cmd.expression);
+      const funcName = store.applyStore('$name');
+      return $value.then(vl => {
+
+        if(vl === null && funcType === Types.VOID) {
+          return Promise.resolve(store);
+        }
+
+        if (vl === null || funcType.type !== 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}.`));
+        } else {
+          store.updateStore('$', vl);
+          store.mode = Modes.RETURN;
+          return Promise.resolve(store);
+        }
+      });
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  }
+
+  executeBreak (store, _) {
+    if(this.checkContext(Context.BREAKABLE)) {
+      store.mode = Modes.BREAK;
+      return Promise.resolve(store);
+    } else {
+      return Promise.reject(new Error("!!!CRITIAL: Break command outside Loop/Switch scope!!!"));
+    }
+  }
+
+  executeAssign (store, cmd) {
+    try {
+      const $value = this.evaluateExpression(store, cmd.expression);
+      return $value.then( vl => {
+        store.updateStore(cmd.id, vl) 
+        return store;
+      });
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  }
+
+  executeDeclaration (store, cmd) {
+    try {
+      const $value = this.evaluateExpression(store, cmd.initial);
+      if(cmd instanceof Commands.ArrayDeclaration) {
+        const $lines = this.evaluateExpression(store, cmd.lines);
+        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) {
+            // 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"));
+          }
+          const line = lineSO.value;
+          const columnSO = values[1];
+          let column = null
+          if (columnSO !== null) {
+            if(columnSO.type !== Types.INTEGER) {
+              // 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"));
+            }
+            column = columnSO.value;
+          }
+          const value = values[2];
+          const temp = new StoreObjectArray(cmd.subtype, line, column, null, cmd.isConst);
+          store.insertStore(cmd.id, temp);
+          if(value !== null) {
+            store.updateStore(cmd.id, value);
+          }
+          return store;
+        });
+        
+      } else {
+        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)
+          return store;
+        });
+      }
+    } catch (e) {
+      return Promise.reject(e);
+    }
+  }
+
+   evaluateExpression (store, exp) {
+
+    if (exp instanceof Expressions.UnaryApp) {
+      return this.evaluateUnaryApp(store, exp);
+    } else if (exp instanceof Expressions.InfixApp) {
+      return this.evaluateInfixApp(store, exp);
+    } else if (exp instanceof Expressions.ArrayAccess) {
+      return this.evaluateArrayAccess(store, exp);
+    } else if (exp instanceof Expressions.VariableLiteral) {
+      return this.evaluateVariableLiteral(store, exp);
+    } else if (exp instanceof Expressions.IntLiteral) {
+      return this.evaluateLiteral(store, exp);
+    } else if (exp instanceof Expressions.RealLiteral) {
+      return this.evaluateLiteral(store, exp);
+    } else if (exp instanceof Expressions.BoolLiteral) {
+      return this.evaluateLiteral(store, exp);
+    } else if (exp instanceof Expressions.StringLiteral) {
+      return this.evaluateLiteral(store, exp);
+    } else if (exp instanceof Expressions.ArrayLiteral) {
+      return this.evaluateArrayLiteral(store, exp);
+    } else if (exp instanceof Expressions.FunctionCall) {
+      return this.evaluateFunctionCall(store, exp);
+    }
+    console.log('null exp');
+    return Promise.resolve(null);
+  }
+
+  evaluateFunctionCall (store, exp) {
+    const func = this.findFunction(exp.id);
+    if(func.returnType === Types.VOID) {
+      // 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) {
+        return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null,null), val));
+      } else {
+        return Promise.resolve(Object.assign(new StoreObject(null,null), val));
+      }
+    });
+  }
+
+  evaluateArrayLiteral (store, exp) {
+    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);
+        if(arr.isValid)
+          return Promise.resolve(arr);
+        else
+          return Promise.reject(new Error(`Invalid array`))
+      });
+    } else {
+      return this.evaluateVector(store, exp.value).then(list => {
+        const stoArray = new StoreObjectArray(list[0].type, list.length, null, list);
+        if(stoArray.isValid)
+          return Promise.resolve(stoArray);
+        else
+          return Promise.reject(new Error(`Invalid array`))
+      });
+    }
+  }
+
+  evaluateVector (store, exps) {
+    return Promise.all(exps.map( exp => this.evaluateExpression(store, exp)));
+  }
+
+  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))
+    } ));
+  }
+
+  evaluateLiteral (_, exp) {
+    return Promise.resolve(new StoreObject(exp.type, exp.value));
+  }
+
+  evaluateVariableLiteral (store, exp) {
+    try {
+      const val = store.applyStore(exp.id);
+      if (val.type === Types.ARRAY) {
+        return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null), val));
+      } else {
+        return Promise.resolve(Object.assign(new StoreObject(null,null), val));
+      }
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  }
+
+  evaluateArrayAccess (store, exp) {
+    const mustBeArray = store.applyStore(exp.id);
+    if (mustBeArray.type !== Types.ARRAY) {
+      // TODO: better error message
+      return Promise.reject(new Error(`${exp.id} is not of type array`));
+    }
+    const $line = this.evaluateExpression(store, exp.line);
+    const $column = this.evaluateExpression(store, exp.column);
+    return Promise.all([$line, $column]).then(values => {
+      const lineSO = values[0];
+      const columnSO = values[1];
+      if(lineSO.type !== Types.INTEGER) {
+        // 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"));
+      }
+      const line = lineSO.value;
+      let column = null;
+      if(columnSO !== null) {
+        if(columnSO.type !== Types.INTEGER) {
+          // 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"));
+        }
+        column = columnSO.value;
+      }
+
+      if (line >= mustBeArray.lines) {
+        // TODO: better error message
+        return Promise.reject(new Error(`${exp.id}: index out of bounds: ${lines}`));
+      }
+      if (column !== null && mustBeArray.columns === null ){
+        // TODO: better error message
+        return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
+      }
+      if(column !== null && column >= mustBeArray.columns) {
+        // TODO: better error message
+        return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
+      }
+  
+      if (column !== null) {
+        return Promise.resolve(mustBeArray.value[line].value[column]);
+      } else {
+        return Promise.resolve(mustBeArray.value[line]);
+      }
+    });
+  }
+
+  evaluateUnaryApp (store, unaryApp) {
+    const $left = this.evaluateExpression(store, unaryApp.left);
+    return $left.then( left => {
+      if (!canApplyUnaryOp(unaryApp.op, left)) {
+        // TODO: better urgent error message
+        return Promise.reject(new Error(`Cannot use this op to ${left.type}`));
+      }
+      switch (unaryApp.op) {
+        case Operators.ADD:
+          return new StoreObject(left.type, +left.value);
+        case Operators.SUB:
+          return new StoreObject(left.type, -left.value);
+        case Operators.NOT:
+          return new StoreObject(left.type, !left.value);
+        default:
+        return Promise.reject(new Error('!!!Critical Invalid UnaryApp '+ unaryApp.op));
+      }
+    });
+  }
+
+  evaluateInfixApp (store, infixApp) {
+    const $left = this.evaluateExpression(store, infixApp.left);
+    const $right = this.evaluateExpression(store, infixApp.right);
+    return Promise.all([$left, $right]).then(values => {
+      const left = values[0];
+      const right = values[1];
+      if (!canApplyInfixOp(infixApp.op, left, right)) {
+        // TODO: better urgent error message
+        return Promise.reject(new Error(`Cannot use this op to ${left.type} and ${right.type}`));
+      }
+      switch (infixApp.op) {
+        case Operators.ADD:
+          return new StoreObject(left.type, left.value + right.value);
+        case Operators.SUB:
+          return new StoreObject(left.type, left.value - right.value);
+        case Operators.MULT:
+          return new StoreObject(left.type, left.value * right.value);
+        case Operators.DIV:
+          return new StoreObject(left.type, left.value / right.value);
+        case Operators.MOD:
+          return new StoreObject(left.type, left.value % right.value);
+        case Operators.GT:
+          return new StoreObject(Types.BOOLEAN, left.value > right.value);
+        case Operators.GE:
+          return new StoreObject(Types.BOOLEAN, left.value >= right.value);
+        case Operators.LT:
+          return new StoreObject(Types.BOOLEAN, left.value < right.value);
+        case Operators.LE:
+          return new StoreObject(Types.BOOLEAN, left.value <= right.value);
+        case Operators.EQ:
+          return new StoreObject(Types.BOOLEAN, left.value === right.value);
+        case Operators.NEQ:
+          return new StoreObject(Types.BOOLEAN, left.value !== right.value);
+        case Operators.AND:
+          return new StoreObject(Types.BOOLEAN, left.value && right.value);
+        case Operators.OR:
+          return new StoreObject(Types.BOOLEAN, left.value || right.value);
+        default:
+          return Promise.reject(new Error('!!!Critical Invalid InfixApp '+ infixApp.op));
+      }
+    });
+  }
+
+}

+ 6 - 0
js/processor/modes.js

@@ -0,0 +1,6 @@
+export const Modes = Object.freeze({
+  RETURN: Symbol('mode:return'),
+  BREAK: Symbol('mode:break'),
+  PAUSE: Symbol('mode:pause'),
+  RUN: Symbol('mode:run')
+});

+ 73 - 0
js/processor/store/store.js

@@ -0,0 +1,73 @@
+import { Modes } from './../modes';
+export class Store {
+
+  constructor() {
+    this.store = {};
+    this.nextStore = null;
+    this.mode = Modes.RUN; 
+  }
+
+  extendStore (nextStore) {
+    this.nextStore = nextStore;
+  }
+
+  applyStore (id) {
+    if(!this.store[id]) {
+      if (this.nextStore !== null) {
+        return this.nextStore.applyStore(id);
+      } else {
+        // TODO: better error message
+        throw new Error(`Variable ${id} not found.`);
+      }
+    }
+    const val = this.store[id];
+    if (val.isRef) {
+      return val.getRefObj();
+    }
+    return this.store[id];
+  }
+
+  updateStore (id, stoObj) {
+    if(!this.store[id]) {
+      if(this.nextStore !== null) {
+        this.nextStore.updateStore(id, stoObj);
+        return this;
+      } else {
+        // TODO: better error message
+        throw new Error(`Variable ${id} not found.`);
+      }
+    } else {
+      const oldObj = this.store[id];
+      if(oldObj.readOnly) {
+        // TODO: better error message
+        throw new Error("Cannot change value of a read only variable: " + id);
+      }
+      if(oldObj.isCompatible(stoObj)) {
+        if(oldObj.isRef) {
+          oldObj.updateRef(stoObj);
+          return this;
+        }
+        stoObj.setID(id);
+        this.store[id] = Object.freeze(stoObj);
+        return this;
+      } else {
+        // TODO: better error message
+        throw new Error(`${oldObj.type} is not compatible with the value given`);
+      }
+    }
+  }
+
+  //In case of future use of ref, it needs to have a special function to update the storeRefObject
+  // and no the StoreObject refferenced by it
+  // updateStoreRef(id, stoObjAddress) {...}
+
+  insertStore (id, stoObj) {
+    if (this.store[id]) {
+      // TODO: better error message
+      throw new Error(`${id} is already defined`);
+    }
+    stoObj.setID(id);
+    this.store[id] = Object.freeze(stoObj);
+    return this;
+  }
+}

+ 40 - 0
js/processor/store/storeObject.js

@@ -0,0 +1,40 @@
+export class StoreObject {
+
+  constructor (type, value, readOnly = false) {
+    this._type = type;
+    this._value = value;
+    this._readOnly = readOnly;
+    this._id = null;
+  }
+
+  setID (id) {
+    this._id = id;
+  }
+
+  get id () {
+    return this._id;
+  }
+
+  get inStore () {
+    return this.id !== null;
+  }
+
+  get type () {
+    return this._type;
+  }
+
+  get value () {
+    return this._value;
+  }
+
+  get readOnly () {
+    return this._readOnly;
+  }
+
+  isCompatible (another) {
+    if( another instanceof StoreObject) {
+      return this.type === another.type;
+    }
+    return false;
+  }
+}

+ 71 - 0
js/processor/store/storeObjectArray.js

@@ -0,0 +1,71 @@
+import { Types } from './../../ast/types';
+import { StoreObject } from './storeObject';
+
+export class StoreObjectArray extends StoreObject {
+
+  constructor (subtype, lines, columns, value, readOnly) {
+    super(Types.ARRAY, value, readOnly);
+    this._lines = lines;
+    this._columns = columns;
+    this._subtype = subtype;
+  }
+
+  get lines () {
+    return this._lines;
+  }
+
+  get columns () {
+    return this._columns;
+  }
+
+  get subtype () {
+    return this._subtype;
+  }
+
+  isCompatible (another) {
+    if(another instanceof StoreObjectArray) {
+      if(this.lines === another.lines &&
+        this.columns === another.columns &&
+        this.subtype === another.subtype) {
+          return super.isCompatible(another);
+        }
+    }
+    return false;
+  }
+
+  get isVector () {
+    return this.columns === null;
+  }
+
+  get isValid () {
+    if (this.value !== null) {
+      if( this.isVector) {
+        if(this.value.length !== this.lines) {
+          return false;
+        }
+        const mustBeNull = this.value.find(v => v.type !== this.subtype);
+        if(!!mustBeNull) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+    if(this.lines !== this.value.length) {
+      return false;
+    }
+    for (let i = 0; i < this.lines; i++) {
+      for (let j = 0; j < this.columns; j++) {
+        const arr = this.value[i];
+        if(arr.length !== this.columns) {
+          return false;
+        }
+        const mustBeNull = arr.find(v => v.type !== this.subtype);
+        if(!!mustBeNull) {
+          return false;
+        }            
+      }
+    }
+      return true;
+    }
+  }
+}

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

@@ -0,0 +1,34 @@
+import { StoreObject } from './storeObject';
+
+export class StoreObjectRef extends StoreObject {
+
+  constructor (refID, store) {
+    super(null, null, false);
+    this.refID = refID;
+    this.store = store;
+  }
+
+  get isRef () {
+    return true;
+  }
+
+  get type () {
+    return this.store.applyStore(this.refID).type;
+  }
+
+  get value () {
+    return this.store.applyStore(this.refID).value;
+  }
+
+  getRefObj () {
+    return this.store.applyStore(this.refID);
+  }
+
+  updateRef (stoObj) {
+    this.store.updateStore(this.refID, stoObj);
+  }
+
+  isCompatible (another) {
+    return this.store.applyStore(this.refID).isCompatible(another);
+  }
+}

+ 17 - 0
js/util/inputTest.js

@@ -0,0 +1,17 @@
+import { Input } from './../io/input';
+
+export class InputTest extends Input {
+
+  constructor (inputList) {
+    super();
+    this.inputList = inputList;
+  }
+
+  requestInput (callback) {
+    if(this.inputList.length <= 0) {
+      throw new Error('The amount of requests exceeded the amount of available inputs');
+    } else {
+      callback(this.inputList.splice(0,1)[0]);
+    }
+  }
+}

+ 13 - 0
js/util/outputTest.js

@@ -0,0 +1,13 @@
+import { Output } from './../io/output';
+
+export class OutputTest extends Output {
+
+  constructor () {
+    super();
+    this.list = [];
+  }
+
+  sendOutput (text) {
+    this.list.push(text);
+  }
+}

+ 5 - 0
package-lock.json

@@ -4279,6 +4279,11 @@
       "integrity": "sha512-pa9tbBWgU0EE4SWgc85T4sa886ufuQdsgruQANhECYjwqgV4z7Vw/499aCaP8ZH79JDS4vhm8doDG9HO4+e4sA==",
       "dev": true
     },
+    "jquery": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
+      "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
+    },
     "js-tokens": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",

+ 2 - 1
package.json

@@ -43,6 +43,7 @@
     "webpack-cli": "^3.1.0"
   },
   "dependencies": {
-    "antlr4": "^4.7.1"
+    "antlr4": "^4.7.1",
+    "jquery": "^3.3.1"
   }
 }

+ 5 - 1
tests/test17.spec.js

@@ -1,6 +1,7 @@
 import Lexers from './../grammar/';
 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 {
     IVProgParser
@@ -11,6 +12,7 @@ describe('Variable declaration inside a function', () => {
 
       funcao inicio() {
         inteiro a
+        a = a + 1
       }
     }`;
     const lexer = Lexers['pt_br'];
@@ -20,7 +22,9 @@ describe('Variable declaration inside a function', () => {
       functions: [
         new Commands.Function(null,Types.VOID,[],
         new Commands.CommandBlock([
-          new Commands.Declaration('a',Types.INTEGER,null,false)],[]))
+          new Commands.Declaration('a',Types.INTEGER,null,false)],[
+            new Commands.Assign('a',
+              new Expressions.InfixApp(Operators.ADD, new Expressions.VariableLiteral('a'), new Expressions.IntLiteral(1)))]))
       ]
     }
 

+ 26 - 0
tests/test19.spec.js

@@ -0,0 +1,26 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('Multi(*) operation', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a
+      a = -2 + 2 * 4 + 2
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should have higher priority than Sum(+)`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(8);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 26 - 0
tests/test20.spec.js

@@ -0,0 +1,26 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('An Array initialization with expressions', function () {
+
+  const input = `programa {
+
+    funcao inicio() {
+      inteiro a[2] = {2+2,3*5}
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+  const result = [4,15];
+
+  it(`should produce a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect([sto.applyStore('a').value[0].value,sto.applyStore('a').value[1].value]).toEqual(result);
+      done();
+    });
+  });
+});

+ 31 - 0
tests/test21.spec.js

@@ -0,0 +1,31 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A call to a function that returns a valid type', function () {
+
+  const input = `programa {
+
+    funcao inicio() {
+      inteiro a = soma(1, 1)
+    }
+
+    funcao inteiro soma(inteiro a, inteiro b)
+    {
+      retorne a + b
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+  const result = 2;
+
+  it(`should produce a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(result);
+      done();
+    }).catch(err => done(err));
+  });
+});

+ 25 - 0
tests/test22.spec.js

@@ -0,0 +1,25 @@
+import Lexers from './../grammar/';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('An assignment to a variable', function () {
+
+  const input = `programa {
+
+    funcao inicio() {
+      inteiro a
+      a = 5.5
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should respect the variable type`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      done(new Error('Should not have resolved'));
+    }).catch( _ => {expect(1).toEqual(1);
+    done();});
+  });
+});

+ 24 - 0
tests/test23.spec.js

@@ -0,0 +1,24 @@
+import Lexers from './../grammar/';
+import {
+    IVProgParser
+} from './../js/ast/ivprogParser';
+
+describe('Variable initialization with a function call', () => {
+    let input = `programa {
+
+      funcao inicio() {
+        inteiro a = func(5)
+      }
+
+      funcao inteiro fun(inteiro a) {
+        retorne a * 2
+      }
+    }`;
+    const lexer = Lexers['pt_br'];
+
+    it(`should not throw an Error`, () => {
+        const as = new IVProgParser(input, lexer);
+        const fun = as.parseTree.bind(as);
+        expect(fun).not.toThrow();
+    });
+});

+ 27 - 0
tests/test24.spec.js

@@ -0,0 +1,27 @@
+import Lexers from './../grammar/';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('Command Do...While', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      faca {
+        a = a + 1
+      } enquanto(a < 5)
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should result in a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(5);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 26 - 0
tests/test25.spec.js

@@ -0,0 +1,26 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('Assigning an ID to another variable', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 5
+      inteiro b = a
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should result in a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('b').value).toEqual(5);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 26 - 0
tests/test26.spec.js

@@ -0,0 +1,26 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('Assigning a line from a matrix to another vector', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a[2][2] = {{5,2},{8,6}}
+      inteiro b[2] = a[0]
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should result in a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('b')).toBeTruthy();
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 30 - 0
tests/test27.spec.js

@@ -0,0 +1,30 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A finite while loop', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      inteiro b = 0
+      enquanto (a < 5) {
+        a = a + 1
+      }
+      b = 8
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should terminate`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(5);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 32 - 0
tests/test28.spec.js

@@ -0,0 +1,32 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A break command inside a inner while loop', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      inteiro b = 0
+      enquanto (a < 5) {
+        a = a + 1
+        enquanto (b < 1) {
+          pare
+        }
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should terminate the inner while only`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(5);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 28 - 0
tests/test29.spec.js

@@ -0,0 +1,28 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A break command inside a for loop', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      para(a = 0;a < 5; a = a + 1) {
+        pare
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should terminate it`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(0);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 38 - 0
tests/test30.spec.js

@@ -0,0 +1,38 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A break command inside a switch..case', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      escolha (a) {
+        caso 2:
+          a = a + 1
+          pare
+        caso 1:
+          a = a + 2
+          pare
+        caso 0:
+          a = -5
+          pare
+        caso contrario:
+          a = 5 + 8
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should terminate it`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(-5);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 37 - 0
tests/test31.spec.js

@@ -0,0 +1,37 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A case without return/break', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 1
+      escolha (a) {
+        caso 0:
+          a = a + 1
+          pare
+        caso 1:
+          a = a + 2
+        caso 2:
+          a = a * 2
+          pare
+        caso contrario:
+          a = 5 + 8
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should fall through`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(6);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 19 - 0
tests/test32.spec.js

@@ -0,0 +1,19 @@
+import { InputTest } from './../js/util/inputTest';
+
+describe('Input test util class', () => {
+  const inTest = new InputTest(['0','2']);
+  it('should return the values given', (done) => {
+    const v1 = new Promise((resolve, _) => {
+      inTest.requestInput(resolve);
+    });
+
+    const v2 = new Promise((resolve, _) => {
+      inTest.requestInput(resolve);
+    });
+
+    Promise.all([v1,v2]).then(list => {
+      expect(list).toEqual(['0','2']);
+      done();
+    }).catch(err => done(err));
+  });
+});

+ 37 - 0
tests/test33.spec.js

@@ -0,0 +1,37 @@
+import Lexers from './../grammar/';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A non-const global variable', function () {
+
+  let input = `programa {
+
+    inteiro a = 5
+
+    funcao inicio() {
+      escolha (a) {
+        caso 0:
+          a = a + 1
+          pare
+        caso 1:
+          a = a + 2
+        caso 2:
+          a = a * 2
+          pare
+        caso contrario:
+          a = 5 + 8
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should be modifiable inside a function`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(13);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 31 - 0
tests/test34.spec.js

@@ -0,0 +1,31 @@
+import Lexers from './../grammar/';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('IfThenElse command ', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      se (a > 2) {
+        a = 5
+      } senao se (a < 2) {
+        a = 10
+      } senao {
+        a = -1
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should produce a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(10);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 34 - 0
tests/test35.spec.js

@@ -0,0 +1,34 @@
+import Lexers from './../grammar/';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A recursive call', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = fib(3)
+    }
+
+    funcao inteiro fib(inteiro n) {
+      se (n <= 0 ) {
+        retorne 0
+      } senao se (n == 1) {
+        retorne 1
+      } senao {
+        retorne fib(n-1) + fib(n-2)
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should produce a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(2);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 11 - 0
tests/test36.spec.js

@@ -0,0 +1,11 @@
+import { OutputTest } from './../js/util/outputTest';
+
+describe('Output test util class', () => {
+  it('should store the values it received', () => {
+    const values = ['1','2'];
+
+    const out = new OutputTest();
+    values.forEach( v => out.sendOutput(v));
+    expect(out.list).toEqual(['1','2']);
+  });
+});

+ 29 - 0
tests/test37.spec.js

@@ -0,0 +1,29 @@
+import Lexers from './../grammar/';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+import { InputTest } from './../js/util/inputTest';
+
+describe('The read function', function () {
+
+  const code = `programa {
+
+    funcao inicio() {
+      inteiro a;
+      leia(a);
+    }
+  }`;
+
+  const input = new InputTest(['0xff']);
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should read data from the input and convert it to the appropriate type`, function (done) {
+    const parser = new IVProgParser(code, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.registerInput(input);
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(255);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 29 - 0
tests/test38.spec.js

@@ -0,0 +1,29 @@
+import Lexers from './../grammar/';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+import { OutputTest } from './../js/util/outputTest';
+
+describe('The write function', function () {
+
+  const code = `programa {
+
+    funcao inicio() {
+      real a = 8.01
+      escreva(a)
+    }
+  }`;
+
+  const output = new OutputTest();
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should print the value passed to it, no matter it's type`, function (done) {
+    const parser = new IVProgParser(code, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.registerOutput(output);
+    exec.interpretAST().then(sto => {
+      expect(output.list).toEqual(['8.01']);
+      done();
+    }).catch( err => done(err));
+  });
+});