Преглед на файлове

Merge branch 'includeBuild' of LInE/ivprog into visualui

Lucas de Souza преди 5 години
родител
ревизия
81a882a33f
променени са 38 файла, в които са добавени 38772 реда и са изтрити 179 реда
  1. 1 1
      .gitignore
  2. 37742 0
      build/ivprog.bundle.js
  3. 1 0
      build/ivprog.bundle.js.map
  4. 59 11
      i18n/pt/error.json
  5. 5 0
      i18n/pt/ui.json
  6. 12 1
      js/ast/error/syntaxErrorFactory.js
  7. 13 0
      js/ast/expressions/arrayAccess.js
  8. 5 0
      js/ast/expressions/arrayLiteral.js
  9. 5 0
      js/ast/expressions/boolLiteral.js
  10. 22 0
      js/ast/expressions/functionCall.js
  11. 7 0
      js/ast/expressions/infixApp.js
  12. 5 0
      js/ast/expressions/intLiteral.js
  13. 5 0
      js/ast/expressions/realLiteral.js
  14. 4 0
      js/ast/expressions/stringLiteral.js
  15. 6 0
      js/ast/expressions/unaryApp.js
  16. 4 0
      js/ast/expressions/variableLiteral.js
  17. 45 6
      js/ast/ivprogParser.js
  18. 12 0
      js/processor/definedFunctions.js
  19. 392 1
      js/processor/error/processorErrorFactory.js
  20. 146 89
      js/processor/ivprogProcessor.js
  21. 126 60
      js/processor/semantic/semanticAnalyser.js
  22. 19 7
      js/processor/store/storeObjectArray.js
  23. 15 0
      js/processor/store/storeObjectArrayAddress.js
  24. 4 3
      js/typeSystem/baseTypes.js
  25. 8 0
      js/typeSystem/compoundType.js
  26. 9 0
      js/typeSystem/multiType.js
  27. 4 0
      js/typeSystem/type.js
  28. 2 0
      tests/test03.spec.js
  29. 2 0
      tests/test05.spec.js
  30. 2 0
      tests/test06.spec.js
  31. 2 0
      tests/test07.spec.js
  32. 2 0
      tests/test08.spec.js
  33. 2 0
      tests/test10.spec.js
  34. 2 0
      tests/test11.spec.js
  35. 2 0
      tests/test12.spec.js
  36. 33 0
      tests/testCallMainFunction.spec.js
  37. 25 0
      tests/testDuplicateFunctions.spec.js
  38. 22 0
      tests/testDuplicateVariable.spec.js

+ 1 - 1
.gitignore

@@ -1,5 +1,5 @@
 #compiled files
-/build
+#/build
 
 # dependencies
 /node_modules

Файловите разлики са ограничени, защото са твърде много
+ 37742 - 0
build/ivprog.bundle.js


Файловите разлики са ограничени, защото са твърде много
+ 1 - 0
build/ivprog.bundle.js.map


+ 59 - 11
i18n/pt/error.json

@@ -17,21 +17,69 @@
   "invalid_global_var": "Erro crítico: Chamada inválida da função initGlobal fora do contexto BASE",
   "not_implemented": "Erro interno crítico: A função definida pelo sistema $0 não foi implementada.",
   "function_missing": "A função $0 não foi encontrada",
-  "invalid_parameters_size": "A quantidade de parâmetros fornecidos está incorreta. Esperava-se $0, encontrou-se $1",
-  "invalid_ref": "Você deve fornecer apenas um identificador como parâmetro",
-  "invalid_parameter_type": "O valor fornecido como parâmetro é do tipo $0, mas o tipo esperado é $1",
-  "unknown_command": "Erro interno crítico: Comando desconhecido encontrado",
+  "function_missing_full": "A função $0 na linha: $1, coluna: $2 não foi encontrada",
+  "invalid_parameters_size_full": "Erro na linha $0: a quantidade de parâmetros fornecidos à função $1 está incorreta. Esperava-se $2, encontrou-se $3.",
+  "invalid_parameters_size": "A quantidade de parâmetros fornecidos à função $0 está incorreta. Esperava-se $1, encontrou-se $2",
+  "invalid_ref_full": "A expressão $0 fornecida como parâmetro para a função $1 na linha $2 não é válida para esta função. Use uma variável ou posição de vetor.",
+  "invalid_ref": "A expressão $0 fornecida como parâmetro para a função $1 não é válida para esta função. Use uma variável ou posição de vetor.",
+  "invalid_parameter_type_full": "A expressão $0 fornecida como parâmetro para a função $1 na linha $2 não é compatível com o tipo esperado.",
+  "invalid_parameter_type": "A expressão $0 fornecida como parâmetro para a função $1 não é compatível com o tipo esperado.",
+  "unknown_command_full": "Erro interno crítico: comando desconhecido encontrado na linha $0",
+  "unknown_command": "Erro interno crítico: comando desconhecido encontrado!",
+  "loop_condition_type_full": "Erro na linha: $0, coluna $1: a condição dos laços de repetição deve ser do tipo lógico",
   "loop_condition_type": "A condição dos laços de repetição deve ser do tipo lógico",
+  "endless_loop_full": "Possível laço infinito detectado no seu código. Verifique a linha $0",
+  "endless_loop": "Possível laço infinito detectado no seu código.",
+  "for_condition_type_full": "Erro na linha: $0, coluna $1: a condição de parada do comando para(...) deve ser do tipo lógico",
+  "for_condition_type": "A condição de parada do comando para(...) deve ser do tipo lógico",
+  "if_condition_type_full": "Erro na linha: $0, coluna $1: a condição de um comando se...senao deve ser do tipo lógico",
   "if_condition_type": "A condição de um comando se...senao deve ser do tipo lógico",
-  "invalid_return_type": "A função $0 deve retornar um tipo $1, ao invés de $1",
-  "unexpected_break_command": "Erro interno crítico: Comando pare encontrado fora do contexto de um laço/escolha..caso",
+  "invalid_return_type_full": "Erro na linha $0: a expressão não produz um tipo compatível com a função $1. Tipo esperado: $2.",
+  "invalid_return_type": "A expressão não produz um tipo compatível com a função $0. Tipo esperado: $1.",
+  "invalid_void_return_full": "Erro na linha $0: a função $1 não pode retornar uma expressão vazia, use uma espressão do tipo $2",
+  "invalid_void_return": "A função $0 não pode retornar uma expressão vazia, use uma espressão do tipo $1",
+  "unexpected_break_command_full": "Erro interno crítico: comando pare encontrado fora do contexto de um laço/escolha..caso na linha $0",
+  "unexpected_break_command": "Erro interno crítico: comando pare encontrado fora do contexto de um laço/escolha..caso",
   "invalid_dimension": "As dimensões de um vetor/matriz devem ser do tipo inteiro",
-  "void_in_expression": "A função $0 não pode ser utilizada aqui pois seu tipo de retorno é vazio",
-  "invalid_array": "Expressão literal de Vetor/Mariz inválida",
+  "void_in_expression_full": "Erro na linha: $0, coluna: $1: a função $2 não pode ser utilizada em uma expressão pois seu tipo de retorno é vazio",
+  "void_in_expression": "A função $0 não pode ser utilizada em uma expressão pois seu tipo de retorno é vazio",
+  "invalid_array_access_full": "Identificador $0 na linha: $1, coluna: $2 não se refere a um vetor/matriz válido",
   "invalid_array_access": "Identificador $0 não se refere a um vetor/matriz válido",
-  "column_outbounds": "Número de colunas $0 é inválido para a matriz $1 que possui $2 colunas",
-  "line_outbounds": "Número de linhas $0 é invaálido para a matriz $1 que possui $2 linhas",
+  "invalid_matrix_access_full": "Identificador $0 na linha: $1, coluna: $2 não se refere a uma matriz válida",
+  "invalid_matrix_access": "Identificador $0 não se refere a uma matriz válida",
+  "matrix_column_outbounds_full": "Erro na linha $0: número de colunas $1 é inválido para a matriz $2 que possui $3 colunas",
+  "matrix_column_outbounds": "Número de colunas $0 é inválido para a matriz $1 que possui $2 colunas",
+  "matrix_line_outbounds_full": "Erro na linha $0: número de linhas $1 é inválido para a matriz $2 que possui $3 linhas",
+  "matrix_line_outbounds": "Número de linhas $0 é inválido para a matriz $1 que possui $2 linhas",
+  "vector_line_outbounds_full": "Erro na linha $0: número de linhas $1 é inválido para a matriz $2 que possui $3 linhas",
+  "vector_line_outbounds": "Número de linhas $0 é inválido para a matriz $1 que possui $2 linhas",
+  "vector_not_matrix_full": "Erro na linha $0: $1 não é uma matriz",
+  "vector_not_matrix": "$1 não é uma matriz",
+  "invalid_infix_op_full": "Erro na linha $0: não é possível aplicar a operação $1 entre os tipos $2 e $3",
   "invalid_infix_op": "Não é possível aplicar a operação $0 entre os tipos $1 e $2",
+  "invalid_unary_op_full": "Erro na linha $0: não é possível aplicar a operação $1 ao tipo $2",
   "invalid_unary_op": "Não é possível aplicar a operação $0 ao tipo $1",
-  "unknown_op": "Erro interno crítico: Operação $0 desconhecida"
+  "unknown_op": "Erro interno crítico: Operação $0 desconhecida",
+  "duplicate_function": "A função $0 na linha: $1, coluna: $2 já foi definida anteriormente.",
+  "duplicate_variable": "A variável $0 na linha: $1, coluna: $2 já foi declarada anteriormente.",
+  "main_parameters": "A função inicio não pode ter parâmetros.",
+  "symbol_not_found_full": "A variável $0 na linha: $1, coluna: $2 não foi declarada",
+  "symbol_not_found": "A variável $0 não foi declarada",
+  "array_dimension_not_int_full": "As dimensões de um vetor/matriz na linha: $0 devem ser do tipo inteiro.",
+  "array_dimension_not_int": "As dimensões de um vetor/matriz devem ser do tipo inteiro.",
+  "array_dimension_not_positive_full": "As dimensões de um vetor/matriz na linha: $0 devem ser valores positivos.",
+  "array_dimension_not_positive": "As dimensões de um vetor/matriz devem ser valores positivos.",
+  "incompatible_types_full": "O tipo $0 não é compatível com o tipo resultante da expressão na linha $1",
+  "incompatible_types": "O tipo $0 não é compatível com o tipo resultante da expressão fornecida.",
+  "incompatible_types_array_full": "A expressão $0 é incompatível com o tipo $1 na linha: $2, coluna: $3.",
+  "incompatible_types_array": "A expressão $0 é incompatível com o tipo $1.",
+  "invalid_case_type_full": "O caso $0 na linha $1 é incompatível com o tipo $2.",
+  "invalid_case_type": "O caso $0 é incompatível com o tipo $1.",
+  "function_no_return": "A função $0 não possui um retorno acessível. Toda função deve ter ao menos um retorno no seu corpo principal.",
+  "invalid_array_literal_type_full": "Erro na linha $0: a expressão $1 não resulta em um tipo compatível.",
+  "invalid_array_literal_type": "A expressão $0 não resulta em um tipo compatível.",
+  "invalid_array_literal_line_full": "Erro na linha $0: esperava-se $1 linhas mas encontrou $2.",
+  "invalid_array_literal_line": "Esperava-se $0 linhas mas encontrou $1.",
+  "invalid_array_literal_column_full": "Erro na linha $0: esperava-se $1 colunas mas encontrou $2.",
+  "invalid_array_literal_column": "Esperava-se $0 colunas mas encontrou $1."
 }

+ 5 - 0
i18n/pt/ui.json

@@ -12,6 +12,9 @@
   "start": "inicio",
   "void": "vazio",
   "integer": "inteiro",
+  "and": "E",
+  "or": "OU",
+  "not": "nao",
   "real": "real",
   "program": "programa",
   "text": "cadeia",
@@ -36,6 +39,8 @@
   "text_btn_return":"Retorno",
   "text_comment": "Comentário",
   "join_or": "ou",
+  "matrix_string": "matriz de $0",
+  "vector_string": "vetor de $0",
   "text_attribution": "Atribuição",
   "text_if":"se",
   "text_break":"pare",

+ 12 - 1
js/ast/error/syntaxErrorFactory.js

@@ -39,7 +39,7 @@ export const SyntaxErrorFactory = Object.freeze({
     const context = [token.line, cmdName];
     return new SyntaxError(LocalizedStrings.getError("invalid_break_command", context));
   },
-  invalid_terminal: () => {
+  invalid_terminal: (token) => {
     const context = [token.text, token.line, token.column];
     return new SyntaxError(LocalizedStrings.getError('invalid_terminal', context));
   },
@@ -55,5 +55,16 @@ export const SyntaxErrorFactory = Object.freeze({
   invalid_id_format: (token) => {
     const context = [token.text, token.line, token.column];
     return new SyntaxError(LocalizedStrings.getError("invalid_id_format", context));
+  },
+  duplicate_function: (token) => {
+    const context = [token.text, token.line, token.column];
+    return new SyntaxError(LocalizedStrings.getError("duplicate_function", context));
+  },
+  main_parameters: () => {
+    return new SyntaxError(LocalizedStrings.getError("main_parameters"));
+  },
+  duplicate_variable: (token) => {
+    const context = [token.text, token.line, token.column];
+    return new SyntaxError(LocalizedStrings.getError("duplicate_variable", context));
   }
 });

+ 13 - 0
js/ast/expressions/arrayAccess.js

@@ -8,4 +8,17 @@ export class ArrayAccess extends Expression {
 		this.line = line;
 		this.column = column;
 	}
+
+	toString () {
+		const strLine = this.line.toString();
+		let strColumn = null;
+		if(this.column) {
+			strColumn = this.column.toString();
+		}
+		if(strColumn) {
+			return `${this.id}[${strLine}][${strColumn}]`;
+		} else {
+			return `${this.id}[${strLine}]`;
+		}
+	}
 }

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

@@ -79,4 +79,9 @@ export class ArrayLiteral extends Literal {
     }
     return valid;
   }
+
+  toString () {
+    const strList = this.value.map(arrayLiteral => arrayLiteral.toString());
+    return "{" + strList.join(',') + "}";
+  }
 }

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

@@ -1,5 +1,6 @@
 import { Literal } from './literal';
 import { Types } from './../../typeSystem/types';
+import { convertBoolToString } from "./../../typeSystem/parsers";
 
 export class BoolLiteral extends Literal {
   
@@ -7,4 +8,8 @@ export class BoolLiteral extends Literal {
     super(Types.BOOLEAN);
     this.value = value;
   }
+
+  toString () {
+    return convertBoolToString(this.value);
+  }
 }

+ 22 - 0
js/ast/expressions/functionCall.js

@@ -1,4 +1,5 @@
 import { Expression } from './expression';
+import { LanguageDefinedFunction } from '../../processor/definedFunctions';
 
 export class FunctionCall extends Expression {
 
@@ -8,7 +9,28 @@ export class FunctionCall extends Expression {
 		this.actualParameters = actualParameters;
 	}
 
+	get isMainCall () {
+		return this.id === null;
+	}
+
 	get parametersSize () {
 		return this.actualParameters.length;
 	}
+
+	toString () {
+		let name = null;
+		if(this.isMainCall) {
+			name = LanguageDefinedFunction.getMainFunctionName();
+		} else {
+			name = LanguageDefinedFunction.getLocalName(this.id);
+		}
+		let params = null;
+		if(this.actualParameters.length == 0) {
+			params = "()";
+		} else {
+			const strParams = this.actualParameters.map(v => v.toString());
+			params = "(" + strParams.join(",") + ")";
+		}
+		return name + params;
+	}
 }

+ 7 - 0
js/ast/expressions/infixApp.js

@@ -8,4 +8,11 @@ export class InfixApp extends Expression {
     this.left = left;
     this.right = right;
   }
+
+  toString () {
+    const l = this.left.toString();
+    const op = this.op.value;
+    const r = this.right.toString();
+    return l + op + r;
+  }
 }

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

@@ -1,5 +1,6 @@
 import { Literal } from './literal';
 import { Types } from './../../typeSystem/types';
+import { convertToString } from './../../typeSystem/parsers';
 
 export class IntLiteral extends Literal {
   
@@ -7,4 +8,8 @@ export class IntLiteral extends Literal {
     super(Types.INTEGER);
     this.value = value;
   }
+
+  toString() {
+    return convertToString(this.value, this.type);
+  }
 }

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

@@ -1,5 +1,6 @@
 import { Literal } from './literal';
 import { Types } from './../../typeSystem/types';
+import { convertToString } from './../../typeSystem/parsers';
 
 export class RealLiteral extends Literal {
   
@@ -7,4 +8,8 @@ export class RealLiteral extends Literal {
     super(Types.REAL);
     this.value = value;
   }
+
+  toString() {
+    return convertToString(this.value, this.type);
+  }
 }

+ 4 - 0
js/ast/expressions/stringLiteral.js

@@ -7,4 +7,8 @@ export class StringLiteral extends Literal {
     super(Types.STRING);
     this.value = value;
   }
+
+  toString() {
+    return this.value;
+  }
 }

+ 6 - 0
js/ast/expressions/unaryApp.js

@@ -5,4 +5,10 @@ export class UnaryApp extends InfixApp {
   constructor (op, left) {
     super(op, left, null);
   }
+
+  toString () {
+    const l = this.left.toString();
+    const op = this.op.value;
+    return op + l;
+  }
 }

+ 4 - 0
js/ast/expressions/variableLiteral.js

@@ -7,4 +7,8 @@ export class VariableLiteral extends Literal {
     super(Types.UNDEFINED);
     this.id = id;
   }
+
+  toString () {
+    return this.id;
+  }
 }

+ 45 - 6
js/ast/ivprogParser.js

@@ -47,6 +47,8 @@ export class IVProgParser {
     this.parsingArrayDimension = 0;
     this.scope = [];
     this.langFuncs = LanguageService.getCurrentLangFuncs();
+    this.definedFuncsNameList = [];
+    this.definedVariablesStack = [];
   }
 
   parseTree () {
@@ -71,10 +73,22 @@ export class IVProgParser {
     this.scope.push(scope);
   }
 
+  pushVariableStack () {
+    this.definedVariablesStack.push([]);
+  }
+
   popScope () {
     return this.scope.pop();
   }
 
+  popVariableStack () {
+    return this.definedVariablesStack.pop();
+  }
+
+  getCurrentVariableStack () {
+    return this.definedVariablesStack[this.definedVariablesStack.length - 1];
+  }
+
   isEOF () {
     this.getToken(this.pos);
     return this.tokenStream.fetchedEOF;
@@ -90,13 +104,16 @@ export class IVProgParser {
       this.consumeNewLines();
       this.checkOpenCurly();
       this.pos++;
+      this.pushVariableStack();
       while(true) {
         this.consumeNewLines();
         const token = this.getToken();
         if (token.type === this.lexerClass.RK_CONST || this.isVariableType(token)) {
           globalVars = globalVars.concat(this.parseGlobalVariables());
         } else if (token.type === this.lexerClass.RK_FUNCTION) {
+          this.pushVariableStack();
           functions = functions.concat(this.parseFunction());
+          this.popVariableStack();
         } else {
           break;
         }
@@ -108,6 +125,7 @@ export class IVProgParser {
       if(!this.isEOF()) {
         throw SyntaxErrorFactory.extra_lines();
       }
+      this.popVariableStack();
       return {global: globalVars, functions: functions};
     } else {
       throw SyntaxErrorFactory.token_missing_one(this.lexer.literalNames[this.lexerClass.RK_PROGRAM], token);
@@ -203,6 +221,23 @@ export class IVProgParser {
     return true;
   }
 
+  checkFunctionDuplicate (functionID, funcIDToken) {
+    const id = functionID === null ? "$main" : functionID;
+    const index = this.definedFuncsNameList.indexOf(id);
+    if(index !== -1) {
+      throw SyntaxErrorFactory.duplicate_function(funcIDToken);
+    }
+    this.definedFuncsNameList.push(id);
+  }
+
+  checkVariableDuplicate (variableID, variableIDToken) {
+    const index = this.getCurrentVariableStack().indexOf(variableID);
+    if(index !== -1) {
+      throw SyntaxErrorFactory.duplicate_variable(variableIDToken);
+    }
+    this.getCurrentVariableStack().push(variableID);
+  }
+
   consumeForSemiColon () {
     const eosToken = this.getToken();
     if (eosToken.type === this.lexerClass.EOS && eosToken.text.match(';')) {
@@ -250,7 +285,7 @@ export class IVProgParser {
     let dim2 = null;
     const idToken = this.getToken();
     const idString = this.parseID();
-    
+    this.checkVariableDuplicate(idString,idToken);
     // Check for array or vector
     // ID[int/IDi][int/IDj]
     if (this.checkOpenBrace(true)) {
@@ -372,7 +407,6 @@ export class IVProgParser {
     this.checkOpenCurly();
     const beginArray = this.getToken();
     if (this.parsingArrayDimension >= 2) {
-      // TODO: better error message
       throw SyntaxErrorFactory.token_missing_list(`Array dimensions exceed maximum size of 2 at line ${beginArray.line}`);
     }
     this.pos++;
@@ -441,7 +475,9 @@ export class IVProgParser {
         dimensions++;
       }
     }
+    const funcIDToken = this.getToken();
     const functionID = this.parseID();
+    this.checkFunctionDuplicate(functionID, funcIDToken);
     this.checkOpenParenthesis();
     this.pos++;
     this.consumeNewLines();
@@ -461,10 +497,11 @@ export class IVProgParser {
     }
     const func = new Commands.Function(functionID, returnType, formalParams, commandsBlock);
     if (functionID === null && !func.isMain) {
-      // TODO: better error message
       throw SyntaxErrorFactory.invalid_main_return(LanguageDefinedFunction.getMainFunctionName(),
         this.lexer.literalNames[this.lexerClass.RK_VOID],
         token.line);
+    } else if (func.isMain && formalParams.length !== 0) {
+      throw SyntaxErrorFactory.main_parameters();
     }
     this.popScope();
     return func;
@@ -479,7 +516,9 @@ export class IVProgParser {
     while(true) {
       let dimensions = 0;
       const typeString = this.parseType();
+      const idToken = this.getToken();
       const idString = this.parseID();
+      this.checkVariableDuplicate(idString, idToken);
       if (this.checkOpenBrace(true)) {
         this.pos++;
         dimensions++;
@@ -592,7 +631,6 @@ export class IVProgParser {
     const token = this.getToken();
     if (this.isVariableType(token)) {
       if(!this.insideScope(IVProgParser.FUNCTION)) {
-        // TODO better error message
         throw SyntaxErrorFactory.invalid_var_declaration(token.line);
       }
       this.pushScope(IVProgParser.BASE);
@@ -614,7 +652,6 @@ export class IVProgParser {
       return this.parseFor();
     } else if (token.type === this.lexerClass.RK_BREAK ) {
       if(!this.insideScope(IVProgParser.BREAKABLE)) {
-        // TODO better error message
         throw SyntaxErrorFactory.invalid_break_command(
           this.lexer.literalNames[this.lexerClass.RK_BREAK],
           token
@@ -710,7 +747,6 @@ export class IVProgParser {
       } else if(maybeIf.type === this.lexerClass.RK_IF) {
         elseBlock = this.parseIfThenElse();
       } else {
-        // TODO better error message
         throw SyntaxErrorFactory.token_missing_list([this.lexer.literalNames[this.lexerClass.RK_IF], '{'], maybeIf);
       }
       return new Commands.IfThenElse(logicalExpression, cmdBlocks, elseBlock);
@@ -1069,6 +1105,9 @@ export class IVProgParser {
   getFunctionName (id) {
     const name = LanguageDefinedFunction.getInternalName(id);
     if (name === null) {
+      if (id === LanguageDefinedFunction.getMainFunctionName()) {
+        return null;
+      }
       return id;
     } else {
       return name;

+ 12 - 0
js/processor/definedFunctions.js

@@ -113,4 +113,16 @@ export const LanguageDefinedFunction = Object.freeze({
     }
     return funcsObject[internalName];
   },
+  getLocalName: (internalName) => {
+    if (internalName.indexOf(".") !== -1) {
+      const names = internalName.split(".");
+      const libName = LanguageService.getCurrentLangLibs()[names[0]];
+      const funName = LanguageService.getCurrentLangFuncs()[names[1]];
+      return `${libName}.${funName}`;
+    } else if (LanguageService.getCurrentLangFuncs()[internalName]) {
+      return LanguageService.getCurrentLangFuncs()[internalName];
+    } else { 
+      return internalName
+    }
+  }
 });

+ 392 - 1
js/processor/error/processorErrorFactory.js

@@ -1,7 +1,398 @@
 import { RuntimeError } from './runtimeError';
 import { SemanticError } from './semanticError';
 import { LocalizedStrings } from './../../services/localizedStringsService';
+import { Operators } from '../../ast/operators';
+
+function translateType (type, dim) {
+  switch (dim) {
+    case 0:
+      return LocalizedStrings.getUI(type);
+    default:
+      const transType = LocalizedStrings.getUI(type);
+      if(dim === 1)
+        return LocalizedStrings.getUI("vector_string", [transType])
+      else
+        return LocalizedStrings.getUI("matrix_string", [transType])
+  }
+}
+
+function translateOp (op) {
+  switch(op.ord) {
+    case Operators.AND.ord:
+    case Operators.OR.ord:
+    case Operators.NOT.ord:
+      return LocalizedStrings.getUI(op.value);
+    default:
+      return op.value;
+  }
+}
 
 export const ProcessorErrorFactory  = Object.freeze({
-  
+  symbol_not_found_full: (id, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [id, sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("symbol_not_found_full", context));
+    } else {
+      return ProcessorErrorFactory.symbol_not_found(id);
+    }
+  },
+  symbol_not_found: (id) => {
+    const context = [id];
+    return new SemanticError(LocalizedStrings.getError("symbol_not_found", context));
+  },
+  function_missing_full: (id, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [id, sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("function_missing_full", context));
+    } else {
+      return ProcessorErrorFactory.function_missing(id);
+    }
+  },
+  function_missing: (id) => {
+    const context = [id];
+    return new SemanticError(LocalizedStrings.getError("function_missing", context));
+  },
+  main_missing: () => {
+    return new SemanticError(LocalizedStrings.getError("main_missing"));
+  },        // TODO: better urgent error message
+  array_dimension_not_int_full: (sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line];
+      return new SemanticError(LocalizedStrings.getError("array_dimension_not_int_full", context));
+    } else {
+      return ProcessorErrorFactory.array_dimension_not_int();
+    }
+  },
+  array_dimension_not_int: () => {
+    return new SemanticError(LocalizedStrings.getError("array_dimension_not_int"));
+  },
+  unknown_command_full: (sourceInfo)=> {
+    if(sourceInfo) {
+      const context = [sourceInfo.line];
+      return new RuntimeError(LocalizedStrings.getError("unknown_command_full", context));
+    } else {
+      return ProcessorErrorFactory.unknown_command();
+    }
+    
+  },
+  unknown_command: ()=> {
+    return new RuntimeError(LocalizedStrings.getError("unknown_command"));
+  },
+  incompatible_types_full: (type, dim, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [translateType(type, dim), sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("incompatible_types_full", context));
+    } else {
+      return ProcessorErrorFactory.incompatible_types(type, dim);
+    }
+  },
+  incompatible_types: (type, dim) => {
+    const context = [translateType(type, dim)];
+    return new SemanticError(LocalizedStrings.getError("incompatible_types", context));
+  },
+  incompatible_types_array_full: (exp, type, dim, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [exp, translateType(type, dim), sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("incompatible_types_array_full", context));
+    } else {
+      return ProcessorErrorFactory.incompatible_types_array(exp, type, dim);
+    }
+  },
+  incompatible_types_array: (exp, type, dim) => {
+    const context = [exp, translateType(type, dim)];
+    return new SemanticError(LocalizedStrings.getError("incompatible_types_array", context));
+  },
+  loop_condition_type_full: (sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("loop_condition_type_full", context));
+    } else {
+      return ProcessorErrorFactory.loop_condition_type();
+    }
+  },
+  loop_condition_type: () => {
+    return new SemanticError(LocalizedStrings.getError("loop_condition_type"));
+  },
+  endless_loop_full: (sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line];
+      return new SemanticError(LocalizedStrings.getError("endless_loop_full", context));
+    } else {
+      return ProcessorErrorFactory.endless_loop();
+    }
+  },
+  endless_loop: () => {
+    return new SemanticError(LocalizedStrings.getError("endless_loop"));
+  },
+  for_condition_type_full: (sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("for_condition_type_full", context));
+    } else {
+      return ProcessorErrorFactory.for_condition_type();
+    }
+  },
+  for_condition_type: () => {
+    return new SemanticError(LocalizedStrings.getError("for_condition_type"));
+  },
+  if_condition_type_full: (sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("if_condition_type_full", context));
+    } else {
+      return ProcessorErrorFactory.if_condition_type();
+    }
+  },
+  if_condition_type: () => {
+    return new SemanticError(LocalizedStrings.getError("if_condition_type"));
+  },
+  invalid_global_var: () => {
+    return new RuntimeError(LocalizedStrings.getError("invalid_global_var"))
+  },
+  not_implemented: (id) => {
+    const context  = [id]
+    return new RuntimeError(LocalizedStrings.getError("not_implemented", context))
+  },
+  invalid_case_type_full: (exp, type, dim, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [exp, translateType(type, dim), sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("invalid_case_type_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_case_type(exp, type, dim);
+    }
+  },
+  invalid_case_type: (exp, type, dim) => {
+    const context = [exp, translateType(type, dim)];
+    return new SemanticError(LocalizedStrings.getError("invalid_case_type", context));
+  },
+  void_in_expression_full: (id, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, sourceInfo.column, id];
+      return new SemanticError(LocalizedStrings.getError("void_in_expression_full", context));
+    } else {
+      return ProcessorErrorFactory.void_in_expression(id);
+    }
+  },
+  void_in_expression: (id) => {
+    const context = [id];
+    return new SemanticError(LocalizedStrings.getError("void_in_expression", context));
+  },
+  invalid_array_access_full: (id, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [id, sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("invalid_array_access_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_array_access(id);
+    }
+  },
+  invalid_array_access: (id) => {
+    const context = [id];
+    return new SemanticError(LocalizedStrings.getError("invalid_array_access", context));
+  },
+  invalid_matrix_access_full: (id, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [id, sourceInfo.line, sourceInfo.column];
+      return new SemanticError(LocalizedStrings.getError("invalid_matrix_access_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_matrix_access(id);
+    }
+  },
+  invalid_matrix_access: (id) => {
+    const context = [id];
+    return new SemanticError(LocalizedStrings.getError("invalid_matrix_access", context));
+  },
+  matrix_column_outbounds_full: (id, value, columns, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, value, id, columns];
+      return new RuntimeError(LocalizedStrings.getError("matrix_column_outbounds_full", context));
+    } else {
+      return ProcessorErrorFactory.matrix_column_outbounds(id, value, columns);
+    }
+  },
+  matrix_column_outbounds: (id, value, columns) => {
+    const context = [value, id, columns];
+    return new RuntimeError(LocalizedStrings.getError("matrix_column_outbounds", context));
+  },
+  matrix_line_outbounds_full: (id, value, lines, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, value, id, lines];
+      return new RuntimeError(LocalizedStrings.getError("matrix_line_outbounds_full", context));
+    } else {
+      return ProcessorErrorFactory.matrix_line_outbounds(id, value, lines);
+    }
+  },
+  matrix_line_outbounds: (id, value, lines) => {
+    const context = [value, id, lines];
+    return new RuntimeError(LocalizedStrings.getError("matrix_line_outbounds", context));
+  },
+  vector_line_outbounds_full: (id, value, lines, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, value, id, lines];
+      return new RuntimeError(LocalizedStrings.getError("vector_line_outbounds_full", context));
+    } else {
+      return ProcessorErrorFactory.vector_line_outbounds(id, value, lines);
+    }
+  },
+  vector_line_outbounds: (id, value, lines) => {
+    const context = [value, id, lines];
+    return new RuntimeError(LocalizedStrings.getError("vector_line_outbounds", context));
+  },
+  vector_not_matrix_full: (id, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, id];
+      return new RuntimeError(LocalizedStrings.getError("vector_not_matrix_full", context));
+    } else {
+      return ProcessorErrorFactory.vector_not_matrix(id);
+    }
+  },
+  vector_not_matrix: (id) => {
+    const context = [id];
+    return new RuntimeError(LocalizedStrings.getError("vector_not_matrix", context));
+  },
+  function_no_return: (id) => {
+    const context = [id];
+    return new SemanticError(LocalizedStrings.getError("function_no_return", context));
+  },
+  invalid_void_return_full: (id, type, dim, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, id, translateType(type, dim)];
+      return new SemanticError(LocalizedStrings.getError("invalid_void_return_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_void_return(id, type, dim);
+    }
+  },
+  invalid_void_return: (id, type, dim) => {
+    const context = [id, translateType(type, dim)];
+    return new SemanticError(LocalizedStrings.getError("invalid_void_return_full", context));
+  },
+  invalid_return_type_full: (id, type, dim, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, id, translateType(type, dim)];
+      return new SemanticError(LocalizedStrings.getError("invalid_return_type_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_return_type(id, type, dim);
+    }
+  },
+  invalid_return_type: (id, type, dim) => {
+    const context = [id, translateType(type, dim)];
+    return new SemanticError(LocalizedStrings.getError("invalid_return_type", context));
+  },
+  invalid_parameters_size_full: (id, expected, actual, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, id, expected, actual];
+      return new SemanticError(LocalizedStrings.getError("invalid_parameters_size_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_parameters_size(id, expected, actual);
+    }
+  },
+  invalid_parameters_size: (id, expected, actual) => {
+    const context = [id, expected, actual];
+    return new SemanticError(LocalizedStrings.getError("invalid_parameters_size", context));
+  },
+  invalid_parameter_type_full: (id, exp, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [exp, id, sourceInfo.line];
+      return new SemanticError(LocalizedStrings.getError("invalid_parameter_type_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_parameter_type(id, exp);
+    }
+  },
+  invalid_parameter_type: (id, exp) => {
+    const context = [exp, id];
+    return new SemanticError(LocalizedStrings.getError("invalid_parameter_type_full", context));
+  },
+  invalid_ref_full: (id, exp, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [exp, id , sourceInfo.line];
+      return new SemanticError(LocalizedStrings.getError("invalid_ref_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_ref(id, exp);
+    }
+  },
+  invalid_ref: (id, exp) => {
+    const context = [exp, id];
+    return new SemanticError(LocalizedStrings.getError("invalid_ref", context));
+  },
+  unexpected_break_command_full: (sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line];
+      return new RuntimeError(LocalizedStrings.getError("unexpected_break_command_full", context));
+    } else {
+      return ProcessorErrorFactory.unexpected_break_command();
+    }
+  },
+  unexpected_break_command: () => {
+    return new RuntimeError(LocalizedStrings.getError("unexpected_break_command"));
+  },
+  invalid_array_literal_type_full: (exp, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, exp];
+      return new RuntimeError(LocalizedStrings.getError("invalid_array_literal_type_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_array_literal_type(exp);
+    }
+  },
+  invalid_array_literal_type: (exp) => {
+    const context = [exp];
+    return new RuntimeError(LocalizedStrings.getError("invalid_array_literal_type", context));
+  },
+  invalid_array_literal_line_full: (expected, actual, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, expected, actual];
+      return new RuntimeError(LocalizedStrings.getError("invalid_array_literal_line_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_array_literal_type(expected, actual);
+    }
+  },
+  invalid_array_literal_line: (expected, actual) => {
+    const context = [expected, actual];
+    return new RuntimeError(LocalizedStrings.getError("invalid_array_literal_line", context));
+  },
+  invalid_array_literal_column_full: (expected, actual, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, expected, actual];
+      return new RuntimeError(LocalizedStrings.getError("invalid_array_literal_column_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_array_literal_column(expected, actual);
+    }
+  },
+  invalid_array_literal_column: (expected, actual) => {
+    const context = [expected, actual];
+    return new RuntimeError(LocalizedStrings.getError("invalid_array_literal_column", context));
+  },
+  invalid_unary_op_full: (opName, type, dim, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, translateOp(opName), translateType(type, dim)];
+      return new RuntimeError(LocalizedStrings.getError("invalid_unary_op_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_unary_op(opName, type, dim);
+    }
+  },
+  invalid_unary_op: (opName, type, dim) => {
+    const context = [translateOp(opName), translateType(type, dim)];
+    return new RuntimeError(LocalizedStrings.getError("invalid_unary_op", context));
+  },
+  invalid_infix_op_full: (opName, typeLeft, dimLeft, typeRight, dimRight,  sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, translateOp(opName), translateType(typeLeft, dimLeft), translateType(typeRight, dimRight)];
+      return new RuntimeError(LocalizedStrings.getError("invalid_infix_op_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_infix_op(opName, typeLeft, dimLeft, typeRight, dimRight);
+    }
+  },
+  invalid_infix_op: (opName, typeLeft, dimLeft, typeRight, dimRight) => {
+    const context = [translateOp(opName), translateType(typeLeft, dimLeft), translateType(typeRight, dimRight)];
+    return new RuntimeError(LocalizedStrings.getError("invalid_infix_op", context));
+  },
+  array_dimension_not_positive_full: (sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line];
+      return new SemanticError(LocalizedStrings.getError("array_dimension_not_positive_full", context));
+    } else {
+      return ProcessorErrorFactory.array_dimension_not_positive();
+    }
+  },
+  array_dimension_not_positive: () => {
+    return new SemanticError(LocalizedStrings.getError("array_dimension_not_positive"));
+  }
 });

+ 146 - 89
js/processor/ivprogProcessor.js

@@ -16,6 +16,8 @@ import { CompoundType } from './../typeSystem/compoundType';
 import { convertToString } from '../typeSystem/parsers';
 import { Config } from '../util/config';
 import Decimal from 'decimal.js';
+import { ProcessorErrorFactory } from './error/processorErrorFactory';
+import { RuntimeError } from './error/runtimeError';
 
 export class IVProgProcessor {
 
@@ -27,6 +29,10 @@ export class IVProgProcessor {
     Config.setConfig({loopTimeout: ms});
   }
 
+  static get MAIN_INTERNAL_ID () {
+    return "$main";
+  }
+
   constructor (ast) {
     this.ast = ast;
     this.globalStore = new Store("$global");
@@ -83,15 +89,14 @@ export class IVProgProcessor {
     this.initGlobal();
     const mainFunc = this.findMainFunction();
     if(mainFunc === null) {
-      // TODO: Better error message
-      throw new Error("Missing main funciton.");
+      throw ProcessorErrorFactory.main_missing();
     }
     return this.runFunction(mainFunc, [], this.globalStore);
   }
 
   initGlobal () {
     if(!this.checkContext(Context.BASE)) {
-      throw new Error("!!!CRITICAL: Invalid call to initGlobal outside BASE context!!!");
+      throw ProcessorErrorFactory.invalid_global_var();
     }
     this.ast.global.forEach(decl => {
       this.executeCommand(this.globalStore, decl).then(sto => this.globalStore = sto);
@@ -106,21 +111,21 @@ export class IVProgProcessor {
     if(name.match(/^\$.+$/)) {
       const fun = LanguageDefinedFunction.getFunction(name);
       if(!!!fun) {
-        throw new Error("!!!Internal Error. Language defined function not implemented -> " + name + "!!!");
+        throw ProcessorErrorFactory.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.`);
+        throw ProcessorErrorFactory.function_missing(name);
       }
       return val;
     }
   }
 
   runFunction (func, actualParameters, store) {
-    const funcName = func.isMain ? 'main' : func.name;
+    const funcName = func.isMain ? IVProgProcessor.MAIN_INTERNAL_ID : func.name;
     let funcStore = new Store(funcName);
     funcStore.extendStore(this.globalStore);
     let returnStoreObject = null;
@@ -148,18 +153,21 @@ export class IVProgProcessor {
   }
 
   associateParameters (formalList, actualList, callerStore, calleeStore) {
+    const funcName = calleeStore.name === IVProgProcessor.MAIN_INTERNAL_ID ? 
+      LanguageDefinedFunction.getMainFunctionName() : calleeStore.name;
+
     if (formalList.length != actualList.length) {
-      // TODO: Better error message
-      throw new Error("Numbers of parameters doesn't match");
+      throw ProcessorErrorFactory.invalid_parameters_size(funcName, formalList.length, actualList.length);
     }
     const promises$ = actualList.map(actualParameter => this.evaluateExpression(callerStore, actualParameter));
     return Promise.all(promises$).then(values => {
       for (let i = 0; i < values.length; i++) {
         const stoObj = values[i];
+        const exp = actualList[i]
         const formalParameter = formalList[i];
         if(formalParameter.type.isCompatible(stoObj.type)) {
           if(formalParameter.byRef && !stoObj.inStore) {
-            throw new Error('You must inform a variable as parameter');
+            throw ProcessorErrorFactory.invalid_ref(funcName, exp.toString());
           }
 
           if(formalParameter.byRef) {
@@ -175,7 +183,7 @@ export class IVProgProcessor {
             calleeStore.insertStore(formalParameter.id, realValue);
           }
         } else {
-          throw new Error(`Parameter ${formalParameter.id} is not compatible with the value given.`);
+          throw ProcessorErrorFactory.invalid_parameter_type(funcName, exp.toString());
         }
       }
       return calleeStore;
@@ -195,7 +203,7 @@ export class IVProgProcessor {
   executeCommand (store, cmd) {
 
     if(this.forceKill) {
-      return Promise.reject("Interrupção forçada do programa!");
+      return Promise.reject("FORCED_KILL!");
     } else if (store.mode === Modes.PAUSE) {
       return Promise.resolve(this.executeCommand(store, cmd));
     } else if(store.mode === Modes.RETURN) {
@@ -224,12 +232,13 @@ export class IVProgProcessor {
       return this.executeFor(store, cmd);
     } else if (cmd instanceof Commands.Switch) {
       return this.executeSwitch(store, cmd);
-    } else if (cmd instanceof Commands.FunctionCall) {
+    } else if (cmd instanceof Expressions.FunctionCall) {
+      
       return this.executeFunctionCall(store, cmd);
     } else if (cmd instanceof Commands.SysCall) {
       return this.executeSysCall(store, cmd);
     } else {
-      throw new Error("!!!CRITICAL A unknown command was found!!!\n" + cmd);
+      throw ProcessorErrorFactory.unknown_command(cmd.sourceInfo);
     }
   }
 
@@ -239,12 +248,18 @@ export class IVProgProcessor {
   }
 
   executeFunctionCall (store, cmd) {
-    const func = this.findFunction(cmd.id);
+    let func = null;
+    if(cmd.isMainCall) {
+      func = this.findMainFunction();
+    } else {
+      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`));
+          const funcName = func.name === IVProgProcessor.MAIN_INTERNAL_ID ? 
+            LanguageDefinedFunction.getMainFunctionName() : func.name;
+          return Promise.reject(ProcessorErrorFactory.function_no_return(funcName));
         } else {
           return store;
         }
@@ -333,25 +348,21 @@ export class IVProgProcessor {
         const $value = outerRef.evaluateExpression(sto, cmd.expression);
         return $value.then(vl => {
           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`));
+            return Promise.reject(ProcessorErrorFactory.loop_condition_type_full(cmd.sourceInfo));
           }
           if (vl.value) {
             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 Promise.reject(ProcessorErrorFactory.endless_loop_full(cmd.sourceInfo));
               }
             }
             return outerRef.executeCommand(sto, cmd);
           } else {
             outerRef.context.pop();
             outerRef.loopTimers.pop();
-            console.log("Clear Timeout...");
             return sto;
           }
         })
@@ -381,9 +392,8 @@ export class IVProgProcessor {
               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 Promise.reject(ProcessorErrorFactory.endless_loop_full(cmd.sourceInfo));
                 }
               }
               return outerRef.executeCommand(sto, cmd);
@@ -391,13 +401,10 @@ export class IVProgProcessor {
           } else {
             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`));
+          return Promise.reject(ProcessorErrorFactory.loop_condition_type_full(cmd.sourceInfo));
         }
       })
       
@@ -423,9 +430,7 @@ export class IVProgProcessor {
             return Promise.resolve(store);
           }
         } else {
-          // TODO: Better error message -- Inform line and column from token!!!!
-          // THIS IF SHOULD BE IN A SEMANTIC ANALYSER
-          return Promise.reject(new Error(`If expression must be of type boolean`));
+          return Promise.reject(ProcessorErrorFactory.if_condition_type_full(cmd.sourceInfo));
         }
       });
     } catch (error) {
@@ -437,7 +442,8 @@ export class IVProgProcessor {
     try {
       const funcType = store.applyStore('$').type;
       const $value = this.evaluateExpression(store, cmd.expression);
-      const funcName = store.name;
+      const funcName = store.name === IVProgProcessor.MAIN_INTERNAL_ID ? 
+        LanguageDefinedFunction.getMainFunctionName() : store.name;
       return $value.then(vl => {
 
         if(vl === null && funcType.isCompatible(Types.VOID)) {
@@ -445,9 +451,9 @@ export class IVProgProcessor {
         }
 
         if (vl === null || !funcType.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} must return ${funcType.type} instead of ${vl.type}.`));
+          const stringInfo = funcType.stringInfo();
+          const info = stringInfo[0];
+          return Promise.reject(ProcessorErrorFactory.invalid_return_type_full(funcName, info.type, info.dim, cmd.sourceInfo));
         } else {
           let realValue = this.parseStoreObjectValue(vl);
           store.updateStore('$', realValue);
@@ -460,12 +466,12 @@ export class IVProgProcessor {
     }
   }
 
-  executeBreak (store, _) {
+  executeBreak (store, cmd) {
     if(this.checkContext(Context.BREAKABLE)) {
       store.mode = Modes.BREAK;
       return Promise.resolve(store);
     } else {
-      return Promise.reject(new Error("!!!CRITIAL: Break command outside Loop/Switch scope!!!"));
+      return Promise.reject(ProcessorErrorFactory.unexpected_break_command_full(cmd.sourceInfo));
     }
   }
 
@@ -485,7 +491,7 @@ 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"));
+      return Promise.reject(ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo));
     }
     const line$ = this.evaluateExpression(store, cmd.line);
     const column$ = this.evaluateExpression(store, cmd.column);
@@ -493,45 +499,55 @@ export class IVProgProcessor {
     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"));
+        return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
       }
       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"));
+          return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
         }
         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(mustBeArray.isVector) {
+          return Promise.reject(ProcessorErrorFactory.vector_line_outbounds_full(cmd.id, line, mustBeArray.lines, cmd.sourceInfo));
+        } else {
+          return Promise.reject(ProcessorErrorFactory.matrix_line_outbounds_full(cmd.id, line, mustBeArray.lines, cmd.sourceInfo));
+        }
+      } else if (line < 0) {
+        throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
       }
       if (column !== null && mustBeArray.columns === null ){
-        // TODO: better error message
-        return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
+        return Promise.reject(ProcessorErrorFactory.vector_not_matrix_full(cmd.id, cmd.sourceInfo));
       }
-      if(column !== null && column >= mustBeArray.columns) {
-        // TODO: better error message
-        return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
+      if(column !== null ) {
+        if (column >= mustBeArray.columns) {
+          return Promise.reject(ProcessorErrorFactory.matrix_column_outbounds_full(cmd.id, column,mustBeArray.columns, cmd.sourceInfo));
+        } else if (column < 0) {
+          throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
+        }
       }
 
       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));
+          const type = mustBeArray.type.innerType;
+          const stringInfo = type.stringInfo()
+          const info = stringInfo[0]
+          return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo));
         }
         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));
+          const type = mustBeArray.type;
+          const stringInfo = type.stringInfo()
+          const info = stringInfo[0]
+          const exp = cmd.expression.toString()
+          return Promise.reject(ProcessorErrorFactory.incompatible_types_array_full(exp,info.type, info.dim-1, cmd.sourceInfo));
         }
         newArray.value[line] = value;
         store.updateStore(cmd.id, newArray);
@@ -549,20 +565,22 @@ export class IVProgProcessor {
         return Promise.all([$lines, $columns, $value]).then(values => {
           const lineSO = values[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"));
+            return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
           }
           const line = lineSO.number;
+          if(line < 0) {
+            throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
+          }
           const columnSO = values[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"));
+              return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo));
             }
             column = columnSO.number;
+            if(column < 0) {
+              throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
+            }
           }
           const value = values[2];
           const temp = new StoreObjectArray(cmd.type, line, column, null);
@@ -642,10 +660,13 @@ export class IVProgProcessor {
   }
 
   evaluateFunctionCall (store, exp) {
+    if(exp.isMainCall) {
+      return Promise.reject(ProcessorErrorFactory.void_in_expression_full(LanguageDefinedFunction.getMainFunctionName(), exp.sourceInfo));
+    }
     const func = this.findFunction(exp.id);
     if(Types.VOID.isCompatible(func.returnType)) {
       // TODO: better error message
-      return Promise.reject(new Error(`Function ${exp.id} cannot be used inside an expression`));
+      return Promise.reject(ProcessorErrorFactory.void_in_expression_full(exp.id, exp.sourceInfo));
     }
     const $newStore = this.runFunction(func, exp.actualParameters, store);
     return $newStore.then( sto => {
@@ -662,24 +683,53 @@ export class IVProgProcessor {
   }
 
   evaluateArrayLiteral (store, exp) {
+    const errorHelperFunction = (validationResult, exp) => {
+      const errorCode = validationResult[0];
+      switch(errorCode) {
+        case StoreObjectArray.WRONG_COLUMN_NUMBER: {
+          const columnValue = validationResult[1];
+          return Promise.reject(ProcessorErrorFactory.invalid_array_literal_column_full(arr.columns, columnValue, exp.sourceInfo));
+        }
+        case StoreObjectArray.WRONG_LINE_NUMBER: {
+          const lineValue = validationResult[1];
+          return Promise.reject(ProcessorErrorFactory.invalid_array_literal_line_full(arr.lines, lineValue, exp.sourceInfo));
+        }
+        case StoreObjectArray.WRONG_TYPE: {
+          let line = null;
+          let strExp = null;
+          if (validationResult.length > 2) {
+            line = validationResult[1];
+            const column = validationResult[2];
+            strExp = exp.value[line].value[column].toString()
+          } else {
+            line = validationResult[1];
+            strExp = exp.value[line].toString()
+          }
+          return Promise.reject(ProcessorErrorFactory.invalid_array_literal_type_full(strExp, exp.sourceInfo));            }
+      }
+    };
     if(!exp.isVector) {
       const $matrix = this.evaluateMatrix(store, exp.value);
       return $matrix.then(list => {
         const type = new CompoundType(list[0].type.innerType, 2);
         const arr = new StoreObjectArray(type, list.length, list[0].lines, list);
-        if(arr.isValid)
+        const checkResult = arr.isValid;
+        if(checkResult.length == 0)
           return Promise.resolve(arr);
-        else
-          return Promise.reject(new Error(`Invalid array`))
+        else {
+          return errorHelperFunction(checkResult, exp);
+        }
       });
     } else {
       return this.evaluateVector(store, exp.value).then(list => {
         const type = new CompoundType(list[0].type, 1);
         const stoArray = new StoreObjectArray(type, list.length, null, list);
-        if(stoArray.isValid)
+        const checkResult = stoArray.isValid;
+        if(checkResult.length == 0)
           return Promise.resolve(stoArray);
-        else
-          return Promise.reject(new Error(`Invalid array`))
+        else {
+          return errorHelperFunction(checkResult, exp);
+        }
       });
     }
   }
@@ -718,9 +768,7 @@ export class IVProgProcessor {
   evaluateArrayAccess (store, exp) {
     const mustBeArray = store.applyStore(exp.id);
     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`));
+      return Promise.reject(ProcessorErrorFactory.invalid_array_access_full(exp.id, exp.sourceInfo));
     }
     const $line = this.evaluateExpression(store, exp.line);
     const $column = this.evaluateExpression(store, exp.column);
@@ -728,32 +776,36 @@ export class IVProgProcessor {
       const lineSO = values[0];
       const columnSO = values[1];
       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"));
+        return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(exp.sourceInfo));
       }
       const line = lineSO.number;
       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"));
+          return Promise.reject(ProcessorErrorFactory.array_dimension_not_int_full(exp.sourceInfo));
         }
         column = columnSO.number;
       }
 
       if (line >= mustBeArray.lines) {
-        // TODO: better error message
-        return Promise.reject(new Error(`${exp.id}: index out of bounds: ${lines}`));
+        if(mustBeArray.isVector) {
+          return Promise.reject(ProcessorErrorFactory.vector_line_outbounds_full(exp.id, line, mustBeArray.lines, exp.sourceInfo));
+        } else {
+          return Promise.reject(ProcessorErrorFactory.matrix_line_outbounds_full(exp.id, line, mustBeArray.lines, exp.sourceInfo));
+        }
+      } else if (line < 0) {
+        throw ProcessorErrorFactory.array_dimension_not_positive_full(exp.sourceInfo);
       }
       if (column !== null && mustBeArray.columns === null ){
-        // TODO: better error message
-        return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
+        return Promise.reject(ProcessorErrorFactory.vector_not_matrix_full(exp.id, exp.sourceInfo));
       }
-      if(column !== null && column >= mustBeArray.columns) {
-        // TODO: better error message
-        return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
+      if(column !== null ) {
+        if (column >= mustBeArray.columns) {
+          return Promise.reject(ProcessorErrorFactory.matrix_column_outbounds_full(exp.id, column,mustBeArray.columns, exp.sourceInfo));
+        } else if (column < 0) {
+          throw ProcessorErrorFactory.array_dimension_not_positive_full(exp.sourceInfo);
+        }
+        
       }
       return Promise.resolve(new StoreObjectArrayAddress(mustBeArray.id, line, column, store));
     });
@@ -764,8 +816,9 @@ export class IVProgProcessor {
     return $left.then( left => {
       const resultType = resultTypeAfterUnaryOp(unaryApp.op, left.type);
       if (Types.UNDEFINED.isCompatible(resultType)) {
-        // TODO: better urgent error message
-        return Promise.reject(new Error(`Cannot use this op to ${left.type}`));
+        const stringInfo = left.type.stringInfo();
+        const info = stringInfo[0];
+        return Promise.reject(ProcessorErrorFactory.invalid_unary_op_full(unaryApp.op, info.type, info.dim, unaryApp.sourceInfo));
       }
       switch (unaryApp.op.ord) {
         case Operators.ADD.ord:
@@ -775,7 +828,7 @@ export class IVProgProcessor {
         case Operators.NOT.ord:
           return new StoreObject(resultType, !left.value);
         default:
-        return Promise.reject(new Error('!!!Critical Invalid UnaryApp '+ unaryApp.op));
+          return Promise.reject(new RuntimeError('!!!Critical Invalid UnaryApp '+ unaryApp.op));
       }
     });
   }
@@ -788,8 +841,12 @@ export class IVProgProcessor {
       const right = values[1];
       const resultType = resultTypeAfterInfixOp(infixApp.op, left.type, right.type);
       if (Types.UNDEFINED.isCompatible(resultType)) {
-        // TODO: better urgent error message
-        return Promise.reject(new Error(`Cannot use this ${infixApp.op} to ${left.type} and ${right.type}`));
+        const stringInfoLeft = left.type.stringInfo();
+        const infoLeft = stringInfoLeft[0];
+        const stringInfoRight = right.type.stringInfo();
+        const infoRight = stringInfoRight[0];
+        return Promise.reject(ProcessorErrorFactory.invalid_infix_op_full(infixApp.op, infoLeft.type, infoLeft.dim,
+          infoRight.type,infoRight.dim,infixApp.sourceInfo));
       }
       let result = null;
       switch (infixApp.op.ord) {
@@ -883,7 +940,7 @@ export class IVProgProcessor {
         case Operators.OR.ord:
           return new StoreObject(resultType, left.value || right.value);
         default:
-          return Promise.reject(new Error('!!!Critical Invalid InfixApp '+ infixApp.op));
+          return Promise.reject(new RuntimeError('!!!Critical Invalid InfixApp '+ infixApp.op));
       }
     });
   }
@@ -898,7 +955,7 @@ export class IVProgProcessor {
             break;
           }
           default: {
-            throw new Error("Three dimensional array address...");
+            throw new RuntimeError("Three dimensional array address...");
           }
         }
       } else {

+ 126 - 60
js/processor/semantic/semanticAnalyser.js

@@ -1,7 +1,7 @@
 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 { ArrayDeclaration, While, For, Switch, 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';
@@ -17,6 +17,7 @@ export class SemanticAnalyser {
     const lexer = new this.lexerClass(null);
     this.literalNames = lexer.literalNames;
     this.symbolMap = null;
+    this.currentFunction = null;
   }
 
   pushMap () {
@@ -43,24 +44,27 @@ export class SemanticAnalyser {
       if(symMap.next) {
         return this.findSymbol(id, symMap.next);
       }
-      throw new Error("variable not defined "+id);
+      return null;
     } else {
       return symMap.map[id];
     }
   }
 
+  getMainFunction () {
+    return this.ast.functions.find(v => v.isMain);
+  }
+
   findFunction (name) {
     if(name.match(/^\$.+$/)) {
       const fun = LanguageDefinedFunction.getFunction(name);
       if(!!!fun) {
-        throw new Error("!!!Internal Error. Language defined function not implemented -> " + name + "!!!");
+        throw ProcessorErrorFactory.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 null;
       }
       return val;
     }
@@ -73,12 +77,9 @@ export class SemanticAnalyser {
     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...");
+      throw ProcessorErrorFactory.main_missing();
     }
     for (let i = 0; i < functions.length; i++) {
-
       const fun = functions[i];
       this.assertFunction(fun);
     }
@@ -96,18 +97,18 @@ export class SemanticAnalyser {
       if(declaration.initial === null) {
         const lineType = this.evaluateExpressionType(declaration.lines);
         if (!lineType.isCompatible(Types.INTEGER)) {
-          throw new Error("dim must be int");
+          throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
         }
         if (declaration.columns !== null) {
           const columnType = this.evaluateExpressionType(declaration.columns);
           if (!columnType.isCompatible(Types.INTEGER)) {
-            throw new Error("dim must be int");
+            throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
           }
         }
         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.evaluateArrayLiteral(declaration.id, 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 {
@@ -118,11 +119,15 @@ export class SemanticAnalyser {
       const resultType = this.evaluateExpressionType(declaration.initial);
       if(resultType instanceof MultiType) {
         if(!resultType.isCompatible(declaration.type)) {
-          throw new Error('Invalid type');  
+          const stringInfo = declaration.type.stringInfo();
+          const info = stringInfo[0];
+          throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, declaration.sourceInfo);
         }
         this.insertSymbol(declaration.id, {id: declaration.id, type: declaration.type})
       } else if(!declaration.type.isCompatible(resultType)) {
-        throw new Error('Invalid type');
+        const stringInfo = declaration.type.stringInfo();
+        const info = stringInfo[0];
+        throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, declaration.sourceInfo);
       } else {
         this.insertSymbol(declaration.id, {id: declaration.id, type: declaration.type})
       }
@@ -142,28 +147,37 @@ export class SemanticAnalyser {
     } else if (expression instanceof Literal) {
       return this.evaluateLiteralType(expression);
     } else if (expression instanceof FunctionCall) {
+      if (expression.isMainCall) {
+        throw ProcessorErrorFactory.void_in_expression_full(LanguageDefinedFunction.getMainFunctionName(), expression.sourceInfo);
+      }
       const fun = this.findFunction(expression.id);
+      if(fun === null) {
+        throw ProcessorErrorFactory.function_missing_full(expression.id, expression.sourceInfo);
+      }
       if (fun.returnType.isCompatible(Types.VOID)) {
-        throw new Error("void return");
+        throw ProcessorErrorFactory.void_in_expression_full(expression.id, expression.sourceInfo);
       }
       this.assertParameters(fun, expression.actualParameters);
       return fun.returnType;
     } else if (expression instanceof ArrayAccess) {
       const arrayTypeInfo = this.findSymbol(expression.id, this.symbolMap);
+      if(arrayTypeInfo === null) {
+        throw ProcessorErrorFactory.symbol_not_found_full(expression.id, expression.sourceInfo);
+      }
       if (!(arrayTypeInfo.type instanceof CompoundType)) {
-        throw new Error("it's not an array");
+        throw ProcessorErrorFactory.invalid_array_access_full(expression.id, expression.sourceInfo);
       }
       const lineType = this.evaluateExpressionType(expression.line);
       if (!lineType.isCompatible(Types.INTEGER)) {
-        throw new Error("line must be integer");
+        throw ProcessorErrorFactory.array_dimension_not_int_full(expression.sourceInfo);
       }
       if (expression.column !== null) {
         if (arrayTypeInfo.columns === null) {
-          throw new Error("it's not a matrix");
+          throw ProcessorErrorFactory.invalid_matrix_access_full(expression.id, expression.sourceInfo);
         }
         const columnType = this.evaluateExpressionType(expression.column);
         if(!columnType.isCompatible(Types.INTEGER)) {
-          throw new Error("column must be integer");
+          throw ProcessorErrorFactory.array_dimension_not_int_full(expression.sourceInfo);
         }
       }
       const arrType = arrayTypeInfo.type;
@@ -190,6 +204,9 @@ export class SemanticAnalyser {
       return literal.type;
     } else if (literal instanceof VariableLiteral) {
       const typeInfo = this.findSymbol(literal.id, this.symbolMap);
+      if(typeInfo === null) {
+        throw ProcessorErrorFactory.symbol_not_found_full(literal.id, literal.sourceInfo);
+      }
       if (typeInfo.type instanceof CompoundType) {
         return typeInfo.type;
       }
@@ -205,9 +222,10 @@ export class SemanticAnalyser {
           if(last === null) {
             last = e;
           } else if(!last.isCompatible(e)) {
-            throw new Error("invalid value type for array");
-          } else {
-            last = e;
+            const strInfo = last.stringInfo();
+            const info = strInfo[0];
+            const strExp = literal.toString();
+            throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
           }
         }
       }
@@ -218,21 +236,33 @@ export class SemanticAnalyser {
     }
   }
 
-  evaluateArrayLiteral (lines, columns, type, literal) {
+  evaluateArrayLiteral (id, 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");
+          throw ProcessorErrorFactory.array_dimension_not_int_full(literal.sourceInfo);
         }
-        if ((lines instanceof IntLiteral) && !lines.value.eq(literal.value.length)) {
-          throw new Error("invalid array size");
+        if ((lines instanceof IntLiteral)) {
+          if (!lines.value.eq(literal.value.length)) {
+            if(type.dimensions > 1) {
+              throw ProcessorErrorFactory.matrix_line_outbounds_full(id, literal.value.length, lines.values.toNumber(), literal.sourceInfo)
+            } else {
+              throw ProcessorErrorFactory.vector_line_outbounds_full(id, literal.value.length, lines.values.toNumber(), literal.sourceInfo)
+            }
+          } else if (line.value.isNeg()) {
+            throw ProcessorErrorFactory.array_dimension_not_positive_full(literal.sourceInfo);
+          }
+          
         }
         literal.value.reduce((last, next) => {
           const eType = this.evaluateExpressionType(next);
           if (!last.canAccept(eType)) {
-            throw new Error("invalid value type for array");
+            const strInfo = last.stringInfo();invalid
+            const info = strInfo[0];
+            const strExp = literal.toString();
+            throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
           }
           return last;
         }, type);
@@ -240,14 +270,23 @@ export class SemanticAnalyser {
       } else {
         const dimType = this.evaluateExpressionType(columns);
         if (!dimType.isCompatible(Types.INTEGER)) {
-          throw new Error("dim must be int");
+          throw ProcessorErrorFactory.array_dimension_not_int_full(literal.sourceInfo);
         }
-        if ((columns instanceof IntLiteral) && !columns.value.eq(literal.value.length)) {
-          throw new Error("invalid array size");
+        if ((columns instanceof IntLiteral)) {
+          if (!columns.value.eq(literal.value.length)) {
+            if(type.dimensions > 1) {
+              throw ProcessorErrorFactory.matrix_column_outbounds_full(id, literal.value.length, columns.values.toNumber(), literal.sourceInfo)
+            } else {
+              throw ProcessorErrorFactory.invalid_matrix_access_full(id, literal.sourceInfo);
+            }
+          } else if (columns.value.isNeg()) {
+            throw ProcessorErrorFactory.array_dimension_not_positive_full(literal.sourceInfo);
+          }
+          
         }
         for (let i = 0; i < columns; i++) {
           const anotherArray = literal.value[i];
-          this.evaluateArrayLiteral(lines, null, type, anotherArray)
+          this.evaluateArrayLiteral(id, lines, null, type, anotherArray)
         }
       }
 
@@ -255,18 +294,24 @@ export class SemanticAnalyser {
 
       const resultType = this.evaluateExpressionType(literal);
       if (!(resultType instanceof CompoundType)) {
-        throw new Error("initial must be of type array");
+        const strInfo = type.stringInfo();
+        const info = strInfo[0];
+        const strExp = literal.toString();
+        throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
       }
       if (!type.isCompatible(resultType)) {
-        throw new Error("invalid array type");
+        const strInfo = type.stringInfo();
+        const info = strInfo[0];
+        const strExp = literal.toString();
+        throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
       }
       return true;
-
     }
   }
 
   assertFunction (fun) {
     this.pushMap();
+    this.currentFunction = fun;
     fun.formalParameters.forEach(formalParam => {
       if(formalParam.type instanceof CompoundType) {
         if(formalParam.type.dimensions > 1) {
@@ -282,7 +327,7 @@ export class SemanticAnalyser {
     const optional = fun.returnType.isCompatible(Types.VOID);
     const valid = this.assertReturn(fun, optional);
     if (!valid) {
-      throw new Error("function has no accessible return");
+      throw ProcessorErrorFactory.function_no_return(fun.name);
     }
     this.popMap();
   }
@@ -297,7 +342,7 @@ export class SemanticAnalyser {
     if (cmd instanceof While) {
       const resultType = this.evaluateExpressionType(cmd.expression);
       if (!resultType.isCompatible(Types.BOOLEAN)) {
-        throw new Error("condition not boolean");
+        throw ProcessorErrorFactory.loop_condition_type_full(cmd.sourceInfo);
       }
       this.checkCommands(type, cmd.commands, optional);
       return false;
@@ -305,7 +350,7 @@ export class SemanticAnalyser {
       this.checkCommand(type, cmd.assignment, optional);
       const resultType = this.evaluateExpressionType(cmd.condition);
       if (!resultType.isCompatible(Types.BOOLEAN)) {
-        throw new Error("condition not boolean");
+        throw ProcessorErrorFactory.for_condition_type_full(cmd.sourceInfo);
       }
       this.checkCommand(type, cmd.increment, optional);
       this.checkCommands(type, cmd.commands, optional);
@@ -319,7 +364,10 @@ export class SemanticAnalyser {
         if (aCase.expression !== null) {
           const caseType = this.evaluateExpressionType(aCase.expression);
           if (!sType.isCompatible(caseType)) {
-            throw new Error("invalid type in case");
+            const strInfo = sType.stringInfo();
+            const info = strInfo[0];
+            const strExp = aCase.expression.toString();
+            throw ProcessorErrorFactory.invalid_case_type_full(strExp, info.type, info.dim, aCase.sourceInfo);
           }
         } else {
           hasDefault = true;
@@ -330,43 +378,53 @@ export class SemanticAnalyser {
 
     } else if (cmd instanceof ArrayIndexAssign) {
       const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
+      if(typeInfo === null) {
+        throw ProcessorErrorFactory.symbol_not_found_full(cmd.id, cmd.sourceInfo);
+      }
       if(!(typeInfo.type instanceof CompoundType)) {
-        throw new Error(cmd.id + " is not an array.");
+        throw ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo);
       }
       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");
+        throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
       }
       const columnExp = cmd.column;
       if (typeInfo.columns === null && columnExp !== null) {
-        throw new Error(cmd.id + " is not a matrix");
+        throw ProcessorErrorFactory.invalid_matrix_access_full(cmd.id, cmd.sourceInfo);
       } else if (columnExp !== null) {
         const columnType = this.evaluateExpressionType(columnExp);
         if (!columnType.isCompatible(Types.INTEGER)) {
-          throw new Error("array dimension must be of type int");
+          throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
         }
       }
       // 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);
+        this.evaluateArrayLiteral(cmd.id, 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);
+      if(typeInfo === null) {
+        throw ProcessorErrorFactory.symbol_not_found_full(cmd.id, cmd.sourceInfo);
+      }
       const exp = cmd.expression;
       if(exp instanceof ArrayLiteral) {
         if(!(typeInfo.type instanceof CompoundType)) {
-          throw new Error("type not compatible");
+          const stringInfo = typeInfo.type.stringInfo();
+          const info = stringInfo[0];
+          throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo);
         }
-        this.evaluateArrayLiteral(typeInfo.lines, typeInfo.columns, typeInfo.type, exp);
+        this.evaluateArrayLiteral(cmd.id, typeInfo.lines, typeInfo.columns, typeInfo.type, exp);
       } else {
         const resultType = this.evaluateExpressionType(exp);
         if(!resultType.isCompatible(typeInfo.type)) {
-          throw new Error("type not compatible");
+          const stringInfo = typeInfo.type.stringInfo();
+          const info = stringInfo[0];
+          throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo);
         }
       }
       return optional;
@@ -375,7 +433,7 @@ export class SemanticAnalyser {
     } else if (cmd instanceof IfThenElse) {
       const resultType = this.evaluateExpressionType(cmd.condition);
       if (!resultType.isCompatible(Types.BOOLEAN)) {
-        throw new Error("condition not boolean");
+        throw ProcessorErrorFactory.if_condition_type_full(cmd.sourceInfo);
       }
       if(cmd.ifFalse instanceof IfThenElse) {
         return this.checkCommands(type, cmd.ifTrue.commands, optional) && this.checkCommand(type, cmd.ifFalse, optional);
@@ -384,17 +442,29 @@ export class SemanticAnalyser {
       }
 
     } else if (cmd instanceof FunctionCall) {
-      const fun = this.findFunction(cmd.id);
+      let fun = null;
+      if (cmd.isMainCall) {
+        fun = this.getMainFunction();
+      } else {
+        fun = this.findFunction(cmd.id);
+      }
+      if(fun === null) {
+        throw ProcessorErrorFactory.function_missing_full(cmd.id, cmd.sourceInfo);
+      }
       this.assertParameters(fun, cmd.actualParameters);
       return optional;
     } else if (cmd instanceof Return) {
+      const funcName = this.currentFunction.isMain ? LanguageDefinedFunction.getMainFunctionName() : this.currentFunction.name
       if (cmd.expression === null && !type.isCompatible(Types.VOID)) {
-        throw new Error('invalid return type');
+        const stringInfo = type.stringInfo();
+        const info = stringInfo[0];
+        throw ProcessorErrorFactory.invalid_void_return_full(funcName, info.type, info.dim, cmd.sourceInfo);
       } else if (cmd.expression !== null) {
         const resultType = this.evaluateExpressionType(cmd.expression);
         if (!type.isCompatible(resultType)) {
-          console.log(resultType);
-          throw new Error('invalid return type');
+          const stringInfo = type.stringInfo();
+          const info = stringInfo[0];
+          throw ProcessorErrorFactory.invalid_return_type_full(funcName, info.type, info.dim, cmd.sourceInfo);
         } else {
           return true;
         }
@@ -412,14 +482,14 @@ export class SemanticAnalyser {
 
   assertParameters (fun, actualParametersList) {
     if (fun.formalParameters.length !== actualParametersList.length) {
-      throw new Error("wrong number of parameters...");
+      throw ProcessorErrorFactory.invalid_parameters_size_full(fun.name, actualParametersList.length, fun.formalParameters.length, null);
     }
     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");
+          throw ProcessorErrorFactory.invalid_parameter_type_full(id, param.toString(), param.sourceInfo);
         }
       }
       const resultType = this.evaluateExpressionType(param);
@@ -432,18 +502,14 @@ export class SemanticAnalyser {
           }
         }
         if(shared <= 0) {
-          throw new Error(`Parameter ${formalParam.id} is not compatible with the value given.`);
+          throw ProcessorErrorFactory.invalid_parameter_type_full(id, param.toString(), param.sourceInfo);
         }
       } else if (resultType instanceof MultiType) {
         if(!resultType.isCompatible(formalParam.type)) {
-          throw new Error(`Parameter ${formalParam.id} is not compatible with the value given.`);
+          throw ProcessorErrorFactory.invalid_parameter_type_full(id, param.toString(), param.sourceInfo);
         }
       } 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.`);
+        throw ProcessorErrorFactory.invalid_parameter_type_full(id, param.toString(), param.sourceInfo);
       }
 
     }

+ 19 - 7
js/processor/store/storeObjectArray.js

@@ -2,6 +2,18 @@ import { StoreObject } from './storeObject';
 
 export class StoreObjectArray extends StoreObject {
 
+  static get WRONG_LINE_NUMBER () {
+    return 1;
+  }
+
+  static get WRONG_TYPE () {
+    return 2;
+  }
+
+  static get WRONG_COLUMN_NUMBER () {
+    return 3;
+  }
+
   constructor (type, lines, columns, value = null, readOnly = false) {
     super(type, value, readOnly);
     this._lines = lines;
@@ -37,31 +49,31 @@ export class StoreObjectArray extends StoreObject {
     if (this.value !== null) {
       if( this.isVector) {
         if(this.value.length !== this.lines) {
-          return false;
+          return [StoreObjectArray.WRONG_LINE_NUMBER, this.value.length];;
         }
         const mustBeNull = this.value.find(v => !this.type.canAccept(v.type) );
         if(!!mustBeNull) {
-          return false;
+          return [StoreObjectArray.WRONG_TYPE, this.value.indexOf(mustBeNull)];;
         }
       }
-      return true;
+      return [];
     } else {
     if(this.lines !== this.value.length) {
-      return false;
+      return [StoreObjectArray.WRONG_LINE_NUMBER, this.value.length];
     }
     for (let i = 0; i < this.lines; i++) {
       for (let j = 0; j < this.columns; j++) {
         const arr = this.value[i];
         if(arr.length !== this.columns) {
-          return false;
+          return [StoreObjectArray.WRONG_COLUMN_NUMBER, arr.length];
         }
         const mustBeNull = arr.find(v => !this.type.canAccept(v.type) );
         if(!!mustBeNull) {
-          return false;
+          return [StoreObjectArray.WRONG_TYPE, i, arr.indexOf(mustBeNull)];
         }            
       }
     }
-      return true;
+      return [];
     }
   }
 }

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

@@ -1,6 +1,7 @@
 import { StoreObject } from './storeObject';
 import { StoreObjectArray } from './storeObjectArray';
 import { CompoundType } from '../../typeSystem/compoundType';
+import { ProcessorErrorFactory } from '../error/processorErrorFactory';
 
 export class StoreObjectArrayAddress extends StoreObject {
 
@@ -22,8 +23,22 @@ export class StoreObjectArrayAddress extends StoreObject {
 
   get refValue () {
     const refLine = this.store.applyStore(this.refID).value[this.line];
+    if(!refLine) {
+      if(this.getArrayObject().isVector) {
+        throw ProcessorErrorFactory.vector_line_outbounds(this.refID, this.line, this.getArrayObject().lines);
+      } else {
+        throw ProcessorErrorFactory.matrix_line_outbounds(this.refID, this.line, this.getArrayObject().lines);
+      }
+    }
     if (this.column !== null) {
       const refColumn = refLine.value[this.column];
+      if(!refColumn) {
+        if(this.getArrayObject().isVector) {
+          throw ProcessorErrorFactory.vector_not_matrix(this.refID);
+        } else {
+          throw ProcessorErrorFactory.matrix_column_outbounds(this.refID, this.column, this.getArrayObject().columns);
+        }
+      }
       return refColumn;
     }
     return refLine;

+ 4 - 3
js/typeSystem/baseTypes.js

@@ -16,11 +16,12 @@ class BaseType {
   }
 }
 
+// Base types names are the same as i18n ui type keys
 export const BaseTypes = Object.freeze({
-  INTEGER: new BaseType("int", 0),
+  INTEGER: new BaseType("integer", 0),
   REAL: new BaseType("real", 1),
-  STRING: new BaseType("string", 2),
-  BOOLEAN: new BaseType("bool", 3),
+  STRING: new BaseType("text", 2),
+  BOOLEAN: new BaseType("boolean", 3),
   VOID: new BaseType("void", 4),
   UNDEFINED: new BaseType("undefined", 5)
 })

+ 8 - 0
js/typeSystem/compoundType.js

@@ -18,6 +18,14 @@ export class CompoundType extends Type {
     return false;
   }
 
+  stringInfo () {
+    const list = this.innerType.stringInfo();
+    list.forEach(v => {
+      v.dim = this.dimensions;
+    });
+    return list;
+  }
+
   canAccept (another) {
     if(another instanceof CompoundType) {
       return this.dimensions > another.dimensions && this.innerType.isCompatible(another.innerType);

+ 9 - 0
js/typeSystem/multiType.js

@@ -15,6 +15,15 @@ export class MultiType extends Type {
     return null;
   }
 
+  stringInfo () {
+    let list = [];
+    for (let i = 0; i < this.types.length; i++) {
+      const t = this.types[i];
+      list = list.concat(t.stringInfo());
+    }
+    return list;
+  }
+
   isCompatible (another) {
     if(another instanceof Type) {
       for (let i = 0; i < this.types.length; i++) {

+ 4 - 0
js/typeSystem/type.js

@@ -12,6 +12,10 @@ export class Type {
     return this.baseType.ord;
   }
 
+  stringInfo () {
+    return [{type: this.baseType.name, dim: 0}];
+  }
+
   isCompatible (another) {
     if(another instanceof Type) {
       return this.baseType.isCompatible(another.baseType);

+ 2 - 0
tests/test03.spec.js

@@ -13,7 +13,9 @@ describe('Expressions which ends with ID terminals', () => {
 
     it(`should not result in SyntaxError`, () => {
         const as = new IVProgParser(input, lexer);
+        as.pushVariableStack();
         const fun = as.parseFunction.bind(as);
         expect(fun).not.toThrow();
+        as.popVariableStack();
     });
 });

+ 2 - 0
tests/test05.spec.js

@@ -19,7 +19,9 @@ describe('IfThenElse command', () => {
 
     it(`should not result in SyntaxError`, () => {
         const as = new IVProgParser(input, lexer);
+        as.pushVariableStack();
         const fun = as.parseFunction.bind(as);
         expect(fun).not.toThrow();
+        as.popVariableStack();
     });
 });

+ 2 - 0
tests/test06.spec.js

@@ -15,7 +15,9 @@ describe('While command', () => {
 
     it(`should not result in SyntaxError`, () => {
         const as = new IVProgParser(input, lexer);
+        as.pushVariableStack();
         const fun = as.parseFunction.bind(as);
         expect(fun).not.toThrow();
+        as.popVariableStack();
     });
 });

+ 2 - 0
tests/test07.spec.js

@@ -16,7 +16,9 @@ describe('For command', () => {
 
     it(`should not result in SyntaxError`, () => {
         const as = new IVProgParser(input, lexer);
+        as.pushVariableStack();
         const fun = as.parseFunction.bind(as);
         expect(fun).not.toThrow();
+        as.popVariableStack();
     });
 });

+ 2 - 0
tests/test08.spec.js

@@ -18,7 +18,9 @@ describe('Break command inside a loop', () => {
 
     it(`should not result in SyntaxError`, () => {
         const as = new IVProgParser(input, lexer);
+        as.pushVariableStack();
         const fun = as.parseFunction.bind(as);
         expect(fun).not.toThrow();
+        as.popVariableStack();
     });
 });

+ 2 - 0
tests/test10.spec.js

@@ -20,7 +20,9 @@ describe('IfThenElseIfThenElse command chain', () => {
 
     it(`should not result in SyntaxError`, () => {
         const as = new IVProgParser(input, lexer);
+        as.pushVariableStack();
         const fun = as.parseFunction.bind(as);
         expect(fun).not.toThrow();
+        as.popVariableStack();
     });
 });

+ 2 - 0
tests/test11.spec.js

@@ -16,7 +16,9 @@ describe('DoWhile command', () => {
 
     it(`should not result in SyntaxError`, () => {
         const as = new IVProgParser(input, lexer);
+        as.pushVariableStack();
         const fun = as.parseFunction.bind(as);
         expect(fun).not.toThrow();
+        as.popVariableStack();
     });
 });

+ 2 - 0
tests/test12.spec.js

@@ -17,7 +17,9 @@ describe('SwitchCase command', () => {
 
     it(`should not result in SyntaxError`, () => {
         const as = new IVProgParser(input, lexer);
+        as.pushVariableStack();
         const fun = as.parseFunction.bind(as);
         expect(fun).not.toThrow();
+        as.popVariableStack();
     });
 });

+ 33 - 0
tests/testCallMainFunction.spec.js

@@ -0,0 +1,33 @@
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+import { SemanticAnalyser } from "./../js/processor/semantic/semanticAnalyser";
+import { LanguageService } from '../js/services/languageService';
+
+describe('A call to the main function', function () {
+
+  let input = `programa {
+      inteiro a = 0
+      funcao inicio () {
+        se (a > 5) {
+          retorne
+        } senao {
+          a = a + 1
+          inicio()
+        }
+      }
+    }`;
+
+  const lexer = LanguageService.getCurrentLexer();
+
+  it(`should produce a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const semantic = new SemanticAnalyser(parser.parseTree());
+    const exec = new IVProgProcessor(semantic.analyseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto).toBeTruthy();
+      done();
+    }).catch(err => {
+      done(err);
+    });
+  });
+});

+ 25 - 0
tests/testDuplicateFunctions.spec.js

@@ -0,0 +1,25 @@
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { LanguageService } from '../js/services/languageService';
+
+describe('A code with a duplicate function', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      escreva(Matematica.tan(90))
+    }
+
+    funcao vazio inicio() {
+
+    }
+  }`;
+
+  const lexer = LanguageService.getCurrentLexer();
+
+  it(`should throw a syntax exception`, function () {
+    const parser = new IVProgParser(input, lexer);
+    const func = parser.parseTree;
+    func.bind(parser);
+    expect(func).toThrow();
+  });
+});

+ 22 - 0
tests/testDuplicateVariable.spec.js

@@ -0,0 +1,22 @@
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { LanguageService } from '../js/services/languageService';
+
+describe('A code with a duplicate variable declarations', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      real a = 90.0, a = 0.0
+      escreva(Matematica.tan(a))
+    }
+  }`;
+
+  const lexer = LanguageService.getCurrentLexer();
+
+  it(`should throw a syntax exception`, function () {
+    const parser = new IVProgParser(input, lexer);
+    const func = parser.parseTree;
+    func.bind(parser);
+    expect(func).toThrow();
+  });
+});