Browse Source

Autalizado assinatura de função

Douglas Lima 5 years ago
parent
commit
1cba2ab96c
43 changed files with 2929 additions and 600 deletions
  1. 3 8
      grammar/en/ivprog.g4
  2. 33 0
      grammar/en/langFunctions.js
  3. 10 0
      grammar/en/langLibs.js
  4. 3 8
      grammar/es/ivprog.g4
  5. 33 0
      grammar/es/langFunctions.js
  6. 10 0
      grammar/es/langLibs.js
  7. 9 3
      grammar/index.js
  8. 3 8
      grammar/pt/ivprog.g4
  9. 33 0
      grammar/pt/langFunctions.js
  10. 10 0
      grammar/pt/langLibs.js
  11. 90 0
      js/assessment/ivprogAssessment.js
  12. 186 37
      js/ast/ivprogParser.js
  13. 22 0
      js/ast/sourceInfo.js
  14. 5 2
      js/main-sidebar.js
  15. 36 2
      js/processor/compatibilityTable.js
  16. 109 21
      js/processor/definedFunctions.js
  17. 352 194
      js/processor/ivprogProcessor.js
  18. 58 0
      js/processor/lib/arrays.js
  19. 57 0
      js/processor/lib/io.js
  20. 188 0
      js/processor/lib/lang.js
  21. 209 0
      js/processor/lib/math.js
  22. 94 0
      js/processor/lib/strings.js
  23. 451 0
      js/processor/semantic/semanticAnalyser.js
  24. 8 6
      js/processor/store/store.js
  25. 15 1
      js/processor/store/storeObject.js
  26. 12 16
      js/processor/store/storeObjectArray.js
  27. 86 0
      js/processor/store/storeObjectArrayAddress.js
  28. 43 0
      js/processor/store/storeObjectArrayAddressRef.js
  29. 9 0
      js/processor/store/storeObjectRef.js
  30. 28 18
      js/services/languageService.js
  31. 2 50
      js/services/localizedStringsService.js
  32. 26 0
      js/typeSystem/baseTypes.js
  33. 28 0
      js/typeSystem/compoundType.js
  34. 29 0
      js/typeSystem/multiType.js
  35. 66 0
      js/typeSystem/parsers.js
  36. 21 0
      js/typeSystem/type.js
  37. 21 0
      js/typeSystem/types.js
  38. 37 0
      js/visualUI/algorithm.js
  39. 189 123
      js/visualUI/commands_sidebar.js
  40. 111 52
      js/visualUI/functions.js
  41. 159 48
      js/visualUI/functions_sidebar.js
  42. 28 0
      package-lock.json
  43. 7 3
      package.json

+ 3 - 8
grammar/en/ivprog.g4

@@ -1,12 +1,5 @@
 lexer grammar ivprog;
 
-@lexer::members{
-  //Translate to fit your language
-  ivprog.MAIN_FUNCTION_NAME = "start";
-  ivprog.READ_FUNCTION_NAME = "read";
-  ivprog.WRITE_FUNCTION_NAME = "write";
-}
-
 // BEGIN i18n Lexical rules
 RK_PROGRAM
   : 'program'
@@ -171,7 +164,9 @@ ID
   : [a-zA-Z_] [a-zA-Z0-9_]*
   ;
 
-// ID_BIBLIOTECA     : ID '.' ID;
+LIB_ID
+  : ID '.' ID
+  ;
 
 INTEGER
   : [0-9]+

+ 33 - 0
grammar/en/langFunctions.js

@@ -0,0 +1,33 @@
+/* This is a dictionary of the language defined functions
+**/
+export default {
+  main_function: "start",
+  $read: "read",
+  $write: "write",
+  $numElements: "numero_elementos",
+  $matrixLines: "matriz_linhas",
+  $matrixColumns: "matriz_colunas",
+  $substring: "subcadeia",
+  $length: "comprimento",
+  $uppercase: "caixa_alta",
+  $lowercase: "caixa_baixa",
+  $charAt: "char_at",
+  $isReal: "e_real",
+  $isInt: "e_inteiro",
+  $isBool: "e_logico",
+  $castReal: "como_real",
+  $castInt: "como_inteiro",
+  $castBool: "como_logico",
+  $castString: "como_cadeia",
+  $sin: "sen",
+  $cos: "cos",
+  $tan: "tan",
+  $sqrt: "raiz_quadrada",
+  $pow: "pot",
+  $log: "log",
+  $abs: "modulo",
+  $negate: "trocar_sinal",
+  $invert: "inverter_valor",
+  $max: "maximo",
+  $min: "minimo"
+}

+ 10 - 0
grammar/en/langLibs.js

@@ -0,0 +1,10 @@
+/**
+ * This is the dictionary of the language defined libraries
+ */
+export default {
+  $mathLib: "Matematica",
+  $ioLib: "ES",
+  $strLib: "Texto",
+  $arrayLib: "Arranjo",
+  $langLib: "IV"
+}

+ 3 - 8
grammar/es/ivprog.g4

@@ -1,12 +1,5 @@
 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
 RK_PROGRAM
   : 'programa'
@@ -171,7 +164,9 @@ ID
   : [a-zA-Z_] [a-zA-Z0-9_]*
   ;
 
-// ID_BIBLIOTECA     : ID '.' ID;
+LIB_ID
+  : ID '.' ID
+  ;
 
 INTEGER
   : [0-9]+

+ 33 - 0
grammar/es/langFunctions.js

@@ -0,0 +1,33 @@
+/* This is a dictionary of the language defined functions
+**/
+export default {
+  main_function: "inicio",
+  $read: "leia",
+  $write: "escreva",
+  $numElements: "numero_elementos",
+  $matrixLines: "matriz_linhas",
+  $matrixColumns: "matriz_colunas",
+  $substring: "subcadeia",
+  $length: "comprimento",
+  $uppercase: "caixa_alta",
+  $lowercase: "caixa_baixa",
+  $charAt: "char_at",
+  $isReal: "e_real",
+  $isInt: "e_inteiro",
+  $isBool: "e_logico",
+  $castReal: "como_real",
+  $castInt: "como_inteiro",
+  $castBool: "como_logico",
+  $castString: "como_cadeia",
+  $sin: "sen",
+  $cos: "cos",
+  $tan: "tan",
+  $sqrt: "raiz_quadrada",
+  $pow: "pot",
+  $log: "log",
+  $abs: "modulo",
+  $negate: "trocar_sinal",
+  $invert: "inverter_valor",
+  $max: "maximo",
+  $min: "minimo"
+}

+ 10 - 0
grammar/es/langLibs.js

@@ -0,0 +1,10 @@
+/**
+ * This is the dictionary of the language defined libraries
+ */
+export default {
+  $mathLib: "Matematica",
+  $ioLib: "ES",
+  $strLib: "Texto",
+  $arrayLib: "Arranjo",
+  $langLib: "IV"
+}

+ 9 - 3
grammar/index.js

@@ -1,7 +1,13 @@
 import * as PT from './pt/ivprog.g4';
+import PTFuncs from './pt/langFunctions';
+import PTLibs from './pt/langLibs';
 import * as EN from './en/ivprog.g4';
+import ENFuncs from './en/langFunctions';
+import ENLibs from './en/langLibs';
 import * as ES from './es/ivprog.g4';
+import ESFuncs from './es/langFunctions';
+import ESLibs from './es/langLibs';
 
-exports.pt = PT.ivprog;
-exports.en = EN.ivprog;
-exports.es = ES.ivprog;
+exports.pt = {lexer: PT.ivprog, langFuncs: PTFuncs, langLibs: PTLibs};
+exports.en = {lexer: EN.ivprog, langFuncs: ENFuncs, langLibs: ENLibs};
+exports.es = {lexer: ES.ivprog, langFuncs: ESFuncs, langLibs: ESLibs};

+ 3 - 8
grammar/pt/ivprog.g4

@@ -1,12 +1,5 @@
 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
 RK_PROGRAM
   : 'programa'
@@ -171,7 +164,9 @@ ID
   : [a-zA-Z_] [a-zA-Z0-9_]*
   ;
 
-// ID_BIBLIOTECA     : ID '.' ID;
+LIB_ID
+  : ID '.' ID
+  ;
 
 INTEGER
   : [0-9]+

+ 33 - 0
grammar/pt/langFunctions.js

@@ -0,0 +1,33 @@
+/* This is a dictionary of the language defined functions
+**/
+export default {
+  main_function: "inicio",
+  $read: "leia",
+  $write: "escreva",
+  $numElements: "numero_elementos",
+  $matrixLines: "matriz_linhas",
+  $matrixColumns: "matriz_colunas",
+  $substring: "subcadeia",
+  $length: "comprimento",
+  $uppercase: "caixa_alta",
+  $lowercase: "caixa_baixa",
+  $charAt: "char_at",
+  $isReal: "e_real",
+  $isInt: "e_inteiro",
+  $isBool: "e_logico",
+  $castReal: "como_real",
+  $castInt: "como_inteiro",
+  $castBool: "como_logico",
+  $castString: "como_cadeia",
+  $sin: "sen",
+  $cos: "cos",
+  $tan: "tan",
+  $sqrt: "raiz_quadrada",
+  $pow: "pot",
+  $log: "log",
+  $abs: "modulo",
+  $negate: "trocar_sinal",
+  $invert: "inverter_valor",
+  $max: "maximo",
+  $min: "minimo"
+}

+ 10 - 0
grammar/pt/langLibs.js

@@ -0,0 +1,10 @@
+/**
+ * This is the dictionary of the language defined libraries
+ */
+export default {
+  $mathLib: "Matematica",
+  $ioLib: "ES",
+  $strLib: "Texto",
+  $arrayLib: "Arranjo",
+  $langLib: "IV"
+}

+ 90 - 0
js/assessment/ivprogAssessment.js

@@ -0,0 +1,90 @@
+import { IVProgParser } from "./../ast/ivprogParser";
+import { SemanticAnalyser } from "./../processor/semantic/semanticAnalyser";
+import { IVProgProcessor } from "./../processor/ivprogProcessor";
+import { InputTest } from "./../util/inputTest";
+import { OutputTest } from "./../util/outputTest";
+
+export class IVProgAssessment {
+
+  constructor (textCode, testCases, domConsole) {
+    this.textCode = textCode;
+    this.testCases = testCases;
+    this.domConsole = domConsole;
+  }
+
+  runTest () {
+    const outerRef = this;
+    return new Promise((resolve, _) => {
+      try {
+        // try and show error messages through domconsole
+        const parser = IVProgParser.createParser(outerRef.textCode);
+        const semantic = new SemanticAnalyser(parser.parseTree());
+        const validTree = semantic.analyseTree();
+        // loop test cases and show messages through domconsole
+        const tests = outerRef.testCases.map( (t, name) => {
+          return outerRef.evaluateTestCase(new IVProgProcessor(validTree), t.input, t.output, name);
+        });
+        Promise.all(tests).then(results => {
+          const count = results.reduce((lastValue, nextValue) =>  lastValue + nextValue, 0);
+          resolve(count / outerRef.testCases.length);
+        }).catch(err => {
+          outerRef.domConsole.err("Erro durante a execução do programa");// try and show error messages through domconsole
+          outerRef.domConsole.err(err.message);
+          resolve(0);
+        })
+      } catch (error) {
+        outerRef.domConsole.err("Erro durante a execução do programa");// try and show error messages through domconsole
+        outerRef.domConsole.err(error.message);
+        resolve(0);
+      }
+    });
+  }
+
+  evaluateTestCase (prog, inputList, outputList, name) {
+    const outerThis = this;
+    return new Promise((resolve, reject) => {
+      const input = new InputTest(inputList);
+      const output = new OutputTest();
+      prog.registerInput(input);
+      prog.registerOutput(output);
+      const startTime = Date.now()
+      prog.interpretAST().then( _ => {
+        const millis = Date.now() - startTime;
+        if (input.inputList.length !== input.index) {
+          outerThis.domConsole.err(`Caso de teste ${name + 1}: Falhou, ainda restam entradas!`);
+          outerThis.domConsole.info(`Levou ${millis}ms`);
+          resolve(1 * (input.index/inputList.length));
+        } else if (output.list.length < outputList.length) {
+          outerThis.domConsole.err(`Caso de teste ${name + 1}: Falhou <${inputList.join(", ")};${outputList.join(", ")};${output.list.join(", ")}>`);
+          outerThis.domConsole.info(`Levou ${millis}ms`);
+          resolve(1 * (output.list.length/outputList.length));
+        } else if (output.list.length > outputList.length) {
+          outerThis.domConsole.err(`Caso de teste ${name + 1}: Falhou <${inputList.join(", ")};${outputList.join(", ")};${output.list.join(", ")}>`);
+          outerThis.domConsole.info(`Levou ${millis}ms`);
+          resolve(1 * (outputList.length/output.list.length));
+        } else {
+          const isOk = outerThis.checkOutput(output.list, outputList);
+          if(!isOk) {
+            outerThis.domConsole.err(`Caso de teste ${name + 1}: Falhou <${inputList.join(", ")};${outputList.join(", ")};${output.list.join(", ")}>`);
+            outerThis.domConsole.info(`Levou ${millis}ms`);
+            resolve(0);
+          } else {
+            outerThis.domConsole.info(`Caso de teste ${name + 1}: OK!`);
+            outerThis.domConsole.info(`Levou ${millis}ms`);
+            resolve(1);
+          }
+        }
+      }).catch( _ => resolve(0));
+    })
+  }
+
+  checkOutput (aList, bList) {
+    for (let i = 0; i < aList.length; i++) {
+      const outValue = aList[i];
+      if(outValue != bList[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+}

+ 186 - 37
js/ast/ivprogParser.js

@@ -1,13 +1,22 @@
 import { CommonTokenStream, InputStream } from 'antlr4/index';
 import * as Expressions from './expressions/';
 import * as Commands from './commands/';
-import { Types, toInt, toString } 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';
-import { NAMES } from './../processor/definedFunctions';
+import { LanguageDefinedFunction } from './../processor/definedFunctions';
+import { LanguageService } from '../services/languageService';
 
 export class IVProgParser {
 
+  static createParser (input) {
+    const lexerClass = LanguageService.getCurrentLexer();
+    return new IVProgParser(input, lexerClass);
+  }
+
   // <BEGIN scope consts>
   static get BASE () {
     return 0;
@@ -37,6 +46,7 @@ export class IVProgParser {
     this.functionTypes = this.variableTypes.concat(this.lexerClass.RK_VOID);
     this.parsingArrayDimension = 0;
     this.scope = [];
+    this.langFuncs = LanguageService.getCurrentLangFuncs();
   }
 
   parseTree () {
@@ -204,7 +214,6 @@ export class IVProgParser {
 
   parseGlobalVariables () {
     const decl = this.parseMaybeConst();
-    const eosToken = this.getToken();
     this.checkEOS();
     this.pos++;
     return decl;
@@ -239,7 +248,9 @@ export class IVProgParser {
     let initial = null;
     let dim1 = null;
     let dim2 = null;
+    const idToken = this.getToken();
     const idString = this.parseID();
+    
     // Check for array or vector
     // ID[int/IDi][int/IDj]
     if (this.checkOpenBrace(true)) {
@@ -260,17 +271,26 @@ export class IVProgParser {
     }
 
     const equalsToken = this.getToken();
+    if(isConst && equalsToken.type !== this.lexerClass.EQUAL ) {
+      throw SyntaxErrorFactory.const_not_init(idToken);
+    }
     if(equalsToken.type === this.lexerClass.EQUAL) {
       this.pos++;
       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);
     }
+    declaration.sourceInfo = SourceInfo.createSourceInfo(idToken);
     const commaToken = this.getToken();
     if(commaToken.type === this.lexerClass.COMMA) {
       this.pos++;
@@ -320,21 +340,32 @@ export class IVProgParser {
   **/
   getIntLiteral (token) {
     const text = token.text;
-    return new Expressions.IntLiteral(toInt(text));
+    const sourceInfo = SourceInfo.createSourceInfo(token);
+    const exp = new Expressions.IntLiteral(toInt(text));
+    exp.sourceInfo = sourceInfo;
+    return exp;
   }
 
   getRealLiteral (token) {
-    return new Expressions.RealLiteral(parseFloat(token.text));
+    const sourceInfo = SourceInfo.createSourceInfo(token);
+    const exp = new Expressions.RealLiteral(toReal(token.text));
+    exp.sourceInfo = sourceInfo;
+    return exp;
   }
 
   getStringLiteral (token) {
     const text = token.text;
-    return new Expressions.StringLiteral(toString(text));
+    const sourceInfo = SourceInfo.createSourceInfo(token);
+    const exp = new Expressions.StringLiteral(toString(text));
+    exp.sourceInfo = sourceInfo;
+    return exp;
   }
 
   getBoolLiteral (token) {
-    const val = token.type === this.lexerClass.RK_TRUE ? true : false;
-    return new Expressions.BoolLiteral(val);
+    const val = toBool(token.text);
+    const exp = new Expressions.BoolLiteral(val);
+    exp.sourceInfo = SourceInfo.createSourceInfo(token);;
+    return exp;
   }
 
   parseArrayLiteral () {
@@ -350,6 +381,7 @@ export class IVProgParser {
     const data = this.parseExpressionList();
     this.consumeNewLines();
     this.checkCloseCurly()
+    const endArray = this.getToken();
     this.pos++;
     this.parsingArrayDimension--;
     if (this.parsingArrayDimension === 0) {
@@ -359,7 +391,15 @@ export class IVProgParser {
       //   throw new Error(`Invalid array at line ${beginArray.line}`);
       // }
     }
-    return new Expressions.ArrayLiteral(data);
+    const sourceInfo = SourceInfo.createSourceInfoFromList(beginArray, endArray);
+    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;
   }
 
   /*
@@ -367,7 +407,10 @@ export class IVProgParser {
   * @returns object with fields type and value
   **/
   parseVariable (token) {
-    return new Expressions.VariableLiteral(token.text);
+    const sourceInfo = SourceInfo.createSourceInfo(token);
+    const exp = new Expressions.VariableLiteral(token.text);
+    exp.sourceInfo = sourceInfo;
+    return exp;
   }
 
   /*
@@ -384,7 +427,20 @@ export class IVProgParser {
       return null;
     }
     this.pos++;
-    const returnType = this.parseType();
+    const funType = this.parseType();
+    let dimensions = 0;
+    if(this.checkOpenBrace(true)) {
+      this.pos++;
+      this.checkCloseBrace();
+      this.pos++;
+      dimensions++;
+      if(this.checkOpenBrace(true)) {
+        this.pos++;
+        this.checkCloseBrace();
+        this.pos++;
+        dimensions++;
+      }
+    }
     const functionID = this.parseID();
     this.checkOpenParenthesis();
     this.pos++;
@@ -399,10 +455,14 @@ export class IVProgParser {
     }
     this.consumeNewLines();
     const commandsBlock = this.parseCommandBlock();
+    let returnType = funType;
+    if(dimensions > 0) {
+      returnType = new CompoundType(funType, dimensions);
+    }
     const func = new Commands.Function(functionID, returnType, formalParams, commandsBlock);
     if (functionID === null && !func.isMain) {
       // TODO: better error message
-      throw SyntaxErrorFactory.invalid_main_return(this.lexerClass.MAIN_FUNCTION_NAME,
+      throw SyntaxErrorFactory.invalid_main_return(LanguageDefinedFunction.getMainFunctionName(),
         this.lexer.literalNames[this.lexerClass.RK_VOID],
         token.line);
     }
@@ -432,7 +492,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;
@@ -446,16 +512,25 @@ export class IVProgParser {
     const token = this.getToken();
     if(token.type !== this.lexerClass.ID) {
       throw SyntaxErrorFactory.id_missing(token);
-    } 
+    }
     this.pos++;
     if (this.insideScope(IVProgParser.FUNCTION)) {
-      if (token.text === this.lexerClass.MAIN_FUNCTION_NAME){
+      if (token.text === LanguageDefinedFunction.getMainFunctionName()){
         return null;
       }
     }
     return token.text;
   }
 
+  parseMaybeLibID () {
+    const token = this.getToken();
+    if(token.type !== this.lexerClass.ID && token.type !== this.lexerClass.LIB_ID) {
+      throw SyntaxErrorFactory.id_missing(token);
+    } 
+    this.pos++;
+    return token.text;
+  }
+
   parseType () {
     const token = this.getToken();
     if(token.type === this.lexerClass.ID && this.insideScope(IVProgParser.FUNCTION)) {
@@ -468,7 +543,7 @@ export class IVProgParser {
       switch(token.type) {
         case this.lexerClass.RK_INTEGER:
           return Types.INTEGER;
-        case this.lexerClass.RK_LOGIC:
+        case this.lexerClass.RK_BOOLEAN:
           return Types.BOOLEAN;
         case this.lexerClass.RK_REAL:
           return Types.REAL;
@@ -529,6 +604,8 @@ export class IVProgParser {
       return cmd;
     } else if (token.type === this.lexerClass.ID) {
       return this.parseIDCommand();
+    } else if (token.type === this.lexerClass.LIB_ID) {
+      return this.parseIDCommand();
     } else if (token.type === this.lexerClass.RK_RETURN) {
       return this.parseReturn();
     } else if (token.type === this.lexerClass.RK_WHILE) {
@@ -697,21 +774,56 @@ export class IVProgParser {
   }
 
   parseIDCommand () {
-    const id = this.parseID();
+    const refToken = this.getToken();
+    const isID = refToken.type === this.lexerClass.ID;
+    const id = this.parseMaybeLibID();
+    if(this.checkOpenBrace(true)) {
+      this.pos++;
+      let lineExpression = null;
+      let columnExpression = null;
+      this.consumeNewLines();
+      lineExpression = this.parseExpression()
+      this.consumeNewLines();
+      this.checkCloseBrace();
+      this.pos++;
+      if (this.checkOpenBrace(true)) {
+        this.pos++
+        this.consumeNewLines();
+        columnExpression = this.parseExpression();
+        this.consumeNewLines();
+        this.checkCloseBrace();
+        this.pos++;
+      }
+      const equalToken = this.getToken();
+      if (equalToken.type !== this.lexerClass.EQUAL) {
+        throw SyntaxErrorFactory.token_missing_one('=', equalToken);
+      }
+      this.pos++;
+      const exp = this.parseExpressionOR();
+      this.checkEOS();
+      this.pos++;
+      const cmd = new Commands.ArrayIndexAssign(id, lineExpression, columnExpression, exp);
+      cmd.sourceInfo = SourceInfo.createSourceInfo(equalToken);
+      return cmd;
+    }
     const equalOrParenthesis = this.getToken();
-    if (equalOrParenthesis.type === this.lexerClass.EQUAL) {
+    if (isID && equalOrParenthesis.type === this.lexerClass.EQUAL) {
       this.pos++
       const exp = this.parseExpressionOR();
       this.checkEOS();
       this.pos++;
-      return (new Commands.Assign(id, exp));
+      const cmd = new Commands.Assign(id, exp);
+      cmd.sourceInfo = SourceInfo.createSourceInfo(equalOrParenthesis);
+      return cmd;
     } else if (equalOrParenthesis.type === this.lexerClass.OPEN_PARENTHESIS) {
       const funcCall = this.parseFunctionCallCommand(id);
       this.checkEOS();
       this.pos++;
       return funcCall;
-    } else {
+    } else if (isID) {
       throw SyntaxErrorFactory.token_missing_list(['=','('], equalOrParenthesis);
+    } else {
+      throw SyntaxErrorFactory.invalid_id_format(refToken);
     }
   }
 
@@ -731,7 +843,10 @@ export class IVProgParser {
     if(!isLast) {
       this.consumeForSemiColon();
     }
-    return new Commands.Assign(id, exp);
+    const sourceInfo = SourceInfo.createSourceInfo(equal);
+    const cmd = new Commands.Assign(id, exp);
+    cmd.sourceInfo = sourceInfo;
+    return cmd;
   }
 
   parseCases () {
@@ -793,11 +908,13 @@ export class IVProgParser {
   parseExpressionOR () {
     let exp1 = this.parseExpressionAND();
     while (this.getToken().type === this.lexerClass.OR_OPERATOR) {
+      const opToken = this.getToken();
       this.pos++;
       const or = convertFromString('or');
       this.consumeNewLines();
       const exp2 = this.parseExpressionAND();
       const finalExp = new Expressions.InfixApp(or, exp1, exp2);
+      finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
       exp1 = finalExp
     }
     return exp1;
@@ -806,11 +923,13 @@ export class IVProgParser {
   parseExpressionAND () {
     let exp1 = this.parseExpressionNot();
     while (this.getToken().type === this.lexerClass.AND_OPERATOR) {
+      const opToken = this.getToken();
       this.pos++;
       const and = convertFromString('and');
       this.consumeNewLines();
       const exp2 = this.parseExpressionNot();
       const finalExp = new Expressions.InfixApp(and, exp1, exp2);
+      finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
       exp1 = finalExp;
     }
     return exp1;
@@ -819,10 +938,14 @@ export class IVProgParser {
   parseExpressionNot () {
     const maybeNotToken = this.getToken();
     if (maybeNotToken.type === this.lexerClass.NOT_OPERATOR) {
+      const opToken = this.getToken();
       this.pos++;
       const not = convertFromString('not');
       const exp1 = this.parseExpressionRel();
-      return new Expressions.UnaryApp(not, exp1);
+      finalExp = new Expressions.UnaryApp(not, exp1);
+      finalExp.sourceInfo = SourceInfo.createSourceInfo(opToken);
+      return finalExp;
+      
     } else {
       return this.parseExpressionRel();
     }
@@ -836,6 +959,7 @@ export class IVProgParser {
       const rel = convertFromString(relToken.text);
       const exp2 = this.parseExpression();
       const finalExp = new Expressions.InfixApp(rel, exp1, exp2);
+      finalExp.sourceInfo = SourceInfo.createSourceInfo(relToken);
       exp1 = finalExp;
     }
     return exp1;
@@ -849,6 +973,7 @@ export class IVProgParser {
       const op = convertFromString(sumOpToken.text);
       const factor2 = this.parseFactor();
       const finalExp = new Expressions.InfixApp(op, factor, factor2);
+      finalExp.sourceInfo = SourceInfo.createSourceInfo(sumOpToken);
       factor = finalExp;
     }
     return factor;
@@ -862,6 +987,7 @@ export class IVProgParser {
       const op = convertFromString(multOpToken.text);
       const term2 =this.parseTerm();
       const finalExp = new Expressions.InfixApp(op, term, term2);
+      finalExp.sourceInfo = SourceInfo.createSourceInfo(multOpToken);
       term = finalExp;
     }
     return term;
@@ -869,10 +995,14 @@ export class IVProgParser {
 
   parseTerm () {
     const token = this.getToken();
+    let sourceInfo = null;
     switch(token.type) {
       case this.lexerClass.SUM_OP:
         this.pos++;
-        return new Expressions.UnaryApp(convertFromString(token.text), this.parseTerm());
+        sourceInfo = SourceInfo.createSourceInfo(token);
+        const exp = new Expressions.UnaryApp(convertFromString(token.text), this.parseTerm());
+        exp.sourceInfo = sourceInfo;
+        return exp;
       case this.lexerClass.INTEGER:
         this.pos++;
         return this.getIntLiteral(token);
@@ -889,6 +1019,7 @@ export class IVProgParser {
       case this.lexerClass.OPEN_CURLY:
         return this.parseArrayLiteral();
       case this.lexerClass.ID:
+      case this.lexerClass.LIB_ID:
         return this.parseIDTerm();
       case this.lexerClass.OPEN_PARENTHESIS:
         return this.parseParenthesisExp();
@@ -898,47 +1029,61 @@ export class IVProgParser {
   }
 
   parseIDTerm () {
-    const id = this.parseID();
-    const last = this.pos;
-    if(this.checkOpenBrace(true)) {
+    const tokenA = this.getToken();
+    const id = this.parseMaybeLibID();
+    const isID = tokenA.type === this.lexerClass.ID;
+    if(isID && this.checkOpenBrace(true)) {
+      let tokenB = null;
       this.pos++;
       const firstIndex = this.parseExpression();
       let secondIndex = null;
       this.consumeNewLines();
       this.checkCloseBrace();
+      tokenB = this.getToken();
       this.pos++;
       if(this.checkOpenBrace(true)){
         this.pos++;
         secondIndex = this.parseExpression();
         this.consumeNewLines();
         this.checkCloseBrace();
+        tokenB = this.getToken();
         this.pos++;
       }
-
-      return new Expressions.ArrayAccess(id, firstIndex, secondIndex);
+      const sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB); 
+      const exp = new Expressions.ArrayAccess(id, firstIndex, secondIndex);
+      exp.sourceInfo = sourceInfo;
+      return exp;
 
     } else if (this.checkOpenParenthesis(true)) {
       return this.parseFunctionCallExpression(id);
+    } else if (isID) {
+      const sourceInfo = SourceInfo.createSourceInfo(tokenA);
+      const exp = new Expressions.VariableLiteral(id);
+      exp.sourceInfo = sourceInfo;
+      return exp;
     } else {
-      this.pos = last;
-      return new Expressions.VariableLiteral(id);
+      throw SyntaxErrorFactory.invalid_id_format(tokenA);
     }
   }
 
   getFunctionName (id) {
-    if (id === this.lexerClass.READ_FUNCTION_NAME) {
-      return NAMES.READ;
-    } else if (id === this.lexerClass.WRITE_FUNCTION_NAME) {
-      return NAMES.WRITE;
-    } else {
+    const name = LanguageDefinedFunction.getInternalName(id);
+    if (name === null) {
       return id;
+    } else {
+      return name;
     }
   }
 
   parseFunctionCallExpression (id) {
+    const tokenA = this.getToken(this.pos - 1);
     const actualParameters = this.parseActualParameters();
+    const tokenB = this.getToken(this.pos - 1);
     const funcName = this.getFunctionName(id);
-    return new Expressions.FunctionCall(funcName, actualParameters);
+    const sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
+    const cmd = new Expressions.FunctionCall(funcName, actualParameters);
+    cmd.sourceInfo = sourceInfo;
+    return cmd;
   }
 
   parseFunctionCallCommand (id) {
@@ -947,12 +1092,16 @@ export class IVProgParser {
 
   parseParenthesisExp () {
     this.checkOpenParenthesis();
+    const tokenA = this.getToken();
     this.pos++;
     this.consumeNewLines();
     const exp = this.parseExpressionOR();
     this.consumeNewLines();
     this.checkCloseParenthesis();
+    const tokenB = this.getToken();
+    const sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
     this.pos++;
+    exp.sourceInfo = sourceInfo;
     return exp;
   }
 

+ 22 - 0
js/ast/sourceInfo.js

@@ -0,0 +1,22 @@
+export class SourceInfo {
+
+  static createSourceInfo (token) {
+    return new SourceInfo(token.line, token.column, token.text.length);
+  }
+
+  static createSourceInfoFromList (tokenA, tokenB) {
+    const line = tokenA.line;
+    const column = tokenA.column;
+    // copied from https://github.com/UNIVALI-LITE/Portugol-Studio/blob/master/core/src/main/java/br/univali/portugol/nucleo/analise/sintatica/Portugol.g
+    // No idea why...
+    const size = tokenB.tokenIndex + 1 - tokenA.tokenIndex
+    return new SourceInfo(line, column, size);
+  }
+
+  constructor (line, column, size) {
+    this.line = line;
+    this.column = column;
+    this.size = size;
+  }
+
+}

+ 5 - 2
js/main-sidebar.js

@@ -1,10 +1,13 @@
 import { runner } from './runner';
 import { initVisualUI } from './visualUI/functions_sidebar';
-import { LocalizedStrings, StringTypes } from './services/localizedStringsService';
+import { LocalizedStrings} from './services/localizedStringsService';
+import line_i18n from 'line-i18n';
+
+const StringTypes = line_i18n.StringTypes;
 
 export {
   runner,
   initVisualUI,
   LocalizedStrings,
   StringTypes
-}
+}

+ 36 - 2
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,7 +124,37 @@ const unaryMap = buildUnaryCompatibilityTable();
 
 export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpressionType) {
   try {
-    return infixMap.get(operator)[leftExpressionType.ord][rightExpressionType.ord];
+    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
+    }
+    return resultType;
   } catch (e) {
     if (e instanceof TypeError) {
       return Types.UNDEFINED;
@@ -135,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) {

+ 109 - 21
js/processor/definedFunctions.js

@@ -1,28 +1,116 @@
-import * as Commands from './../ast/commands';
-import {Types} from './../ast/types';
+import { LanguageService } from '../services/languageService';
+import {createInputFun, createOutputFun} from './lib/io';
+import {createLengthFun, createLowercaseFun,
+  createrCharAtFun, createSubstringFun,
+  createUppercaseFun} from './lib/strings';
+import {createMatrixColumnsFun, createMatrixLinesFun,
+  createNumElementsFun} from './lib/arrays';
+import {createCastBoolFun, createCastIntFun,
+  createCastRealFun, createCastStringFun,
+  createIsBoolFun, createIsIntFun,
+  createIsRealFun} from './lib/lang';
+import {createAbsFun, createCosFun,
+  createInvertFun, createLogFun,
+  createMaxFun, createMinFun,
+  createNegateFun, createPowFun,
+  createSinFun, createSqrtFun,
+  createTanFun} from './lib/math';
 
-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, false)],
-    block);
-  return func;
+function valueToKey (value, object) {
+  for (const key in object) {
+    if(object.hasOwnProperty(key)){
+      if (object[key] === value) {
+        return key;
+      }
+    }
+  }
+  return null;
 }
 
-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;
+function concatObjects (...objs) {
+  let result = {};
+  for (let i = 0; i < objs.length; i++) {
+    const obj = objs[i];
+    for(const key in obj) {
+      if(obj.hasOwnProperty(key)) {
+        result[key] = obj[key];
+      }
+    }
+  }
+  return result;
 }
 
-export const LanguageDefinedFunction = Object.freeze({
-  $write: createOutputFun(),
-  $read: createInputFun()
-});
+const libsObject = {
+  $mathLib: {
+    $sin: createSinFun(),
+    $cos: createCosFun(),
+    $tan: createTanFun(),
+    $sqrt: createSqrtFun(),
+    $pow: createPowFun(),
+    $log: createLogFun(),
+    $abs: createAbsFun(),
+    $negate: createNegateFun(),
+    $invert: createInvertFun(),
+    $max: createMaxFun(),
+    $min: createMinFun()
+  },
+  $ioLib: {
+    $read: createInputFun(),
+    $write: createOutputFun()
+  },
+  $strLib: {
+    $substring: createSubstringFun(),
+    $length: createLengthFun(),
+    $uppercase: createUppercaseFun(),
+    $lowercase: createLowercaseFun(),
+    $charAt: createrCharAtFun(),
+  },
+  $arrayLib: {
+    $numElements: createNumElementsFun(),
+    $matrixLines: createMatrixLinesFun(),
+    $matrixColumns: createMatrixColumnsFun()
+  },
+  $langLib: {
+    $isReal: createIsRealFun(),
+    $isInt: createIsIntFun(),
+    $isBool: createIsBoolFun(),
+    $castReal: createCastRealFun(),
+    $castInt: createCastIntFun(),
+    $castBool: createCastBoolFun(),
+    $castString: createCastStringFun()
+  }
+}
 
-export const NAMES = Object.freeze({
-  WRITE: '$write',
-  READ: '$read'
+const funcsObject = concatObjects(libsObject.$ioLib, libsObject.$langLib,
+  libsObject.$strLib, libsObject.$arrayLib);
+
+export const LanguageDefinedFunction = Object.freeze({
+  getMainFunctionName: () => LanguageService.getCurrentLangFuncs().main_function,
+  getInternalName: (localName) => {
+    if (localName.indexOf(".") !== -1) {
+      const names = localName.split(".");
+      const lib = valueToKey(names[0], LanguageService.getCurrentLangLibs());
+      const internalName = valueToKey(names[1], LanguageService.getCurrentLangFuncs());
+      if (lib === null || internalName === null) {
+        return null;
+      }
+      return lib + "." + internalName;
+    }
+    const funcName = valueToKey(localName, LanguageService.getCurrentLangFuncs());
+    if(funcName !== null) {
+      if(funcsObject[funcName]) {
+        return funcName;
+      }
+    }
+    return null;
+  },
+  getFunction: (internalName) => {
+    if (internalName.indexOf(".") !== -1) {
+      const names = internalName.split(".");
+      const libName = names[0];
+      const funName = names[1];
+      return libsObject[libName][funName];
+    }
+    return funcsObject[internalName];
+  },
 });

+ 352 - 194
js/processor/ivprogProcessor.js

@@ -4,29 +4,49 @@ 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 { Types } from './../typeSystem/types';
 import { Operators } from './../ast/operators';
-import { NAMES, LanguageDefinedFunction } from './definedFunctions';
+import { LanguageDefinedFunction } from './definedFunctions';
 import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from './compatibilityTable';
 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';
+import { convertToString } from '../typeSystem/parsers';
+
+let loopTimeoutMs = 10000
 
 export class IVProgProcessor {
 
+  static get LOOP_TIMEOUT () {
+    return loopTimeoutMs;
+  }
+
+  static set LOOP_TIMEOUT (ms) {
+    loopTimeoutMs = ms;
+  }
+
   constructor (ast) {
     this.ast = ast;
-    this.globalStore = new Store();
-    this.stores = [this.globalStore];
-    this.context = [Context.BASE];
+    this.globalStore = null;
+    this.stores = null;
+    this.context = null;
     this.input = null;
+    this.forceKill = false;
+    this.loopTimers = [];
     this.output = null;
   }
 
   registerInput (input) {
+    if(this.input !== null)
+      this.input = null;
     this.input = input;
   }
 
   registerOutput (output) {
+    if(this.output !== null)
+      this.output = null;
     this.output = output;
   }
 
@@ -44,7 +64,22 @@ export class IVProgProcessor {
     }
   }
 
+  prepareState () {
+    if(this.stores !== null) {
+      for (let i = 0; i < this.stores.length; i++) {
+        delete this.stores[i];
+      }
+      this.stores = null;
+    }
+    if(this.globalStore !== null)
+      this.globalStore = null;
+    this.globalStore = new Store();
+    this.stores = [this.globalStore];
+    this.context = [Context.BASE];
+  }
+
   interpretAST () {
+    this.prepareState();
     this.initGlobal();
     const mainFunc = this.findMainFunction();
     if(mainFunc === null) {
@@ -69,7 +104,7 @@ export class IVProgProcessor {
 
   findFunction (name) {
     if(name.match(/^\$.+$/)) {
-      const fun = LanguageDefinedFunction[name];
+      const fun = LanguageDefinedFunction.getFunction(name);
       if(!!!fun) {
         throw new Error("!!!Internal Error. Language defined function not implemented -> " + name + "!!!");
       }
@@ -87,7 +122,16 @@ export class IVProgProcessor {
   runFunction (func, actualParameters, store) {
     let funcStore = new Store();
     funcStore.extendStore(this.globalStore);
-    const returnStoreObject = new StoreObject(func.returnType, null);
+    let returnStoreObject = null;
+    if(func.returnType instanceof CompoundType) {
+      if(func.returnType.dimensions > 1) {
+        returnStoreObject = new StoreObjectArray(func.returnType,-1,-1,[[]]);
+      } else {
+        returnStoreObject = new StoreObjectArray(func.returnType,-1,null,[]);
+      }
+    } else {
+      returnStoreObject = new StoreObject(func.returnType, null);
+    }
     const funcName = func.isMain ? 'main' : func.name;
     const funcNameStoreObject = new StoreObject(Types.STRING, funcName, true);
     funcStore.insertStore('$', returnStoreObject);
@@ -115,68 +159,25 @@ 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 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;
+        if(formalParameter.type.isCompatible(stoObj.type)) {
+          if(formalParameter.byRef && !stoObj.inStore) {
+            throw new Error('You must inform a variable as parameter');
           }
-          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);
-              }
 
+          if(formalParameter.byRef) {
+            let ref = null;
+            if (stoObj instanceof StoreObjectArrayAddress) {
+              ref = new StoreObjectArrayAddressRef(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);
-                calleeStore.insertStore(formalParameter.id, ref);
-              } else {
-                calleeStore.insertStore(formalParameter.id, stoObj);
-              }
-
+              ref = new StoreObjectRef(stoObj.id, callerStore);
             }
+            calleeStore.insertStore(formalParameter.id, ref);
+          } else {
+            let realValue = this.parseStoreObjectValue(stoObj);
+            calleeStore.insertStore(formalParameter.id, realValue);
           }
+        } else {
+          throw new Error(`Parameter ${formalParameter.id} is not compatible with the value given.`);
         }
       }
       return calleeStore;
@@ -185,20 +186,21 @@ export class IVProgProcessor {
 
   executeCommands (store, cmds) {
     // helper to partially apply a function, in this case executeCommand
+    const outerRef = this;
     const partial = (fun, cmd) => (sto) => fun(sto, cmd);
     return cmds.reduce((lastCommand, next) => {
-      const nextCommand = partial(this.executeCommand.bind(this), next);
+      const nextCommand = partial(outerRef.executeCommand.bind(outerRef), next);
       return lastCommand.then(nextCommand);
     }, Promise.resolve(store));
   }
 
   executeCommand (store, cmd) {
 
-    while (store.mode === Modes.PAUSE) {
-      continue;
-    }
-
-    if(store.mode === Modes.RETURN) {
+    if(this.forceKill) {
+      return Promise.reject("Interrupção forçada do programa!");
+    } else if (store.mode === Modes.PAUSE) {
+      return Promise.resolve(this.executeCommand(store, cmd));
+    } else if(store.mode === Modes.RETURN) {
       return Promise.resolve(store);
     } else if(this.checkContext(Context.BREAKABLE) && store.mode === Modes.BREAK) {
       return Promise.resolve(store);
@@ -206,6 +208,8 @@ export class IVProgProcessor {
 
     if (cmd instanceof Commands.Declaration) {
       return this.executeDeclaration(store, cmd);
+    } else if (cmd instanceof Commands.ArrayIndexAssign) {
+      return this.executeArrayIndexAssign(store, cmd);
     } else if (cmd instanceof Commands.Assign) {
       return this.executeAssign(store, cmd);
     } else if (cmd instanceof Commands.Break) {
@@ -232,48 +236,21 @@ export class IVProgProcessor {
   }
 
   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);
-    });
+    const func = cmd.langFunc.bind(this);
+    return func(store, cmd);
   }
 
   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));
-    }); 
+    const func = this.findFunction(cmd.id);
+    return this.runFunction(func, cmd.actualParameters, store)
+      .then(sto => {
+        if(!Types.VOID.isCompatible(func.returnType) && sto.mode !== Modes.RETURN) {
+          // TODO: better error message
+          return Promise.reject(new Error(`Function ${func.name} must have a return command`));
+        } else {
+          return store;
+        }
+      })
   }
 
   executeSwitch (store, cmd) {
@@ -343,62 +320,89 @@ export class IVProgProcessor {
   }
 
   executeDoWhile (store, cmd) {
+    const outerRef = this;
     try {
-      this.context.push(Context.BREAKABLE);
-      const $newStore = this.executeCommands(store, cmd.commands);
+      outerRef.loopTimers.push(Date.now());
+      outerRef.context.push(Context.BREAKABLE);
+      const $newStore = outerRef.executeCommands(store, cmd.commands);
       return $newStore.then(sto => {
         if(sto.mode === Modes.BREAK) {
-          this.context.pop();
+          outerRef.context.pop();
           sto.mode = Modes.RUN;
-          return Promise.resolve(sto);
+          outerRef.loopTimers.pop();
+          return sto;
         }
-        const $value = this.evaluateExpression(sto, cmd.expression);
+        const $value = outerRef.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`));
           }
           if (vl.value) {
-            this.context.pop();
-            return this.executeCommand(sto, cmd);
+            outerRef.context.pop();
+            for (let i = 0; i < outerRef.loopTimers.length; i++) {
+              const time = outerRef.loopTimers[i];
+              if(Date.now() - time >= IVProgProcessor.LOOP_TIMEOUT) {
+                console.log("Kill by Timeout...");
+                outerRef.forceKill = true;
+                return Promise.reject(new Error("Potential endless loop detected."));
+              }
+            }
+            return outerRef.executeCommand(sto, cmd);
           } else {
-            this.context.pop();
-            return Promise.resolve(sto);
+            outerRef.context.pop();
+            outerRef.loopTimers.pop();
+            console.log("Clear Timeout...");
+            return sto;
           }
-        });
-      });
+        })
+      })
     } catch (error) {
-      return Promise.reject(error)
+      return Promise.reject(error);
     }
   }
 
   executeWhile (store, cmd) {
+    const outerRef = this;
     try {
-      this.context.push(Context.BREAKABLE);
-      const $value = this.evaluateExpression(store, cmd.expression);
+      outerRef.loopTimers.push(Date.now());
+      outerRef.context.push(Context.BREAKABLE);
+      const $value = outerRef.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);
+            const $newStore = outerRef.executeCommands(store, cmd.commands);
             return $newStore.then(sto => {
-              this.context.pop();
+              outerRef.context.pop();
               if (sto.mode === Modes.BREAK) {
+                outerRef.loopTimers.pop();
                 sto.mode = Modes.RUN;
-                return Promise.resolve(sto);
+                return sto;
               }
-              return this.executeCommand(sto, cmd);
+              for (let i = 0; i < outerRef.loopTimers.length; i++) {
+                const time = outerRef.loopTimers[i];
+                if(Date.now() - time >= IVProgProcessor.LOOP_TIMEOUT) {
+                  console.log("Kill by Timeout...");
+                  outerRef.forceKill = true;
+                  return Promise.reject(new Error("Potential endless loop detected."));
+                }
+              }
+              return outerRef.executeCommand(sto, cmd);
             });
           } else {
-            this.context.pop();
-            return Promise.resolve(store);
+            outerRef.context.pop();
+            outerRef.loopTimers.pop();
+            console.log("Clear Timeout...");
+            return 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);
     }
@@ -408,7 +412,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){
@@ -438,16 +442,17 @@ 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}.`));
         } else {
-          store.updateStore('$', vl);
+          let realValue = this.parseStoreObjectValue(vl);
+          store.updateStore('$', realValue);
           store.mode = Modes.RETURN;
           return Promise.resolve(store);
         }
@@ -470,7 +475,8 @@ export class IVProgProcessor {
     try {
       const $value = this.evaluateExpression(store, cmd.expression);
       return $value.then( vl => {
-        store.updateStore(cmd.id, vl) 
+        let realValue = this.parseStoreObjectValue(vl);
+        store.updateStore(cmd.id, realValue) 
         return store;
       });
     } catch (error) {
@@ -478,6 +484,64 @@ export class IVProgProcessor {
     }
   }
 
+  executeArrayIndexAssign (store, cmd) {
+    const mustBeArray = store.applyStore(cmd.id);
+    if(!(mustBeArray.type instanceof CompoundType)) {
+      return Promise.reject(new Error(cmd.id + " is not a vector/matrix"));
+    }
+    const line$ = this.evaluateExpression(store, cmd.line);
+    const column$ = this.evaluateExpression(store, cmd.column);
+    const value$ =  this.evaluateExpression(store, cmd.expression);
+    return Promise.all([line$, column$, value$]).then(results => {
+      const lineSO = results[0];
+      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"));
+      }
+      const line = lineSO.number;
+      const columnSO = results[1];
+      let column = null
+      if (columnSO !== null) {
+        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"));
+        }
+        column = columnSO.number;
+      }
+      const value = this.parseStoreObjectValue(results[2]);
+      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}`));
+      }
+
+      const newArray = Object.assign(new StoreObjectArray(null,null,null), mustBeArray);
+      if (column !== null) {
+        if (value.type instanceof CompoundType) {
+          return Promise.reject(new Error("Invalid operation. This must be a value: line "+cmd.sourceInfo.line));
+        }
+        newArray.value[line].value[column] = value;
+        store.updateStore(cmd.id, newArray);
+      } else {
+        if(mustBeArray.columns !== null && value.type instanceof CompoundType) {
+          return Promise.reject(new Error("Invalid operation. This must be a vector: line "+cmd.sourceInfo.line));
+        }
+        newArray.value[line] = value;
+        store.updateStore(cmd.id, newArray);
+      }
+      return store;
+    });
+  }
+
   executeDeclaration (store, cmd) {
     try {
       const $value = this.evaluateExpression(store, cmd.initial);
@@ -486,37 +550,65 @@ 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"));
           }
-          const line = lineSO.value;
+          const line = lineSO.number;
           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"));
             }
-            column = columnSO.value;
+            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);
           store.insertStore(cmd.id, temp);
-          if(value !== null) {
-            store.updateStore(cmd.id, value);
+          let realValue = value;
+          if (value !== null) {
+            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);
+              }
+            }
+          } else {
+            realValue = new StoreObjectArray(cmd.type, line, column, [])
+            if(column !== null) {
+              for (let i = 0; i < line; i++) {
+                realValue.value.push(new StoreObjectArray(new CompoundType(cmd.type.innerType, 1), column, null, []));
+              }
+            }
           }
+          realValue.readOnly = cmd.isConst;
+          store.updateStore(cmd.id, realValue);
           return store;
         });
         
       } else {
-        const temp = new StoreObject(cmd.type, null, cmd.isConst);
+        const temp = new StoreObject(cmd.type, null);
         store.insertStore(cmd.id, temp);
         return $value.then(vl => {
-          if (vl !== null)
-            store.updateStore(cmd.id, vl)
+          let realValue = vl;
+          if (vl !== null) {
+            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);
+              }
+            }
+          } else {
+            realValue = new StoreObject(cmd.type,0);
+          }
+          realValue.readOnly = cmd.isConst;
+          store.updateStore(cmd.id, realValue);
           return store;
         });
       }
@@ -548,20 +640,22 @@ export class IVProgProcessor {
     } 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) {
+    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 => {
+      if(sto.mode !== Modes.RETURN) {
+        return Promise.reject(new Error("The function that was called did not had a return command: "+exp.id));
+      }
       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));
@@ -573,7 +667,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
@@ -581,7 +676,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
@@ -597,7 +693,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)
+      });
     } ));
   }
 
@@ -608,7 +707,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));
@@ -620,8 +719,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);
@@ -629,20 +729,20 @@ 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"));
       }
-      const line = lineSO.value;
+      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"));
         }
-        column = columnSO.value;
+        column = columnSO.number;
       }
 
       if (line >= mustBeArray.lines) {
@@ -657,12 +757,7 @@ export class IVProgProcessor {
         // 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]);
-      }
+      return Promise.resolve(new StoreObjectArrayAddress(mustBeArray.id, line, column, store));
     });
   }
 
@@ -670,15 +765,15 @@ 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}`));
       }
       switch (unaryApp.op.ord) {
         case Operators.ADD.ord:
-          return new StoreObject(resultType, +left.value);
+          return new StoreObject(resultType, left.value);
         case Operators.SUB.ord:
-          return new StoreObject(resultType, -left.value);
+          return new StoreObject(resultType, left.value.negated());
         case Operators.NOT.ord:
           return new StoreObject(resultType, !left.value);
         default:
@@ -694,42 +789,85 @@ 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 op to ${left.type} and ${right.type}`));
+        return Promise.reject(new Error(`Cannot use this ${infixApp.op} to ${left.type} and ${right.type}`));
       }
       let result = null;
       switch (infixApp.op.ord) {
-        case Operators.ADD.ord:
-          return new StoreObject(resultType, left.value + right.value);
-        case Operators.SUB.ord:
-          return new StoreObject(resultType, left.value - right.value);
-        case Operators.MULT.ord: {
-          result = left.value * right.value;
-          if (resultType === Types.INTEGER)
-            result = Math.trunc(result);
-          return new StoreObject(resultType, result);
+        case Operators.ADD.ord: {
+          if(Types.STRING.isCompatible(left.type)) {
+            const rightStr = convertToString(right.value, right.type);
+            return new StoreObject(resultType, left.value + rightStr);
+          } else if (Types.STRING.isCompatible(right.type)) {
+            const leftStr = convertToString(left.value, left.type);
+            return new StoreObject(resultType, leftStr + right.value);
+          } else {
+            return new StoreObject(resultType, left.value.plus(right.value));
+          }
         }
+        case Operators.SUB.ord:
+          return new StoreObject(resultType, left.value.minus(right.value));
+        case Operators.MULT.ord:
+          return new StoreObject(resultType, left.value.times(right.value));
         case Operators.DIV.ord: {
           result = left.value / right.value;
-          if (resultType === Types.INTEGER)
-            result = Math.trunc(result);
+          if (Types.INTEGER.isCompatible(resultType))
+            result = left.value.divToInt(right.value);
+          else
+            result = left.value.div(right.value);
           return new StoreObject(resultType, result);
         }
         case Operators.MOD.ord:
-          return new StoreObject(resultType, left.value % right.value);
-        case Operators.GT.ord:
-          return new StoreObject(resultType, left.value > right.value);
-        case Operators.GE.ord:
-          return new StoreObject(resultType, left.value >= right.value);
-        case Operators.LT.ord:
-          return new StoreObject(resultType, left.value < right.value);
-        case Operators.LE.ord:
-          return new StoreObject(resultType, left.value <= right.value);
-        case Operators.EQ.ord:
-          return new StoreObject(resultType, left.value === right.value);
-        case Operators.NEQ.ord:
-          return new StoreObject(resultType, left.value !== right.value);
+          return new StoreObject(resultType, left.value.modulo(right.value));
+        case Operators.GT.ord: {
+          if (Types.STRING.isCompatible(left.type)) {
+            result = left.value.length > right.value.length;
+          } else {
+            result = left.value.gt(right.value);
+          }
+          return new StoreObject(resultType, result);
+        }
+        case Operators.GE.ord: {
+          if (Types.STRING.isCompatible(left.type)) {
+            result = left.value.length >= right.value.length;
+          } else {
+            result = left.value.gte(right.value);
+          }
+          return new StoreObject(resultType, result);
+        }
+        case Operators.LT.ord: {
+          if (Types.STRING.isCompatible(left.type)) {
+            result = left.value.length < right.value.length;
+          } else {
+            result = left.value.lt(right.value);
+          }
+          return new StoreObject(resultType, result);
+        }
+        case Operators.LE.ord: {
+          if (Types.STRING.isCompatible(left.type)) {
+            result = left.value.length <= right.value.length;
+          } else {
+            result = left.value.lte(right.value);
+          }
+          return new StoreObject(resultType, result);
+        }
+        case Operators.EQ.ord: {
+          if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
+            result = left.value.eq(right.value);
+          } else {
+            result = left.value === right.value;
+          }
+          return new StoreObject(resultType, result);
+        }
+        case Operators.NEQ.ord: {
+          if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
+            result = !left.value.eq(right.value);
+          } else {
+            result = left.value !== right.value;
+          }
+          return new StoreObject(resultType, result);
+        }
         case Operators.AND.ord:
           return new StoreObject(resultType, left.value && right.value);
         case Operators.OR.ord:
@@ -740,4 +878,24 @@ export class IVProgProcessor {
     });
   }
 
+  parseStoreObjectValue (vl) {
+    let realValue = vl;
+    if(vl instanceof StoreObjectArrayAddress) {      
+      if(vl.type instanceof CompoundType) {
+        switch(vl.type.dimensions) {
+          case 1: {
+            realValue = new StoreObjectArray(vl.type, vl.value);
+            break;
+          }
+          default: {
+            throw new Error("Three dimensional array address...");
+          }
+        }
+      } else {
+        realValue = new StoreObject(vl.type, vl.value);
+      }
+    }
+    return realValue;
+  }
+
 }

+ 58 - 0
js/processor/lib/arrays.js

@@ -0,0 +1,58 @@
+import { StoreObject } from '../store/storeObject';
+import * as Commands from './../../ast/commands';
+import { Types } from './../../typeSystem/types';
+import { toInt } from "./../../typeSystem/parsers";
+import { CompoundType } from '../../typeSystem/compoundType';
+import { Modes } from '../modes';
+
+/**
+ * num_elements
+ * matrix_lines
+ * matrix_columns
+ */
+
+export function createNumElementsFun () {
+  const numElementsFun = (sto, _) => {
+    const vector  = sto.applyStore("vector");
+    const temp = new StoreObject(Types.INTEGER, toInt(vector.lines));
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(numElementsFun)]);
+  const func = new Commands.Function('$numElements', Types.INTEGER,
+    [new Commands.FormalParameter(new CompoundType(Types.ALL, 1), 'vector', false)],
+    block);
+  return func;
+ }
+
+export function createMatrixLinesFun () {
+  const matrixLinesFun = (sto, _) => {
+    const matrix  = sto.applyStore("matrix");
+    const temp = new StoreObject(Types.INTEGER, toInt(matrix.lines));
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(matrixLinesFun)]);
+  const func = new Commands.Function('$matrixLines', Types.INTEGER,
+    [new Commands.FormalParameter(new CompoundType(Types.ALL, 2), 'matrix', false)],
+    block);
+  return func;
+ }
+
+export function createMatrixColumnsFun () {
+  const matrixColumnsFun = (sto, _) => {
+    const matrix  = sto.applyStore("matrix");
+    const temp = new StoreObject(Types.INTEGER, toInt(matrix.columns));
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(matrixColumnsFun)]);
+  const func = new Commands.Function('$matrixColumns', Types.INTEGER,
+    [new Commands.FormalParameter(new CompoundType(Types.ALL, 2), 'matrix', false)],
+    block);
+  return func;
+ }
+ 

+ 57 - 0
js/processor/lib/io.js

@@ -0,0 +1,57 @@
+import { StoreObject } from './../store/storeObject';
+import * as Commands from './../../ast/commands';
+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.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);
+    }
+    return Promise.resolve(store);
+  }
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(writeFunction)]);
+  const func = new Commands.Function('$write', Types.VOID,
+    [new Commands.FormalParameter(Types.ALL, 'p1', false)],
+    block);
+  return func;
+}
+
+export function createInputFun () {
+  const readFunction = function (store, _) {
+    const request = new Promise((resolve, _) => {
+      this.input.requestInput(resolve);
+    });
+    return request.then(text => {
+      const typeToConvert = store.applyStore('p1').type;
+      let stoObj = null;
+      if (typeToConvert.isCompatible(Types.INTEGER)) {
+        const val = toInt(text);
+        stoObj = new StoreObject(Types.INTEGER, val);
+      } else if (typeToConvert.isCompatible(Types.REAL)) {
+        stoObj = new StoreObject(Types.REAL, toReal(text));
+      } else if (typeToConvert.isCompatible(Types.BOOLEAN)) {
+        stoObj = new StoreObject(Types.BOOLEAN, toBool(text));
+      } else if (typeToConvert.isCompatible(Types.STRING)) {
+        stoObj = new StoreObject(Types.STRING, toString(text));
+      }
+      this.loopTimers.splice(0,this.loopTimers.length)
+      store.updateStore('p1', stoObj);
+      return Promise.resolve(store);
+    });
+  }
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(readFunction)]);
+  const func = new Commands.Function('$read', Types.VOID,
+    [new Commands.FormalParameter(Types.ALL, 'p1', true)],
+    block);
+  return func;
+}

+ 188 - 0
js/processor/lib/lang.js

@@ -0,0 +1,188 @@
+import { StoreObject } from '../store/storeObject';
+import * as Commands from './../../ast/commands';
+import { Types } from './../../typeSystem/types';
+import { toReal, convertToString } from "./../../typeSystem/parsers";
+import { IVProgParser } from '../../ast/ivprogParser';
+import { RealLiteral, IntLiteral, BoolLiteral } from '../../ast/expressions';
+import { Modes } from '../modes';
+
+/**
+ * 
+ * is_real
+ * is_int
+ * is_bool
+ * cast_real
+ * cast_int
+ * cast_bool
+ * cast_string
+ */
+
+export function createIsRealFun () {
+  const isRealFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const parser = IVProgParser.createParser(str.value);
+    let result = false;
+    try {
+      const val = parser.parseTerm();
+      if (val instanceof RealLiteral) {
+        result = true;
+      }
+    } catch (error) { }
+    const temp = new StoreObject(Types.BOOLEAN, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(isRealFun)]);
+  const func = new Commands.Function('$isReal', Types.BOOLEAN,
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
+    block);
+  return func;
+}
+
+export function createIsIntFun () {
+  const isIntFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const parser = IVProgParser.createParser(str.value);
+    let result = false;
+    try {
+      const val = parser.parseTerm();
+      if (val instanceof IntLiteral) {
+        result = true;
+      }
+    } catch (error) { }
+    const temp = new StoreObject(Types.BOOLEAN, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(isIntFun)]);
+  const func = new Commands.Function('$isInt', Types.BOOLEAN,
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
+    block);
+  return func;
+}
+
+export function createIsBoolFun () {
+  const isBoolFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const parser = IVProgParser.createParser(str.value);
+    let result = false;
+    try {
+      const val = parser.parseTerm();
+      if (val instanceof BoolLiteral) {
+        result = true;
+      }
+    } catch (error) { }
+    const temp = new StoreObject(Types.BOOLEAN, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(isBoolFun)]);
+  const func = new Commands.Function('$isBool', Types.BOOLEAN,
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
+    block);
+  return func;
+}
+
+export function createCastRealFun () {
+  const castRealFun = (sto, _) => {
+    const val = sto.applyStore("val");
+    switch (val.type.ord) {
+      case Types.INTEGER.ord: {
+        const temp = new StoreObject(Types.REAL, toReal(val.number));
+        sto.mode = Modes.RETURN;
+        return Promise.resolve(sto.updateStore("$", temp));
+      }
+      case Types.STRING.ord: {
+        const parser = IVProgParser.createParser(val.value);
+        try {
+          const result = parser.parseTerm();
+          if (result instanceof RealLiteral) {
+            const temp = new StoreObject(Types.REAL, result.value);
+            sto.mode = Modes.RETURN;
+            return Promise.resolve(sto.updateStore("$", temp));
+          }
+        } catch (error) { 
+          return Promise.reject("cannot convert string to real");
+        }
+      }
+    }
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(castRealFun)]);
+  const func = new Commands.Function('$castReal', Types.REAL,
+    [new Commands.FormalParameter(Types.ALL, 'val', false)],
+    block);
+  return func;
+}
+
+export function createCastIntFun () {
+  const castIntFun = (sto, _) => {
+    const val = sto.applyStore("val");
+    switch (val.type.ord) {
+      case Types.REAL.ord: {
+        const temp = new StoreObject(Types.INTEGER, Math.floor(val.number));
+        sto.mode = Modes.RETURN;
+        return Promise.resolve(sto.updateStore("$", temp));
+      }
+      case Types.STRING.ord: {
+        const parser = IVProgParser.createParser(val.value);
+        try {
+          const result = parser.parseTerm();
+          if (result instanceof IntLiteral) {
+            const temp = new StoreObject(Types.INTEGER, result.value);
+            sto.mode = Modes.RETURN;
+            return Promise.resolve(sto.updateStore("$", temp));
+          }
+        } catch (error) { 
+          return Promise.reject("cannot convert string to real");
+        }
+      }
+    }
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(castIntFun)]);
+  const func = new Commands.Function('$castInt', Types.INTEGER,
+    [new Commands.FormalParameter(Types.ALL, 'val', false)],
+    block);
+  return func;
+}
+
+export function createCastBoolFun () {
+  const castBoolFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const parser = IVProgParser.createParser(str.value);
+    try {
+      const val = parser.parseTerm();
+      if (val instanceof BoolLiteral) {
+        const temp = new StoreObject(Types.BOOLEAN, val.value);
+        sto.mode = Modes.RETURN;
+        return Promise.resolve(sto.updateStore("$", temp));
+      }
+    } catch (error) { }
+    return Promise.reject("cannot convert " + str.value + " to boolean");
+  }
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(castBoolFun)]);
+  const func = new Commands.Function('$castBool', Types.BOOLEAN,
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
+    block);
+  return func;
+}
+
+export function createCastStringFun () {
+  const castStringFun = function (store, _) {
+    const val = store.applyStore('str');
+    let result = convertToString(val)
+    const temp = new StoreObject(Types.STRING, result);
+    sto.mode = Modes.RETURN;
+    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', false)],
+    block);
+  return func;
+}

+ 209 - 0
js/processor/lib/math.js

@@ -0,0 +1,209 @@
+import { StoreObject } from '../store/storeObject';
+import * as Commands from './../../ast/commands';
+import { Types } from './../../typeSystem/types';
+import { toReal } from "./../../typeSystem/parsers";
+import { Decimal } from 'decimal.js';
+import { MultiType } from '../../typeSystem/multiType';
+import { CompoundType } from '../../typeSystem/compoundType';
+import { Modes } from '../modes';
+
+/**
+ * sin
+ * cos
+ * tan
+ * sqrt
+ * pow
+ * log
+ * abs
+ * negate
+ * invert
+ * max
+ * min
+ */
+
+function convertToRadians (degrees) {
+  return degrees.times(Decimal.acos(-1)).div(180);
+}
+
+export function createSinFun () {
+   const sinFun = (sto, _) => {
+     const x = sto.applyStore('x');
+     const result = Decimal.sin(convertToRadians(x.value));
+     const temp = new StoreObject(Types.REAL, result);
+     sto.mode = Modes.RETURN;
+     return Promise.resolve(sto.updateStore('$', temp));
+   };
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(sinFun)]);
+  const func = new Commands.Function('$sin', Types.REAL,
+    [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
+    block);
+  return func;
+}
+
+export function createCosFun () {
+  const cosFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const result = Decimal.cos(convertToRadians(x.value));
+    const temp = new StoreObject(Types.REAL, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore('$', temp));
+  };
+
+ const block = new Commands.CommandBlock([],  [new Commands.SysCall(cosFun)]);
+ const func = new Commands.Function('$cos', Types.REAL,
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
+   block);
+ return func;
+}
+
+export function createTanFun () {
+  const tanFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const result = Decimal.tan(convertToRadians(x.value));
+    const temp = new StoreObject(Types.REAL, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore('$', temp));
+  };
+
+ const block = new Commands.CommandBlock([],  [new Commands.SysCall(tanFun)]);
+ const func = new Commands.Function('$tan', Types.REAL,
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
+   block);
+ return func;
+}
+
+export function createSqrtFun () {
+  const sqrtFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const result = x.value.sqrt();
+    const temp = new StoreObject(Types.REAL, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore('$', temp));
+  };
+
+ const block = new Commands.CommandBlock([],  [new Commands.SysCall(sqrtFun)]);
+ const func = new Commands.Function('$sqrt', Types.REAL,
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
+   block);
+ return func;
+}
+
+export function createPowFun () {
+  const powFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const y = sto.applyStore('y');
+    const result = x.value.pow(y.value);
+    const temp = new StoreObject(Types.REAL, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore('$', temp));
+  };
+
+ const block = new Commands.CommandBlock([],  [new Commands.SysCall(powFun)]);
+ const func = new Commands.Function('$pow', Types.REAL,
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false),
+    new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'y', false)],
+   block);
+ return func;
+}
+
+export function createLogFun () {
+  const logFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    if (x.value.isNegative()) {
+      return Promise.reject("the value passed to log function cannot be negative");
+    }
+    const result = Decimal.log10(x.value);
+    const temp = new StoreObject(Types.REAL, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore('$', temp));
+  };
+
+ const block = new Commands.CommandBlock([],  [new Commands.SysCall(logFun)]);
+ const func = new Commands.Function('$log', Types.REAL,
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
+   block);
+ return func;
+}
+
+export function createAbsFun () {
+  const absFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const result = x.value.abs();
+    const temp = new StoreObject(x.type, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore('$', temp));
+  };
+
+ const block = new Commands.CommandBlock([],  [new Commands.SysCall(absFun)]);
+ const func = new Commands.Function('$abs', new MultiType([Types.INTEGER, Types.REAL]),
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
+   block);
+ return func;
+}
+
+export function createNegateFun () {
+  const negateFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const result = x.value.negated();
+    const temp = new StoreObject(x.type, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore('$', temp));
+  };
+
+ const block = new Commands.CommandBlock([],  [new Commands.SysCall(negateFun)]);
+ const func = new Commands.Function('$negate', new MultiType([Types.INTEGER, Types.REAL]),
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
+   block);
+ return func;
+}
+
+export function createInvertFun () {
+  const invertFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const result = toReal(1).dividedBy(x.value);
+    const temp = new StoreObject(Types.REAL, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore('$', temp));
+  };
+
+ const block = new Commands.CommandBlock([],  [new Commands.SysCall(invertFun)]);
+ const func = new Commands.Function('$invert', Types.REAL,
+   [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
+   block);
+ return func;
+}
+
+export function createMaxFun () {
+  const maxFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const numbers = x.value.map(stoObj => stoObj.value);
+    const result = Decimal.max(...numbers);
+    const temp = new StoreObject(x.type.innerType, result);
+    sto.mode = Modes.RETURN;
+    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', new MultiType([Types.INTEGER, Types.REAL]),
+   [new Commands.FormalParameter(paramType, 'x', false)],
+   block);
+ return func;
+}
+
+export function createMinFun () {
+  const minFun = (sto, _) => {
+    const x = sto.applyStore('x');
+    const numbers = x.value.map(stoObj => stoObj.value);
+    const result = Decimal.min(...numbers);
+    const temp = new StoreObject(x.type.innerType, result);
+    sto.mode = Modes.RETURN;
+    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', new MultiType([Types.INTEGER, Types.REAL]),
+   [new Commands.FormalParameter(paramType, 'x', false)],
+   block);
+ return func;
+}

+ 94 - 0
js/processor/lib/strings.js

@@ -0,0 +1,94 @@
+import { StoreObject } from '../store/storeObject';
+import * as Commands from './../../ast/commands';
+import { Types } from './../../typeSystem/types';
+import { toInt } from "./../../typeSystem/parsers";
+import { Modes } from '../modes';
+
+/*
+*  substring
+*  length
+*  uppercase
+*  lowercase
+*  charAt
+**/
+
+export function createSubstringFun () {
+  const substringFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const start = sto.applyStore("start");
+    const end = sto.applyStore("end");
+    const result = str.value.substring(start.value, end.value);
+    const temp = new StoreObject(Types.STRING, result);
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  };
+
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(substringFun)]);
+  const func = new Commands.Function('$substring', Types.STRING,
+    [new Commands.FormalParameter(Types.STRING, 'str', false),
+    new Commands.FormalParameter(Types.INTEGER, 'start', false),
+    new Commands.FormalParameter(Types.INTEGER, 'end', false)],
+    block);
+  return func;
+}
+
+export function createLengthFun () {
+  const lengthFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const temp = new StoreObject(Types.INTEGER, toInt(str.value.length));
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(lengthFun)]);
+  const func = new Commands.Function('$length', Types.INTEGER,
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
+    block);
+  return func;
+}
+
+export function createUppercaseFun () {
+  const uppercaseFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const temp = new StoreObject(Types.STRING, str.value.toUpperCase());
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(uppercaseFun)]);
+  const func = new Commands.Function('$uppercase', Types.STRING,
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
+    block);
+  return func;
+}
+
+export function createLowercaseFun () {
+  const lowercaseFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const temp = new StoreObject(Types.STRING, str.value.toLowerCase());
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(lowercaseFun)]);
+  const func = new Commands.Function('$lowercase', Types.STRING,
+    [new Commands.FormalParameter(Types.STRING, 'str', false)],
+    block);
+  return func;
+}
+
+export function createrCharAtFun () {
+  const charAtFun = (sto, _) => {
+    const str = sto.applyStore("str");
+    const idx = sto.applyStore("index");
+    if (idx.value.toNumber() < 0 || idx.value.toNumber() >= str.value.length) {
+      return Promise.reject(new Error("invalid string position"));
+    }
+    const temp = new StoreObject(Types.STRING, str.value.charAt(idx.value.toNumber()));
+    sto.mode = Modes.RETURN;
+    return Promise.resolve(sto.updateStore("$", temp));
+  }
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall(charAtFun)]);
+  const func = new Commands.Function('$charAt', Types.STRING,
+    [new Commands.FormalParameter(Types.STRING, 'str', false),
+    new Commands.FormalParameter(Types.INTEGER, 'index', false)],
+    block);
+  return func;
+}

+ 451 - 0
js/processor/semantic/semanticAnalyser.js

@@ -0,0 +1,451 @@
+import { ProcessorErrorFactory } from './../error/processorErrorFactory';
+import { LanguageDefinedFunction } from './../definedFunctions';
+import { LanguageService } from './../../services/languageService';
+import { ArrayDeclaration, While, For, Switch, Case, Declaration, Assign, Break, IfThenElse, Return, ArrayIndexAssign } from '../../ast/commands';
+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 '../../typeSystem/types';
+import { CompoundType } from '../../typeSystem/compoundType';
+import { MultiType } from '../../typeSystem/multiType';
+
+export class SemanticAnalyser {
+
+  constructor(ast) {
+    this.ast = ast;
+    this.lexerClass = LanguageService.getCurrentLexer();
+    const lexer = new this.lexerClass(null);
+    this.literalNames = lexer.literalNames;
+    this.symbolMap = null;
+  }
+
+  pushMap () {
+    if(this.symbolMap === null) {
+      this.symbolMap = {map:{}, next: null};
+    } else {
+      const n = {map:{}, next: this.symbolMap};
+      this.symbolMap = n;
+    }
+  }
+
+  popMap () {
+    if(this.symbolMap !== null) {
+      this.symbolMap = this.symbolMap.next;
+    }
+  }
+
+  insertSymbol (id, typeInfo) {
+    this.symbolMap.map[id] = typeInfo;
+  }
+
+  findSymbol (id, symMap) {
+    if(!symMap.map[id]) {
+      if(symMap.next) {
+        return this.findSymbol(id, symMap.next);
+      }
+      throw new Error("variable not defined "+id);
+    } else {
+      return symMap.map[id];
+    }
+  }
+
+  findFunction (name) {
+    if(name.match(/^\$.+$/)) {
+      const fun = LanguageDefinedFunction.getFunction(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;
+    }
+  }
+
+  analyseTree () {
+    const globalVars = this.ast.global;
+    this.pushMap();
+    this.assertDeclarations(globalVars);
+    const functions = this.ast.functions;
+    const mainFunc = functions.filter((f) => f.name === null);
+    if (mainFunc.length <= 0) {
+      throw new Error("no main func...");
+    } else if (mainFunc.length > 1) {
+      throw new Error("only one main func...");
+    }
+    for (let i = 0; i < functions.length; i++) {
+
+      const fun = functions[i];
+      this.assertFunction(fun);
+    }
+    return this.ast;
+  }
+
+  assertDeclarations (list) {
+    for (let i = 0; i < list.length; i++) {
+      this.assertDeclaration(list[i]);
+    }
+  }
+
+  assertDeclaration (declaration) {
+    if (declaration instanceof ArrayDeclaration) {
+      if(declaration.initial === null) {
+        const lineType = this.evaluateExpressionType(declaration.lines);
+        if (!lineType.isCompatible(Types.INTEGER)) {
+          throw new Error("dim must be int");
+        }
+        if (declaration.columns !== null) {
+          const columnType = this.evaluateExpressionType(declaration.columns);
+          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});
+        return;
+      }
+      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) {
+        this.insertSymbol(declaration.id, {id: declaration.id, type: declaration.type});
+        return;
+      }
+      const resultType = this.evaluateExpressionType(declaration.initial);
+      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})
+      }
+    }
+  }
+
+  evaluateExpressionType (expression) {
+    if(expression instanceof UnaryApp) {
+      const op = expression.op;
+      const resultType = this.evaluateExpressionType(expression.left);
+      return resultTypeAfterUnaryOp(op, resultType);
+    } else if (expression instanceof InfixApp) {
+      const op = expression.op;
+      const resultTypeLeft = this.evaluateExpressionType(expression.left);
+      const resultTypeRight = this.evaluateExpressionType(expression.right);
+      return resultTypeAfterInfixOp(op, resultTypeLeft, resultTypeRight);
+    } else if (expression instanceof Literal) {
+      return this.evaluateLiteralType(expression);
+    } else if (expression instanceof FunctionCall) {
+      const fun = this.findFunction(expression.id);
+      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 instanceof CompoundType)) {
+        throw new Error("it's not an array");
+      }
+      const lineType = this.evaluateExpressionType(expression.line);
+      if (!lineType.isCompatible(Types.INTEGER)) {
+        throw new Error("line must be integer");
+      }
+      if (expression.column !== null) {
+        if (arrayTypeInfo.columns === null) {
+          throw new Error("it's not a matrix");
+        }
+        const columnType = this.evaluateExpressionType(expression.column);
+        if(!columnType.isCompatible(Types.INTEGER)) {
+          throw new Error("column must be integer");
+        }
+      }
+      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);
+      }
+    }
+  }
+
+  evaluateLiteralType (literal) {
+    if(literal instanceof IntLiteral) {
+      return literal.type;
+    } else if (literal instanceof RealLiteral) {
+      return literal.type;
+    } else if (literal instanceof StringLiteral) {
+      return literal.type;
+    } else if (literal instanceof BoolLiteral) {
+      return literal.type;
+    } else if (literal instanceof VariableLiteral) {
+      const typeInfo = this.findSymbol(literal.id, this.symbolMap);
+      if (typeInfo.type instanceof CompoundType) {
+        return typeInfo.type;
+      }
+      return typeInfo.type;
+    } else {
+      console.warn("Evaluating type only for an array literal...");
+      let last = null;
+      if(literal.value.length === 1) {
+        last = this.evaluateExpressionType(literal.value[0]);
+      } else {
+        for (let i = 0; i < literal.value.length; i++) {
+          const e = this.evaluateExpressionType(literal.value[i]);
+          if(last === null) {
+            last = e;
+          } else if(!last.isCompatible(e)) {
+            throw new Error("invalid value type for array");
+          } else {
+            last = e;
+          }
+        }
+      }
+      if(last instanceof CompoundType) {
+        return new CompoundType(last.innerType, last.dimensions + 1);
+      }
+      return new CompoundType(last, 1);
+    }
+  }
+
+  evaluateArrayLiteral (lines, columns, type, literal) {
+    if (literal instanceof ArrayLiteral) {
+      if (columns === null) {
+        // it's a vector...
+        const dimType = this.evaluateExpressionType(lines);
+        if (!dimType.isCompatible(Types.INTEGER)) {
+          throw new Error("dim must be int");
+        }
+        if ((lines instanceof IntLiteral) && !lines.value.eq(literal.value.length)) {
+          throw new Error("invalid array size");
+        }
+        literal.value.reduce((last, next) => {
+          const eType = this.evaluateExpressionType(next);
+          if (!last.canAccept(eType)) {
+            throw new Error("invalid value type for array");
+          }
+          return last;
+        }, type);
+        return true;
+      } else {
+        const dimType = this.evaluateExpressionType(columns);
+        if (!dimType.isCompatible(Types.INTEGER)) {
+          throw new Error("dim must be int");
+        }
+        if ((columns instanceof IntLiteral) && !columns.value.eq(literal.value.length)) {
+          throw new Error("invalid array size");
+        }
+        for (let i = 0; i < columns; i++) {
+          const anotherArray = literal.value[i];
+          this.evaluateArrayLiteral(lines, null, type, anotherArray)
+        }
+      }
+
+    } else {
+
+      const resultType = this.evaluateExpressionType(literal);
+      if (!(resultType instanceof CompoundType)) {
+        throw new Error("initial must be of type array");
+      }
+      if (!type.isCompatible(resultType)) {
+        throw new Error("invalid array type");
+      }
+      return true;
+
+    }
+  }
+
+  assertFunction (fun) {
+    this.pushMap();
+    fun.formalParameters.forEach(formalParam => {
+      if(formalParam.type instanceof CompoundType) {
+        if(formalParam.type.dimensions > 1) {
+          this.insertSymbol(formalParam.id, {id: formalParam.id, lines: -1, columns: -1, type: formalParam.type});
+        } else {
+          this.insertSymbol(formalParam.id, {id: formalParam.id, lines: -1, columns: null, type: formalParam.type});
+        }
+      } else {
+        this.insertSymbol(formalParam.id, {id: formalParam.id, type: formalParam.type});
+      }
+    })
+    this.assertDeclarations(fun.variablesDeclarations);
+    const optional = fun.returnType.isCompatible(Types.VOID);
+    const valid = this.assertReturn(fun, optional);
+    if (!valid) {
+      throw new Error("function has no accessible return");
+    }
+    this.popMap();
+  }
+
+  assertReturn (fun, optional) {
+    return fun.commands.reduce(
+      (last, next) => this.checkCommand(fun.returnType, next, optional) || last, optional
+    );
+  }
+
+  checkCommand (type, cmd, optional) {
+    if (cmd instanceof While) {
+      const resultType = this.evaluateExpressionType(cmd.expression);
+      if (!resultType.isCompatible(Types.BOOLEAN)) {
+        throw new Error("condition not boolean");
+      }
+      this.checkCommands(type, cmd.commands, optional);
+      return false;
+    } else if (cmd instanceof For) {
+      this.checkCommand(type, cmd.assignment, optional);
+      const resultType = this.evaluateExpressionType(cmd.condition);
+      if (!resultType.isCompatible(Types.BOOLEAN)) {
+        throw new Error("condition not boolean");
+      }
+      this.checkCommand(type, cmd.increment, optional);
+      this.checkCommands(type, cmd.commands, optional);
+      return false;
+    } else if (cmd instanceof Switch) {
+      const sType = this.evaluateExpressionType(cmd.expression);
+      let result = optional;
+      let hasDefault = false;
+      for (let i = 0; i < cmd.cases.length; i++) {
+        const aCase = cmd.cases[i];
+        if (aCase.expression !== null) {
+          const caseType = this.evaluateExpressionType(aCase.expression);
+          if (!sType.isCompatible(caseType)) {
+            throw new Error("invalid type in case");
+          }
+        } else {
+          hasDefault = true;
+        }
+        result = result && this.checkCommands(type, aCase.commands, result);        
+      }
+      return result && hasDefault;
+
+    } else if (cmd instanceof ArrayIndexAssign) {
+      const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
+      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.isCompatible(Types.INTEGER)) {
+        throw new Error("array dimension must be of type int");
+      }
+      const columnExp = cmd.column;
+      if (typeInfo.columns === null && columnExp !== null) {
+        throw new Error(cmd.id + " is not a matrix");
+      } else if (columnExp !== null) {
+        const columnType = this.evaluateExpressionType(columnExp);
+        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.type, exp);
+      } else {
+        // cannot properly evaluate since type system is poorly constructed
+      }
+      return optional;
+    } else if (cmd instanceof Assign) {
+      const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
+      const exp = cmd.expression;
+      if(exp instanceof ArrayLiteral) {
+        if(!(typeInfo.type instanceof CompoundType)) {
+          throw new Error("type not compatible");
+        }
+        this.evaluateArrayLiteral(typeInfo.lines, typeInfo.columns, typeInfo.type, exp);
+      } else {
+        const resultType = this.evaluateExpressionType(exp);
+        if(!resultType.isCompatible(typeInfo.type)) {
+          throw new Error("type not compatible");
+        }
+      }
+      return optional;
+    } else if (cmd instanceof Break) {
+      return optional;
+    } else if (cmd instanceof IfThenElse) {
+      const resultType = this.evaluateExpressionType(cmd.condition);
+      if (!resultType.isCompatible(Types.BOOLEAN)) {
+        throw new Error("condition not boolean");
+      }
+      if(cmd.ifFalse instanceof IfThenElse) {
+        return this.checkCommands(type, cmd.ifTrue.commands, optional) && this.checkCommand(type, cmd.ifFalse, optional);
+      } else {
+        return this.checkCommands(type, cmd.ifTrue.commands, optional) && this.checkCommands(type, cmd.ifFalse.commands,optional);
+      }
+
+    } else if (cmd instanceof FunctionCall) {
+      const fun = this.findFunction(cmd.id);
+      this.assertParameters(fun, cmd.actualParameters);
+      return optional;
+    } else if (cmd instanceof Return) {
+      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 (!type.isCompatible(resultType)) {
+          console.log(resultType);
+          throw new Error('invalid return type');
+        } else {
+          return true;
+        }
+      } else {
+        return true;
+      }
+    }
+  }
+
+  checkCommands (type, cmds, optional) {
+    return cmds.reduce(
+      (last, next) => this.checkCommand(type, next, optional) || last, optional
+    );
+  }
+
+  assertParameters (fun, actualParametersList) {
+    if (fun.formalParameters.length !== actualParametersList.length) {
+      throw new Error("wrong number of parameters...");
+    }
+    for (let i = 0; i < actualParametersList.length; i++) {
+      const param = actualParametersList[i];
+      const formalParam = fun.formalParameters[i];
+      if(formalParam.byRef) {
+        if (!(param instanceof VariableLiteral || param instanceof ArrayAccess)) {
+          throw new Error("Invalid param type for ref");
+        }
+      }
+      const resultType = this.evaluateExpressionType(param);
+      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++;
+          }
+        }
+        if(shared <= 0) {
+          throw new Error(`Parameter ${formalParam.id} is not compatible with the value given.`);
+        }
+      } 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.`);
+      }
+
+    }
+  }
+}

+ 8 - 6
js/processor/store/store.js

@@ -1,4 +1,5 @@
 import { Modes } from './../modes';
+
 export class Store {
 
   constructor() {
@@ -42,17 +43,18 @@ export class Store {
         // 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;
-        }
+      if(oldObj.isRef) {
+        oldObj.updateRef(stoObj);
+        return this;
+      } else if(oldObj.isCompatible(stoObj)) {
         stoObj.setID(id);
         this.store[id] = Object.freeze(stoObj);
         return this;
       } else {
+        const oldType = oldObj.type;
+        const stoType = stoObj.type;
         // TODO: better error message
-        throw new Error(`${oldObj.type} is not compatible with the value given`);
+        throw new Error(`${oldType} is not compatible with type ${stoType} given`);
       }
     }
   }

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

@@ -1,3 +1,5 @@
+import Decimal from 'decimal.js';
+
 export class StoreObject {
 
   constructor (type, value, readOnly = false) {
@@ -26,14 +28,26 @@ export class StoreObject {
   get value () {
     return this._value;
   }
+  
+  get number () {
+    if (this._value instanceof Decimal) {
+      return this._value.toNumber();
+    } else {
+      return null;
+    }
+  }
 
   get readOnly () {
     return this._readOnly;
   }
 
+  set readOnly (value) {
+    this._readOnly = value;
+  }
+
   isCompatible (another) {
     if( another instanceof StoreObject) {
-      return this.type === another.type;
+      return this.type.isCompatible(another.type);
     }
     return false;
   }

+ 12 - 16
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, readOnly) {
-    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,23 +16,21 @@ export class StoreObjectArray extends StoreObject {
     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);
+    if(another instanceof StoreObject) {
+      if(((this.lines === -1 && another.lines > 0) ||
+        (this.lines === another.lines))) {
+          if ((this.columns === -1 && another.columns > 0) ||
+            (this.columns === another.columns)) {
+              return super.isCompatible(another);
+          }
         }
     }
     return false;
   }
 
   get isVector () {
-    return this.columns === null;
+    return this.type.dimensions === 1;
   }
 
   get isValid () {
@@ -43,7 +39,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 +55,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;
         }            

+ 86 - 0
js/processor/store/storeObjectArrayAddress.js

@@ -0,0 +1,86 @@
+import { StoreObject } from './storeObject';
+import { StoreObjectArray } from './storeObjectArray';
+import { CompoundType } from '../../typeSystem/compoundType';
+
+export class StoreObjectArrayAddress extends StoreObject {
+
+  constructor (refID, line, column, store) {
+    super(null, null, false);
+    this.refID = refID;
+    this.store = store;
+    this.line = line;
+    this.column = column;
+  }
+
+  get isRef () {
+    return false;
+  }
+
+  get inStore () {
+    return true;
+  }
+
+  get refValue () {
+    const refLine = this.store.applyStore(this.refID).value[this.line];
+    if (this.column !== null) {
+      const refColumn = refLine.value[this.column];
+      return refColumn;
+    }
+    return refLine;
+  }
+
+  get value () {
+    return this.refValue.value;
+  }
+
+  get type () {
+    return this.refValue.type;
+  }
+
+  get lines () {
+    if(!(this.type instanceof CompoundType)) {
+      return null;
+    }
+    return this.refValue.value.length;
+  }
+
+  get columns () {
+    switch (this.type.dimensions) {
+      case 2:
+        return this.refValue.value[0].value.length;
+      default:
+        return null;
+    }
+  }
+
+  getArrayObject () {
+    return this.store.applyStore(this.refID);
+  }
+
+  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) {
+     newArray.value[this.line].value[this.column] = stoObj;
+     return newArray;
+    } else {
+     newArray.value[this.line] = stoObj;
+     return newArray;
+    }
+  }
+
+  isCompatible (another) {
+    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);
+      }
+    }
+  }
+}

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

@@ -0,0 +1,43 @@
+import { StoreObject } from './storeObject';
+import Decimal from 'decimal.js';
+
+export class StoreObjectArrayAddressRef extends StoreObject {
+
+  constructor (address) {
+    super(null, null, false);
+    this.address = address;
+  }
+
+  get isRef () {
+    return true;
+  }
+
+  get type () {
+    return this.address.type;
+  }
+
+  get value () {
+    return this.address.value;
+  }
+
+  get number () {
+    if (this.value instanceof Decimal) {
+      return this.value.toNumber();
+    } else {
+      return null;
+    }
+  }
+
+  getRefObj () {
+    return this.address.refValue;
+  }
+
+  updateRef (stoObj) {
+    const newArray = this.address.updateArrayObject(stoObj);
+    this.address.store.updateStore(this.address.refID, newArray);
+  }
+
+  isCompatible (another) {
+    return this.address.isCompatible(another);
+  }
+}

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

@@ -1,4 +1,5 @@
 import { StoreObject } from './storeObject';
+import Decimal from 'decimal.js';
 
 export class StoreObjectRef extends StoreObject {
 
@@ -20,6 +21,14 @@ export class StoreObjectRef extends StoreObject {
     return this.store.applyStore(this.refID).value;
   }
 
+  get number () {
+    if (this.value instanceof Decimal) {
+      return this.value.toNumber();
+    } else {
+      return null;
+    }
+  }
+
   getRefObj () {
     return this.store.applyStore(this.refID);
   }

+ 28 - 18
js/services/languageService.js

@@ -1,29 +1,39 @@
 import Lexers from './../../grammar/';
+import line_i18n from 'line-i18n';
 
 const DEFAULT_LANG = "pt";
 
-export const LanguageService  = Object.freeze({
+class LanguageServiceExtended extends line_i18n.LanguageService {
 
-  getLang: () => {
-    const lang = localStorage.getItem('ivprog.lang');
-    if (lang === null || lang === undefined) {
-      console.warn("Internal Error. User language information has not been set. Returning default...");
-      return LanguageService.getDefaultLang();
-    }
-    return lang;
-  },
+  constructor () {
+    super("ivprog.lang", DEFAULT_LANG);
+  }
 
-  getDefaultLang: () => {
-    return DEFAULT_LANG;
-  },
+  getCurrentLexer () {
+    const langInfo = Lexers[this.getLang()];
+    if(langInfo === null || langInfo === undefined) {
+      return Lexers[this.getDefaultLang()].lexer;
+    } else {
+      return langInfo.lexer;
+    }
+  }
 
-  getCurrentLexer: () => {
-    const lexer = Lexers[LanguageService.getLang()];
-    if(lexer === null || lexer === undefined) {
-      return Lexers[DEFAULT_LANG];
+  getCurrentLangFuncs () {
+    const langInfo = Lexers[this.getLang()];
+    if(langInfo === null || langInfo === undefined) {
+      return Lexers[this.getDefaultLang()].langFuncs;
     } else {
-      return lexer;
+      return langInfo.langFuncs;
+    }
+  }
+
+  getCurrentLangLibs () {
+    const langInfo = Lexers[this.getLang()];
+    if(langInfo === null || langInfo === undefined) {
+      return Lexers[this.getDefaultLang()].langLibs;
     }
+    return langInfo.langLibs;
   }
+}
 
-});
+export const LanguageService  = Object.freeze(new LanguageServiceExtended());

+ 2 - 50
js/services/localizedStringsService.js

@@ -1,52 +1,4 @@
 import { LanguageService } from "./languageService";
+import line_i18n from 'line-i18n'
 import Langs from './../../i18n';
-
-export const StringTypes = Object.freeze({
-  ERROR: "error",
-  MESSAGE: "message",
-  UI: "ui"
-});
-
-export const LocalizedStrings = Object.freeze({
-
-  getString: (id, type) => {
-    let i18nObj = Langs[LanguageService.getLang()];
-    if(!!!i18nObj) {
-      console.warn(`Internal Error. The language set at ivprog.lang is not valid: ${LanguageService.getLang()}`);
-      i18nObj = Langs[LanguageService.getDefaultLang()];
-    }
-    if(!!!i18nObj[type]) {
-      return "{MISSING_I18N_TYPE_IDENTIFIER}";
-    } else if (!!!i18nObj[type][id]) {
-      return "{MISSING_I18N_IDENTIFIER}";
-    } else {
-      return i18nObj[type][id];
-    }
-  },
-
-  getOR: () => LocalizedStrings.getUI('join_or'),
-
-  getError: (id, context = []) => {
-    const text = LocalizedStrings.getString(id, StringTypes.ERROR);
-    return LocalizedStrings.processString(text, context)
-  },
-
-  getMessage: (id, context = []) => {
-    const text = LocalizedStrings.getString(id, StringTypes.MESSAGE);
-    return LocalizedStrings.processString(text, context)
-  },
-
-  getUI: (id, context = []) => {
-    const text = LocalizedStrings.getString(id, StringTypes.UI);
-    return LocalizedStrings.processString(text, context)
-  },
-
-  processString: (text, context) => {
-    for (let i = 0; i < context.length; i++) {
-      const v = context[i];
-      text = text.replace('\$'+i, v);
-    }
-    return text;
-  }
-
-});
+export const LocalizedStrings = Object.freeze(new line_i18n.LocalizedStrings(LanguageService, Langs, true));

+ 26 - 0
js/typeSystem/baseTypes.js

@@ -0,0 +1,26 @@
+class BaseType {
+  constructor(name, ord) {
+    this.name = name;
+    this.ord = ord;
+  }
+
+  get value () {
+    return this.name;
+  }
+
+  isCompatible (another) {
+    if(another instanceof BaseType) {
+      return this.name === another.name && this.ord === another.ord;
+    }
+    return false;
+  }
+}
+
+export const BaseTypes = Object.freeze({
+  INTEGER: new BaseType("int", 0),
+  REAL: new BaseType("real", 1),
+  STRING: new BaseType("string", 2),
+  BOOLEAN: new BaseType("bool", 3),
+  VOID: new BaseType("void", 4),
+  UNDEFINED: new BaseType("undefined", 5)
+})

+ 28 - 0
js/typeSystem/compoundType.js

@@ -0,0 +1,28 @@
+import { Type } from "./type";
+
+export class CompoundType extends Type {
+
+  constructor (type, dimensions) {
+    super(null);
+    this.innerType = type;
+    this.dimensions = dimensions;
+  }
+
+  isCompatible (another) {
+    if(another instanceof CompoundType){
+      if(this.dimensions !== another.dimensions) {
+        return false;
+      }
+      return this.innerType.isCompatible(another.innerType);
+    }
+    return false;
+  }
+
+  canAccept (another) {
+    if(another instanceof CompoundType) {
+      return this.dimensions > another.dimensions && this.innerType.isCompatible(another.innerType);
+    } else {
+      return this.innerType.isCompatible(another);
+    }
+  }
+}

+ 29 - 0
js/typeSystem/multiType.js

@@ -0,0 +1,29 @@
+import { Type } from "./type";
+
+export class MultiType extends Type {
+
+  constructor (types) {
+    super(null);
+    this.types = types;
+  }
+
+  get value () {
+    return null;
+  }
+
+  get ord () {
+    return null;
+  }
+
+  isCompatible (another) {
+    if(another instanceof Type) {
+      for (let i = 0; i < this.types.length; i++) {
+        const t = this.types[i];
+        if (t.isCompatible(another)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+}

+ 66 - 0
js/typeSystem/parsers.js

@@ -0,0 +1,66 @@
+import { LanguageService } from "../services/languageService";
+import { Types } from "./types";
+import Decimal from "decimal.js";
+
+export function toInt (str) {
+  return new Decimal(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 Decimal(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");
+  }
+}
+
+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];
+  }
+}
+
+export function convertToString(stoObj, type) {
+  switch (type.ord) {
+    case Types.INTEGER.ord:
+      return stoObj.toString();
+    case Types.REAL.ord: {
+      if (stoObj.dp() <= 0) {
+        return stoObj.toFixed(1);  
+      } else {
+        return stoObj.toNumber();
+      }
+    }
+    case Types.BOOLEAN.ord:
+      return convertBoolToString(stoObj);
+    default:
+      return stoObj;
+  }
+}

+ 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;
+  }
+}

+ 21 - 0
js/typeSystem/types.js

@@ -0,0 +1,21 @@
+import { BaseTypes } from './baseTypes';
+import { Type } from "./type";
+import { MultiType } from "./multiType";
+
+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([INTEGER, REAL, STRING, BOOLEAN]);
+
+export const Types = Object.freeze({
+  INTEGER: INTEGER,
+  REAL: REAL,
+  STRING: STRING,
+  BOOLEAN: BOOLEAN,
+  VOID: VOID,
+  UNDEFINED: UNDEFINED,
+  ALL: ALL
+});

+ 37 - 0
js/visualUI/algorithm.js

@@ -0,0 +1,37 @@
+import $ from 'jquery';
+import { Types } from './types';
+import * as Models from './ivprog_elements';
+import { LocalizedStrings } from './../services/localizedStringsService';
+import * as GlobalsManagement from './globals';
+import * as VariablesManagement from './variables';
+import * as CommandsManagement from './commands';
+import * as CodeManagement from './code_generator';
+import * as VariableValueMenu from './commands/variable_value_menu';
+import * as FunctionsManagement from './functions';
+import { DOMConsole } from './../io/domConsole';
+import { IVProgParser } from './../ast/ivprogParser';
+import { IVProgProcessor } from './../processor/ivprogProcessor';
+import { LanguageService } from '../services/languageService';
+
+var block_render = false;
+
+export function renderAlgorithm () {
+
+	if (block_render) {
+		return;
+	}
+	block_render = true;
+
+ 	$('.all_functions').children().off();
+	$('.all_functions').empty();
+
+	for (var i = 0; i < window.program_obj.functions.length; i++) {
+		FunctionsManagement.renderFunction(window.program_obj.functions[i]);
+	}
+
+	for (var i = 0; i < window.program_obj.globals.length; i++) {
+		GlobalsManagement.renderGlobal(window.program_obj.globals[i]);
+	}	
+
+	setTimeout(function(){ block_render = false; }, 500);
+}

+ 189 - 123
js/visualUI/commands_sidebar.js

@@ -20,7 +20,7 @@ import * as BreaksManagement from './commands/break';
 var has_element_created_draged = false;
 var which_element_is_draged = null;
 
-export function removeCommand (command, function_obj, dom_obj) {
+export function removeCommand(command, function_obj, dom_obj) {
 	console.log('debugging removeCommand');
 	console.log('command');
 	console.log(command);
@@ -38,20 +38,20 @@ export function removeCommand (command, function_obj, dom_obj) {
 	try {
 		if (dom_obj.parent().parent().data('command').commands_block.indexOf(command) > -1) {
 			dom_obj.parent().parent().data('command').commands_block.splice
-			(dom_obj.parent().parent().data('command').commands_block.indexOf(command), 1);
+				(dom_obj.parent().parent().data('command').commands_block.indexOf(command), 1);
 			return true;
-		}	
-	} catch (err) {}
-	
+		}
+	} catch (err) { }
+
 	try {
 		if (dom_obj.parent().parent().data('command').type == Models.COMMAND_TYPES.iftrue) {
 			if (dom_obj.parent().parent().data('command').commands_else.indexOf(command) > -1) {
 				dom_obj.parent().parent().data('command').commands_else.splice
-				(dom_obj.parent().parent().data('command').commands_else.indexOf(command), 1);
+					(dom_obj.parent().parent().data('command').commands_else.indexOf(command), 1);
 				return true;
 			}
 		}
-	} catch (err) {}
+	} catch (err) { }
 
 	console.log('veja: ');
 	console.log(dom_obj.parent());
@@ -66,7 +66,7 @@ export function removeCommand (command, function_obj, dom_obj) {
 	return false;
 }
 
-export function createFloatingCommand (function_obj, function_container, command_type, mouse_event) {
+export function createFloatingCommand(function_obj, function_container, command_type, mouse_event) {
 	var floatingObject;
 
 	switch (command_type) {
@@ -117,10 +117,10 @@ export function createFloatingCommand (function_obj, function_container, command
 
 	floatingObject.draggable().appendTo("body");
 
-	floatingObject.mouseup(function(evt) {
-	  manageCommand(function_obj, function_container, evt, command_type);
+	floatingObject.mouseup(function (evt) {
+		manageCommand(function_obj, function_container, evt, command_type);
 	});
-	
+
 	floatingObject.css("position", "absolute");
 	mouse_event.type = "mousedown.draggable";
 	mouse_event.target = floatingObject[0];
@@ -130,7 +130,7 @@ export function createFloatingCommand (function_obj, function_container, command
 }
 
 // before_after_inside: 1 -> before, 2 -> after, 3 -> inside
-export function renderCommand (command, element_reference, before_after_inside, function_obj) {
+export function renderCommand(command, element_reference, before_after_inside, function_obj) {
 	var createdElement;
 	switch (command.type) {
 		case Models.COMMAND_TYPES.comment:
@@ -188,14 +188,14 @@ export function renderCommand (command, element_reference, before_after_inside,
 			createdElement.insertAfter(element_reference);
 			break;
 
-		case 3: 
+		case 3:
 			element_reference.append(createdElement);
 			break;
 	}
 
 }
 
-export function genericCreateCommand (command_type) {
+export function genericCreateCommand(command_type) {
 
 	switch (command_type) {
 
@@ -212,7 +212,7 @@ export function genericCreateCommand (command_type) {
 			return new Models.Writer([new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.all, null, null, null, true)]);
 
 		case Models.COMMAND_TYPES.attribution:
-			return new Models.Attribution(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_variable, null, null, null, false), 
+			return new Models.Attribution(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_variable, null, null, null, false),
 				[]);
 
 		case Models.COMMAND_TYPES.functioncall:
@@ -222,9 +222,9 @@ export function genericCreateCommand (command_type) {
 			return new Models.IfTrue(new Models.ConditionalExpression(null), null, null);
 
 		case Models.COMMAND_TYPES.repeatNtimes:
-			return new Models.RepeatNTimes(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_variable, null, null, null, false), 
-											new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_variable, null, null, null, false),
-										     null, new Models.ConditionalExpression(null), null, null);
+			return new Models.RepeatNTimes(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_variable, null, null, null, false),
+				new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_variable, null, null, null, false),
+				null, new Models.ConditionalExpression(null), null, null);
 
 		case Models.COMMAND_TYPES.whiletrue:
 			return new Models.WhileTrue(new Models.ConditionalExpression(null), null);
@@ -240,9 +240,9 @@ export function genericCreateCommand (command_type) {
 	}
 }
 
-function manageCommand (function_obj, function_container, event, command_type, function_called) {
+function manageCommand(function_obj, function_container, event, command_type, function_called) {
 
-	$( ".created_element" ).each(function( index ) { 
+	$(".created_element").each(function (index) {
 		$(this).remove();
 	});
 
@@ -258,12 +258,12 @@ function manageCommand (function_obj, function_container, event, command_type, f
 	var esta_na_div_correta = false;
 	if (el.hasClass("commands_list_div")) {
 		esta_na_div_correta = true;
-	} 
+	}
 	for (var i = 0; i < hier.length; i++) {
 		var temp = $(hier[i]);
 		if (temp.hasClass("commands_list_div")) {
 			esta_na_div_correta = true;
-		} 
+		}
 		if (temp.data('fun') == function_obj) {
 			esta_correto = true;
 			break;
@@ -288,21 +288,21 @@ function manageCommand (function_obj, function_container, event, command_type, f
 
 		// Se a lista de comandos estiver vazia, então é o primeiro.
 		// Portanto, ele deve soltar o elemento obrigatoriamente no objeto vazio
-		if ((el.data('fun').commands == null)  || (el.data('fun').commands.length == 0)) {
-				// pode adicionar 
-				el.data('fun').commands = [];
+		if ((el.data('fun').commands == null) || (el.data('fun').commands.length == 0)) {
+			// pode adicionar 
+			el.data('fun').commands = [];
 
-				var new_cmd = null;
-				
-				if (function_called == null) 
-					new_cmd = genericCreateCommand(command_type);
-				else if (command_type == 'functioncall')
-					new_cmd = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
+			var new_cmd = null;
 
-				el.data('fun').commands.push(new_cmd);
+			if (function_called == null)
+				new_cmd = genericCreateCommand(command_type);
+			else if (command_type == 'functioncall')
+				new_cmd = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
+
+			el.data('fun').commands.push(new_cmd);
+
+			renderCommand(new_cmd, $(function_container).find('.commands_list_div'), 3, function_obj);
 
-				renderCommand(new_cmd, $(function_container).find('.commands_list_div'), 3, function_obj);
-			
 		} else { // Entra nesse else, caso já existam outros comandos no bloco:
 
 			findNearbyCommandToAddInFunctionScope(el, event, $(function_container).find('.commands_list_div'), function_obj, command_type, function_called);
@@ -350,7 +350,7 @@ function manageCommand (function_obj, function_container, event, command_type, f
 			}
 		}
 
-		
+
 
 		// se a hierarquia possuir apenas um elemento, então está na raiz dos comandos: 
 		if (hierarquia_bottom_up.length == 1) {
@@ -359,14 +359,14 @@ function manageCommand (function_obj, function_container, event, command_type, f
 			for (var i = 0; i < hier_find.length; i++) {
 				if (typeof $(hier_find[i]).data('command') !== 'undefined') {
 					console.log('QQ2');
-					findBeforeOrAfterCommandToAdd(hier_find[i], event, function_obj, command_type);
+					findBeforeOrAfterCommandToAdd(hier_find[i], event, function_obj, command_type, function_called);
 					sub_elemento = true;
 					break;
 				}
 			}
 			if (!sub_elemento) {
 				console.log('QQ3');
-				findBeforeOrAfterCommandToAdd(el[0], event, function_obj, command_type);
+				findBeforeOrAfterCommandToAdd(el[0], event, function_obj, command_type, function_called);
 			}
 		} else {
 			console.log('QQ4');
@@ -387,28 +387,28 @@ function manageCommand (function_obj, function_container, event, command_type, f
 					}
 				}
 			}
-			
+
 		}
 	}
-	
+
 	has_element_created_draged = false;
 	which_element_is_draged = null;
 }
 
-function insertCommandInBlockHierar (el, event, function_obj, command_type, hier_dom, hier_obj, function_called = null) {
+function insertCommandInBlockHierar(el, event, function_obj, command_type, hier_dom, hier_obj, function_called = null) {
 	var el_jq = $(el);
 	var command_parent = el_jq.data('command');
-	
+
 	if ((el_jq.data('command').type == Models.COMMAND_TYPES.repeatNtimes) ||
-		(el_jq.data('command').type == Models.COMMAND_TYPES.whiletrue)  ||
+		(el_jq.data('command').type == Models.COMMAND_TYPES.whiletrue) ||
 		(el_jq.data('command').type == Models.COMMAND_TYPES.dowhiletrue) ||
-		(el_jq.data('command').type == Models.COMMAND_TYPES.switch) ) {
+		(el_jq.data('command').type == Models.COMMAND_TYPES.switch)) {
 
 		console.log('QQ17');
 
 		if ((el_jq.data('command').type == Models.COMMAND_TYPES.repeatNtimes) ||
-			(el_jq.data('command').type == Models.COMMAND_TYPES.whiletrue)  ||
-			(el_jq.data('command').type == Models.COMMAND_TYPES.dowhiletrue) ) {
+			(el_jq.data('command').type == Models.COMMAND_TYPES.whiletrue) ||
+			(el_jq.data('command').type == Models.COMMAND_TYPES.dowhiletrue)) {
 
 			console.log('QQ18');
 
@@ -417,7 +417,7 @@ function insertCommandInBlockHierar (el, event, function_obj, command_type, hier
 				command_parent.commands_block = [];
 
 				var recentComand = null;
-				if(function_called == null)
+				if (function_called == null)
 					recentComand = genericCreateCommand(command_type);
 				else if (command_type == "functioncall")
 					recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
@@ -436,13 +436,13 @@ function insertCommandInBlockHierar (el, event, function_obj, command_type, hier
 	} else {
 		console.log('QQ19');
 		// entra neste bloco, se soltou o comando sobre outro comando dentro de um subbloco:
-		findBeforeOrAfterCommandToAddInsertBlock(el, event, function_obj, command_type);
+		findBeforeOrAfterCommandToAddInsertBlock(el, event, function_obj, command_type, function_called);
 	}
 }
 
 
 
-function findNearbyCommandToAddInBlockScope (el, event, node_list_commands, function_obj, command_type, command_parent, function_called = null) {
+function findNearbyCommandToAddInBlockScope(el, event, node_list_commands, function_obj, command_type, command_parent, function_called = null) {
 
 	var all_sub = $(node_list_commands).find('div.command_container');
 
@@ -455,7 +455,7 @@ function findNearbyCommandToAddInBlockScope (el, event, node_list_commands, func
 
 	// Descobrindo o elemento mais próximo:
 	for (var i = 0; i < all_sub.length; i++) {
-	
+
 		t_top = all_sub[i].getBoundingClientRect().top;
 		t_bot = all_sub[i].getBoundingClientRect().top + all_sub[i].getBoundingClientRect().height;
 
@@ -472,7 +472,7 @@ function findNearbyCommandToAddInBlockScope (el, event, node_list_commands, func
 		recentComand = genericCreateCommand(command_type);
 	else if (command_type == 'functioncall')
 		recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
-		
+
 	// Está mais próximo da borda de baixo, ou seja.. inserir por último:
 	if ((borda_inferior - event.clientY) < menor_distancia) {
 
@@ -485,7 +485,7 @@ function findNearbyCommandToAddInBlockScope (el, event, node_list_commands, func
 		var index = command_parent.commands_block.indexOf($(elemento_menor_distancia).data('command'));
 
 		if (index > -1) {
-		    command_parent.commands_block.splice(index, 0, recentComand);
+			command_parent.commands_block.splice(index, 0, recentComand);
 		}
 
 		renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
@@ -494,7 +494,7 @@ function findNearbyCommandToAddInBlockScope (el, event, node_list_commands, func
 
 
 
-function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, command_type) {
+function findBeforeOrAfterCommandToAddInsertBlock(el, event, function_obj, command_type, function_called = null) {
 
 	var el_jq = $(el);
 	var command_parent = $(el.parentNode.parentNode).data('command');
@@ -579,8 +579,13 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 	// Está mais próximo da borda de baixo, ou seja.. inserir por último:
 
 	if (d_top < d_bot) {
-		
-		var recentComand = genericCreateCommand(command_type);
+
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
+
 
 		console.log('MMM1');
 
@@ -593,12 +598,15 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 				if (command_parent.commands_else == null || command_parent.commands_else.length == 0) {
 					command_parent.commands_else = [];
 
-					var recentComand = genericCreateCommand(command_type);
-					command_parent.commands_else.push(recentComand);
+					var recentComand = null;
+					if (function_called == null)
+						recentComand = genericCreateCommand(command_type);
+					else if (command_type == 'functioncall') recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
+						command_parent.commands_else.push(recentComand);
 
 					renderCommand(recentComand, el_jq, 3, function_obj);
 				} else { // Se já tem algum comando no bloco:
-					findInBlockCorrectPlace(el_jq, event, function_obj, command_type, true);
+					findInBlockCorrectPlace(el_jq, event, function_obj, command_type, true, function_called);
 				}
 				return;
 			}
@@ -606,7 +614,7 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 			var index = command_parent.commands_else.indexOf(command_target);
 
 			if (index > -1) {
-			    command_parent.commands_else.splice(index, 0, recentComand);
+				command_parent.commands_else.splice(index, 0, recentComand);
 			}
 
 			renderCommand(recentComand, el, 1, function_obj);
@@ -617,16 +625,20 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 				if (command_parent.commands_block == null || command_parent.commands_block.length == 0) {
 					command_parent.commands_block = [];
 					console.log('SSS4');
-					var recentComand = genericCreateCommand(command_type);
+					var recentComand = null;
+					if (function_called == null)
+						recentComand = genericCreateCommand(command_type);
+					else if (command_type == 'functioncall')
+						recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 					command_parent.commands_block.push(recentComand);
 
 					renderCommand(recentComand, el_jq, 3, function_obj);
 				} else {
 					console.log('SSS5');
-					findInBlockCorrectPlace(el_jq, event, function_obj, command_type);
+					findInBlockCorrectPlace(el_jq, event, function_obj, command_type, function_called);
 				}
-				
-				
+
+
 				return;
 			}
 			console.log('MMM6');
@@ -634,17 +646,21 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 			var index = command_parent.commands_block.indexOf(command_target);
 
 			if (index > -1) {
-			    command_parent.commands_block.splice(index, 0, recentComand);
+				command_parent.commands_block.splice(index, 0, recentComand);
 			}
 
 			renderCommand(recentComand, el, 1, function_obj);
 		}
 
-		
+
 
 	} else {
 		console.log('XXX1');
-		var recentComand = genericCreateCommand(command_type);
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 
 		if (is_in_else) {
 
@@ -653,13 +669,17 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 				if (command_parent.commands_else == null || command_parent.commands_else.length == 0) {
 					command_parent.commands_else = [];
 					console.log('SSS1');
-					var recentComand = genericCreateCommand(command_type);
+					var recentComand = null;
+					if (function_called == null)
+						recentComand = genericCreateCommand(command_type);
+					else if (command_type == 'functioncall')
+						recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 					command_parent.commands_else.push(recentComand);
 
 					renderCommand(recentComand, el_jq, 3, function_obj);
 				} else { // Se já tem algum comando no bloco:
 					console.log('SSS2');
-					findInBlockCorrectPlace(el_jq, event, function_obj, command_type, true);
+					findInBlockCorrectPlace(el_jq, event, function_obj, command_type, true, function_called);
 				}
 				return;
 			}
@@ -668,7 +688,7 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 			var index = command_parent.commands_else.indexOf(command_target);
 
 			if (index > -1) {
-			    command_parent.commands_else.splice((index + 1), 0, recentComand);
+				command_parent.commands_else.splice((index + 1), 0, recentComand);
 			}
 
 			renderCommand(recentComand, el, 2, function_obj);
@@ -680,16 +700,20 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 				if (command_parent.commands_block == null || command_parent.commands_block.length == 0) {
 					command_parent.commands_block = [];
 
-					var recentComand = genericCreateCommand(command_type);
+					var recentComand = null;
+					if (function_called == null)
+						recentComand = genericCreateCommand(command_type);
+					else if (command_type == 'functioncall')
+						recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 					command_parent.commands_block.push(recentComand);
 					console.log('SSS6');
 					renderCommand(recentComand, el_jq, 3, function_obj);
 				} else {
 					console.log('SSS7');
-					findInBlockCorrectPlace(el_jq, event, function_obj, command_type);
+					findInBlockCorrectPlace(el_jq, event, function_obj, command_type, function_called);
 				}
-				
-				
+
+
 				return;
 			}
 
@@ -697,40 +721,45 @@ function findBeforeOrAfterCommandToAddInsertBlock (el, event, function_obj, comm
 			var index = command_parent.commands_block.indexOf(command_target);
 
 			if (index > -1) {
-			    command_parent.commands_block.splice((index + 1), 0, recentComand);
+				command_parent.commands_block.splice((index + 1), 0, recentComand);
 			}
 
 			renderCommand(recentComand, el, 2, function_obj);
 		}
 
-		
+
 	}
 }
 
-function insertCommandInBlock (el, event, function_obj, command_type) {
+function insertCommandInBlock(el, event, function_obj, command_type, function_called = 0) {
 	var el_jq = $(el);
 	var command_parent = el_jq.data('command');
 
 	if ((el_jq.data('command').type == Models.COMMAND_TYPES.repeatNtimes) ||
-		(el_jq.data('command').type == Models.COMMAND_TYPES.whiletrue)  ||
-		(el_jq.data('command').type == Models.COMMAND_TYPES.dowhiletrue) ) {
+		(el_jq.data('command').type == Models.COMMAND_TYPES.whiletrue) ||
+		(el_jq.data('command').type == Models.COMMAND_TYPES.dowhiletrue)) {
 
 		// Se não tiver outro comando ainda no bloco, só adiciona: 
 		if (command_parent.commands_block == null || command_parent.commands_block.length == 0) {
 			command_parent.commands_block = [];
 
-			var recentComand = genericCreateCommand(command_type);
+			var recentComand = null;
+			if (function_called == null)
+				recentComand = genericCreateCommand(command_type);
+			else if (command_type == 'functioncall')
+				recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
+
 			command_parent.commands_block.push(recentComand);
 
 			renderCommand(recentComand, el_jq.find('.block_commands'), 3, function_obj);
 		} else { // Se já tem algum comando no bloco:
-			findInBlockCorrectPlace(el, event, function_obj, command_type);
+			findInBlockCorrectPlace(el, event, function_obj, command_type, function_called);
 		}
 
 	} else if (el_jq.data('command').type == Models.COMMAND_TYPES.iftrue) {
 
 		console.log('QQ9');
-		
+
 		// no if ou no else?
 		var correct_div = $(document.elementFromPoint(event.pageX, event.pageY));
 		var is_in_if = true;
@@ -757,24 +786,32 @@ function insertCommandInBlock (el, event, function_obj, command_type) {
 			if (command_parent.commands_block == null || command_parent.commands_block.length == 0) {
 				command_parent.commands_block = [];
 
-				var recentComand = genericCreateCommand(command_type);
+				var recentComand = null;
+				if (function_called == null)
+					recentComand = genericCreateCommand(command_type);
+				else if (command_type == 'functioncall')
+					recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 				command_parent.commands_block.push(recentComand);
 
 				renderCommand(recentComand, el_jq.find('.commands_if'), 3, function_obj);
 			} else { // Se já tem algum comando no bloco:
-				findInBlockCorrectPlace(el_jq.find('.commands_if'), event, function_obj, command_type);
+				findInBlockCorrectPlace(el_jq.find('.commands_if'), event, function_obj, command_type, function_called);
 			}
 
 		} else {
 			if (command_parent.commands_else == null || command_parent.commands_else.length == 0) {
 				command_parent.commands_else = [];
 
-				var recentComand = genericCreateCommand(command_type);
+				var recentComand = null;
+				if (function_called == null)
+					recentComand = genericCreateCommand(command_type);
+				else if (command_type == 'functioncall')
+					recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 				command_parent.commands_else.push(recentComand);
 
 				renderCommand(recentComand, el_jq.find('.commands_else'), 3, function_obj);
 			} else { // Se já tem algum comando no bloco:
-				findInBlockCorrectPlace(el_jq.find('.commands_else'), event, function_obj, command_type, true);
+				findInBlockCorrectPlace(el_jq.find('.commands_else'), event, function_obj, command_type, true, function_called);
 			}
 
 		}
@@ -785,13 +822,13 @@ function insertCommandInBlock (el, event, function_obj, command_type) {
 	}
 }
 
-function addCommandToSwitchCase (event, function_obj, command_type) {
+function addCommandToSwitchCase(event, function_obj, command_type) {
 
 	var el = $(document.elementFromPoint(event.clientX, event.clientY));
 
 	var which_case = el.data('switchcase');
 	var case_div = el;
-	
+
 	if (!which_case) {
 		var hier_find = el.parentsUntil(".all_cases_div");
 		for (var i = 0; i < hier_find.length; i++) {
@@ -806,11 +843,15 @@ function addCommandToSwitchCase (event, function_obj, command_type) {
 	if (which_case.commands_block == null || which_case.commands_block.length < 1) {
 		which_case.commands_block = [];
 
-		var recentComand = genericCreateCommand(command_type);
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 		which_case.commands_block.push(recentComand);
 		renderCommand(recentComand, case_div.find('.case_commands_block'), 3, function_obj);
 	} else {
-		findInBlockCorrectPlaceInSwitchCase(which_case, case_div, event, function_obj, command_type);
+		findInBlockCorrectPlaceInSwitchCase(which_case, case_div, event, function_obj, command_type, function_called);
 	}
 
 }
@@ -818,7 +859,7 @@ function addCommandToSwitchCase (event, function_obj, command_type) {
 
 
 
-function findInBlockCorrectPlaceInSwitchCase (which_case, case_div, event, function_obj, command_type) {
+function findInBlockCorrectPlaceInSwitchCase(which_case, case_div, event, function_obj, command_type) {
 
 	var all_sub = case_div.find('div.command_container');
 
@@ -831,7 +872,7 @@ function findInBlockCorrectPlaceInSwitchCase (which_case, case_div, event, funct
 
 	// Descobrindo o elemento mais próximo:
 	for (var i = 0; i < all_sub.length; i++) {
-	
+
 		t_top = all_sub[i].getBoundingClientRect().top;
 		t_bot = all_sub[i].getBoundingClientRect().top + all_sub[i].getBoundingClientRect().height;
 
@@ -842,10 +883,14 @@ function findInBlockCorrectPlaceInSwitchCase (which_case, case_div, event, funct
 	}
 
 	var borda_inferior = elemento_menor_distancia.parentNode.getBoundingClientRect().top + elemento_menor_distancia.parentNode.getBoundingClientRect().height;
-	
+
 	// Está mais próximo da borda de baixo, ou seja.. inserir por último:
 	if ((borda_inferior - event.clientY) < menor_distancia) {
-		var recentComand = genericCreateCommand(command_type);
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 
 		which_case.commands_block.push(recentComand);
 
@@ -853,18 +898,22 @@ function findInBlockCorrectPlaceInSwitchCase (which_case, case_div, event, funct
 
 	} else {
 
-		var recentComand = genericCreateCommand(command_type);
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 
 		var index = which_case.commands_block.indexOf($(elemento_menor_distancia).data('command'));
 
 		if (index > -1) {
-		    which_case.commands_block.splice(index, 0, recentComand);
-		    renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
+			which_case.commands_block.splice(index, 0, recentComand);
+			renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
 		}
 	}
 }
 
-function findInBlockCorrectPlace (el, event, function_obj, command_type, is_in_else = false) {
+function findInBlockCorrectPlace(el, event, function_obj, command_type, is_in_else = false) {
 	var el_jq = $(el);
 	var all_sub = el_jq.find('div.command_container');
 
@@ -877,7 +926,7 @@ function findInBlockCorrectPlace (el, event, function_obj, command_type, is_in_e
 
 	// Descobrindo o elemento mais próximo:
 	for (var i = 0; i < all_sub.length; i++) {
-	
+
 		t_top = all_sub[i].getBoundingClientRect().top;
 		t_bot = all_sub[i].getBoundingClientRect().top + all_sub[i].getBoundingClientRect().height;
 
@@ -891,13 +940,17 @@ function findInBlockCorrectPlace (el, event, function_obj, command_type, is_in_e
 
 	console.log("menor_distancia: ");
 	console.log(elemento_menor_distancia);
-	
+
 	// Está mais próximo da borda de baixo, ou seja.. inserir por último:
 	if ((borda_inferior - event.clientY) < menor_distancia) {
 
 		console.log('QQ11');
-		
-		var recentComand = genericCreateCommand(command_type);
+
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 
 		var command_parent = el_jq.data('command');
 
@@ -922,7 +975,11 @@ function findInBlockCorrectPlace (el, event, function_obj, command_type, is_in_e
 
 		console.log('QQ12');
 
-		var recentComand = genericCreateCommand(command_type);
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 
 		var command_parent = el_jq.data('command');
 
@@ -931,31 +988,31 @@ function findInBlockCorrectPlace (el, event, function_obj, command_type, is_in_e
 			var index = command_parent.commands_else.indexOf($(elemento_menor_distancia).data('command'));
 
 			if (index > -1) {
-			    command_parent.commands_else.splice(index, 0, recentComand);
-			    renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
+				command_parent.commands_else.splice(index, 0, recentComand);
+				renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
 			}
 
 		} else {
 			var index = command_parent.commands_block.indexOf($(elemento_menor_distancia).data('command'));
 
 			if (index > -1) {
-			    command_parent.commands_block.splice(index, 0, recentComand);
-			    renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
+				command_parent.commands_block.splice(index, 0, recentComand);
+				renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
 			}
 
 		}
-		
+
 	}
 }
 
-function findBeforeOrAfterCommandToAdd (el, event, function_obj, command_type) {
+function findBeforeOrAfterCommandToAdd(el, event, function_obj, command_type, function_called = null) {
 	switch ($(el).data('command').type) {
 		case Models.COMMAND_TYPES.iftrue:
 		case Models.COMMAND_TYPES.switch:
 		case Models.COMMAND_TYPES.repeatNtimes:
 		case Models.COMMAND_TYPES.whiletrue:
 		case Models.COMMAND_TYPES.dowhiletrue:
-			insertCommandInBlock(el, event, function_obj, command_type);
+			insertCommandInBlock(el, event, function_obj, command_type, function_called);
 			return;
 	}
 
@@ -973,31 +1030,40 @@ function findBeforeOrAfterCommandToAdd (el, event, function_obj, command_type) {
 
 	// Está mais próximo da borda de baixo, ou seja.. inserir por último:
 	if (d_top < d_bot) {
-		
-		var recentComand = genericCreateCommand(command_type);
+
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
+
 
 		var index = function_obj.commands.indexOf($(el).data('command'));
 
 		if (index > -1) {
-		    function_obj.commands.splice(index, 0, recentComand);
+			function_obj.commands.splice(index, 0, recentComand);
 		}
 
 		renderCommand(recentComand, el, 1, function_obj);
 
 	} else {
-		var recentComand = genericCreateCommand(command_type);
+		var recentComand = null;
+		if (function_called == null)
+			recentComand = genericCreateCommand(command_type);
+		else if (command_type == 'functioncall')
+			recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 
 		var index = function_obj.commands.indexOf($(el).data('command'));
 
 		if (index > -1) {
-		    function_obj.commands.splice((index + 1), 0, recentComand);
+			function_obj.commands.splice((index + 1), 0, recentComand);
 		}
 
 		renderCommand(recentComand, el, 2, function_obj);
 	}
 }
 
-function findNearbyCommandToAddInFunctionScope (el, event, node_list_commands, function_obj, command_type, function_called = null) {
+function findNearbyCommandToAddInFunctionScope(el, event, node_list_commands, function_obj, command_type, function_called = null) {
 
 	var all_sub = $(node_list_commands).find('div.command_container');
 
@@ -1010,7 +1076,7 @@ function findNearbyCommandToAddInFunctionScope (el, event, node_list_commands, f
 
 	// Descobrindo o elemento mais próximo:
 	for (var i = 0; i < all_sub.length; i++) {
-	
+
 		t_top = all_sub[i].getBoundingClientRect().top;
 		t_bot = all_sub[i].getBoundingClientRect().top + all_sub[i].getBoundingClientRect().height;
 
@@ -1021,16 +1087,16 @@ function findNearbyCommandToAddInFunctionScope (el, event, node_list_commands, f
 	}
 
 	var borda_inferior = elemento_menor_distancia.parentNode.getBoundingClientRect().top + elemento_menor_distancia.parentNode.getBoundingClientRect().height;
-	
+
 	var recentComand = null;
-	if (function_called == null) 
+	if (function_called == null)
 		recentComand = genericCreateCommand(command_type);
 	else if (command_type == 'functioncall')
 		recentComand = new Models.FunctionCall(new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, function_called, null, null, false), null);
 
 	// Está mais próximo da borda de baixo, ou seja.. inserir por último:
 	if ((borda_inferior - event.clientY) < menor_distancia) {
-		
+
 		function_obj.commands.push(recentComand);
 		//
 		renderCommand(recentComand, node_list_commands, 3, function_obj);
@@ -1040,7 +1106,7 @@ function findNearbyCommandToAddInFunctionScope (el, event, node_list_commands, f
 		var index = function_obj.commands.indexOf($(elemento_menor_distancia).data('command'));
 
 		if (index > -1) {
-		    function_obj.commands.splice(index, 0, recentComand);
+			function_obj.commands.splice(index, 0, recentComand);
 		}
 
 		renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
@@ -1101,14 +1167,14 @@ createFloatingCommand = function (function_obj, function_container, command_type
 	}
 	floatingObject.draggable().appendTo("body");
 
-	floatingObject.on('dragstart', function(e) {
+	floatingObject.on('dragstart', function (e) {
 		console.log("TESTEEEEE");
 	}).trigger('dragstart');
 
-	floatingObject.mouseup(function(evt) {
+	floatingObject.mouseup(function (evt) {
 		console.log('mouseup')
 		$(".commands_list_div, .commands_list_div, .block_commands, .command_container").off('mouseenter mouseleave');
-	  manageCommand(function_obj, function_container, evt, command_type);
+		manageCommand(function_obj, function_container, evt, command_type);
 	});
 
 	floatingObject.css("position", "absolute");
@@ -1238,6 +1304,6 @@ manageCommand = function(function_obj, function_container, event, command_type)
 	which_element_is_draged = null;
 }
 */
-export function prepareManageCommand (function_obj, function_container, evt, command_type, function_called = null) {
+export function prepareManageCommand(function_obj, function_container, evt, command_type, function_called = null) {
 	manageCommand(function_obj, function_container, evt, command_type, function_called);
 }

+ 111 - 52
js/visualUI/functions.js

@@ -10,31 +10,41 @@ import * as VariableValueMenu from './commands/variable_value_menu';
 import { DOMConsole } from './../io/domConsole';
 import { IVProgParser } from './../ast/ivprogParser';
 import { IVProgProcessor } from './../processor/ivprogProcessor';
-import { LanguageService } from '../services/languageService';
 import WatchJS from 'melanke-watchjs';
-
+import { SemanticAnalyser } from '../processor/semantic/semanticAnalyser';
+import { IVProgAssessment } from '../assessment/ivprogAssessment';
+import * as AlgorithmManagement from './algorithm';
 
 var counter_new_functions = 0;
 var counter_new_parameters = 0;
 
+let studentTemp = null;
 let domConsole = null;
+window.studentGrade = null;
 const program = new Models.Program();
-const variable1 = new Models.Variable(Types.INTEGER, "a", 1);
-const mainFunction = new Models.Function(LocalizedStrings.getUI("start"), Types.VOID, 0, [], true, false, [variable1]);
-mainFunction.function_comment = new Models.Comment(LocalizedStrings.getUI('text_comment_main'));
+/*const variable1 = new Models.Variable(Types.INTEGER, "a", 1);
 const parameter1 = new Models.Variable(Types.INTEGER, "par_1", 1);
 const command1 = new Models.Comment(new Models.VariableValueMenu(VariableValueMenu.VAR_OR_VALUE_TYPES.only_value, "Testing rendering commands"));
 
 const sumFunction = new Models.Function("soma", Types.INTEGER, 0, [parameter1], false, false, [], null, [command1]);
 
-program.addFunction(mainFunction);
+
 program.addFunction(sumFunction);
+*/
+
+const mainFunction = new Models.Function(LocalizedStrings.getUI("start"), Types.VOID, 0, [], true, false);
+mainFunction.function_comment = new Models.Comment(LocalizedStrings.getUI('text_comment_main'));
+program.addFunction(mainFunction);
 
 window.program_obj = program;
 
+window.generator = CodeManagement.generate;
+window.runCodeAssessment = runCodeAssessment;
+window.renderAlgorithm = AlgorithmManagement.renderAlgorithm;
+
 WatchJS.watch(program.globals, function(){
-      console.log("as globais foram alteradas!");
-  }, 1);
+  AlgorithmManagement.renderAlgorithm();
+}, 1);
 
 function addFunctionHandler () {
 
@@ -63,7 +73,7 @@ function updateReturnType (function_obj, new_type, new_dimensions = 0) {
 }
 
 function removeFunction (function_obj) {
-
+  
   var index = program.functions.indexOf(function_obj);
   if (index > -1) {
     program.functions.splice(index, 1);
@@ -134,7 +144,7 @@ function addHandlers (function_obj, function_container) {
 function renderFunctionReturn (function_obj, function_element) {
 
   var ret = '<div class="ui dropdown function_return">';
-
+    
     if (function_obj.return_dimensions > 0) {
       ret += '<div class="text">'+ LocalizedStrings.getUI("vector") +':'+ LocalizedStrings.getUI(function_obj.return_type);
       ret += '</div>';
@@ -161,32 +171,32 @@ function renderFunctionReturn (function_obj, function_element) {
             + '<div class="item '+(function_obj.return_type == tm.toLowerCase()  && function_obj.return_dimensions > 0 ? ' selected ' : '')+'" data-text="'+ LocalizedStrings.getUI('vector')+':'+LocalizedStrings.getUI(tm.toLowerCase())+' [ ] " data-type="'+tm+'" data-dimensions="1">[ ]</div>'
             + '<div class="item '+(function_obj.return_type == tm.toLowerCase()  && function_obj.return_dimensions > 0 ? ' selected ' : '')+'" data-text="'+ LocalizedStrings.getUI('vector')+':'+LocalizedStrings.getUI(tm.toLowerCase())+' [ ] [ ] " data-type="'+tm+'" data-dimensions="2">[ ] [ ] </div>'
           +  '</div>'
-        + '</div>';
+        + '</div>'; 
     }
 
     ret += '</div></div>';
 
     ret = $(ret);
-
+    
     function_element.find('.function_return').append(ret);
 }
 
 
-function renderFunction (function_obj) {
+export function renderFunction (function_obj) {
 
   var appender = '<div class="ui secondary segment function_div list-group-item">';
 
   if (function_obj.function_comment) {
     //appender += renderComment(function_obj.function_comment, sequence, true, -1);
   }
-
+    
   appender += '<span class="glyphicon glyphicon-move move_function" aria-hidden="true"><i class="icon sort alternate vertical"></i></span>';
 
   appender += (function_obj.is_main ? '<div class="div_start_minimize_v"> </div>' : '<button class="ui icon button large remove_function_button"><i class="red icon times"></i></button>')
     + '<button class="ui icon button tiny minimize_function_button"><i class="icon window minimize"></i></button>';
 
   appender += '<div class="ui small icon buttons add_var_top_button"><div class="ui icon button add_var_button_function"><i class="icon superscript"></i></div>';
-
+  
   appender += '<div class="ui icon button dropdown menu_commands" ><i class="icon code"></i> <div class="menu"> ';
   appender += '<a class="item" data-command="'+Models.COMMAND_TYPES.reader+'"><i class="download icon"></i> ' +LocalizedStrings.getUI('text_read_var')+ '</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.writer+'"><i class="upload icon"></i> '+LocalizedStrings.getUI('text_write_var')+'</a>'
@@ -198,6 +208,7 @@ function renderFunction (function_obj) {
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.whiletrue+'"><i class="sync icon"></i> '+LocalizedStrings.getUI('text_whiletrue')+'</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.dowhiletrue+'"><i class="sync icon"></i> '+LocalizedStrings.getUI('text_dowhiletrue')+'</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.switch+'"><i class="list icon"></i> '+LocalizedStrings.getUI('text_switch')+'</a>'
+        + '<a class="item" data-command="'+Models.COMMAND_TYPES.return+'"><i class="reply icon"></i> '+LocalizedStrings.getUI('text_btn_return')+'</a>'
         + '</div></div></div>';
 
   appender += '<div class="function_signature_div">'+LocalizedStrings.getUI("function")+' ';
@@ -208,11 +219,11 @@ function renderFunction (function_obj) {
   } else {
       appender += '<div class="ui function_return"></div>';
 
-      appender += '<div class="function_name_div"><span class="span_name_function name_function_updated">'+function_obj.name+'</span> <i class="icon small pencil alternate enable_edit_name_function name_function_updated"></i></div> '
+      appender += '<div class="function_name_div"><span class="span_name_function name_function_updated">'+function_obj.name+'</span> <i class="icon small pencil alternate enable_edit_name_function name_function_updated"></i></div> ' 
         + '( <i class="ui icon plus square outline add_parameter_button"></i> <div class="ui large labels parameters_list container_parameters_list">';
   }
-
-  appender += '</div> ) {</div>'
+    
+  appender += '</div> ) </div>'
     + (function_obj.is_hidden ? ' <div class="function_area" style="display: none;"> ' : ' <div class="function_area"> ')
 
     + '<div class="ui top attached segment variables_list_div">'
@@ -220,17 +231,9 @@ function renderFunction (function_obj) {
     + '</div>'
     + '<div class="ui bottom attached segment commands_list_div" id="function_drag_cmd_">';
 
-
-  if (function_obj.commands) {
-    for (var l = 0; l < function_obj.commands.length; l++) {
-      //appender += renderElementCommandGeneric(programa.funcoes[sequence].comandos[l], sequence, l, -1, l);
-
-    }
-  }
-
   appender += '</div>';
 
-  appender += '<div class="function_close_div">}</div>'
+  appender += '<div class="function_close_div"></div>'
     + '</div>'
     + '</div>';
 
@@ -246,7 +249,7 @@ function renderFunction (function_obj) {
   addHandlers(function_obj, appender);
 
 
-  // Rendering parameters:
+  // Rendering parameters: 
   for (var j = 0; j < function_obj.parameters_list.length; j++) {
     renderParameter(function_obj, function_obj.parameters_list[j], appender);
   }
@@ -287,8 +290,15 @@ export function initVisualUI () {
   $('.textual_coding_button').on('click', () => {
     toggleTextualCoding();
   });
+
+  $('.assessment').on('click', () => {
+    runCodeAssessment();
+    is_iassign = true;
+  });
 }
 
+var is_iassign = false;
+
 $( document ).ready(function() {
 
   for (var i = 0; i < program.functions.length; i++) {
@@ -297,29 +307,76 @@ $( document ).ready(function() {
 
 });
 
+
+function runCodeAssessment () {
+  window.studentGrade = null;
+  studentTemp = null;
+  const strCode = CodeManagement.generate();
+  if (strCode == null) {
+    return;
+  }
+  if(domConsole == null)
+    domConsole = new DOMConsole("#ivprog-term");
+  $("#ivprog-term").slideDown(500);
+  const runner = new IVProgAssessment(strCode, testCases, domConsole);
+
+  runner.runTest().then(grade => studentTemp = grade).catch( err => domConsole.err(err.message));
+  
+  gradeMonitor();
+}
+
+function gradeMonitor () {
+
+  if (studentTemp == null) { 
+    setTimeout(gradeMonitor, 50); 
+  } else {
+    window.studentGrade = studentTemp;
+    if (!is_iassign) {
+      parent.getEvaluationCallback(window.studentGrade);
+    } else {
+      is_iassign = false;
+    }
+  }
+
+}
+
 function runCode () {
   const strCode = CodeManagement.generate();
   if (strCode == null) {
     return;
   }
-  domConsole = new DOMConsole("#ivprog-term");
+  if(domConsole == null)
+    domConsole = new DOMConsole("#ivprog-term");
   $("#ivprog-term").slideDown(500);
-  const lexer = LanguageService.getCurrentLexer();
-  const ast = new IVProgParser(strCode, lexer).parseTree();
-  const proc = new IVProgProcessor(ast);
-  proc.registerInput(domConsole);
-  proc.registerOutput(domConsole);
-  proc.interpretAST().then( _ => {
-    domConsole.info("Programa executado com sucesso!");
-    domConsole.info("Aperte qualquer tecla para fechar...");
-    const p = new Promise((resolve, _) => {
-      domConsole.requestInput(resolve);
-    });
-    p.then( _ => {
-      domConsole.dispose();
-      domConsole = null;
-      $("#ivprog-term").hide();
-    })
+  try {
+    const parser = IVProgParser.createParser(strCode);
+    const analyser = new SemanticAnalyser(parser.parseTree());
+    const data = analyser.analyseTree();
+    const proc = new IVProgProcessor(data);
+    proc.registerInput(domConsole);
+    proc.registerOutput(domConsole);
+    
+    proc.interpretAST().then( _ => {
+      domConsole.info("Programa executado com sucesso!");
+    }).catch(err => {
+      domConsole.err(err.message);
+    }) 
+  } catch (error) {
+    domConsole.err(error.message);
+    console.log(error);
+  }
+  
+}
+
+function waitToCloseConsole () {
+  domConsole.info("Aperte qualquer tecla para fechar...");
+  const p = new Promise((resolve, _) => {
+    domConsole.requestInput(resolve, true);
+  });
+  p.then( _ => {
+    domConsole.dispose();
+    domConsole = null;
+    $("#ivprog-term").hide();
   })
 }
 
@@ -359,7 +416,7 @@ function updateParameterType(parameter_obj, new_type, new_dimensions = 0) {
 function renderParameter (function_obj, parameter_obj, function_container) {
   var ret = "";
 
-  ret += '<div class="ui label function_name_parameter"><span class="span_name_parameter label_enable_name_parameter">'+parameter_obj.name+'</span> <i class="icon small pencil alternate enable_edit_name_parameter label_enable_name_parameter"></i>';
+  ret += '<div class="ui label function_name_parameter">';
 
   ret += '<div class="ui dropdown parameter_type">';
 
@@ -373,7 +430,7 @@ function renderParameter (function_obj, parameter_obj, function_container) {
   ret += '<i class="dropdown icon"></i>'
     + '<div class="menu">';
 
-
+  
   for (var tm in Types) {
       if (tm == Types.VOID.toUpperCase()) {
         continue;
@@ -392,21 +449,23 @@ function renderParameter (function_obj, parameter_obj, function_container) {
           + '<div class="item" data-text="'+ LocalizedStrings.getUI('vector')+':'+LocalizedStrings.getUI(tm.toLowerCase())+' [ ] " data-type="'+tm+'" data-dimensions="1">[ ]</div>'
           + '<div class="item" data-text="'+ LocalizedStrings.getUI('vector')+':'+LocalizedStrings.getUI(tm.toLowerCase())+' [ ] [ ] " data-type="'+tm+'" data-dimensions="2">[ ] [ ] </div>'
         +  '</div>'
-      + '</div>';
+      + '</div>'; 
   }
 
   ret += '</div></div>';
 
+  ret += '<span class="span_name_parameter label_enable_name_parameter">'+parameter_obj.name+'</span> <i class="icon small pencil alternate enable_edit_name_parameter label_enable_name_parameter"></i>';
+
   ret += ' <i class="red icon times remove_parameter"></i></div>';
 
   ret = $(ret);
-
+  
   function_container.find('.container_parameters_list').append(ret);
 
   ret.find('.remove_parameter').on('click', function(e){
     removeParameter(function_obj, parameter_obj, ret);
   });
-
+  
   ret.find('.ui.dropdown.parameter_type').dropdown({
     onChange: function(value, text, $selectedItem) {
       if ($($selectedItem).data('dimensions')) {
@@ -552,5 +611,5 @@ function enableNameFunctionUpdate(function_obj, parent_node) {
       opened_input = false;
     }
   });
-
-}
+  
+}

+ 159 - 48
js/visualUI/functions_sidebar.js

@@ -12,23 +12,28 @@ import { IVProgParser } from './../ast/ivprogParser';
 import { IVProgProcessor } from './../processor/ivprogProcessor';
 import { LanguageService } from '../services/languageService';
 import WatchJS from 'melanke-watchjs';
+import { SemanticAnalyser } from '../processor/semantic/semanticAnalyser';
+import { IVProgAssessment } from '../assessment/ivprogAssessment';
+import * as AlgorithmManagement from './algorithm';
 
 
 var counter_new_functions = 0;
 var counter_new_parameters = 0;
 
+let studentTemp = null;
 let domConsole = null;
+window.studentGrade = null;
 const program = new Models.Program();
-const variable1 = new Models.Variable(Types.INTEGER, "a", 1);
-const mainFunction = new Models.Function(LocalizedStrings.getUI("start"), Types.VOID, 0, [], true, false, [variable1]);
+/*const variable1 = new Models.Variable(Types.INTEGER, "a", 1);*/
+const mainFunction = new Models.Function(LocalizedStrings.getUI("start"), Types.VOID, 0, [], true, false);
 mainFunction.function_comment = new Models.Comment(LocalizedStrings.getUI('text_comment_main'));
-const parameter1 = new Models.Variable(Types.INTEGER, "par_1", 1);
+/*const parameter1 = new Models.Variable(Types.INTEGER, "par_1", 1);
 const command1 = new Models.Comment(new Models.VariableValueMenu(VariableValueMenu.VAR_OR_VALUE_TYPES.only_value, "Testing rendering commands"));
 
-const sumFunction = new Models.Function("soma", Types.INTEGER, 0, [parameter1], false, false, [], null, [command1]);
+const sumFunction = new Models.Function("soma", Types.INTEGER, 0, [parameter1], false, false, [], null, [command1]);*/
 
 program.addFunction(mainFunction);
-program.addFunction(sumFunction);
+//program.addFunction(sumFunction);
 
 window.program_obj = program;
 
@@ -178,7 +183,7 @@ function renderFunctionReturn (function_obj, function_element) {
 }
 
 
-function renderFunction (function_obj) {
+export function renderFunction (function_obj) {
 
   var appender = '<div class="ui secondary segment function_div list-group-item">';
 
@@ -194,8 +199,7 @@ function renderFunction (function_obj) {
   appender += '<div class="ui small icon buttons add_var_top_button"><div class="ui icon button add_var_button_function"><i class="icon superscript"></i></div>';
 
   appender += '<div class="ui icon button dropdown menu_commands" ><i class="icon code"></i> <div class="menu"> ';
-  appender += '<a class="item" data-command="'+Models.COMMAND_TYPES.break+'"><i class="download icon"></i> ' +LocalizedStrings.getUI('text_break')+ '</a>'
-        + '<a class="item" data-command="'+Models.COMMAND_TYPES.reader+'"><i class="download icon"></i> ' +LocalizedStrings.getUI('text_read_var')+ '</a>'
+  appender += '<a class="item" data-command="'+Models.COMMAND_TYPES.reader+'"><i class="download icon"></i> ' +LocalizedStrings.getUI('text_read_var')+ '</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.writer+'"><i class="upload icon"></i> '+LocalizedStrings.getUI('text_write_var')+'</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.comment+'"><i class="quote left icon"></i> '+LocalizedStrings.getUI('text_comment')+'</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.attribution+'"><i class="arrow left icon"></i> '+LocalizedStrings.getUI('text_attribution')+'</a>'
@@ -205,6 +209,7 @@ function renderFunction (function_obj) {
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.whiletrue+'"><i class="sync icon"></i> '+LocalizedStrings.getUI('text_whiletrue')+'</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.dowhiletrue+'"><i class="sync icon"></i> '+LocalizedStrings.getUI('text_dowhiletrue')+'</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.switch+'"><i class="list icon"></i> '+LocalizedStrings.getUI('text_switch')+'</a>'
+        + '<a class="item" data-command="'+Models.COMMAND_TYPES.return+'"><i class="reply icon"></i> '+LocalizedStrings.getUI('text_btn_return')+'</a>'
         + '</div></div></div>';
 
   appender += '<div class="function_signature_div">'+LocalizedStrings.getUI("function")+' ';
@@ -219,7 +224,7 @@ function renderFunction (function_obj) {
         + '( <i class="ui icon plus square outline add_parameter_button"></i> <div class="ui large labels parameters_list container_parameters_list">';
   }
 
-  appender += '</div> ) {</div>'
+  appender += '</div> ) </div>'
     + (function_obj.is_hidden ? ' <div class="function_area" style="display: none;"> ' : ' <div class="function_area"> ')
 
     + '<div class="ui top attached segment variables_list_div">'
@@ -228,16 +233,9 @@ function renderFunction (function_obj) {
     + '<div class="ui bottom attached segment commands_list_div" id="function_drag_cmd_">';
 
 
-  if (function_obj.commands) {
-    for (var l = 0; l < function_obj.commands.length; l++) {
-      //appender += renderElementCommandGeneric(programa.funcoes[sequence].comandos[l], sequence, l, -1, l);
-
-    }
-  }
-
   appender += '</div>';
 
-  appender += '<div class="function_close_div">}</div>'
+  appender += '<div class="function_close_div"></div>'
     + '</div>'
     + '</div>';
 
@@ -294,8 +292,15 @@ export function initVisualUI () {
   $('.textual_coding_button').on('click', () => {
     toggleTextualCoding();
   });
+
+  $('.assessment').on('click', () => {
+    runCodeAssessment();
+    is_iassign = true;
+  });
 }
 
+var is_iassign = false;
+
 $( document ).ready(function() {
 
   for (var i = 0; i < program.functions.length; i++) {
@@ -304,26 +309,76 @@ $( document ).ready(function() {
 
 });
 
+
+function runCodeAssessment () {
+  window.studentGrade = null;
+  studentTemp = null;
+  const strCode = CodeManagement.generate();
+  if (strCode == null) {
+    return;
+  }
+  if(domConsole == null)
+    domConsole = new DOMConsole("#ivprog-term");
+  $("#ivprog-term").slideDown(500);
+  const runner = new IVProgAssessment(strCode, testCases, domConsole);
+
+  runner.runTest().then(grade => studentTemp = grade).catch( err => domConsole.err(err.message));
+  
+  gradeMonitor();
+}
+
+function gradeMonitor () {
+
+  if (studentTemp == null) { 
+    setTimeout(gradeMonitor, 50); 
+  } else {
+    window.studentGrade = studentTemp;
+    if (!is_iassign) {
+      parent.getEvaluationCallback(window.studentGrade);
+    } else {
+      is_iassign = false;
+    }
+  }
+
+}
+
 function runCode () {
   const strCode = CodeManagement.generate();
-  domConsole = new DOMConsole("#ivprog-term");
+  if (strCode == null) {
+    return;
+  }
+  if(domConsole == null)
+    domConsole = new DOMConsole("#ivprog-term");
   $("#ivprog-term").slideDown(500);
-  const lexer = LanguageService.getCurrentLexer();
-  const ast = new IVProgParser(strCode, lexer).parseTree();
-  const proc = new IVProgProcessor(ast);
-  proc.registerInput(domConsole);
-  proc.registerOutput(domConsole);
-  proc.interpretAST().then( _ => {
-    domConsole.info("Programa executado com sucesso!");
-    domConsole.info("Aperte qualquer tecla para fechar...");
-    const p = new Promise((resolve, _) => {
-      domConsole.requestInput(resolve);
-    });
-    p.then( _ => {
-      domConsole.dispose();
-      domConsole = null;
-      $("#ivprog-term").hide();
-    })
+  try {
+    const parser = IVProgParser.createParser(strCode);
+    const analyser = new SemanticAnalyser(parser.parseTree());
+    const data = analyser.analyseTree();
+    const proc = new IVProgProcessor(data);
+    proc.registerInput(domConsole);
+    proc.registerOutput(domConsole);
+    
+    proc.interpretAST().then( _ => {
+      domConsole.info("Programa executado com sucesso!");
+    }).catch(err => {
+      domConsole.err(err.message);
+    }) 
+  } catch (error) {
+    domConsole.err(error.message);
+    console.log(error);
+  }
+  
+}
+
+function waitToCloseConsole () {
+  domConsole.info("Aperte qualquer tecla para fechar...");
+  const p = new Promise((resolve, _) => {
+    domConsole.requestInput(resolve, true);
+  });
+  p.then( _ => {
+    domConsole.dispose();
+    domConsole = null;
+    $("#ivprog-term").hide();
   })
 }
 
@@ -363,7 +418,7 @@ function updateParameterType(parameter_obj, new_type, new_dimensions = 0) {
 function renderParameter (function_obj, parameter_obj, function_container) {
   var ret = "";
 
-  ret += '<div class="ui label function_name_parameter"><span class="span_name_parameter label_enable_name_parameter">'+parameter_obj.name+'</span> <i class="icon small pencil alternate enable_edit_name_parameter label_enable_name_parameter"></i>';
+  ret += '<div class="ui label function_name_parameter">';
 
   ret += '<div class="ui dropdown parameter_type">';
 
@@ -401,6 +456,8 @@ function renderParameter (function_obj, parameter_obj, function_container) {
 
   ret += '</div></div>';
 
+  ret += '<span class="span_name_parameter label_enable_name_parameter">'+parameter_obj.name+'</span> <i class="icon small pencil alternate enable_edit_name_parameter label_enable_name_parameter"></i>';
+
   ret += ' <i class="red icon times remove_parameter"></i></div>';
 
   ret = $(ret);
@@ -600,6 +657,7 @@ renderFunction = function(function_obj) {
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.whiletrue+'"><i class="sync icon"></i> '+LocalizedStrings.getUI('text_whiletrue')+'</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.dowhiletrue+'"><i class="sync icon"></i> '+LocalizedStrings.getUI('text_dowhiletrue')+'</a>'
         + '<a class="item" data-command="'+Models.COMMAND_TYPES.switch+'"><i class="list icon"></i> '+LocalizedStrings.getUI('text_switch')+'</a>'
+        + '<a class="item" data-command="'+Models.COMMAND_TYPES.return+'"><i class="reply icon"></i> '+LocalizedStrings.getUI('text_btn_return')+'</a>'
         + '</div></div></div>';
 
   appender += '<div class="function_signature_div">'+LocalizedStrings.getUI("function")+' ';
@@ -613,20 +671,34 @@ renderFunction = function(function_obj) {
       appender += '<div class="function_name_div"><span class="span_name_function name_function_updated">'+function_obj.name+'</span> <i class="icon small pencil alternate enable_edit_name_function name_function_updated"></i></div> '
         + '( <i class="ui icon plus square outline add_parameter_button"></i> <div class="ui large labels parameters_list container_parameters_list">';
 
-			var menu_button = '<button class="fluid ui container segment labeled icon button list-group-item menu-item" draggable="true" data-function="' + function_obj.name + '"><i class="list icon"></i> ' + function_obj.name + '</button>';
-			menu_button = $(menu_button);
+      var menu_button = '<button class="fluid ui container segment labeled icon button list-group-item menu-item" draggable="true" data-function="' + function_obj.name + '"><i class="list icon"></i> <span class="function_name">' + function_obj.name + '</span> (<span class="function_params"></span>) : <span class="function_return_type"></span></button>';
+      var params = "";
+      menu_button = $(menu_button);
+      
+      for (var j = 0; j < function_obj.parameters_list.length; j++) {
+        if (j > 0)
+          params += ',';
+        params += function_obj.parameters_list[j].type;
+      }
       menu_button
         .data('fun',function_obj)
         .on('dragstart', function(e) {
           e.originalEvent.dataTransfer.setData("text",JSON.stringify({type:"function",content:function_obj}));
           //evt.originalEvent.dataTransfer.setData("text",$(this).data('command'));
         })
+        .find('.function_params').text(params)
+        .find('.function_return_type').text(function_obj.type);
 
 			$('.functions_labels').append(menu_button);
-			console.log("aqui")
+      console.log("aqui");
+      
+      //var menu_button = $('.functions_labels > [data-function=' + function_obj.name + ']');
+      //var params = "";
+      //menu_button
+
   }
 
-  appender += '</div> ) {</div>'
+  appender += '</div> ) </div>'
     + (function_obj.is_hidden ? ' <div class="function_area" style="display: none;"> ' : ' <div class="function_area"> ')
 
     + '<div class="ui top attached segment variables_list_div">'
@@ -634,17 +706,9 @@ renderFunction = function(function_obj) {
     + '</div>'
     + '<div class="ui bottom attached segment commands_list_div" id="function_drag_cmd_">';
 
-
-  if (function_obj.commands) {
-    for (var l = 0; l < function_obj.commands.length; l++) {
-      //appender += renderElementCommandGeneric(programa.funcoes[sequence].comandos[l], sequence, l, -1, l);
-
-    }
-  }
-
   appender += '</div>';
 
-  appender += '<div class="function_close_div">}</div>'
+  appender += '<div class="function_close_div"></div>'
     + '</div>'
     + '</div>';
 
@@ -933,3 +997,50 @@ enableNameFunctionUpdate = function(function_obj, parent_node) {
   });
 
 }
+
+addParameter = function (function_obj, function_container) {
+  if (function_obj.parameters_list == null) {
+    function_obj.parameters_list = [];
+  }
+  var new_parameter = new Models.Variable(Types.INTEGER, LocalizedStrings.getUI("new_parameter") + "_" + counter_new_parameters);
+  function_obj.parameters_list.push(new_parameter);
+  counter_new_parameters ++;
+
+  renderParameter(function_obj, new_parameter, function_container);
+
+  var menu_button = $('.functions_labels > [data-function=' + function_obj.name + ']');
+  var params = "";
+  for (var j = 0; j < function_obj.parameters_list.length; j++) {
+    if (j > 0)
+      params += ',';
+    params += function_obj.parameters_list[j].type;
+  }
+  menu_button.find('.function_params').text(params);
+}
+
+updateReturnType = function (function_obj, new_type, new_dimensions = 0) {
+  function_obj.return_type = new_type;
+  function_obj.return_dimensions = new_dimensions;
+
+  var menu_button = $('.functions_labels > [data-function=' + function_obj.name + ']');
+  menu_button.find('.function_return_type').text(new_type);
+}
+
+updateParameterType = function (parameter_obj, new_type, new_dimensions = 0) {
+  parameter_obj.type = new_type;
+  parameter_obj.dimensions = new_dimensions;
+
+  if (new_dimensions > 0) {
+    parameter_obj.rows = new_dimensions;
+    parameter_obj.columns = 2;
+  }
+
+  var menu_button = $('.functions_labels > [data-function=' + function_obj.name + ']');
+  var params = "";
+  for (var j = 0; j < function_obj.parameters_list.length; j++) {
+    if (j > 0)
+      params += ',';
+    params += function_obj.parameters_list[j].type;
+  }
+  menu_button.find('.function_params').text(params);
+}

+ 28 - 0
package-lock.json

@@ -2221,6 +2221,11 @@
       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
       "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
     },
+    "decimal.js": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.0.1.tgz",
+      "integrity": "sha512-vklWB5C4Cj423xnaOtsUmAv0/7GqlXIgDv2ZKDyR64OV3OSzGHNx2mk4p/1EKnB5s70k73cIOOEcG9YzF0q4Lw=="
+    },
     "decode-uri-component": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
@@ -4907,6 +4912,10 @@
         "invert-kv": "^1.0.0"
       }
     },
+    "line-i18n": {
+      "version": "git+https://git.lcalion.com/LInE/line-i18n.git#3d9c23059ba04f63fde6f2263798f66cdc29c889",
+      "from": "git+https://git.lcalion.com/LInE/line-i18n.git"
+    },
     "load-json-file": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
@@ -7232,6 +7241,19 @@
       "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
       "dev": true
     },
+    "ts-loader": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.3.0.tgz",
+      "integrity": "sha512-lGSNs7szRFj/rK9T1EQuayE3QNLg6izDUxt5jpmq0RG1rU2bapAt7E7uLckLCUPeO1jwxCiet2oRaWovc53UAg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.3.0",
+        "enhanced-resolve": "^4.0.0",
+        "loader-utils": "^1.0.2",
+        "micromatch": "^3.1.4",
+        "semver": "^5.0.1"
+      }
+    },
     "tslib": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
@@ -7264,6 +7286,12 @@
       "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
       "dev": true
     },
+    "typescript": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.5.tgz",
+      "integrity": "sha512-muYNWV9j5+3mXoKD6oPONKuGUmYiFX14gfo9lWm9ZXRHOqVDQiB4q1CzFPbF4QLV2E9TZXH6oK55oQ94rn3PpA==",
+      "dev": true
+    },
     "uglify-es": {
       "version": "3.3.9",
       "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",

+ 7 - 3
package.json

@@ -39,13 +39,17 @@
     "karma-mocha-reporter": "^2.2.5",
     "karma-webpack": "^3.0.0",
     "puppeteer-core": "^1.7.0",
-    "webpack": "^4.20.2",
-    "webpack-cli": "^3.1.1"
+    "webpack": "^4.*",
+    "ts-loader": "^5.2.2",
+    "typescript": "^3.1.3",
+    "webpack-cli": "^3.1.0"
   },
   "dependencies": {
     "antlr4": "^4.7.1",
     "jquery": "^3.3.1",
     "melanke-watchjs": "^1.5.0",
-    "server": "^1.0.18"
+    "server": "^1.0.18",
+    "decimal.js": "^10.0.1",
+    "line-i18n": "git+https://git.lcalion.com/LInE/line-i18n.git"
   }
 }