Browse Source

Merge branch 'ast-parse-rework' of LInE/ivprog into master

Implement new array rules
Lucas de Souza 4 years ago
parent
commit
b76de75a0d

+ 8 - 1
i18n/pt/error.json

@@ -7,7 +7,7 @@
   "invalid_array_size": "O tamnho do vetor/matriz excede o máximo de 2 na linha $0",
   "extra_lines": "Nenhum texto é permitido após '}' em 'programa {...}'",
   "invalid_main_return": "A função $0 deve retornar $1 na linha $2",
-  "invalid_var_declaration": "Erro na linha $0. Variáveis só podem ser declarados no corpo principal da função e de preferência nas primeiras linhas.",
+  "invalid_var_declaration": "Erro na linha $0: variáveis só podem ser declaradas no corpo principal da função e nas primeiras linhas, antes de qualquer comando.",
   "invalid_break_command": "Erro na linha $0. O comando $1 não pode ser usado fora de uma estrutura de repetição ou 'escolha...caso'",
   "invalid_terminal": "Não é possível utilizar $0 na expressão da linha: $1, coluna: $2. Tente um valor númerico, variável ou chamada de função.",
   "const_not_init": "Erro na linha: $0, coluna: $1. Uma variável declarada como const deve ser inicializada",
@@ -96,6 +96,13 @@
   "inform_valid_function_duplicated" : "Já existe uma função com o nome <span class='ivprog-error-varname'>$0</span>, você precisa de nomes distintos.",
   "inform_valid_param_duplicated" : "Já existe um parâmetro 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.",
   "invalid_character": "O caractere $0 na linha $1 não pode ser utilizado neste contexto.",
+  "annonymous_array_literal": "Erro na linha $0: a notação de vetor/matriz só permitida durante a inicialização de uma variável desse tipo. Ex: inteiro vec[3] ← {1,2,3}.",
+  "invalid_matrix_literal_line": "A expressão $0 na linha $1 não possui um número de elementos igual a linha anterior. Todas as linhas de uma matriz devem ter a mesma quantidade de elementos.",
+  "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.",
   "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."
 }

js/ast/ivprogLexer.js → js/ast/ast_helpers.js


+ 48 - 16
js/ast/error/syntaxErrorFactory.js

@@ -3,11 +3,15 @@ import { SyntaxError } from './syntaxError';
 
 const LocalizedStrings = LocalizedStringsService.getInstance();
 
+function createError (message_id, context = []) {
+  return new SyntaxError(LocalizedStrings.getError(message_id, context));
+}
+
 export const SyntaxErrorFactory = Object.freeze({
   extra_lines: () => new SyntaxError(LocalizedStrings.getError("extra_lines")),
   token_missing_one: (expected, token) => {
     const context = [expected, token.text, token.line, token.column];
-    return new SyntaxError(LocalizedStrings.getError("token_missing_one", context));
+    return createError("token_missing_one", context);
   },
   token_missing_list: (expectedList, token) => {
     const line = expectedList.join(LocalizedStrings.getOR());
@@ -15,62 +19,90 @@ export const SyntaxErrorFactory = Object.freeze({
   },
   id_missing: (token) => {
     const context = [token.text, token.line, token.column];
-    return new SyntaxError(LocalizedStrings.getError("id_missing", context));
+    return createError("id_missing", context);
   },
   eos_missing: (token) => {
     const context = [token.line, token.column];
-    return new SyntaxError(LocalizedStrings.getError("eos_missing", context));
+    return createError("eos_missing", context);
   },
   invalid_array_dimension: (typeName, token) => {
     const context = [token.line, token.column, typeName];
-    return new SyntaxError(LocalizedStrings.getError("invalid_array_dimension", context));
+    return createError("invalid_array_dimension", context);
   },
   invalid_array_size: (token) => {
     const context = [token.line];
-    return new SyntaxError(LocalizedStrings.getError("invalid_array_size", context));
+    return createError("invalid_array_size", context);
   },
   invalid_main_return: (name, typeName, token) => {
     const context = [name, typeName, token.line];
-    return new SyntaxError(LocalizedStrings.getError("invalid_main_return", context));
+    return createError("invalid_main_return", context);
   },
   invalid_var_declaration: (token) => {
     const context = [token.line];
-    return new SyntaxError(LocalizedStrings.getError("invalid_var_declaration", context));
+    return createError("invalid_var_declaration", context);
   },
   invalid_break_command: (cmdName, token) => {
     const context = [token.line, cmdName];
-    return new SyntaxError(LocalizedStrings.getError("invalid_break_command", context));
+    return createError("invalid_break_command", context);
   },
   invalid_terminal: (token) => {
     const context = [token.text, token.line, token.column];
-    return new SyntaxError(LocalizedStrings.getError('invalid_terminal', context));
+    return createError('invalid_terminal', context);
   },
   invalid_type: (list, token) => {
     const line = list.join(LocalizedStrings.getOR());
     const context = [token.text, token.line, token.column, line]
-    return new SyntaxError(LocalizedStrings.getError("invalid_type", context));
+    return createError("invalid_type", context);
   },
   const_not_init: (token) => {
     const context = [token.line, token.column];
-    return new SyntaxError(LocalizedStrings.getError("const_not_init", context));
+    return createError("const_not_init", context);
   },
   invalid_id_format: (token) => {
     const context = [token.text, token.line, token.column];
-    return new SyntaxError(LocalizedStrings.getError("invalid_id_format", context));
+    return createError("invalid_id_format", context);
   },
   duplicate_function: (token) => {
     const context = [token.text, token.line, token.column];
-    return new SyntaxError(LocalizedStrings.getError("duplicate_function", context));
+    return createError("duplicate_function", context);
   },
   main_parameters: () => {
-    return new SyntaxError(LocalizedStrings.getError("main_parameters"));
+    return createError("main_parameters");
   },
   duplicate_variable: (token) => {
     const context = [token.text, token.line, token.column];
-    return new SyntaxError(LocalizedStrings.getError("duplicate_variable", context));
+    return createError("duplicate_variable", context);
   },
   invalid_character: (text, line, column) => {
     const context = [text, line];
-    return new SyntaxError(LocalizedStrings.getError("invalid_character", context));
+    return createError("invalid_character", context);
+  },
+  annonymous_array_literal: (token) => {
+    const context = [token.line];
+    return createError("annonymous_array_literal", context);
+  },
+  invalid_matrix_literal_line: (exp, sourceInfo) => {
+    const context = [exp, sourceInfo.line];
+    return createError("invalid_matrix_literal_line", context);
+  },
+  cannot_infer_matrix_line: (name, sourceInfo) => {
+    const context = [name, sourceInfo.line];
+    return createError("cannot_infer_matrix_line", context);
+  },
+  cannot_infer_matrix_column: (name, sourceInfo) => {
+    const context = [name, sourceInfo.line];
+    return createError("cannot_infer_matrix_column", context);
+  },
+  cannot_infer_vector_size: (name, sourceInfo) => {
+    const context = [name, sourceInfo.line];
+    return createError("cannot_infer_vector_size", context);
+  },
+  matrix_to_vector_attr: (name, exp, sourceInfo) => {
+    const context = [sourceInfo.line, exp, name];
+    return createError("matrix_to_vector_attr", context);
+  },
+  vector_to_matrix_attr: (name, exp, sourceInfo) => {
+    const context = [sourceInfo.line, exp, name];
+    return createError("vector_to_matrix_attr", context);
   }
 });

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

@@ -25,7 +25,7 @@ export class ArrayLiteral extends Literal {
     if (!(element instanceof ArrayLiteral)){
       return null;
     } else {
-      return element.value[0].length;
+      return element.value.length;
     }
   }
 
@@ -34,17 +34,18 @@ export class ArrayLiteral extends Literal {
   }
 
   get isValid () {
-    return true;//this.validateType() && this.validateSize();
+    return this.validateSize() && this.validateType();
   }
 
   validateType () {
-    // let valid = true;
+    let valid = true;
+    // const subtype = this.subtype;
     // if(this.columns !== null) {
-    //   const len = this.columns;
-    //   const len2 = this.lines;
-    //   for (let i = len - 1; i >= 0; i--) {
-    //     for (let j = len2 - 1; j >= 0; j--) {
-    //       if(this.value[i].value[j].type !== this.subtype) {
+    //   const len = this.lines;
+    //   const len2 = this.columns;
+    //   for (let i = len - 1; i >= 0 && valid; --i) {
+    //     for (let j = len2 - 1; j >= 0 && valid; --j) {
+    //       if(!this.value[i].value[j].type.isCompatilbe(subtype)) {
     //         valid = false;
     //         break;
     //       }
@@ -52,31 +53,34 @@ export class ArrayLiteral extends Literal {
     //   }
     // } else {
     //   const len = this.lines;
-    //   for (var i = len - 1; i >= 0; i--) {
-    //     if(this.value[i].type !== this.subtype) {
+    //   for (var i = len - 1; i >= 0 && valid; i--) {
+    //     if(!this.value[i].type.isCompatilbe(subtype)) {
     //       valid = false;
     //       break;
     //     }
     //   }
     // }
-    return true;//valid;
+    // Cannot validate type since no information on variables literals are available
+    return valid;
   }
 
   validateSize () {
     let valid = true;
-    if(this.columns !== null) {
-      const equalityTest = data.value.map(v => v.length)
-      .reduce((old, next) => {
-        if (old === null) {
-          return next;
-        } else if (old === next) {
-          return old
-        } else {
-          return -1;
-        }
-      }, null);
-      valid = equalityTest !== -1;
-    }
+    // if(this.columns !== null) {
+    //   const equalityTest = this.value.map(v => v.value.length)
+    //     .reduce((old, next) => {
+    //       console.log(next);
+    //       if (old == null) {
+    //         return next;
+    //       } else if (old === next) {
+    //         return old
+    //       } else {
+    //         return -1;
+    //       }
+    //     }, null);
+    //   valid = equalityTest !== -1;
+    // }
+    // check is now made inside IVProgParser.parseVectorList(...)
     return valid;
   }
 

+ 168 - 46
js/ast/ivprogParser.js

@@ -1,10 +1,10 @@
 import { CommonTokenStream, InputStream } from 'antlr4/index';
 import * as Expressions from './expressions/';
 import * as Commands from './commands/';
-import { recover } from "./ivprogLexer";
+import * as AstHelpers from "./ast_helpers";
 import { toInt, toString, toBool, toReal } from './../typeSystem/parsers';
 import { Types } from "./../typeSystem/types";
-import { CompoundType } from "./../typeSystem/compoundType";
+import { ArrayType } from "../typeSystem/array_type";
 import { SourceInfo } from './sourceInfo';
 import { convertFromString } from './operators';
 import { SyntaxErrorFactory } from './error/syntaxErrorFactory';
@@ -35,8 +35,9 @@ export class IVProgParser {
 
   constructor (input, lexerClass) {
     this.lexerClass = lexerClass;
-    this.lexer = new lexerClass(new InputStream(input));
-    this.lexer.recover = recover.bind(this.lexer);
+    this.inputStream = new InputStream(input)
+    this.lexer = new lexerClass(this.inputStream);
+    this.lexer.recover = AstHelpers.recover.bind(this.lexer);
     this.tokenStream = new CommonTokenStream(this.lexer);
     this.tokenStream.fill();
     this.pos = 1;
@@ -233,10 +234,10 @@ export class IVProgParser {
     this.definedFuncsNameList.push(id);
   }
 
-  checkVariableDuplicate (variableID, variableIDToken) {
+  checkVariableDuplicate (variableID, sourceInfo) {
     const index = this.getCurrentVariableStack().indexOf(variableID);
     if(index !== -1) {
-      throw SyntaxErrorFactory.duplicate_variable(variableIDToken);
+      throw SyntaxErrorFactory.duplicate_variable(sourceInfo);
     }
     this.getCurrentVariableStack().push(variableID);
   }
@@ -286,49 +287,111 @@ export class IVProgParser {
     let initial = null;
     let dim1 = null;
     let dim2 = null;
-    const idToken = this.getToken();
+    let dimensions = 0;
+    const sourceInfo = SourceInfo.createSourceInfo(this.getToken())
     const idString = this.parseID();
-    this.checkVariableDuplicate(idString,idToken);
+    this.checkVariableDuplicate(idString, sourceInfo);
     // Check for array or vector
-    // ID[int/IDi][int/IDj]
+    // ID[int/IDi?][int/IDj?]
     if (this.checkOpenBrace(true)) {
-      this.pos++;
+      this.pos += 1;
       this.consumeNewLines();
       dim1 = this.parseArrayDimension();
       this.consumeNewLines();
       this.checkCloseBrace();
-      this.pos++;
+      this.pos += 1;
+      dimensions += 1
       if(this.checkOpenBrace(true)) {
-        this.pos++;
+        this.pos += 1;
         this.consumeNewLines();
         dim2 = this.parseArrayDimension();
         this.consumeNewLines();
         this.checkCloseBrace();
+        this.pos += 1;
+        dimensions += 1
+      }
+      return this.parseArrayDeclaration(typeString, isConst, idString, sourceInfo, dimensions, dim1, dim2);
+    } else {
+      const equalsToken = this.getToken();
+      if(isConst && equalsToken.type !== this.lexerClass.EQUAL ) {
+        throw SyntaxErrorFactory.const_not_init(sourceInfo);
+      }
+      if(equalsToken.type === this.lexerClass.EQUAL) {
         this.pos++;
+        initial = this.parseExpressionOR();
+      }
+      let declaration =  declaration = new Commands.Declaration(idString, typeString, initial, isConst);
+      declaration.sourceInfo = sourceInfo;
+      const commaToken = this.getToken();
+      if(commaToken.type === this.lexerClass.COMMA) {
+        this.pos++;
+        this.consumeNewLines();
+        return [declaration]
+        .concat(this.parseDeclaration(typeString, isConst));
+      } else {
+        return [declaration]
       }
     }
+  }
 
+  parseArrayDeclaration (typeString, isConst, idString, sourceInfo, dimensions, dim1, dim2) {
     const equalsToken = this.getToken();
+    let n_lines = dim1;
+    let n_columns = dim2;
+    let initial = null;
+    let dim_is_id = false;
+    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");
+      }
+    }
     if(isConst && equalsToken.type !== this.lexerClass.EQUAL ) {
-      throw SyntaxErrorFactory.const_not_init(idToken);
+      throw SyntaxErrorFactory.const_not_init(sourceInfo);
     }
     if(equalsToken.type === this.lexerClass.EQUAL) {
-      this.pos++;
-      initial = this.parseExpressionOR();
+      if(dim_is_id) {
+        // TODO better error message
+        throw new Error("Cannot init array with a variable as dimesion");
+      }
+      this.pos += 1
+      initial = this.parseArrayLiteral(typeString);
     }
-    let declaration = null;
-    let dimensions = 0;
-    if (dim1 !== null) {
-      dimensions++;
-      if(dim2 !== null) {
-        dimensions++;
+    if(initial == null && dim1 == null) {
+      if(dimensions > 1) {
+        throw SyntaxErrorFactory.cannot_infer_matrix_line(idString, sourceInfo);
+      }
+      throw SyntaxErrorFactory.cannot_infer_vector_size(idString, sourceInfo);
+    }
+    if(dimensions > 1) {
+      if(initial == null &&  dim2 == null) {
+        throw SyntaxErrorFactory.cannot_infer_matrix_column(idString, sourceInfo);
       }
-      declaration = new Commands.ArrayDeclaration(idString,
-        new CompoundType(typeString, dimensions), dim1, dim2, initial, isConst);
-    } else {
-      declaration = new Commands.Declaration(idString, typeString, initial, isConst);
     }
-    declaration.sourceInfo = SourceInfo.createSourceInfo(idToken);
+
+    if(dimensions === 1 && initial != null && !initial.isVector) {
+      const expString = initial.toString();
+      throw SyntaxErrorFactory.matrix_to_vector_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);
+    }
+
+    if(dim1 == null) {
+      n_lines = new Expressions.IntLiteral(toInt(initial.lines));
+      n_lines.sourceInfo = sourceInfo;
+    }
+
+    if (dimensions > 1) {
+      if(dim2 == null) {
+        n_columns = new Expressions.IntLiteral(toInt(initial.columns));
+        n_columns.sourceInfo = sourceInfo;
+      } 
+    }
+    const declaration = new Commands.ArrayDeclaration(idString,
+      new ArrayType(typeString, dimensions), n_lines, n_columns, initial, isConst);
+    declaration.sourceInfo = sourceInfo;
     const commaToken = this.getToken();
     if(commaToken.type === this.lexerClass.COMMA) {
       this.pos++;
@@ -336,7 +399,7 @@ export class IVProgParser {
       return [declaration]
       .concat(this.parseDeclaration(typeString, isConst));
     } else {
-       return [declaration]
+      return [declaration]
     }
   }
 
@@ -366,6 +429,8 @@ export class IVProgParser {
       //parse as variable
       this.pos++;
       return this.parseVariable(dimToken);
+    } else if(dimToken.type === this.lexerClass.CLOSE_BRACE) {
+      return null;
     } else {
       throw SyntaxErrorFactory.invalid_array_dimension(this.lexer.literalNames[this.lexerClass.RK_INTEGER], dimToken);
     }
@@ -406,39 +471,88 @@ export class IVProgParser {
     return exp;
   }
 
-  parseArrayLiteral () {
+  parseArrayLiteral (typeString) {
     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}`);
     }
-    this.pos++;
-    this.parsingArrayDimension++;
+    this.pos += 1;
+    this.parsingArrayDimension += 1;
     this.consumeNewLines();
-    const data = this.parseExpressionList();
+    let data = null;
+    const maybeCurlyOpen = this.checkOpenCurly(true);
+    if(maybeCurlyOpen) {
+      // This is potentially a list of vectors
+      data = this.parseVectorList(typeString);
+    } else {
+      data = this.parseExpressionList();
+    }
     this.consumeNewLines();
     this.checkCloseCurly()
     const endArray = this.getToken();
-    this.pos++;
-    this.parsingArrayDimension--;
-    if (this.parsingArrayDimension === 0) {
-      // if (!data.isValid) {
-      //   // TODO: better error message
-      //   console.log('invalid array');
-      //   throw new Error(`Invalid array at line ${beginArray.line}`);
-      // }
-    }
+    this.pos += 1;
+    this.parsingArrayDimension -= 1;
     const sourceInfo = SourceInfo.createSourceInfoFromList(beginArray, endArray);
     let dataDim = 1;
     if(data[0] instanceof Expressions.ArrayLiteral) {
-      dataDim++;
+      dataDim += 1;
+    } else if(data.length == 1) {
+      console.log("Talvez uma variável seja uma melhor opção");
     }
-    const type = new CompoundType(Types.UNDEFINED, dataDim);
+    const type = new ArrayType(typeString, dataDim);
     const exp = new Expressions.ArrayLiteral(type, data);
     exp.sourceInfo = sourceInfo;
     return exp;
   }
 
+  /** 
+   * Returns a list of ArrayLiterals. Helper function for parsing matrices
+  */
+  parseVectorList (typeString) {
+    let list = [];
+    let lastSize = null;
+    while(true) {
+      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}`);
+      }
+      this.pos += 1;
+      this.parsingArrayDimension += 1;
+      this.consumeNewLines();
+      const data = this.parseExpressionList();
+      this.consumeNewLines();
+      this.checkCloseCurly()
+      const endArray = this.getToken();
+      this.pos += 1;
+      this.parsingArrayDimension -= 1;
+      const sourceInfo = SourceInfo.createSourceInfoFromList(beginArray, endArray);
+      if(lastSize == null) {
+        lastSize = data.length;
+      } else if (lastSize !== data.length) {
+        const expString = this.inputStream.getText(beginArray.start, endArray.stop);
+        throw SyntaxErrorFactory.invalid_matrix_literal_line(expString, sourceInfo);
+      }
+      const type = new ArrayType(typeString, 1);
+      const exp = new Expressions.ArrayLiteral(type, data);
+      exp.sourceInfo = sourceInfo;
+      list.push(exp);
+      const commaToken = this.getToken();
+      if(commaToken.type !== this.lexerClass.COMMA) {
+        break;
+      } 
+      this.pos += 1;
+      this.consumeNewLines();
+    }
+    if(list.length == 1) {
+      console.log("Talvez um vetor seja uma melhor opção");
+    }
+    return list
+  }
+
   /*
   * Returns an object {type: 'variable', value: value}.
   * @returns object with fields type and value
@@ -496,7 +610,7 @@ export class IVProgParser {
     const commandsBlock = this.parseCommandBlock();
     let returnType = funType;
     if(dimensions > 0) {
-      returnType = new CompoundType(funType, dimensions);
+      returnType = new ArrayType(funType, dimensions);
     }
     const func = new Commands.Function(functionID, returnType, formalParams, commandsBlock);
     if (functionID === null && !func.isMain) {
@@ -536,7 +650,7 @@ export class IVProgParser {
       }
       let type = null;
       if(dimensions > 0) {
-        type = new CompoundType(typeString, dimensions);
+        type = new ArrayType(typeString, dimensions);
       } else {
         type = typeString;
       }
@@ -608,6 +722,7 @@ export class IVProgParser {
       hasOpen = true;
     }
     this.consumeNewLines();
+    let parsedCommand =  false;
     while(true) {
 
       const cmd = this.parseCommand();
@@ -615,8 +730,13 @@ export class IVProgParser {
         break;
       if(cmd !== -1) {
         if (cmd instanceof Array) {
+          if(parsedCommand) {
+            const lastToken = this.getToken(this.pos - 1);
+            throw SyntaxErrorFactory.invalid_var_declaration(lastToken);
+          }
           variablesDecl = variablesDecl.concat(cmd);
         } else {
+          parsedCommand = true;
           commands.push(cmd);
         }
       }
@@ -634,7 +754,7 @@ export class IVProgParser {
     const token = this.getToken();
     if (this.isVariableType(token)) {
       if(!this.insideScope(IVProgParser.FUNCTION)) {
-        throw SyntaxErrorFactory.invalid_var_declaration(token.line);
+        throw SyntaxErrorFactory.invalid_var_declaration(token);
       }
       this.pushScope(IVProgParser.BASE);
       const varType = this.parseType();
@@ -1065,7 +1185,9 @@ export class IVProgParser {
         this.pos++;
         return this.getBoolLiteral(token);
       case this.lexerClass.OPEN_CURLY:
-        return this.parseArrayLiteral();
+        // No more annonymous array
+        // return this.parseArrayLiteral();
+        throw SyntaxErrorFactory.annonymous_array_literal(token);
       case this.lexerClass.ID:
       case this.lexerClass.LIB_ID:
         return this.parseIDTerm();

+ 5 - 4
js/ast/sourceInfo.js

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

+ 100 - 38
js/processor/ivprogProcessor.js

@@ -12,12 +12,14 @@ import * as Commands from './../ast/commands/';
 import * as Expressions from './../ast/expressions/';
 import { StoreObjectArrayAddress } from './store/storeObjectArrayAddress';
 import { StoreObjectArrayAddressRef } from './store/storeObjectArrayAddressRef';
-import { CompoundType } from './../typeSystem/compoundType';
+import { ArrayType } from './../typeSystem/array_type';
 import { convertToString } from '../typeSystem/parsers';
 import { Config } from '../util/config';
 import Decimal from 'decimal.js';
 import { ProcessorErrorFactory } from './error/processorErrorFactory';
 import { RuntimeError } from './error/runtimeError';
+import { Type } from '../typeSystem/type';
+import { Literal } from '../ast/expressions/literal';
 
 export class IVProgProcessor {
 
@@ -127,7 +129,7 @@ export class IVProgProcessor {
     let funcStore = new Store(funcName);
     funcStore.extendStore(this.globalStore);
     let returnStoreObject = null;
-    if(func.returnType instanceof CompoundType) {
+    if(func.returnType instanceof ArrayType) {
       if(func.returnType.dimensions > 1) {
         returnStoreObject = new StoreObjectArray(func.returnType,-1,-1,[[]]);
       } else {
@@ -162,6 +164,8 @@ export class IVProgProcessor {
     return Promise.all(promises$).then(values => {
       for (let i = 0; i < values.length; i++) {
         const stoObj = values[i];
+        // console.log(calleeStore.name);
+        // console.log(stoObj);
         const exp = actualList[i];
         let shouldTypeCast = false;
         const formalParameter = formalList[i];
@@ -496,7 +500,7 @@ export class IVProgProcessor {
 
   executeArrayIndexAssign (store, cmd) {
     const mustBeArray = store.applyStore(cmd.id);
-    if(!(mustBeArray.type instanceof CompoundType)) {
+    if(!(mustBeArray.type instanceof ArrayType)) {
       return Promise.reject(ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo));
     }
     const line$ = this.evaluateExpression(store, cmd.line);
@@ -517,6 +521,7 @@ export class IVProgProcessor {
         column = columnSO.number;
       }
       const value = this.parseStoreObjectValue(results[2]);
+      let actualValue = value;
       if (line >= mustBeArray.lines) {
         if(mustBeArray.isVector) {
           return Promise.reject(ProcessorErrorFactory.vector_line_outbounds_full(cmd.id, line, mustBeArray.lines, cmd.sourceInfo));
@@ -539,33 +544,49 @@ export class IVProgProcessor {
 
       const newArray = Object.assign(new StoreObjectArray(null,null,null), mustBeArray);
       if (column !== null) {
-        if (value.type instanceof CompoundType || !newArray.type.canAccept(value.type)) {
-          const type = mustBeArray.type.innerType;
-          const stringInfo = type.stringInfo()
-          const info = stringInfo[0]
-          return Promise.reject(ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo));
+        if (!newArray.type.canAccept(value.type)) {
+          if(!Config.enable_type_casting || !Store.canImplicitTypeCast(mustBeArray.type.innerType, value.type)) {
+            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));
+          }
+          actualValue = Store.doImplicitCasting(mustBeArray.type.innerType, value);
         }
-        newArray.value[line].value[column] = value;
+        newArray.value[line].value[column] = actualValue;
         store.updateStore(cmd.id, newArray);
       } else {
-        if((mustBeArray.columns !== null && value.type instanceof CompoundType) || !newArray.type.canAccept(value.type)) {
-          const type = mustBeArray.type;
-          const stringInfo = type.stringInfo()
-          const info = stringInfo[0]
-          const exp = cmd.expression.toString()
-          return Promise.reject(ProcessorErrorFactory.incompatible_types_array_full(exp,info.type, info.dim-1, cmd.sourceInfo));
+        if(!newArray.type.canAccept(value.type)) {
+          if(!Config.enable_type_casting || !Store.canImplicitTypeCast(mustBeArray.type.innerType, value.type)) {
+            const type = mustBeArray.type;
+            const stringInfo = type.stringInfo();
+            const info = stringInfo[0];
+            const exp = cmd.expression.toString();
+            return Promise.reject(ProcessorErrorFactory.incompatible_types_array_full(exp,info.type, info.dim-1, cmd.sourceInfo));
+          }
+          actualValue = Store.doImplicitCasting(mustBeArray.type.innerType, value);
         }
-        newArray.value[line] = value;
+        newArray.value[line] = actualValue;
         store.updateStore(cmd.id, newArray);
       }
       return store;
     });
   }
 
+  /**
+   * 
+   * @param {Store} store 
+   * @param {Commands.Declaration} cmd 
+   */
   executeDeclaration (store, cmd) {
     try {
-      const $value = this.evaluateExpression(store, cmd.initial);
+      let $value = Promise.resolve(null);
       if(cmd instanceof Commands.ArrayDeclaration) {
+        if(cmd.initial !== null) {
+          // array can only be initialized by a literal....
+          $value = this.evaluateArrayLiteral(store, cmd.initial, cmd.type);
+        }
         const $lines = this.evaluateExpression(store, cmd.lines);
         const $columns = cmd.columns === null ? null: this.evaluateExpression(store, cmd.columns);
         return Promise.all([$lines, $columns, $value]).then(values => {
@@ -594,7 +615,7 @@ export class IVProgProcessor {
           let realValue = value;
           if (value !== null) {
             if(value instanceof StoreObjectArrayAddress) {
-              if(value.type instanceof CompoundType) {
+              if(value.type instanceof ArrayType) {
                 realValue = Object.assign(new StoreObjectArray(null,null,null), value.refValue);
               } else {
                 realValue = Object.assign(new StoreObject(null,null), value.refValue);
@@ -604,7 +625,7 @@ export class IVProgProcessor {
             realValue = new StoreObjectArray(cmd.type, line, column, [])
             if(column !== null) {
               for (let i = 0; i < line; i++) {
-                realValue.value.push(new StoreObjectArray(new CompoundType(cmd.type.innerType, 1), column, null, []));
+                realValue.value.push(new StoreObjectArray(new ArrayType(cmd.type.innerType, 1), column, null, []));
               }
             }
           }
@@ -614,6 +635,9 @@ export class IVProgProcessor {
         });
         
       } else {
+        if(cmd.initial !== null) {
+          $value = this.evaluateExpression(store, cmd.initial);
+        }
         const temp = new StoreObject(cmd.type, null);
         store.insertStore(cmd.id, temp);
         return $value.then(vl => {
@@ -629,8 +653,8 @@ export class IVProgProcessor {
               }
             }
             if(vl instanceof StoreObjectArrayAddress) {
-              if(vl.type instanceof CompoundType) {
-                return Promise.reject(new Error("!!!Critical Error: Compatibility check failed, a Type accepts a CompoundType"))
+              if(vl.type instanceof ArrayType) {
+                return Promise.reject(new Error("!!!Critical Error: Compatibility check failed, a Type accepts a ArrayType"))
               } else {
                 realValue = Object.assign(new StoreObject(null,null), vl.refValue);
               }
@@ -667,7 +691,7 @@ export class IVProgProcessor {
     } else if (exp instanceof Expressions.StringLiteral) {
       return this.evaluateLiteral(store, exp);
     } else if (exp instanceof Expressions.ArrayLiteral) {
-      return this.evaluateArrayLiteral(store, exp);
+      return Promise.reject(new Error("Internal Error: The system should not eval an array literal."))
     } else if (exp instanceof Expressions.FunctionCall) {
       return this.evaluateFunctionCall(store, exp);
     }
@@ -696,13 +720,22 @@ export class IVProgProcessor {
     });
   }
 
-  evaluateArrayLiteral (store, exp) {
+  /**
+   * 
+   * @param {Store} store 
+   * @param {Expressions.ArrayLiteral} exp 
+   * @param {ArrayType} type 
+   */
+  evaluateArrayLiteral (store, exp, type) {
     const errorHelperFunction = (validationResult, exp) => {
       const errorCode = validationResult[0];
+      let expectedColumns = null;
+      let actualColumns = null;
       switch(errorCode) {
         case StoreObjectArray.WRONG_COLUMN_NUMBER: {
-          const columnValue = validationResult[1];
-          return Promise.reject(ProcessorErrorFactory.invalid_array_literal_column_full(arr.columns, columnValue, exp.sourceInfo));
+          expectedColumns = validationResult[1];
+          actualColumns = validationResult[2];
+          return Promise.reject(ProcessorErrorFactory.invalid_array_literal_column_full(expectedColumns, actualColumns, exp.sourceInfo));
         }
         case StoreObjectArray.WRONG_LINE_NUMBER: {
           const lineValue = validationResult[1];
@@ -719,13 +752,13 @@ export class IVProgProcessor {
             line = validationResult[1];
             strExp = exp.value[line].toString()
           }
+          // TODO - fix error message
           return Promise.reject(ProcessorErrorFactory.invalid_array_literal_type_full(strExp, exp.sourceInfo));            }
       }
     };
     if(!exp.isVector) {
-      const $matrix = this.evaluateMatrix(store, exp.value);
+      const $matrix = this.evaluateMatrix(store, exp.value, type);
       return $matrix.then(list => {
-        const type = new CompoundType(list[0].type.innerType, 2);
         const arr = new StoreObjectArray(type, list.length, list[0].lines, list);
         const checkResult = arr.isValid;
         if(checkResult.length == 0)
@@ -735,8 +768,8 @@ export class IVProgProcessor {
         }
       });
     } else {
-      return this.evaluateVector(store, exp.value).then(list => {
-        const type = new CompoundType(list[0].type, 1);
+      return this.evaluateVector(store, exp.value, type).then(list => {
+        const type = new ArrayType(list[0].type, 1);
         const stoArray = new StoreObjectArray(type, list.length, null, list);
         const checkResult = stoArray.isValid;
         if(checkResult.length == 0)
@@ -748,16 +781,45 @@ export class IVProgProcessor {
     }
   }
 
-  evaluateVector (store, exps) {
-    return Promise.all(exps.map( exp => this.evaluateExpression(store, exp)));
+  /**
+   * Evalautes a list of literals and expression composing the vector
+   * @param {Store} store 
+   * @param {Literal[]} exps 
+   * @param {ArrayType} type
+   * @returns {Promise<StoreObject[]>} store object list
+   */
+  evaluateVector (store, exps, type) {
+    const actual_values = Promise.all(exps.map( exp => this.evaluateExpression(store, exp)));
+    return actual_values.then( values => {
+      return values.map((v, index) => {
+        if(!type.canAccept(v.type)) {
+          if (!Config.enable_type_casting || !Store.canImplicitTypeCast(type.innerType, v.type)) {
+            const stringInfo = v.type.stringInfo();
+            const info = stringInfo[0];
+            const exp_str = exps[index].toString();
+            // TODO - fix error message
+            throw ProcessorErrorFactory.invalid_array_literal_type_full(exp_str, exps[index].sourceInfo);
+          }
+          const new_value = Store.doImplicitCasting(type.innerType, v);
+          return new_value;
+        }
+        return v;
+      });
+    });
   }
 
-  evaluateMatrix (store, exps) {
+  /**
+   * Evaluates a list of array literals composing the matrix
+   * @param {Store} store 
+   * @param {Expressions.ArrayLiteral[]} exps 
+   * @param {ArrayType} type 
+   */
+  evaluateMatrix (store, exps, type) {
     return Promise.all(exps.map( vector => {
-      const $vector = this.evaluateVector(store, vector.value)
+      const vec_type = new ArrayType(type.innerType, 1);
+      const $vector = this.evaluateVector(store, vector.value, vec_type);
       return $vector.then(list => {
-        const type = new CompoundType(list[0].type, 1);
-        return new StoreObjectArray(type, list.length, null, list)
+        return new StoreObjectArray(vec_type, list.length, null, list)
       });
     } ));
   }
@@ -781,7 +843,7 @@ export class IVProgProcessor {
 
   evaluateArrayAccess (store, exp) {
     const mustBeArray = store.applyStore(exp.id);
-    if (!(mustBeArray.type instanceof CompoundType)) {
+    if (!(mustBeArray.type instanceof ArrayType)) {
       return Promise.reject(ProcessorErrorFactory.invalid_array_access_full(exp.id, exp.sourceInfo));
     }
     const $line = this.evaluateExpression(store, exp.line);
@@ -1016,10 +1078,10 @@ export class IVProgProcessor {
   parseStoreObjectValue (vl) {
     let realValue = vl;
     if(vl instanceof StoreObjectArrayAddress) {      
-      if(vl.type instanceof CompoundType) {
+      if(vl.type instanceof ArrayType) {
         switch(vl.type.dimensions) {
           case 1: {
-            realValue = new StoreObjectArray(vl.type, vl.value);
+            realValue = new StoreObjectArray(vl.type, vl.value.length, null, vl.value);
             break;
           }
           default: {

+ 4 - 4
js/processor/lib/arrays.js

@@ -2,7 +2,7 @@ import { StoreObject } from '../store/storeObject';
 import * as Commands from './../../ast/commands';
 import { Types } from './../../typeSystem/types';
 import { toInt } from "./../../typeSystem/parsers";
-import { CompoundType } from '../../typeSystem/compoundType';
+import { ArrayType } from '../../typeSystem/array_type';
 import { Modes } from '../modes';
 
 /**
@@ -21,7 +21,7 @@ export function createNumElementsFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(numElementsFun)]);
   const func = new Commands.Function('$numElements', Types.INTEGER,
-    [new Commands.FormalParameter(new CompoundType(Types.ALL, 1), 'vector', false)],
+    [new Commands.FormalParameter(new ArrayType(Types.ALL, 1), 'vector', false)],
     block);
   return func;
  }
@@ -36,7 +36,7 @@ export function createMatrixLinesFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(matrixLinesFun)]);
   const func = new Commands.Function('$matrixLines', Types.INTEGER,
-    [new Commands.FormalParameter(new CompoundType(Types.ALL, 2), 'matrix', false)],
+    [new Commands.FormalParameter(new ArrayType(Types.ALL, 2), 'matrix', false)],
     block);
   return func;
  }
@@ -51,7 +51,7 @@ export function createMatrixColumnsFun () {
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(matrixColumnsFun)]);
   const func = new Commands.Function('$matrixColumns', Types.INTEGER,
-    [new Commands.FormalParameter(new CompoundType(Types.ALL, 2), 'matrix', false)],
+    [new Commands.FormalParameter(new ArrayType(Types.ALL, 2), 'matrix', false)],
     block);
   return func;
  }

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

@@ -4,7 +4,7 @@ import { Types } from './../../typeSystem/types';
 import { toReal } from "./../../typeSystem/parsers";
 import { Decimal } from 'decimal.js';
 import { MultiType } from '../../typeSystem/multiType';
-import { CompoundType } from '../../typeSystem/compoundType';
+import { ArrayType } from '../../typeSystem/array_type';
 import { Modes } from '../modes';
 import { Config } from '../../util/config';
 
@@ -229,7 +229,7 @@ export function createMaxFun () {
     sto.mode = Modes.RETURN;
     return Promise.resolve(sto.updateStore('$', temp));
   };
- const paramType = new CompoundType(new MultiType([Types.INTEGER, Types.REAL]), 1);
+ const paramType = new ArrayType(new MultiType([Types.INTEGER, Types.REAL]), 1);
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(maxFun)]);
  const func = new Commands.Function('$max', new MultiType([Types.INTEGER, Types.REAL]),
    [new Commands.FormalParameter(paramType, 'x', false)],
@@ -246,7 +246,7 @@ export function createMinFun () {
     sto.mode = Modes.RETURN;
     return Promise.resolve(sto.updateStore('$', temp));
   };
- const paramType = new CompoundType(new MultiType([Types.INTEGER, Types.REAL]), 1);
+ const paramType = new ArrayType(new MultiType([Types.INTEGER, Types.REAL]), 1);
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(minFun)]);
  const func = new Commands.Function('$min', new MultiType([Types.INTEGER, Types.REAL]),
    [new Commands.FormalParameter(paramType, 'x', false)],

+ 104 - 111
js/processor/semantic/semanticAnalyser.js

@@ -2,11 +2,11 @@ import { ProcessorErrorFactory } from './../error/processorErrorFactory';
 import { LanguageDefinedFunction } from './../definedFunctions';
 import { LanguageService } from './../../services/languageService';
 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 { InfixApp, UnaryApp, FunctionCall, IntLiteral, RealLiteral, StringLiteral, BoolLiteral, VariableLiteral, ArrayAccess } from '../../ast/expressions';
 import { Literal } from '../../ast/expressions/literal';
 import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from '../compatibilityTable';
 import { Types } from '../../typeSystem/types';
-import { CompoundType } from '../../typeSystem/compoundType';
+import { ArrayType } from '../../typeSystem/array_type';
 import { MultiType } from '../../typeSystem/multiType';
 import { Config } from '../../util/config';
 import { Store } from '../store/store';
@@ -103,22 +103,8 @@ export class SemanticAnalyser {
 
   assertDeclaration (declaration) {
     if (declaration instanceof ArrayDeclaration) {
-      if(declaration.initial === null) {
-        const lineType = this.evaluateExpressionType(declaration.lines);
-        if (!lineType.isCompatible(Types.INTEGER)) {
-          throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
-        }
-        if (declaration.columns !== null) {
-          const columnType = this.evaluateExpressionType(declaration.columns);
-          if (!columnType.isCompatible(Types.INTEGER)) {
-            throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
-          }
-        }
-        this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type, isConst: declaration.isConst});
-        return;
-      }
-      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, isConst: declaration.isConst});
+      this.assertArrayDeclaration(declaration);
+      this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type});
 
     } else {
       if(declaration.initial === null) {
@@ -145,6 +131,25 @@ export class SemanticAnalyser {
     }
   }
 
+  assertArrayDeclaration (declaration) {
+    if(declaration.initial === null) {
+      const lineType = this.evaluateExpressionType(declaration.lines);
+      if (!lineType.isCompatible(Types.INTEGER)) {
+        throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
+      }
+      if (declaration.columns !== null) {
+        const columnType = this.evaluateExpressionType(declaration.columns);
+        if (!columnType.isCompatible(Types.INTEGER)) {
+          throw ProcessorErrorFactory.array_dimension_not_int_full(declaration.sourceInfo);
+        }
+      }  
+    } else {
+      this.evaluateArrayLiteral(declaration);
+    }
+    this.insertSymbol(declaration.id, {id: declaration.id, lines: declaration.lines, columns: declaration.columns, type: declaration.type});
+    return;
+  }
+
   evaluateExpressionType (expression) {
     // TODO: Throw operator error in case type == UNDEFINED
     if(expression instanceof UnaryApp) {
@@ -192,7 +197,7 @@ export class SemanticAnalyser {
       if(arrayTypeInfo === null) {
         throw ProcessorErrorFactory.symbol_not_found_full(expression.id, expression.sourceInfo);
       }
-      if (!(arrayTypeInfo.type instanceof CompoundType)) {
+      if (!(arrayTypeInfo.type instanceof ArrayType)) {
         throw ProcessorErrorFactory.invalid_array_access_full(expression.id, expression.sourceInfo);
       }
       const lineType = this.evaluateExpressionType(expression.line);
@@ -216,7 +221,7 @@ export class SemanticAnalyser {
         if(arrayTypeInfo.columns === null) {
           return arrType.innerType;
         }
-        return new CompoundType(arrType.innerType, 1);
+        return new ArrayType(arrType.innerType, 1);
       }
     }
   }
@@ -235,7 +240,7 @@ export class SemanticAnalyser {
       if(typeInfo === null) {
         throw ProcessorErrorFactory.symbol_not_found_full(literal.id, literal.sourceInfo);
       }
-      if (typeInfo.type instanceof CompoundType) {
+      if (typeInfo.type instanceof ArrayType) {
         return typeInfo.type;
       }
       return typeInfo.type;
@@ -257,83 +262,25 @@ export class SemanticAnalyser {
           }
         }
       }
-      if(last instanceof CompoundType) {
-        return new CompoundType(last.innerType, last.dimensions + 1);
+      if(last instanceof ArrayType) {
+        return new ArrayType(last.innerType, last.dimensions + 1);
       }
-      return new CompoundType(last, 1);
+      return new ArrayType(last, 1);
     }
   }
 
-  evaluateArrayLiteral (/*id, lines, columns, type, literal*/) {
-    /* if (literal instanceof ArrayLiteral) {
-      const dimType = this.evaluateExpressionType(lines);
-      if (!dimType.isCompatible(Types.INTEGER)) {
-        throw ProcessorErrorFactory.array_dimension_not_int_full(literal.sourceInfo);
-      }
-      if ((lines instanceof IntLiteral)) {
-        if (!lines.value.eq(literal.value.length)) {
-          if(type.dimensions > 1) {
-            throw ProcessorErrorFactory.matrix_line_outbounds_full(id, literal.value.length, lines.value.toNumber(), literal.sourceInfo)
-          } else {
-            throw ProcessorErrorFactory.vector_line_outbounds_full(id, literal.value.length, lines.value.toNumber(), literal.sourceInfo)
-          }
-        } else if (lines.value.isNeg()) {
-          throw ProcessorErrorFactory.array_dimension_not_positive_full(literal.sourceInfo);
-        }
-      }
-      if (columns === null) {
-        // it's a vector...
-        literal.value.reduce((last, next) => {
-          const eType = this.evaluateExpressionType(next);
-          if (!last.canAccept(eType)) {
-            const strInfo = last.stringInfo();
-            const info = strInfo[0];
-            const strExp = literal.toString();
-            throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
-          }
-          return last;
-        }, type);
-        return true;
-      } else {
-        const dimType = this.evaluateExpressionType(columns);
-        if (!dimType.isCompatible(Types.INTEGER)) {
-          throw ProcessorErrorFactory.array_dimension_not_int_full(literal.sourceInfo);
-        }
-        if ((columns instanceof IntLiteral)) {
-          const columnValue = literal.value[0].value.length;
-          if (!columns.value.eq(columnValue)) {
-            if(type.dimensions > 1) {
-              throw ProcessorErrorFactory.matrix_column_outbounds_full(id, literal.value.length, columns.value.toNumber(), literal.sourceInfo)
-            } else {
-              throw ProcessorErrorFactory.invalid_matrix_access_full(id, literal.sourceInfo);
-            }
-          } else if (columns.value.isNeg()) {
-            throw ProcessorErrorFactory.array_dimension_not_positive_full(literal.sourceInfo);
-          }
-          for (let i = 0; i < columns; i++) {
-            const anotherArray = literal.value[i];
-            this.evaluateArrayLiteral(id, columns, null, type, anotherArray)
-          }
-        }
-      }
-
+  evaluateArrayLiteral (arrayDeclaration) {
+    const type =  arrayDeclaration.type;
+    const literal = arrayDeclaration.initial;
+    if(arrayDeclaration.isVector) {
+      this.evaluateVectorLiteralType(literal, type);
     } else {
-
-      const resultType = this.evaluateExpressionType(literal);
-      if (!(resultType instanceof CompoundType)) {
-        const strInfo = type.stringInfo();
-        const info = strInfo[0];
-        const strExp = literal.toString();
-        throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
-      }
-      if (!type.isCompatible(resultType)) {
-        const strInfo = type.stringInfo();
-        const info = strInfo[0];
-        const strExp = literal.toString();
-        throw ProcessorErrorFactory.incompatible_types_array_full(strExp,info.type, info.dim, literal.sourceInfo);
-      }
-      return true;
-    } */
+      // TODO matrix type check
+      for(let i = 0; i < literal.lines; ++i) {
+        const line_literal = literal.value[i];
+        this.evaluateVectorLiteralType(line_literal, new ArrayType(type.innerType, 1));
+      }
+    }
     return true;
   }
 
@@ -341,7 +288,7 @@ export class SemanticAnalyser {
     this.pushMap();
     this.currentFunction = fun;
     fun.formalParameters.forEach(formalParam => {
-      if(formalParam.type instanceof CompoundType) {
+      if(formalParam.type instanceof ArrayType) {
         if(formalParam.type.dimensions > 1) {
           this.insertSymbol(formalParam.id, {id: formalParam.id, lines: -1, columns: -1, type: formalParam.type});
         } else {
@@ -405,11 +352,12 @@ export class SemanticAnalyser {
       return result && hasDefault;
 
     } else if (cmd instanceof ArrayIndexAssign) {
+      // TODO - rework!!!!!
       const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
       if(typeInfo === null) {
         throw ProcessorErrorFactory.symbol_not_found_full(cmd.id, cmd.sourceInfo);
       }
-      if(!(typeInfo.type instanceof CompoundType)) {
+      if(!(typeInfo.type instanceof ArrayType)) {
         throw ProcessorErrorFactory.invalid_array_access_full(cmd.id, cmd.sourceInfo);
       }
       const exp = cmd.expression;
@@ -421,37 +369,61 @@ export class SemanticAnalyser {
       const columnExp = cmd.column;
       if (typeInfo.columns === null && columnExp !== null) {
         throw ProcessorErrorFactory.invalid_matrix_access_full(cmd.id, cmd.sourceInfo);
+      } else if (!typeInfo.type.isVector && columnExp == null) {
+        throw new Error("Cannot assign to matrix line");      
       } else if (columnExp !== null) {
         const columnType = this.evaluateExpressionType(columnExp);
         if (!columnType.isCompatible(Types.INTEGER)) {
           throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
         }
       }
-      // exp can be a arrayLiteral, a single value exp or an array access
-      if(exp instanceof ArrayLiteral) {
-        this.evaluateArrayLiteral(cmd.id, typeInfo.lines, (columnExp ? typeInfo.columns : null), typeInfo.type, exp);
+      // exp a single value exp or an array access
+      const exp_type = this.evaluateExpressionType(exp);
+      if(exp_type instanceof ArrayType) {
+        // TODO better error message
+        throw new Error("Cannot assign a matrix/vector");
+      }
+      let compatible = false;
+      if(exp_type instanceof MultiType) {
+        compatible = exp_type.isCompatible(typeInfo.type.innerType);
       } else {
-        // cannot properly evaluate since type system is poorly constructed
+        compatible = typeInfo.type.canAccept(exp_type);
+      }
+      if(!compatible) {
+        if(!Config.enable_type_casting || !Store.canImplicitTypeCast(typeInfo.type.innerType, exp_type)) {
+          throw new Error("invalid vector element type");
+        }
       }
       return optional;
     } else if (cmd instanceof Assign) {
+      // TODO - rework since there is no literal array assignment
       const typeInfo = this.findSymbol(cmd.id, this.symbolMap);
       if(typeInfo === null) {
         throw ProcessorErrorFactory.symbol_not_found_full(cmd.id, cmd.sourceInfo);
       }
       const exp = cmd.expression;
-      if(exp instanceof ArrayLiteral) {
-        if(!(typeInfo.type instanceof CompoundType)) {
-          const stringInfo = typeInfo.type.stringInfo();
-          const info = stringInfo[0];
-          throw ProcessorErrorFactory.incompatible_types_full(info.type, info.dim, cmd.sourceInfo);
+      const exp_type = this.evaluateExpressionType(exp);
+      if(exp_type instanceof ArrayType) {
+        if(!(typeInfo.type instanceof ArrayType)) {
+          // TODO better error message
+          throw new Error("Cannot assign an array to a non-array variable ");
+        } 
+        // Both are arrays...
+        // if both don't have same dimensions and type, cannot perform assignment
+        if(!exp_type.isCompatible(typeInfo.type)) {
+          if(exp_type.dimensions === typeInfo.type.dimensions && !exp_type.innerType.isCompatible(typeInfo.type.innerType)) {
+            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);
+            }
+          } else {
+            // TODO better error message
+            throw new Error("Cannot assign a vector to matrix or matrix to vector");
+          }
         }
-        this.evaluateArrayLiteral(cmd.id, typeInfo.lines, typeInfo.columns, typeInfo.type, exp);
-      } else {
-        const resultType = this.evaluateExpressionType(exp);
-        if((!resultType.isCompatible(typeInfo.type) && !Config.enable_type_casting)
-          || (!resultType.isCompatible(typeInfo.type) && Config.enable_type_casting
-          && !Store.canImplicitTypeCast(typeInfo.type, resultType))) {
+      } 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);
@@ -536,7 +508,7 @@ export class SemanticAnalyser {
         for (let j = 0; j < resultType.types.length; ++j) {
           const element = resultType.types[j];
           if(formalParam.type.types.indexOf(element) !== -1) {
-            shared++;
+            shared += 1;
           }
         }
         if(shared <= 0) {
@@ -571,4 +543,25 @@ export class SemanticAnalyser {
 
     }
   }
+
+  evaluateVectorLiteralType (literal, type) {
+    for(let i = 0; i < literal.value.length; i+=1) {
+      const exp = literal.value[i];
+      const expType = this.evaluateExpressionType(exp);
+      let compatible = false;
+      if(expType instanceof MultiType) {
+        compatible = expType.isCompatible(type.innerType);
+      } else {
+        compatible = type.canAccept(expType);
+      }
+      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");
+        }
+      }
+    }
+    return type;
+  }
 }

+ 26 - 29
js/processor/store/storeObjectArray.js

@@ -29,14 +29,11 @@ export class StoreObjectArray extends StoreObject {
   }
 
   isCompatible (another) {
-    if(another instanceof StoreObject) {
-      if(((this.lines === -1 && another.lines > 0) ||
-        (this.lines === another.lines))) {
-          if ((this.columns === -1 && another.columns > 0) ||
-            (this.columns === another.columns)) {
-              return super.isCompatible(another);
-          }
-        }
+    if(another instanceof StoreObjectArray) {
+      if((this.isVector && another.isVector) ||
+        (!this.isVector && !another.isVector)) {
+          return super.isCompatible(another);
+      }
     }
     return false;
   }
@@ -51,29 +48,29 @@ export class StoreObjectArray extends StoreObject {
         if(this.value.length !== this.lines) {
           return [StoreObjectArray.WRONG_LINE_NUMBER, this.value.length];;
         }
-        const mustBeNull = this.value.find(v => !this.type.canAccept(v.type) );
-        if(!!mustBeNull) {
-          return [StoreObjectArray.WRONG_TYPE, this.value.indexOf(mustBeNull)];;
-        }
+        // const mustBeNull = this.value.find(v => !this.type.canAccept(v.type) );
+        // if(!!mustBeNull) {
+        //   return [StoreObjectArray.WRONG_TYPE, this.value.indexOf(mustBeNull)];;
+        // }
+        return [];
+      } else if(this.lines !== this.value.length) {
+        return [StoreObjectArray.WRONG_LINE_NUMBER, this.value.length];
       }
-      return [];
-    } else {
-    if(this.lines !== this.value.length) {
-      return [StoreObjectArray.WRONG_LINE_NUMBER, this.value.length];
-    }
-    for (let i = 0; i < this.lines; i++) {
-      for (let j = 0; j < this.columns; j++) {
-        const arr = this.value[i];
-        if(arr.length !== this.columns) {
-          return [StoreObjectArray.WRONG_COLUMN_NUMBER, arr.length];
+      for (let i = 0; i < this.lines; i += 1) {
+        const thisRef = this;
+        const arrayObject = this.value[i];
+        if(arrayObject.lines !== this.columns) {
+          return [StoreObjectArray.WRONG_COLUMN_NUMBER, this.columns, arrayObject.lines];
         }
-        const mustBeNull = arr.find(v => !this.type.canAccept(v.type) );
-        if(!!mustBeNull) {
-          return [StoreObjectArray.WRONG_TYPE, i, arr.indexOf(mustBeNull)];
-        }            
+        // const mustBeNull = arrayObject.value.find(v => !arrayObject.type.canAccept(v.type) );
+        // if(!!mustBeNull) {
+        //   console.log(mustBeNull);
+        //   console.log(thisRef.type.canAccept(mustBeNull));
+        //   console.log(thisRef.type);
+        //   return [StoreObjectArray.WRONG_TYPE, i, arrayObject.value.indexOf(mustBeNull)];
+        // }
       }
-    }
-      return [];
-    }
+    } 
+    return [];
   }
 }

+ 4 - 4
js/processor/store/storeObjectArrayAddress.js

@@ -1,6 +1,6 @@
 import { StoreObject } from './storeObject';
 import { StoreObjectArray } from './storeObjectArray';
-import { CompoundType } from '../../typeSystem/compoundType';
+import { ArrayType } from '../../typeSystem/array_type';
 import { ProcessorErrorFactory } from '../error/processorErrorFactory';
 
 export class StoreObjectArrayAddress extends StoreObject {
@@ -53,7 +53,7 @@ export class StoreObjectArrayAddress extends StoreObject {
   }
 
   get lines () {
-    if(!(this.type instanceof CompoundType)) {
+    if(!(this.type instanceof ArrayType)) {
       return null;
     }
     return this.refValue.value.length;
@@ -77,7 +77,7 @@ export class StoreObjectArrayAddress extends StoreObject {
     const newArray = Object.assign(new StoreObjectArray(null,null,null), anArray);
     if(!stoObj.type.isCompatible(this.type)) {
       throw new Error(`Invalid operation: cannot assign the value given to ${this.refID}`);
-    } else if (this.type instanceof CompoundType && this.type.canAccept(stoObj.type)) {
+    } else if (this.type instanceof ArrayType && this.type.canAccept(stoObj.type)) {
       throw new Error(`Invalid operation: cannot assign the value given to ${this.refID}`);
     }
     if (this.column !== null) {
@@ -91,7 +91,7 @@ export class StoreObjectArrayAddress extends StoreObject {
 
   isCompatible (another) {
     if(this.type.isCompatible(another.type)) {
-      if(another.type instanceof CompoundType) {
+      if(another.type instanceof ArrayType) {
         return this.lines === another.lines && this.columns === another.columns;
       } else {
         this.refValue.isCompatible(another);

+ 9 - 5
js/typeSystem/compoundType.js

@@ -1,6 +1,6 @@
 import { Type } from "./type";
 
-export class CompoundType extends Type {
+export class ArrayType extends Type {
 
   constructor (type, dimensions) {
     super(null);
@@ -8,8 +8,12 @@ export class CompoundType extends Type {
     this.dimensions = dimensions;
   }
 
+  get isVector () {
+    return this.dimensions == 1;
+  }
+
   isCompatible (another) {
-    if(another instanceof CompoundType){
+    if(another instanceof ArrayType){
       if(this.dimensions !== another.dimensions) {
         return false;
       }
@@ -27,10 +31,10 @@ export class CompoundType extends Type {
   }
 
   canAccept (another) {
-    if(another instanceof CompoundType) {
-      return this.dimensions > another.dimensions && this.innerType.isCompatible(another.innerType);
+    if(another instanceof ArrayType) {
+      return false;// return this.dimensions > another.dimensions && this.innerType.isCompatible(another.innerType);
     } else {
-      return this.innerType.isCompatible(another);
+      return this.dimensions == 1 && this.innerType.isCompatible(another);
     }
   }
 }

+ 1 - 0
templates/runner.html

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.0/semantic.min.css" integrity="sha256-9mbkOfVho3ZPXfM7W8sV2SndrGDuh7wuyLjtsWeTI1Q=" crossorigin="anonymous" />
   <link rel="stylesheet" type="text/css" href="css/ivprog-visual-1.0.css">