瀏覽代碼

Implement all semantic error messages

Lucas de Souza 5 年之前
父節點
當前提交
d8189f446e
共有 3 個文件被更改,包括 207 次插入31 次删除
  1. 24 7
      i18n/pt/error.json
  2. 148 0
      js/processor/error/processorErrorFactory.js
  3. 35 24
      js/processor/semantic/semanticAnalyser.js

+ 24 - 7
i18n/pt/error.json

@@ -18,9 +18,12 @@
   "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",
   "function_missing_full": "A função $0 na linha: $1, coluna: $2 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",
+  "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": "Erro interno crítico: Comando desconhecido ($0) 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",
@@ -28,14 +31,27 @@
   "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 $2",
+  "invalid_return_type_full": "Erro na linha $0: a expressão não produz um tipo compatível com o retorno de tipo $1.",
+  "invalid_return_type": "A expressão não produz um tipo compatível com o retorno de tipo $0.",
+  "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": "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_full": "Erro na linha: $0, coluna: $1: a função $2 não pode ser utilizada aqui pois seu tipo de retorno é vazio",
   "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",
+  "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 é invá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_column_outbounds_full": "Erro na linha $0: número de colunas $1 é inválido para a matriz $2 que possui $3 colunas",
+  "vector_column_outbounds": "Número de colunas $0 é inválido para a matriz $1 que possui $2 colunas",
+  "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",
   "invalid_infix_op": "Não é possível aplicar a operação $0 entre os tipos $1 e $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",
@@ -51,5 +67,6 @@
   "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."
+  "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."
 }

+ 148 - 0
js/processor/error/processorErrorFactory.js

@@ -126,5 +126,153 @@ export const ProcessorErrorFactory  = Object.freeze({
   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 SemanticError(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 SemanticError(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 SemanticError(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 SemanticError(LocalizedStrings.getError("matrix_line_outbounds", context));
+  },
+  vector_column_outbounds_full: (id, value, columns, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, value, id, columns];
+      return new SemanticError(LocalizedStrings.getError("vector_column_outbounds_full", context));
+    } else {
+      return ProcessorErrorFactory.vector_column_outbounds(id, value, columns);
+    }
+  },
+  vector_column_outbounds: (id, value, columns) => {
+    const context = [value, id, columns];
+    return new SemanticError(LocalizedStrings.getError("vector_column_outbounds", context));
+  },
+  vector_line_outbounds_full: (id, value, lines, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, value, id, lines];
+      return new SemanticError(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 SemanticError(LocalizedStrings.getError("vector_line_outbounds", 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, value, count, sourceInfo) => {
+    if(sourceInfo) {
+      const context = [sourceInfo.line, id, value, count];
+      return new SemanticError(LocalizedStrings.getError("invalid_parameters_size_full", context));
+    } else {
+      return ProcessorErrorFactory.invalid_parameters_size(id, value, count);
+    }
+  },
+  invalid_parameters_size: (id, value, count) => {
+    const context = [id, value, count];
+    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));
   }
 });

+ 35 - 24
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';
@@ -107,7 +107,7 @@ export class SemanticAnalyser {
         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 {
@@ -147,14 +147,14 @@ export class SemanticAnalyser {
       return this.evaluateLiteralType(expression);
     } else if (expression instanceof FunctionCall) {
       if (expression.isMainCall) {
-        throw new Error("void return used in expression");
+        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 used in expression");
+        throw ProcessorErrorFactory.void_in_expression_full(expression.id, expression.sourceInfo);
       }
       this.assertParameters(fun, expression.actualParameters);
       return fun.returnType;
@@ -164,7 +164,7 @@ export class SemanticAnalyser {
         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)) {
@@ -172,7 +172,7 @@ export class SemanticAnalyser {
       }
       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)) {
@@ -235,7 +235,7 @@ 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...
@@ -244,12 +244,16 @@ export class SemanticAnalyser {
           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(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)
+          }
         }
         literal.value.reduce((last, next) => {
           const eType = this.evaluateExpressionType(next);
           if (!last.canAccept(eType)) {
-            const strInfo = last.stringInfo();
+            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);
@@ -262,11 +266,15 @@ export class SemanticAnalyser {
         if (!dimType.isCompatible(Types.INTEGER)) {
           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(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);
+          }
         }
         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)
         }
       }
 
@@ -306,7 +314,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();
   }
@@ -361,7 +369,7 @@ export class SemanticAnalyser {
         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;
@@ -371,7 +379,7 @@ export class SemanticAnalyser {
       }
       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)) {
@@ -380,7 +388,7 @@ export class SemanticAnalyser {
       }
       // 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
       }
@@ -397,7 +405,7 @@ export class SemanticAnalyser {
           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)) {
@@ -434,12 +442,15 @@ export class SemanticAnalyser {
       return optional;
     } else if (cmd instanceof Return) {
       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(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(info.type, info.dim, cmd.sourceInfo);
         } else {
           return true;
         }
@@ -457,14 +468,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);
@@ -477,14 +488,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)) {
-        throw new Error(`Parameter ${formalParam.id} is not compatible with the value given.`);
+        throw ProcessorErrorFactory.invalid_parameter_type_full(id, param.toString(), param.sourceInfo);
       }
 
     }