Kaynağa Gözat

Merge branch 'error-messages' of LInE/ivprog into master

Lucas de Souza 4 yıl önce
ebeveyn
işleme
2019ec2242

+ 30 - 8
i18n/pt/error.json

@@ -69,13 +69,13 @@
   "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_full": "Era esperado um $0 mas a expressão $1 na linha $2 resulta em $3.",
+  "incompatible_types": "Era esperado um $0 mas a expressão $1 resulta em $2.",
   "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.",
+  "function_no_return": "A função $0 não possui um comando de devolução acessível. Toda função deve ter ao menos um comando 'devolva' 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.",
@@ -88,8 +88,8 @@
   "test_case_failed_exception": "<div class='assessment-div-detail' onClick='ivprogCore.openAssessmentDetail(event)' data-page=\"$2\"> <span>Caso de teste $0 falhou</span>: $1",
   "test_case_exception": "Ocorreu uma exceção no caso de teste $0: $1",
   "invalid_type_conversion": "O valor $0 não pode ser convertido para o tipo $1",
-  "invalid_read_type":"A entrada \"$0\" não é do tipo $1, que é o tipo da variável <span class='ivprog-error-varname'>$2</span>.",
-  "invalid_read_type_array":"A entrada \"$0\" não é do tipo $1, que é o tipo aceito pela variável <span class='ivprog-error-varname'>$2</span> que é um $3.",
+  "invalid_read_type":"Erro na linha $0: A entrada \"$1\" não é do tipo $2, que é o tipo da variável <span class='ivprog-error-varname'>$3</span>.",
+  "invalid_read_type_array":"Erro na linha $0: A entrada \"$1\" não é do tipo $2, que é o tipo aceito pela variável <span class='ivprog-error-varname'>$3</span> que é um $4.",
   "inform_valid_identifier": "Informe um nome válido! O nome não pode ser uma palavra reservadoa e deve começar com letras e conter apenas letras, números e _",
   "inform_valid_global_duplicated": "Já existe uma variável global com o nome <span class='ivprog-error-varname'>$0</span>, você precisa de nomes distintos.",
   "inform_valid_variable_duplicated" : "Já existe uma variável com o nome <span class='ivprog-error-varname'>$0</span> na função <span class='ivprog-error-varname'>$1</span>, você precisa de nomes distintos.",
@@ -101,10 +101,32 @@
   "cannot_infer_matrix_line": "Não é possível inferir o número de linhas da matriz $0 na linha $1. É necessário que ela seja inicializada ou que o valor seja informado de forma explícita.",
   "cannot_infer_matrix_column": "Não é possível inferir o número de colunas da matriz $0 na linha $1. É necessário que ela seja inicializada ou que o valor seja informado de forma explícita.",
   "cannot_infer_vector_size": "Não é possível inferir o número de elementos do vetor $0 na linha $1. É necessário que ele seja inicializado ou que o valor seja informado de forma explícita",
-  "matrix_to_vector_attr":  "Erro na linha $0: $1 representa uma matriz e não pode ser atribuída ao vetor $2.",
-  "vector_to_matrix_attr":  "Err na linha $0: $1 representa um vetor e não pode ser atribuído a matriz $2.",
+  "matrix_to_vector_literal_attr":  "Erro na linha $0: A expressão $1 representa uma matriz e não pode ser atribuída ao vetor $2.",
+  "vector_to_matrix_literal_attr":  "Erro na linha $0: A expressão $1 representa um vetor e não pode ser atribuído a matriz $2.",
   "invalid_const_ref_full": "A variável $0 fornecida como parâmetro para a função $1 na linha $2 é uma constante e não pode ser usada neste contexto. Use uma variável ou posição de vetor.",
   "invalid_const_ref": "A variável $0 fornecida como parâmetro para a função $1 é uma constante e não pode ser usada neste contexto. Use uma variável ou posição de vetor.",
   "invalid_const_assignment_full": "Erro na linha $0: $1 é uma constante e portanto não pode ter seu valor alterado",
-  "invalid_const_assignment": "$0 é uma constante e portanto não pode ter seu valor alterado"
+  "invalid_const_assignment": "$0 é uma constante e portanto não pode ter seu valor alterado",
+  "array_init_not_literal": "Erro na linha $0: Vetor/Matriz só pode ser inicializado por literal. Ex: real vetor[] <- {1,2,3}",
+  "array_exceeds_2d": "Erro na linha $0: O número máximo de dimensões que um arranjo pode ter é 2. Elemento de 3 ou mais dimensões encontrado!",
+  "invalid_matrix_id_dimension": "Erro na linha $0: Você deve definir todas as dimensões da matriz quando uma delas é definida por uma variável! Ex: real mat1[var][5], mat2[5][var]",
+  "invalid_vector_init": "Erro na linha $0: Não se pode inicializar um vetor que teve seu tamanho declarado utilizando uma variável! Utilize uma atribuição de vetores ou use um laço de repetição.",
+  "invalid_matrix_init": "Erro na linha $0: Não se pode inicializar uma matrix que teve ao menos uma das suas dimensões declaradas utilizando uma variável! Utilize uma atribuição de matrizes ou use um laço de repetição.",
+  "invalid_vector_assignment_full": "Erro na linha $0: Só se pode atribuir um vetor a outro desde que eles comportem o mesmo número de elementos. $1 comporta $2 e $3 comporta $4!",
+  "invalid_vector_assignment": "Só se pode atribuir um vetor a outro desde que eles comportem o mesmo número de elementos. $0 comporta $1 e $2 comporta $3!",
+  "invalid_matrix_assignment_full": "Erro na linha $0: Só se pode atribuir uma matriz a outra desde que ambas possuam dimensões de mesmo tamanho. $1 tem $2 linhas e $3 colunas, enquanto $4 possui $5 linhas e $6 colunas!",
+  "invalid_matrix_assignment": "Só se pode atribuir uma matriz a outra desde que ambas possuam dimensões de mesmo tamanho. $0 tem $1 linhas e $2 colunas, enquanto $3 possui $4 linhas e $5 colunas!",
+  "matrix_to_vector_attr":  "Erro na linha $0: $1 representa uma matriz e não pode ser atribuída ao vetor $2.",
+  "vector_to_matrix_attr":  "Erro na linha $0: $1 representa um vetor e não pode ser atribuído a matriz $2.",
+  "invalid_matrix_index_assign_full": "Erro na linha $0: A posição $1 da matriz $2 aceita apenas vetores de tamanho $3, mas $4 tem tamanho $5",
+  "invalid_matrix_index_assign": "A linha $0 da matriz $1 aceita apenas vetores de tamanho $2, mas $3 tem tamanho $4",
+  "invalid_number_elements_vector": "Esperava-se por $0 elementos na linha $1 mas a expressão $2 possui $3 elementos.",
+  "invalid_number_lines_matrix": "Esperava-se por uma matriz com $0 linhas na linha $1 mas a expressão $2 possui $3 linhas",
+  "divsion_by_zero_full": "Erro na linha $0: A expressão $1 resulta em uma divisão por 0.",
+  "divsion_by_zero": "A expressão $0 resulta em uma divisão por 0.",
+  "undefined_tanget_value": "Erro na linha $0: A tangente de $1° não é indefinida.",
+  "negative_log_value": "Erro na linha $0: Não se pode calcular o log de um valor negativo.",
+  "invalid_string_index": "Erro na linha $0 durante a execução da função $1: $2 é um índice inválido para a cadeia de texto $3. Os valores válidos vão de 0 à $4",
+  "negative_sqrt_value": "Erro na linha $0: Não é permitido calcular a raiz quadrada de um número negativo.",
+  "exceeded_recursive_calls": "Erro na execução da linha $0: Número de chamadas recursivas execedeu o limite máximo definido!"
 }

+ 25 - 5
js/ast/error/syntaxErrorFactory.js

@@ -73,7 +73,7 @@ export const SyntaxErrorFactory = Object.freeze({
     const context = [token.text, token.line, token.column];
     return createError("duplicate_variable", context);
   },
-  invalid_character: (text, line, column) => {
+  invalid_character: (text, line, _column) => {
     const context = [text, line];
     return createError("invalid_character", context);
   },
@@ -97,12 +97,32 @@ export const SyntaxErrorFactory = Object.freeze({
     const context = [name, sourceInfo.line];
     return createError("cannot_infer_vector_size", context);
   },
-  matrix_to_vector_attr: (name, exp, sourceInfo) => {
+  matrix_to_vector_literal_attr: (name, exp, sourceInfo) => {
     const context = [sourceInfo.line, exp, name];
-    return createError("matrix_to_vector_attr", context);
+    return createError("matrix_to_vector_literal_attr", context);
   },
-  vector_to_matrix_attr: (name, exp, sourceInfo) => {
+  vector_to_matrix_literal_attr: (name, exp, sourceInfo) => {
     const context = [sourceInfo.line, exp, name];
-    return createError("vector_to_matrix_attr", context);
+    return createError("vector_to_matrix_literal_attr", context);
+  },
+  array_init_not_literal: (sourceInfo) => {
+    const context = [sourceInfo.line];
+    return createError("array_init_not_literal", context);
+  },
+  array_exceeds_2d: (sourceInfo) => {
+    const context = [sourceInfo.line];
+    return createError("array_exceeds_2d", context);
+  },
+  invalid_matrix_id_dimension: (sourceInfo) => {
+    const context = [sourceInfo.line];
+    return createError("invalid_matrix_id_dimension", context);
+  },
+  invalid_vector_init: (sourceInfo) => {
+    const context = [sourceInfo.line];
+    return createError("invalid_vector_init", context);
+  },
+  invalid_matrix_init: (sourceInfo) => {
+    const context = [sourceInfo.line];
+    return createError("invalid_matrix_init", context);
   }
 });

+ 8 - 2
js/ast/expressions/arrayAccess.js

@@ -15,10 +15,16 @@ export class ArrayAccess extends Expression {
 		if(this.column) {
 			strColumn = this.column.toString();
 		}
+		let text = null;
 		if(strColumn) {
-			return `${this.id}[${strLine}][${strColumn}]`;
+			text = `${this.id}[${strLine}][${strColumn}]`;
 		} else {
-			return `${this.id}[${strLine}]`;
+			text = `${this.id}[${strLine}]`;
+		}
+		if(this.parenthesis ){
+			return `(${text})`
+		} else {
+			return text;
 		}
 	}
 }

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

@@ -8,7 +8,7 @@ export class ArrayLiteral extends Literal {
   }
 
   get subtype () {
-    let element = this.value[0];
+    const element = this.value[0];
     if (element instanceof ArrayLiteral) {
       return element.value[0].type;
     } else {
@@ -21,7 +21,7 @@ export class ArrayLiteral extends Literal {
   }
 
   get columns () {
-    let element = this.value[0];
+    const element = this.value[0];
     if (!(element instanceof ArrayLiteral)){
       return null;
     } else {
@@ -38,7 +38,7 @@ export class ArrayLiteral extends Literal {
   }
 
   validateType () {
-    let valid = true;
+    const valid = true;
     // const subtype = this.subtype;
     // if(this.columns !== null) {
     //   const len = this.lines;
@@ -65,7 +65,7 @@ export class ArrayLiteral extends Literal {
   }
 
   validateSize () {
-    let valid = true;
+    const valid = true;
     // if(this.columns !== null) {
     //   const equalityTest = this.value.map(v => v.value.length)
     //     .reduce((old, next) => {
@@ -86,6 +86,11 @@ export class ArrayLiteral extends Literal {
 
   toString () {
     const strList = this.value.map(arrayLiteral => arrayLiteral.toString());
-    return "{" + strList.join(',') + "}";
+    const text = "{" + strList.join(',') + "}";
+    if(this.parenthesis) {
+      return `(${text})`;
+    } else {
+      return text;
+    }
   }
 }

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

@@ -10,6 +10,11 @@ export class BoolLiteral extends Literal {
   }
 
   toString () {
-    return convertBoolToString(this.value);
+    const text = convertBoolToString(this.value);
+    if(this.parenthesis) {
+      return `(${text})`
+    } else {
+      return text;
+    }
   }
 }

+ 10 - 1
js/ast/expressions/expression.js

@@ -1,7 +1,8 @@
 export class Expression {
 
   constructor () {
-    this._sourceInfo = null;
+		this._sourceInfo = null;
+		this._parenthesis = false;
   }
 
   set sourceInfo (sourceInfo) {
@@ -11,4 +12,12 @@ export class Expression {
 	get sourceInfo () {
 		return this._sourceInfo;
 	}
+
+	set parenthesis (flag) {
+		this._parenthesis = flag;
+	}
+
+	get parenthesis () {
+		return this._parenthesis;
+	}
 }

+ 5 - 1
js/ast/expressions/functionCall.js

@@ -31,6 +31,10 @@ export class FunctionCall extends Expression {
 			const strParams = this.actualParameters.map(v => v.toString());
 			params = "(" + strParams.join(",") + ")";
 		}
-		return name + params;
+		if(this.parenthesis) {
+			return `(${name + params})`;
+		} else {
+			return name + params;
+		}
 	}
 }

+ 5 - 1
js/ast/expressions/infixApp.js

@@ -13,6 +13,10 @@ export class InfixApp extends Expression {
     const l = this.left.toString();
     const op = this.op.value;
     const r = this.right.toString();
-    return l + op + r;
+    if(this.parenthesis) {
+      return  `(${l + op + r})`;
+    } else {
+      return l + op + r;
+    }
   }
 }

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

@@ -10,6 +10,11 @@ export class IntLiteral extends Literal {
   }
 
   toString() {
-    return convertToString(this.value, this.type);
+    const text = convertToString(this.value, this.type);
+    if(this.parenthesis) {
+      return `(${text})`;
+    } else {
+      return text;
+    }
   }
 }

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

@@ -10,6 +10,11 @@ export class RealLiteral extends Literal {
   }
 
   toString() {
-    return convertToString(this.value, this.type);
+    const text = convertToString(this.value, this.type);
+    if (this.parenthesis) {
+      return `(${text})`;
+    } else {
+      return text;
+    }
   }
 }

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

@@ -9,6 +9,11 @@ export class StringLiteral extends Literal {
   }
 
   toString() {
-    return '"' + this.value + '"';
+    const text = '"' + this.value + '"';
+    if(this.parenthesis) {
+      return `(${text})`;
+    } else {
+      return text;
+    }
   }
 }

+ 5 - 1
js/ast/expressions/unaryApp.js

@@ -9,6 +9,10 @@ export class UnaryApp extends InfixApp {
   toString () {
     const l = this.left.toString();
     const op = this.op.value;
-    return op + l;
+    if(this.parenthesis) {
+      return `(${op + l})`;
+    } else {
+      return op + l;
+    }
   }
 }

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

@@ -9,6 +9,10 @@ export class VariableLiteral extends Literal {
   }
 
   toString () {
-    return this.id;
+    if(this.parenthesis) {
+      return `(${this.id})`;
+    } else {
+      return this.id;
+    }
   }
 }

+ 15 - 15
js/ast/ivprogParser.js

@@ -294,7 +294,7 @@ export class IVProgParser {
     // Check for array or vector
     // ID[int/IDi?][int/IDj?]
     if (this.checkOpenBrace(true)) {
-      this.pos += 1;
+      this.pos += 1;    
       this.consumeNewLines();
       dim1 = this.parseArrayDimension();
       this.consumeNewLines();
@@ -343,8 +343,7 @@ export class IVProgParser {
     if(dim1 instanceof Expressions.VariableLiteral || dim2 instanceof Expressions.VariableLiteral) {
       dim_is_id = true;
       if(dimensions > 1 && (dim1 == null || dim2 == null)) {
-        // TODO better error message
-        throw new Error("array with id dimension must have all dims");
+        throw SyntaxErrorFactory.invalid_matrix_id_dimension(SourceInfo.createSourceInfo(equalsToken));
       }
     }
     if(isConst && equalsToken.type !== this.lexerClass.EQUAL ) {
@@ -352,8 +351,11 @@ export class IVProgParser {
     }
     if(equalsToken.type === this.lexerClass.EQUAL) {
       if(dim_is_id) {
-        // TODO better error message
-        throw new Error("Cannot init array with a variable as dimesion");
+        if(dimensions == 1) {
+          throw SyntaxErrorFactory.invalid_vector_init(SourceInfo.createSourceInfo(equalsToken));
+        } else {
+          throw SyntaxErrorFactory.invalid_matrix_init(SourceInfo.createSourceInfo(equalsToken));
+        }
       }
       this.pos += 1
       initial = this.parseArrayLiteral(typeString);
@@ -372,10 +374,10 @@ export class IVProgParser {
 
     if(dimensions === 1 && initial != null && !initial.isVector) {
       const expString = initial.toString();
-      throw SyntaxErrorFactory.matrix_to_vector_attr(idString, expString, initial.sourceInfo);
+      throw SyntaxErrorFactory.matrix_to_vector_literal_attr(idString, expString, initial.sourceInfo);
     } else if (dimensions > 1 && initial != null && initial.isVector) {
       const expString = initial.toString();
-      throw SyntaxErrorFactory.vector_to_matrix_attr(idString, expString, initial.sourceInfo);
+      throw SyntaxErrorFactory.vector_to_matrix_literal_attr(idString, expString, initial.sourceInfo);
     }
 
     if(dim1 == null) {
@@ -474,13 +476,12 @@ export class IVProgParser {
   parseArrayLiteral (typeString) {
     const openCurly = this.checkOpenCurly(true);
     if(!openCurly) {
-      // const invalid_token = this.getToken();
-      throw new Error("Array can only be init with a literal");
+      const invalid_token = this.getToken();
+      throw SyntaxErrorFactory.array_init_not_literal(SourceInfo.createSourceInfo(invalid_token));
     }
     const beginArray = this.getToken();
     if (this.parsingArrayDimension >= 2) {
-      // TODO better message
-      throw SyntaxErrorFactory.token_missing_list(`Array dimensions exceed maximum size of 2 at line ${beginArray.line}`);
+      throw SyntaxErrorFactory.array_exceeds_2d(SourceInfo.createSourceInfo(beginArray));
     }
     this.pos += 1;
     this.parsingArrayDimension += 1;
@@ -521,8 +522,7 @@ export class IVProgParser {
       this.checkOpenCurly();
       const beginArray = this.getToken();
       if (this.parsingArrayDimension >= 2) {
-        // TODO better message
-        throw SyntaxErrorFactory.token_missing_list(`Array dimensions exceed maximum size of 2 at line ${beginArray.line}`);
+        throw SyntaxErrorFactory.array_exceeds_2d(SourceInfo.createSourceInfo(beginArray));
       }
       this.pos += 1;
       this.parsingArrayDimension += 1;
@@ -1285,9 +1285,9 @@ export class IVProgParser {
     this.consumeNewLines();
     this.checkCloseParenthesis();
     const tokenB = this.getToken();
-    const sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
     this.pos += 1;
-    exp.sourceInfo = sourceInfo;
+    exp.sourceInfo = SourceInfo.createSourceInfoFromList(tokenA, tokenB);
+    exp.parenthesis = true;
     return exp;
   }
 

+ 179 - 82
js/processor/error/processorErrorFactory.js

@@ -5,411 +5,508 @@ import { LanguageDefinedFunction } from '../definedFunctions';
 
 const LocalizedStrings = LocalizedStringsService.getInstance();
 
+function createRuntimeError (i18n_id, context = []) {
+  return new RuntimeError(LocalizedStrings.getError(i18n_id, context))
+}
+
+function createSemanticError (i18n_id, context = []) {
+  return new SemanticError(LocalizedStrings.getError(i18n_id, context))
+}
+
 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));
+      return createSemanticError("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));
+    return createSemanticError("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));
+      return createSemanticError("function_missing_full", context);
     } else {
       return ProcessorErrorFactory.function_missing(id);
     }
   },
   function_missing: (id) => {
     const context = [id];
-    return new SemanticError(LocalizedStrings.getError("function_missing", context));
+    return createSemanticError("function_missing", context);
   },
   main_missing: () => {
-    return new SemanticError(LocalizedStrings.getError("main_missing"));
-  },        // TODO: better urgent error message
+    return createSemanticError("main_missing");
+  },
   array_dimension_not_int_full: (sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line];
-      return new SemanticError(LocalizedStrings.getError("array_dimension_not_int_full", context));
+      return createSemanticError("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"));
+    return createSemanticError("array_dimension_not_int");
   },
   unknown_command_full: (sourceInfo)=> {
     if(sourceInfo) {
       const context = [sourceInfo.line];
-      return new RuntimeError(LocalizedStrings.getError("unknown_command_full", context));
+      return createRuntimeError("unknown_command_full", context);
     } else {
       return ProcessorErrorFactory.unknown_command();
     }
     
   },
   unknown_command: ()=> {
-    return new RuntimeError(LocalizedStrings.getError("unknown_command"));
+    return createRuntimeError("unknown_command");
   },
-  incompatible_types_full: (type, dim, sourceInfo) => {
-    if(sourceInfo) {
-      const context = [LocalizedStrings.translateType(type, dim), sourceInfo.line, sourceInfo.column];
-      return new SemanticError(LocalizedStrings.getError("incompatible_types_full", context));
+  incompatible_types_full: (left_type, left_dim, right_type, right_dim, exp, source_info) => {
+    if(source_info) {
+      const context = [LocalizedStrings.translateType(left_type, left_dim), exp, source_info.line,
+        LocalizedStrings.translateType(right_type, right_dim)];
+      return createSemanticError("incompatible_types_full", context);
     } else {
-      return ProcessorErrorFactory.incompatible_types(type, dim);
+      return ProcessorErrorFactory.incompatible_types(left_type, left_dim, right_type, right_dim, exp);
     }
   },
-  incompatible_types: (type, dim) => {
-    const context = [LocalizedStrings.translateType(type, dim)];
-    return new SemanticError(LocalizedStrings.getError("incompatible_types", context));
+  incompatible_types: (left_type, left_dim, right_type, right_dim, exp) => {
+    const context = [LocalizedStrings.translateType(left_type, left_dim), exp,
+      LocalizedStrings.translateType(right_type, right_dim)];
+    return createSemanticError("incompatible_types", context);
   },
   incompatible_types_array_full: (exp, type, dim, sourceInfo) => {
     if(sourceInfo) {
       const context = [exp, LocalizedStrings.translateType(type, dim), sourceInfo.line, sourceInfo.column];
-      return new SemanticError(LocalizedStrings.getError("incompatible_types_array_full", context));
+      return createSemanticError("incompatible_types_array_full", context);
     } else {
       return ProcessorErrorFactory.incompatible_types_array(exp, type, dim);
     }
   },
   incompatible_types_array: (exp, type, dim) => {
     const context = [exp, LocalizedStrings.translateType(type, dim)];
-    return new SemanticError(LocalizedStrings.getError("incompatible_types_array", context));
+    return createSemanticError("incompatible_types_array", context);
   },
   loop_condition_type_full: (exp, sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line, sourceInfo.column, exp];
-      return new SemanticError(LocalizedStrings.getError("loop_condition_type_full", context));
+      return createSemanticError("loop_condition_type_full", context);
     } else {
       return ProcessorErrorFactory.loop_condition_type(exp);
     }
   },
   loop_condition_type: (exp) => {
     const context = [exp];
-    return new SemanticError(LocalizedStrings.getError("loop_condition_type", context));
+    return createSemanticError("loop_condition_type", context);
   },
   endless_loop_full: (sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line];
-      return new SemanticError(LocalizedStrings.getError("endless_loop_full", context));
+      return createSemanticError("endless_loop_full", context);
     } else {
       return ProcessorErrorFactory.endless_loop();
     }
   },
   endless_loop: () => {
-    return new SemanticError(LocalizedStrings.getError("endless_loop"));
+    return createSemanticError("endless_loop");
   },
   for_condition_type_full: (exp, sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line, sourceInfo.column, exp];
-      return new SemanticError(LocalizedStrings.getError("for_condition_type_full", context));
+      return createSemanticError("for_condition_type_full", context);
     } else {
       return ProcessorErrorFactory.for_condition_type(exp);
     }
   },
   for_condition_type: (exp) => {
     const context = [exp];
-    return new SemanticError(LocalizedStrings.getError("for_condition_type", context));
+    return createSemanticError("for_condition_type", context);
   },
   if_condition_type_full: (exp, sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line, sourceInfo.column, exp];
-      return new SemanticError(LocalizedStrings.getError("if_condition_type_full", context));
+      return createSemanticError("if_condition_type_full", context);
     } else {
       return ProcessorErrorFactory.if_condition_type(exp);
     }
   },
   if_condition_type: (exp) => {
     const context = [exp];
-    return new SemanticError(LocalizedStrings.getError("if_condition_type", context));
+    return createSemanticError("if_condition_type", context);
   },
   invalid_global_var: () => {
-    return new RuntimeError(LocalizedStrings.getError("invalid_global_var"))
+    return createRuntimeError("invalid_global_var")
   },
   not_implemented: (id) => {
     const context  = [id]
-    return new RuntimeError(LocalizedStrings.getError("not_implemented", context))
+    return createRuntimeError("not_implemented", context)
   },
   invalid_case_type_full: (exp, type, dim, sourceInfo) => {
     if(sourceInfo) {
       const context = [exp, LocalizedStrings.translateType(type, dim), sourceInfo.line, sourceInfo.column];
-      return new SemanticError(LocalizedStrings.getError("invalid_case_type_full", context));
+      return createSemanticError("invalid_case_type_full", context);
     } else {
       return ProcessorErrorFactory.invalid_case_type(exp, type, dim);
     }
   },
   invalid_case_type: (exp, type, dim) => {
     const context = [exp, LocalizedStrings.translateType(type, dim)];
-    return new SemanticError(LocalizedStrings.getError("invalid_case_type", context));
+    return createSemanticError("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));
+      return createSemanticError("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));
+    return createSemanticError("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));
+      return createSemanticError("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));
+    return createSemanticError("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));
+      return createSemanticError("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));
+    return createSemanticError("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));
+      return createRuntimeError("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));
+    return createRuntimeError("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));
+      return createRuntimeError("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));
+    return createRuntimeError("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));
+      return createRuntimeError("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));
+    return createRuntimeError("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));
+      return createRuntimeError("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));
+    return createRuntimeError("vector_not_matrix", context);
   },
   function_no_return: (id) => {
     const context = [id];
-    return new SemanticError(LocalizedStrings.getError("function_no_return", context));
+    return createSemanticError("function_no_return", context);
   },
   invalid_void_return_full: (id, type, dim, sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line, id, LocalizedStrings.translateType(type, dim)];
-      return new SemanticError(LocalizedStrings.getError("invalid_void_return_full", context));
+      return createSemanticError("invalid_void_return_full", context);
     } else {
       return ProcessorErrorFactory.invalid_void_return(id, type, dim);
     }
   },
   invalid_void_return: (id, type, dim) => {
     const context = [id, LocalizedStrings.translateType(type, dim)];
-    return new SemanticError(LocalizedStrings.getError("invalid_void_return_full", context));
+    return createSemanticError("invalid_void_return_full", context);
   },
   invalid_return_type_full: (id, type, dim, sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line, id, LocalizedStrings.translateType(type, dim)];
-      return new SemanticError(LocalizedStrings.getError("invalid_return_type_full", context));
+      return createSemanticError("invalid_return_type_full", context);
     } else {
       return ProcessorErrorFactory.invalid_return_type(id, type, dim);
     }
   },
   invalid_return_type: (id, type, dim) => {
     const context = [id, LocalizedStrings.translateType(type, dim)];
-    return new SemanticError(LocalizedStrings.getError("invalid_return_type", context));
+    return createSemanticError("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));
+      return createSemanticError("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));
+    return createSemanticError("invalid_parameters_size", context);
   },
   invalid_parameter_type_full: (fun_name, exp, sourceInfo) => {
     if(sourceInfo) {
       const context = [exp, LanguageDefinedFunction.getLocalName(fun_name), sourceInfo.line];
-      return new SemanticError(LocalizedStrings.getError("invalid_parameter_type_full", context));
+      return createSemanticError("invalid_parameter_type_full", context);
     } else {
       return ProcessorErrorFactory.invalid_parameter_type(fun_name, exp);
     }
   },
   invalid_parameter_type: (fun_name, exp) => {
     const context = [exp, LanguageDefinedFunction.getLocalName(fun_name)];
-    return new SemanticError(LocalizedStrings.getError("invalid_parameter_type_full", context));
+    return createSemanticError("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));
+      return createSemanticError("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));
+    return createSemanticError("invalid_ref", context);
   },
   unexpected_break_command_full: (sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line];
-      return new RuntimeError(LocalizedStrings.getError("unexpected_break_command_full", context));
+      return createRuntimeError("unexpected_break_command_full", context);
     } else {
       return ProcessorErrorFactory.unexpected_break_command();
     }
   },
   unexpected_break_command: () => {
-    return new RuntimeError(LocalizedStrings.getError("unexpected_break_command"));
+    return createRuntimeError("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));
+      return createRuntimeError("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));
+    return createRuntimeError("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));
+      return createRuntimeError("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));
+    return createRuntimeError("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));
+      return createRuntimeError("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));
+    return createRuntimeError("invalid_array_literal_column", context);
   },
   invalid_unary_op_full: (expString, opName, type, dim, sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line, expString, LocalizedStrings.translateOp(opName), LocalizedStrings.translateType(type, dim)];
-      return new RuntimeError(LocalizedStrings.getError("invalid_unary_op_full", context));
+      return createRuntimeError("invalid_unary_op_full", context);
     } else {
       return ProcessorErrorFactory.invalid_unary_op(opName, type, dim);
     }
   },
   invalid_unary_op: (expString, opName, type, dim) => {
     const context = [expString, LocalizedStrings.translateOp(opName), LocalizedStrings.translateType(type, dim)];
-    return new RuntimeError(LocalizedStrings.getError("invalid_unary_op", context));
+    return createRuntimeError("invalid_unary_op", context);
   },
   invalid_infix_op_full: (expString, opName, typeLeft, dimLeft, typeRight, dimRight,  sourceInfo) => {
     if(sourceInfo) {
       const context = [sourceInfo.line, expString, LocalizedStrings.translateOp(opName), LocalizedStrings.translateType(typeLeft, dimLeft), LocalizedStrings.translateType(typeRight, dimRight)];
-      return new RuntimeError(LocalizedStrings.getError("invalid_infix_op_full", context));
+      return createRuntimeError("invalid_infix_op_full", context);
     } else {
       return ProcessorErrorFactory.invalid_infix_op(opName, typeLeft, dimLeft, typeRight, dimRight);
     }
   },
   invalid_infix_op: (expString, opName, typeLeft, dimLeft, typeRight, dimRight) => {
     const context = [expString, LocalizedStrings.translateOp(opName), LocalizedStrings.translateType(typeLeft, dimLeft), LocalizedStrings.translateType(typeRight, dimRight)];
-    return new RuntimeError(LocalizedStrings.getError("invalid_infix_op", context));
+    return createRuntimeError("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));
+      return createSemanticError("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"));
+    return createSemanticError("array_dimension_not_positive");
   },
   invalid_type_conversion: (value, type, dim) => {
     const context = [value, LocalizedStrings.translateType(type, dim)];
-    return new RuntimeError(LocalizedStrings.getError("invalid_type_conversion", context));
+    return createRuntimeError("invalid_type_conversion", context);
   },
-  invalid_read_type: (exp, type, dim, name) => {
-    const context = [exp, LocalizedStrings.translateType(type, dim), name];
-    return new RuntimeError(LocalizedStrings.getError("invalid_read_type", context))
+  invalid_read_type: (exp, type, dim, name, source_info) => {
+    const context = [source_info.line, exp, LocalizedStrings.translateType(type, dim), name];
+    return createRuntimeError("invalid_read_type", context)
   },
-  invalid_read_type_array: (exp, typePos, dimPos, name, typeArray, dimArray) => {
-    const context = [exp, LocalizedStrings.translateType(typePos, dimPos), name,LocalizedStrings.translateType(typeArray, dimArray)];
-    return new RuntimeError(LocalizedStrings.getError("invalid_read_type_array", context))
+  invalid_read_type_array: (exp, typePos, dimPos, name, typeArray, dimArray, sourceInfo) => {
+    const context = [sourceInfo.line, exp, LocalizedStrings.translateType(typePos, dimPos), name,LocalizedStrings.translateType(typeArray, dimArray)];
+    return createRuntimeError("invalid_read_type_array", context)
   },
   invalid_const_ref_full: (fun_name, exp, sourceInfo)=> {
     if(sourceInfo) {
       const context = [exp, LanguageDefinedFunction.getLocalName(fun_name), sourceInfo.line];
-      return new SemanticError(LocalizedStrings.getError("invalid_const_ref_full", context));
+      return createSemanticError("invalid_const_ref_full", context);
     } else {
       return ProcessorErrorFactory.invalid_const_ref(fun_name, exp);
     }
   },
   invalid_const_ref: (fun_name, exp) => {
     const context = [exp, LanguageDefinedFunction.getLocalName(fun_name)];
-    return new SemanticError(LocalizedStrings.getError("invalid_const_ref", context));
+    return createSemanticError("invalid_const_ref", context);
   },
   invalid_const_assignment_full: (var_id, source_info) => {
     if(source_info) {
       const context = [source_info.line, var_id];
-      return new SemanticError(LocalizedStrings.getError("invalid_const_assignment_full", context));
+      return createSemanticError("invalid_const_assignment_full", context);
     } else {
       return ProcessorErrorFactory.invalid_const_assignment(var_id);
     }
   },
   invalid_const_assignment: (var_id) => {
     const context = [var_id];
-    return new SemanticError(LocalizedStrings.getError("invalid_const_assignment", context));
+    return createSemanticError("invalid_const_assignment", context);
+  },
+  invalid_vector_assignment_full: (left_id, left_size, right_id, right_size, source_info) => {
+    if(source_info)  {
+      const context = [source_info.line, left_id, left_size, right_id, right_size]
+      return createRuntimeError("invalid_vector_assignment_full", context);
+    } else {
+      return ProcessorErrorFactory.invalid_vector_assignment(left_id, left_size, right_id, right_size);
+    }
+  },
+  invalid_vector_assignment: (left_id, left_size, right_id, right_size) => {
+    const context = [left_id, left_size, right_id, right_size]
+    return createRuntimeError("invalid_vector_assignment", context);
+  },
+  invalid_matrix_assignment_full: (left_id, left_line, left_column, right_id, right_line, right_column, source_info) => {
+    if(source_info)  {
+      const context = [source_info.line, left_id, left_line, left_column, right_id, right_line, right_column]
+      return createRuntimeError("invalid_matrix_assignment_full", context);
+    } else {
+      return ProcessorErrorFactory.invalid_matrix_assignment(left_id, left_line, left_column, right_id, right_line, right_column);
+    }
+  },
+  invalid_matrix_assignment: (left_id, left_line, left_column, right_id, right_line, right_column) => {
+    const context = [left_id, left_line, left_column, right_id, right_line, right_column]
+    return createRuntimeError("invalid_matrix_assignment", context);
+  },
+  matrix_to_vector_attr: (left_id, right_id, source_info) => {
+    // SourceInfo have to be valid...
+    const context = [source_info.line, right_id, left_id];
+    return createSemanticError("matrix_to_vector_attr", context);
+  },
+  vector_to_matrix_attr: (left_id, right_id, source_info) => {
+    // SourceInfo have to be valid...
+    const context = [source_info.line, right_id, left_id];
+    return createSemanticError("vector_to_matrix_attr", context);
+  },
+  invalid_matrix_index_assign_full: (mat_id, mat_line, mat_size, exp, exp_size, source_info) => {
+    if(source_info){
+      const context = [source_info.line, mat_line, mat_id, mat_size, exp, exp_size];
+      return createRuntimeError("invalid_matrix_index_assign_full", context);
+    } else {
+      return ProcessorErrorFactory.invalid_matrix_index_assign(mat_id, mat_line, mat_size, exp, exp_size)
+    }
+  },
+  invalid_matrix_index_assign: (mat_id, mat_line, mat_size, exp, exp_size) =>{
+    const context = [mat_line, mat_id, mat_size, exp, exp_size];
+    return createRuntimeError("invalid_matrix_index_assign", context);
+  },
+  invalid_number_elements_vector: (expected_num, exp, actual_num, source_info) => {
+    // SourceInfo have to be valid...
+    const context = [expected_num, source_info.line, exp, actual_num];
+    return createRuntimeError("invalid_number_elements_vector", context);
+  },
+  invalid_number_lines_matrix: (expected_num, exp, actual_num, source_info) => {
+    // SourceInfo have to be valid...
+    const context = [expected_num, source_info.line, exp, actual_num];
+    return createRuntimeError("invalid_number_lines_matrix", context);
+  },
+  divsion_by_zero_full: (exp, source_info) => {
+    if(source_info) {
+      const context = [source_info.line, exp];
+      return createRuntimeError("divsion_by_zero_full", context);
+    } else {
+      return ProcessorErrorFactory.divsion_by_zero(exp);
+    }
+  },
+  divsion_by_zero: (exp) => {
+    const context = [exp];
+    return createRuntimeError("divsion_by_zero", context);
+  },
+  undefined_tanget_value: (value, source_info) => {
+    const context = [source_info.line, value];
+    return createRuntimeError("undefined_tanget_value", context);
+  },
+  negative_log_value: (source_info) => {
+    return createRuntimeError("negative_log_value",[source_info.line]);
+  },
+  invalid_string_index: (index, str, source_info) => {
+    const local_fun_name = LanguageDefinedFunction.getLocalName("$charAt");
+    const context = [source_info.line, local_fun_name, index, str, str.length - 1];
+    return createRuntimeError("invalid_string_index", context);
+  },
+  negative_sqrt_value: (source_info) => {
+    return createRuntimeError("negative_sqrt_value",[source_info.line]);
+  },
+  exceeded_recursive_calls: (source_info) => {
+    const context = [source_info.line];
+    return createRuntimeError("exceeded_recursive_calls", context);
   }
 });

+ 58 - 30
js/processor/ivprogProcessor.js

@@ -42,6 +42,10 @@ export class IVProgProcessor {
     this.forceKill = false;
     this.loopTimers = [];
     this.output = null;
+    /**
+     * Stores the sourceInfo of every function call, command or expression
+     */
+    this.function_call_stack = [];
   }
 
   registerInput (input) {
@@ -90,7 +94,7 @@ export class IVProgProcessor {
     return this.initGlobal().then( _ => {
       const mainFunc = this.findMainFunction();
       if(mainFunc === null) {
-        throw ProcessorErrorFactory.main_missing();
+        return Promise.reject(ProcessorErrorFactory.main_missing())
       }
       return this.runFunction(mainFunc, [], this.globalStore);
     });
@@ -98,7 +102,7 @@ export class IVProgProcessor {
 
   initGlobal () {
     if(!this.checkContext(Context.BASE)) {
-      throw ProcessorErrorFactory.invalid_global_var();
+      return Promise.reject(ProcessorErrorFactory.invalid_global_var())
     }
     return this.executeCommands(this.globalStore, this.ast.global);
   }
@@ -145,7 +149,7 @@ export class IVProgProcessor {
       LanguageDefinedFunction.getMainFunctionName() : callee_store.name;
 
     if (formal_params.length != effective_params.length) {
-      throw ProcessorErrorFactory.invalid_parameters_size(funcName, formal_params.length, effective_params.length);
+      return Promise.reject(ProcessorErrorFactory.invalid_parameters_size(funcName, formal_params.length, effective_params.length))
     }
     const promises$ = effective_params.map(actual_param => this.evaluateExpression(caller_store, actual_param));
     return Promise.all(promises$).then(values => {
@@ -161,12 +165,12 @@ export class IVProgProcessor {
             && Store.canImplicitTypeCast(formalParameter.type, sto_value.type)) {
               shouldTypeCast =  true;
           } else {
-            throw ProcessorErrorFactory.invalid_parameter_type(funcName, exp.toString());
+            return Promise.reject(ProcessorErrorFactory.invalid_parameter_type(funcName, exp.toString()))
           }
         }
 
         if(formalParameter.byRef && !sto_value.inStore()) {
-          throw ProcessorErrorFactory.invalid_ref(funcName, exp.toString());
+          return Promise.reject(ProcessorErrorFactory.invalid_ref(funcName, exp.toString()))
         }
 
         if(formalParameter.byRef) {
@@ -247,7 +251,7 @@ export class IVProgProcessor {
     } else if (cmd instanceof Commands.SysCall) {
       return this.executeSysCall(store, cmd);
     } else {
-      throw ProcessorErrorFactory.unknown_command(cmd.sourceInfo);
+      return Promise.reject(ProcessorErrorFactory.unknown_command(cmd.sourceInfo))
     }
   }
 
@@ -263,6 +267,10 @@ export class IVProgProcessor {
     } else {
       func = this.findFunction(cmd.id);
     }
+    if(this.function_call_stack.length >= Config.max_call_stack) {
+      return Promise.reject(ProcessorErrorFactory.exceeded_recursive_calls(cmd.sourceInfo));
+    }
+    this.function_call_stack.push(cmd.sourceInfo);
     return this.runFunction(func, cmd.actualParameters, store)
       .then(sto => {
         sto.destroy();
@@ -271,6 +279,7 @@ export class IVProgProcessor {
             LanguageDefinedFunction.getMainFunctionName() : func.name;
           return Promise.reject(ProcessorErrorFactory.function_no_return(funcName));
         } else {
+          this.function_call_stack.pop();
           return store;
         }
       });
@@ -479,7 +488,7 @@ export class IVProgProcessor {
     try {
       const inStore = store.applyStore(cmd.id);
       if(inStore.isConst) {
-        throw ProcessorErrorFactory.invalid_const_assignment_full(cmd.id, cmd.sourceInfo);
+        return Promise.reject(ProcessorErrorFactory.invalid_const_assignment_full(cmd.id, cmd.sourceInfo))
       }
       const $value = this.evaluateExpression(store, cmd.expression);
       return $value.then( vl => {
@@ -490,15 +499,22 @@ export class IVProgProcessor {
           } else {
             const stringInfo = inStore.type.stringInfo()
             const info = stringInfo[0]
-            return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo));
+            const exp_type_string_info = vl.type.stringInfo();
+            const exp_type_info = exp_type_string_info[0];
+            const exp = cmd.expression.toString();
+            return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type, exp_type_info.dim,  exp, cmd.sourceInfo));
           }
         }
 
         if(inStore instanceof ArrayStoreValue) {
           const columns = realValue.columns == null ? 0 : realValue.columns;
           if(inStore.lines !== realValue.lines || inStore.columns !== columns){
-            // TODO better error message
-            throw new Error("exp exceeds the number of elements of the vector");
+            const exp = cmd.expression.toString();
+            if(inStore.isVector()) {
+              return Promise.reject(ProcessorErrorFactory.invalid_vector_assignment_full(cmd.id, inStore.lines, exp, realValue.lines, cmd.sourceInfo));
+            } else {
+              return Promise.reject(ProcessorErrorFactory.invalid_matrix_assignment_full(cmd.id, inStore.lines, inStore.columns, exp, realValue.lines, realValue.columns, cmd.sourceInfo));
+            }            
           }
         }
         
@@ -514,7 +530,7 @@ export class IVProgProcessor {
     const mustBeArray = store.applyStore(cmd.id);
     let used_dims = 0;
     if(mustBeArray.isConst) {
-      throw ProcessorErrorFactory.invalid_const_assignment_full(cmd.id, cmd.sourceInfo);
+      return Promise.reject(ProcessorErrorFactory.invalid_const_assignment_full(cmd.id, cmd.sourceInfo))
     }
     if(!(mustBeArray.type instanceof ArrayType)) {
       return Promise.reject(ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo));
@@ -544,7 +560,7 @@ export class IVProgProcessor {
           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);
+        return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo))
       }
       if (column != null && mustBeArray.columns === 0 ){
         return Promise.reject(ProcessorErrorFactory.vector_not_matrix_full(cmd.id, cmd.sourceInfo));
@@ -553,7 +569,7 @@ export class IVProgProcessor {
         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);
+          return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo))
         }
       }
 
@@ -562,24 +578,25 @@ export class IVProgProcessor {
           const type = mustBeArray.type.innerType;
           const stringInfo = type.stringInfo();
           const info = stringInfo[0];
-          // const exp = cmd.expression.toString();
-          return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo));
+          const exp_type_string_info = value.type.stringInfo();
+          const exp_type_info = exp_type_string_info[0];
+          const exp = cmd.expression.toString();
+          return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type, exp_type_info.dim,  exp, cmd.sourceInfo));
         }
         actualValue = Store.doImplicitCasting(mustBeArray.type.innerType, value);
       }
 
       const current_value = mustBeArray.getAt(line, column);
-      console.log(current_value);
       if(current_value instanceof ArrayStoreValue) {
         if(current_value.lines !== actualValue.lines || current_value.columns !== actualValue.columns){
-          // TODO better error message
-          throw new Error("exp exceeds the number of elements of the vector");
+          const exp = cmd.expression.toString();
+          return Promise.reject(ProcessorErrorFactory.invalid_matrix_index_assign_full(cmd.id, line, current_value.lines, exp, actualValue.lines, cmd.sourceInfo))
         }
       }
 
       // mustBeArray.setAt(actualValue, line, column);
       // store.updateStore(cmd.id, mustBeArray);
-      return store.updateStoreArray(cmd.id,actualValue, line, column);
+      return store.updateStoreArray(cmd.id, actualValue, line, column);
     });
   }
 
@@ -607,7 +624,10 @@ export class IVProgProcessor {
               } else {
                 const stringInfo = vl.type.stringInfo();
                 const info = stringInfo[0];
-                return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo));
+                const exp_type_string_info = vl.type.stringInfo();
+                const exp_type_info = exp_type_string_info[0];
+                const exp = cmd.expression.toString();
+                return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type, exp_type_info.dim,  exp, cmd.sourceInfo));
               }
             }
             temp = new StoreValue(cmd.type, realValue.get(), null, cmd.isConst);
@@ -637,7 +657,7 @@ export class IVProgProcessor {
       }
       const line = line_sv.get().toNumber();
       if(line < 0) {
-        throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
+        return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo));
       }
       let column = null
       if (column_sv !== null) {
@@ -646,7 +666,7 @@ export class IVProgProcessor {
         }
         column = column_sv.get().toNumber();
         if(column < 0) {
-          throw ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo);
+          return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(cmd.sourceInfo));
         }
       }
       let $value = Promise.resolve(null);
@@ -700,13 +720,18 @@ export class IVProgProcessor {
     if(Types.VOID.isCompatible(func.returnType)) {
       return Promise.reject(ProcessorErrorFactory.void_in_expression_full(exp.id, exp.sourceInfo));
     }
+    if(this.function_call_stack.length >= Config.max_call_stack) {
+      return Promise.reject(ProcessorErrorFactory.exceeded_recursive_calls(exp.sourceInfo));
+    }
+    this.function_call_stack.push(exp.sourceInfo);
     const $newStore = this.runFunction(func, exp.actualParameters, store);
     return $newStore.then( sto => {
       if(sto.mode !== Modes.RETURN) {
-        return Promise.reject(new Error("The function that was called did not have a return command: "+exp.id));
+        return Promise.reject(new Error("!!!Internal error: the function that was called did not have a return command or did not set the store mode properly -> "+exp.id));
       }
       const val = sto.applyStore('$');
       sto.destroy();
+      this.function_call_stack.pop();
       return Promise.resolve(val);
     });
   }
@@ -720,7 +745,7 @@ export class IVProgProcessor {
   evaluateArrayLiteral (store, exp, type, lines, columns) {
     if(!exp.isVector) {
       if(columns == null) {
-        throw new Error("Vector cannot be initialized by a matrix");
+        return Promise.reject(new Error("This should never happen: Vector cannot be initialized by a matrix"));
       }
       const $matrix = this.evaluateMatrix(store, exp, type, lines, columns);
       return Promise.all($matrix).then(vectorList => {
@@ -729,7 +754,7 @@ export class IVProgProcessor {
       });
     } else {
       if(columns != null) {
-        throw new Error("Matrix cannot be initialized by a vector");
+        return Promise.reject(new Error("This should never happen: Matrix cannot be initialized by a vector"));
       }
       return this.evaluateVector(store, exp, type, lines).then(list => {
         return Promise.resolve(list);
@@ -748,7 +773,7 @@ export class IVProgProcessor {
   evaluateVector (store, exps, type, n_elements) {
     const values =  exps.value;
     if(n_elements !== values.length) {
-      throw new Error("invalid number of elements to array literal...");
+      return Promise.reject(ProcessorErrorFactory.invalid_number_elements_vector(n_elements, exps.toString(), values.length, exps.sourceInfo));
     }
     const actual_values = Promise.all(values.map( exp => this.evaluateExpression(store, exp)));
     return actual_values.then( values => {
@@ -759,7 +784,7 @@ export class IVProgProcessor {
             // const info = stringInfo[0];
             const exp_str = values[index].toString();
             // TODO - fix error message
-            throw ProcessorErrorFactory.invalid_array_literal_type_full(exp_str, values[index].sourceInfo);
+            return Promise.reject(ProcessorErrorFactory.invalid_array_literal_type_full(exp_str, values[index].sourceInfo));
           }
           const new_value = Store.doImplicitCasting(type.innerType, v);
           return new_value;
@@ -779,7 +804,7 @@ export class IVProgProcessor {
   evaluateMatrix (store, exps, type, lines, columns) {
     const values = exps.value;
     if(values.length !== lines) {
-      throw new Error("Invalid number of lines to matrix literal...");
+      return Promise.reject(ProcessorErrorFactory.invalid_number_lines_matrix(lines,exps.toString(),values.length, exps.sourceInfo));
     }
     return values.map( vector => {
       const vec_type = new ArrayType(type.innerType, 1);
@@ -827,7 +852,7 @@ export class IVProgProcessor {
           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);
+        return Promise.reject(ProcessorErrorFactory.array_dimension_not_positive_full(exp.sourceInfo));
       }
       if (column !== null && mustBeArray.columns === 0 ){
         return Promise.reject(ProcessorErrorFactory.vector_not_matrix_full(exp.id, exp.sourceInfo));
@@ -836,7 +861,7 @@ export class IVProgProcessor {
         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.reject(ProcessorErrorFactory.array_dimension_not_positive_full(exp.sourceInfo));
         }
       }
       const result = mustBeArray.getAt(line, column);
@@ -915,6 +940,9 @@ export class IVProgProcessor {
           return new StoreValue(resultType, result);
         }
         case Operators.DIV.ord: {
+          if(right.get() == 0) {
+            return Promise.reject(ProcessorErrorFactory.divsion_by_zero_full(infixApp.toString(), infixApp.sourceInfo));
+          }
           if (Types.INTEGER.isCompatible(resultType))
             result = left.get().divToInt(right.get());
           else

+ 2 - 3
js/processor/lib/io.js

@@ -47,14 +47,13 @@ export function createInputFun () {
       } catch (_) {
         const stringInfo = typeToConvert.stringInfo()[0]
         const realObject = store.getStoreObject("p1");
-        console.log(realObject);
         if (realObject.getReferenceDimension() > 0) {
           const arrayInfo = realObject.type.stringInfo()[0];
           const dim = realObject.getReferenceDimension();
-          const error = ProcessorErrorFactory.invalid_read_type_array(text, stringInfo.type, stringInfo.dim, realObject.getRefObj(), arrayInfo.type, dim);
+          const error = ProcessorErrorFactory.invalid_read_type_array(text, stringInfo.type, stringInfo.dim, realObject.getRefObj(), arrayInfo.type, dim, this.function_call_stack.pop());
           return Promise.reject(error);
         }
-        const error = ProcessorErrorFactory.invalid_read_type(text, stringInfo.type, stringInfo.dim, realObject.getRefObj());
+        const error = ProcessorErrorFactory.invalid_read_type(text, stringInfo.type, stringInfo.dim, realObject.getRefObj(), this.function_call_stack.pop());
         return Promise.reject(error);
       }
       this.loopTimers.splice(0, this.loopTimers.length)

+ 9 - 7
js/processor/lib/math.js

@@ -6,6 +6,7 @@ import { MultiType } from '../../typeSystem/multiType';
 import { ArrayType } from '../../typeSystem/array_type';
 import { Modes } from '../modes';
 import { StoreValue } from '../store/value/store_value';
+import { ProcessorErrorFactory } from '../error/processorErrorFactory';
 
 /**
  * sin
@@ -79,12 +80,11 @@ export function createCosFun () {
 }
 
 export function createTanFun () {
-  const tanFun = (sto, _) => {
+  const tanFun = function (sto, _) {
     const x = sto.applyStore('x');
     const angle = x.get().mod(360);
     if(angle.eq(90) || angle.eq(270)) {
-      // TODO better error message
-      return Promise.reject("Tangent of "+x.get().toNumber()+"° is undefined.");
+      return Promise.reject(ProcessorErrorFactory.undefined_tanget_value(x.get().toNumber(), this.function_call_stack.pop()));
     }
     const result = Decimal.tan(convertToRadians(angle));
     const temp = new StoreValue(Types.REAL, result);
@@ -101,8 +101,11 @@ export function createTanFun () {
 }
 
 export function createSqrtFun () {
-  const sqrtFun = (sto, _) => {
+  const sqrtFun = function (sto, _) {
     const x = sto.applyStore('x');
+    if(x.get().isNeg()) {
+      return Promise.reject(ProcessorErrorFactory.negative_sqrt_value(this.function_call_stack.pop()));
+    }
     const result = x.get().sqrt();
     const temp = new StoreValue(Types.REAL, result);
     sto.insertStore("$", temp);
@@ -137,11 +140,10 @@ export function createPowFun () {
 }
 
 export function createLogFun () {
-  const logFun = (sto, _) => {
+  const logFun = function (sto, _) {
     const x = sto.applyStore('x');
     if (x.get().isNegative()) {
-      // TODO better error message
-      return Promise.reject(new Error("the value passed to log function cannot be negative"));
+      return Promise.reject(ProcessorErrorFactory.negative_log_value(this.function_call_stack.pop()));
     }
     const result = Decimal.log10(x.get());
     const temp = new StoreValue(Types.REAL, result);

+ 3 - 3
js/processor/lib/strings.js

@@ -3,6 +3,7 @@ import { Types } from './../../typeSystem/types';
 import { toInt } from "./../../typeSystem/parsers";
 import { Modes } from '../modes';
 import { StoreValue } from '../store/value/store_value';
+import { ProcessorErrorFactory } from '../error/processorErrorFactory';
 
 /*
 *  substring
@@ -79,12 +80,11 @@ export function createLowercaseFun () {
 }
 
 export function createrCharAtFun () {
-  const charAtFun = (sto, _) => {
+  const charAtFun = function (sto, _) {
     const str = sto.applyStore("str");
     const idx = sto.applyStore("index");
     if (idx.get().toNumber() < 0 || idx.get().toNumber() >= str.get().length) {
-      // TODO better error message
-      return Promise.reject(new Error("invalid string position"));
+      return Promise.reject(ProcessorErrorFactory.invalid_string_index(idx.get().toNumber(), str.get(), this.function_call_stack.pop()));
     }
     const temp = new StoreValue(Types.STRING, str.get().charAt(idx.get().toNumber()));
     sto.insertStore("$", temp);

+ 38 - 16
js/processor/semantic/semanticAnalyser.js

@@ -48,14 +48,14 @@ export class SemanticAnalyser {
     this.symbolMap.map[id] = typeInfo;
   }
 
-  findSymbol (id, symMap) {
-    if(!symMap.map[id]) {
-      if(symMap.next) {
-        return this.findSymbol(id, symMap.next);
+  findSymbol (id, symbol_map) {
+    if(!symbol_map.map[id]) {
+      if(symbol_map.next) {
+        return this.findSymbol(id, symbol_map.next);
       }
       return null;
     } else {
-      return symMap.map[id];
+      return symbol_map.map[id];
     }
   }
 
@@ -117,7 +117,10 @@ export class SemanticAnalyser {
         if(!resultType.isCompatible(declaration.type)) {
           const stringInfo = declaration.type.stringInfo();
           const info = stringInfo[0];
-          throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, declaration.sourceInfo);
+          const result_string_info = resultType.stringInfo();
+          const result_info = result_string_info[0];
+          const exp = declaration.initial;
+          throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, result_info.type, result_info.dim,  exp.toString(), declaration.sourceInfo);
         }
         this.insertSymbol(declaration.id, {id: declaration.id, type: declaration.type, isConst: declaration.isConst})
       } else if((!declaration.type.isCompatible(resultType) && !Config.enable_type_casting)
@@ -125,7 +128,10 @@ export class SemanticAnalyser {
         && !Store.canImplicitTypeCast(declaration.type, resultType))) {
         const stringInfo = declaration.type.stringInfo();
         const info = stringInfo[0];
-        throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, declaration.sourceInfo);
+        const result_string_info = resultType.stringInfo();
+        const result_info = result_string_info[0];
+        const exp = declaration.initial;
+        throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, result_info.type, result_info.dim,  exp.toString(), declaration.sourceInfo);
       } else {
         this.insertSymbol(declaration.id, {id: declaration.id, type: declaration.type, isConst: declaration.isConst});
       }
@@ -246,7 +252,7 @@ export class SemanticAnalyser {
       }
       return typeInfo.type;
     } else {
-      console.warn("Evaluating type only for an array literal...");
+      // console.warn("Evaluating type only for an array literal...");
       let last = null;
       if(literal.value.length === 1) {
         last = this.evaluateExpressionType(literal.value[0]);
@@ -401,7 +407,11 @@ export class SemanticAnalyser {
       }
       if(!compatible) {
         if(!Config.enable_type_casting || !Store.canImplicitTypeCast(access_type, exp_type)) {
-          throw new Error("invalid vector element type");
+          const access_type_string_info = access_type.stringInfo();
+          const access_type_info = access_type_string_info[0];
+          const exp_type_string_info = exp_type.stringInfo();
+          const exp_type_info = exp_type_string_info[0];
+          throw ProcessorErrorFactory.incompatible_types_full(access_type_info.type, access_type_info.dim - used_dims, exp_type_info.type, exp_type_info.dim, exp.toString(), cmd.sourceInfo);
         }
       }
       return optional;
@@ -428,18 +438,28 @@ export class SemanticAnalyser {
             if(!Config.enable_type_casting || !Store.canImplicitTypeCast(typeInfo.type.innerType, exp_type.innerType)) {
               const stringInfo = typeInfo.type.stringInfo();
               const info = stringInfo[0];
-              throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo);
+              const exp_type_string_info = exp_type.stringInfo();
+              const exp_type_info = exp_type_string_info[0];
+              throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type, exp_type_info.dim,  exp.toString(), cmd.sourceInfo);
             }
           } else {
-            // TODO better error message
-            throw new Error("Cannot assign a vector to matrix or matrix to vector");
+            switch(exp_type.dimensions) {
+              case 1: {
+                throw ProcessorErrorFactory.vector_to_matrix_attr(cmd.id, exp.toString(),cmd.sourceInfo);
+              }
+              case 2: {
+                throw ProcessorErrorFactory.matrix_to_vector_attr(cmd.id, exp.toString(),cmd.sourceInfo);
+              }
+            }
           }
         }
       } else if(!exp_type.isCompatible(typeInfo.type)) {
         if(!Config.enable_type_casting || !Store.canImplicitTypeCast(typeInfo.type, exp_type)) {
           const stringInfo = typeInfo.type.stringInfo();
           const info = stringInfo[0];
-          throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo);
+          const exp_type_string_info = exp_type.stringInfo();
+          const exp_type_info = exp_type_string_info[0];
+          throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, exp_type_info.type, exp_type_info.dim,  exp.toString(), cmd.sourceInfo);
         }
       }
       return optional;
@@ -569,10 +589,12 @@ export class SemanticAnalyser {
         compatible = type.canAccept(expType, 1);
       }
       if(!compatible) {
-        // vector wrong type
-        // TODO better error message
         if(!Config.enable_type_casting || !Store.canImplicitTypeCast(type.innerType, expType)) {
-          throw new Error("invalid vector element type");
+          const stringInfo = type.stringInfo();
+          const info = stringInfo[0];
+          const result_string_info = expType.stringInfo();
+          const result_info = result_string_info[0];
+          throw ProcessorErrorFactory.incompatible_types_full(info.type, 0, result_info.type, result_info.dim,  exp.toString(), literal.sourceInfo);
         }
       }
     }

+ 1 - 1
js/services/localizedStringsService.js

@@ -16,7 +16,7 @@ class IVProgLocalizedStrings extends line_i18n.LocalizedStrings {
       case 0:
         return type_string;
       default:
-        if(dim === 1)
+        if(dim > 1)
           return this.getUI("matrix_info_string", [type_string])
         else
           return this.getUI("vector_info_string", [type_string])

+ 3 - 2
js/util/config.js

@@ -7,15 +7,16 @@ class ConfigObject {
     this.default_lang = 'pt';
     this.enable_type_casting = true;
     this.idle_input_interval = 5000;
+    this.max_call_stack = 100;
   }
 
   setConfig (opts) {
     for (const key in opts) {
-      if(this.hasOwnProperty(key)){
+      if(Object.prototype.hasOwnProperty.call(this, key)){
         this[key] = opts[key];
       }
     }
   }
 }
-let config = new ConfigObject();
+const config = new ConfigObject();
 export const Config = config;

+ 20 - 0
js/util/either.ts

@@ -0,0 +1,20 @@
+type Left<T> = { tag: "left", value: T };
+type Right<T> = { tag: "right", value: T };
+export type Either<L, R> = Left<L> | Right<R>;
+
+export function left<T> (value: T): Left<T> {
+  return {tag: "left", value: value}
+}
+
+export function right<T> (value: T): Right<T> {
+  return {tag: "right", value: value}
+}
+
+export function match<T, L, R> (input: Either<L, R>, left: (l: L) => T, right: (right: R) => T) {
+  switch(input.tag) {
+    case "left":
+      return left(input.value);
+    case "right":
+      return right(input.value);
+  }
+}