Browse Source

Merge branch 'features_10_2021' of LInE/iVProg into master

GitAdmin 2 years ago
parent
commit
ae3637aafc

+ 21 - 1
i18n/ui.csv

@@ -9,6 +9,9 @@ btn_arithmetic_division,Divisão,Division,División
 btn_arithmetic_module,Módulo,Remainder,Resto
 btn_break,Pare,break,break
 btn_case,Caso,Case,Caso
+btn_add_var,Adicionar variável,Add a variable,Add a variable
+btn_drag_and_drop_function,Mover função,Move function,Mover función 
+btn_delete_function,Excluir função,Delete function,Borrar función 
 expression_invalid,Expressão inválida. Verifique a sintáxe antes de continuar.,Invalid expression. Check the syntax before proceeding.,Expresión no válida. Verifique la sintaxis antes de continuar.
 expression_undelcared_variable,Variáveis não declaradas:,Undeclared variables:,Variables no declaradas:
 expression_undeclared_function,Funções não definidas:,Undefined functions:,Funcíon no declaradas:
@@ -41,6 +44,8 @@ text_edit_expression_cancel,Cancelar edição,Cancel edition,Cancelar edición
 text_add_function,Adicionar uma nova função ao programa,Add a new function to the program,Agregar una nueva función al programa
 text_move_command,Mover comando,Move command,Mover comando
 text_add_parameters,Adicionar um novo parâmetro,Add a new parameter,Agregar un nuevo parámetro
+text_parameter_reference,Definir parâmetro como passagem por referência,Define parameter passed by reference,Define parameter passed by reference
+text_parameter_copy,Definir parâmetro como passagem por cópia,Define parameter passed by copy,Define parameter passed by copy
 text_comment_start,Comentário inicial da função...,Function initial comment,Comentario inicial de la función
 text_comment_main,Esta é a função principal...,This is the main funcion,Esta es la función principal
 text_read_var,Entrada/Leitura de dados,Input/Read data,Entrada/Lectura de dados
@@ -72,8 +77,10 @@ text_config_programming_textual,Textual,Textual,Textual
 text_config_programming_visual,Visual,Visual,Visual
 text_logic_expression,Lógicos,Logic,Lógicos
 text_arithmetic_expression,Aritméticos,Arithmetics,Aritmética
-text_iftrue,Se verdadeiro então,If true then,Si verdad entonces
+text_iftrue,Se condição senão,If condition else,Si condicion sino
 text_message_error_activity_file,Aconteceu um erro ao processar a atividade. <br> Recarregue a página para tentar novamente.,There was an error processing the activity.<br> Reload the page to try again.,Se produjo un error al procesar la actividad.<br> Recargar la página para volver a intentarlo.
+text_message_error_upload_file,Não foi possível carregar o arquivo.<br>Verifique o conteúdo do arquivo e tente novamente.,It was not possible upload the file.<br>Verify the file's content and try again.,text_message_error_upload_file
+text_message_error_upload_close,Fechar,Close,Close
 text_message_error_activity_reload,Recarregar,Reload,Recargar
 text_repeatNtimes,Repita N vezes,Repeat N times,Repetir N veces
 text_receives,recebe,receives,receives
@@ -126,6 +133,19 @@ inform_valid_expression,Construa uma expressão lógica!,Construct a logic expre
 tooltip_terminal_clear,Limpa o terminal removendo todos os textos já escritos e os pendentes.,Clears the terminal by removing all wrriten and pending text.,Borra el terminal eliminando todo el texto escrito y pendiente.
 tooltip_terminal_show,Exibe o terminal caso esteja escondido,Shows the terminal if it is hidden,Muestra el terminal si está oculto.
 tooltip_terminal_hide,Esconde o terminal caso não esteja escondido,Hides the terminal if it is not on display,Oculta el terminal si no está en exhibición
+tooltip_menu_read,Comando para receber dados pelo teclado,Command to input data from keyboard,Command to input data from keyboard
+tooltip_menu_write,Comando para apresentar conteúdo ao usuário,Command to present content to user,Command to present content to user
+tooltip_menu_comments,Bloco para comentários internos do programador,Block to comments from developer,Block to comments from developer
+tooltip_menu_attribution,Comando para atribuir uma expressão a uma variável,Command to assign an expression to a variable,Command to assign an expression to a variable
+tooltip_menu_call_function,Comando para realizar a chamada de uma função,Command to execute a function call,Command to execute a function call
+tooltip_menu_if_else,Estrutura para que os comandos só sejam executados de acordo com as condições estabelecidas,Structure in which command only run when the conditions are satisfied,Structure in which command only run when the conditions are satisfied
+tooltip_menu_repeat_n_times,Estrutura para executar um bloco de comandos repetidamente,Structure to execute a block of commands repeatedly,Structure to execute a block of commands repeatedly
+tooltip_menu_repeat_whiletrue,Estrutura para repetir um bloco de comandos enquanto a condição for verdadeira,Structure to execute a block repeatdly while condition is true,Structure to execute a block repeatdly while condition is true
+tooltip_menu_repeat_dowhiletrue,Estrutura que executa um bloco e o repete enquanto a condição for verdadeira,Structure that executes a block and repeat while the condition is true,Structure that executes a block and repeat while the condition is true
+tooltip_menu_repeat_switch,Estrutura de escolha do bloco a ser executado,Structure that choices the block to be executed,Structure that choices the block to be executed
+tooltip_menu_repeat_return,Comando para devolver o resultado e finalizar a função,Command to return the result and finish the function,Command to return the result and finish the function
+tooltip_move_var,Mover variável,Move variable,Move variable
+tooltip_remove_var,Excluir variável,Delete variable,Delete variable
 text_ivprog_version,Versão,Version,Version
 text_teacher_filter,Filtro,Filter,Filter
 text_teacher_filter_active,Ativado,Activated,Activated

+ 1 - 1
js/ast/error/syntaxError.js

@@ -1,6 +1,6 @@
 export class SyntaxError extends Error {
   constructor (msg, id) {
-    super(...msg);
+    super(msg);
     this.id = id;
     this._context = {};
     if (Error.captureStackTrace) Error.captureStackTrace(this, SyntaxError);

File diff suppressed because it is too large
+ 3 - 0
js/filesaver.min.js


+ 18 - 0
js/iassign-integration-functions.js

@@ -818,4 +818,22 @@ function showInvalidData () {
   $('.dimmer_content_message').css('display', 'block');
   $('.ui.height_100.add_accordion').dimmer('add content', '.dimmer_content_message');
   $('.ui.height_100.add_accordion').dimmer('show');
+  $('.dimmer_content_message button').on('click', function(e) {
+    window.parent.location.reload()
+  })
 }
+
+
+function showInvalidFile () {
+  $('.ui.height_100.add_accordion').dimmer({
+    closable: true
+  });
+  $('.dimmer_content_message h3').html(LocalizedStrings.getUI('text_message_error_upload_file'));
+  $('.dimmer_content_message button').text(LocalizedStrings.getUI('text_message_error_upload_close'));
+  $('.dimmer_content_message').css('display', 'block');
+  $('.ui.height_100.add_accordion').dimmer('add content', '.dimmer_content_message');
+  $('.ui.height_100.add_accordion').dimmer('show');
+  $('.dimmer_content_message button').on('click', function(e) {
+    $('.ui.height_100.add_accordion').dimmer('hide');
+  })
+}

+ 3 - 3
js/io/domConsole.js

@@ -195,7 +195,7 @@ export class DOMConsole {
     // console.debug("Caling appendText");
     const write_time = Date.now();
     this.pending_writes.push(0);
-    await Utils.sleep(5);
+    await Utils.sleep(3);
     this.pending_writes.pop();
     if (this.last_clear >= write_time) {
       return;
@@ -219,7 +219,7 @@ export class DOMConsole {
   async _appendTextLn (text, type, filter = true) {
     const write_time = Date.now();
     this.pending_writes.push(0);
-    await Utils.sleep(5);
+    await Utils.sleep(3);
     this.pending_writes.pop();
     if (this.last_clear >= write_time) {
       return;
@@ -240,7 +240,7 @@ export class DOMConsole {
   async _appendUserInput (text) {
     const write_time = Date.now();
     this.pending_writes.push(0);
-    await Utils.sleep(5);
+    await Utils.sleep(3);
     this.pending_writes.pop();
     if (this.last_clear >= write_time) {
       return;

+ 2 - 2
js/processor/error/runtimeError.js

@@ -1,7 +1,8 @@
 export class RuntimeError extends Error {
   constructor (msg, id) {
-    super(...msg);
+    super(msg);
     this.id = id;
+    this._context = {};
     if (Error.captureStackTrace) Error.captureStackTrace(this, RuntimeError);
   }
 
@@ -13,4 +14,3 @@ export class RuntimeError extends Error {
     this._context = contextObj;
   }
 }
-

+ 2 - 2
js/processor/error/semanticError.js

@@ -1,7 +1,8 @@
 export class SemanticError extends Error {
   constructor (msg, id) {
-    super(...msg);
+    super(msg);
     this.id = id;
+    this._context = {};
     if (Error.captureStackTrace) Error.captureStackTrace(this, SemanticError);
   }
 
@@ -13,4 +14,3 @@ export class SemanticError extends Error {
     this._context = contextObj;
   }
 }
-

+ 2 - 2
js/processor/ivprogProcessor.js

@@ -374,7 +374,7 @@ export class IVProgProcessor {
     this.instruction_count += 1;
     if (this.instruction_count % Config.suspend_threshold == 0) {
       //every Config.suspend_threshold instruction should briefly delay its execution in order to allow the browser to process other things
-      await Utils.sleep(5);
+      await Utils.sleep(3);
     }
 
     // Checks if it must interrupt the execution for some reason
@@ -1038,7 +1038,7 @@ export class IVProgProcessor {
     this.instruction_count += 1;
     if (this.instruction_count % Config.suspend_threshold == 0) {
       //every Config.suspend_threshold instruction should briefly delay its execution in order to allow the browser to process other things
-      await Utils.sleep(5);
+      await Utils.sleep(3);
     }
     if (this.mode === Modes.ABORT) {
       throw LocalizedStrings.getMessage("aborted_execution");

+ 149 - 67
js/processor/lib/lang.js

@@ -1,15 +1,15 @@
-import * as Commands from './../../ast/commands';
-import { Types } from './../../typeSystem/types';
+import * as Commands from "./../../ast/commands";
+import { Types } from "./../../typeSystem/types";
 import * as Parsers from "./../../typeSystem/parsers";
-import { IVProgParser } from '../../ast/ivprogParser';
-import { RealLiteral, IntLiteral, BoolLiteral } from '../../ast/expressions';
-import { Modes } from '../modes';
-import { MultiType } from '../../typeSystem/multiType';
-import { ProcessorErrorFactory } from '../error/processorErrorFactory';
-import { StoreValue } from '../store/value/store_value';
+import { IVProgParser } from "../../ast/ivprogParser";
+import { RealLiteral, IntLiteral, BoolLiteral } from "../../ast/expressions";
+import { Modes } from "../modes";
+import { MultiType } from "../../typeSystem/multiType";
+import { ProcessorErrorFactory } from "../error/processorErrorFactory";
+import { StoreValue } from "../store/value/store_value";
 
 /**
- * 
+ *
  * is_real
  * is_int
  * is_bool
@@ -32,17 +32,23 @@ export function createIsRealFun () {
       }
     } catch (error) {
       // ignore
-     }
+    }
     const temp = new StoreValue(Types.BOOLEAN, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
     return sto;
-  }
+  };
 
-  const block = new Commands.CommandBlock([],  [new Commands.SysCall(isRealFun)]);
-  const func = new Commands.Function('$isReal', Types.BOOLEAN,
-    [new Commands.FormalParameter(Types.STRING, 'str', false)],
-    block);
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(isRealFun)]
+  );
+  const func = new Commands.Function(
+    "$isReal",
+    Types.BOOLEAN,
+    [new Commands.FormalParameter(Types.STRING, "str", false)],
+    block
+  );
   return func;
 }
 
@@ -56,19 +62,22 @@ export function createIsIntFun () {
       if (val instanceof IntLiteral) {
         result = true;
       }
-    } catch { 
+    } catch {
       // ignore
     }
     const temp = new StoreValue(Types.BOOLEAN, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
     return sto;
-  }
+  };
 
-  const block = new Commands.CommandBlock([],  [new Commands.SysCall(isIntFun)]);
-  const func = new Commands.Function('$isInt', Types.BOOLEAN,
-    [new Commands.FormalParameter(Types.STRING, 'str', false)],
-    block);
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(isIntFun)]);
+  const func = new Commands.Function(
+    "$isInt",
+    Types.BOOLEAN,
+    [new Commands.FormalParameter(Types.STRING, "str", false)],
+    block
+  );
   return func;
 }
 
@@ -82,19 +91,25 @@ export function createIsBoolFun () {
       if (val instanceof BoolLiteral) {
         result = true;
       }
-    } catch (error) { 
+    } catch (error) {
       // ignore
     }
     const temp = new StoreValue(Types.BOOLEAN, result);
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
     return sto;
-  }
+  };
 
-  const block = new Commands.CommandBlock([],  [new Commands.SysCall(isBoolFun)]);
-  const func = new Commands.Function('$isBool', Types.BOOLEAN,
-    [new Commands.FormalParameter(Types.STRING, 'str', false)],
-    block);
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(isBoolFun)]
+  );
+  const func = new Commands.Function(
+    "$isBool",
+    Types.BOOLEAN,
+    [new Commands.FormalParameter(Types.STRING, "str", false)],
+    block
+  );
   return func;
 }
 
@@ -115,25 +130,44 @@ export function createCastRealFun () {
         try {
           const result = parser.parseTerm();
           if (result instanceof RealLiteral) {
-            const temp = new StoreValue(Types.REAL, result.value);
+            const temp = new StoreValue(
+              Types.REAL,
+              Parsers.toReal(result.value)
+            );
             sto.insertStore("$", temp);
             sto.mode = Modes.RETURN;
             return sto;
           }
         } catch (error) {
           // ignore
-         }
+        }
       }
     }
     const typeStringInfoArray = Types.REAL.stringInfo();
     const typeInfo = typeStringInfoArray[0];
-    throw ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim);
-  }
+    throw ProcessorErrorFactory.invalid_type_conversion(
+      value,
+      typeInfo.type,
+      typeInfo.dim
+    );
+  };
 
-  const block = new Commands.CommandBlock([],  [new Commands.SysCall(castRealFun)]);
-  const func = new Commands.Function('$castReal', Types.REAL,
-    [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.STRING]), 'val', false)],
-    block);
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(castRealFun)]
+  );
+  const func = new Commands.Function(
+    "$castReal",
+    Types.REAL,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.INTEGER, Types.STRING]),
+        "val",
+        false
+      ),
+    ],
+    block
+  );
   return func;
 }
 
@@ -144,13 +178,19 @@ export function createCastIntFun () {
     switch (val.type.ord) {
       case Types.REAL.ord: {
         value = value.toNumber();
-        const temp = new StoreValue(Types.INTEGER, Math.floor(value));
+        const temp = new StoreValue(
+          Types.INTEGER,
+          Parsers.toInt(Math.floor(value))
+        );
         sto.insertStore("$", temp);
         sto.mode = Modes.RETURN;
         return sto;
       }
       case Types.CHAR.ord: {
-        const temp = new StoreValue(Types.INTEGER, value.charCodeAt(0));
+        const temp = new StoreValue(
+          Types.INTEGER,
+          Parsers.toInt(value.charCodeAt(0))
+        );
         sto.insertStore("$", temp);
         sto.mode = Modes.RETURN;
         return sto;
@@ -160,32 +200,51 @@ export function createCastIntFun () {
         try {
           const result = parser.parseTerm();
           if (result instanceof IntLiteral) {
-            const temp = new StoreValue(Types.INTEGER, result.value);
+            const temp = new StoreValue(
+              Types.INTEGER,
+              Parsers.toInt(result.value)
+            );
             sto.insertStore("$", temp);
             sto.mode = Modes.RETURN;
             return sto;
           }
-        } catch (error) { 
+        } catch (error) {
           // ignore
         }
       }
     }
     const typeStringInfoArray = Types.INTEGER.stringInfo();
     const typeInfo = typeStringInfoArray[0];
-    throw ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim);
-  }
+    throw ProcessorErrorFactory.invalid_type_conversion(
+      value,
+      typeInfo.type,
+      typeInfo.dim
+    );
+  };
 
-  const block = new Commands.CommandBlock([],  [new Commands.SysCall(castIntFun)]);
-  const func = new Commands.Function('$castInt', Types.INTEGER,
-    [new Commands.FormalParameter(new MultiType([Types.REAL, Types.STRING]), 'val', false)],
-    block);
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(castIntFun)]
+  );
+  const func = new Commands.Function(
+    "$castInt",
+    Types.INTEGER,
+    [
+      new Commands.FormalParameter(
+        new MultiType([Types.REAL, Types.STRING, Types.CHAR]),
+        "val",
+        false
+      ),
+    ],
+    block
+  );
   return func;
 }
 
 export function createCastBoolFun () {
   const castBoolFun = async (sto, _) => {
     const str = sto.applyStore("str");
-    const value = str.get(); 
+    const value = str.get();
     const parser = IVProgParser.createParser(value);
     try {
       const val = parser.parseTerm();
@@ -195,51 +254,74 @@ export function createCastBoolFun () {
         sto.mode = Modes.RETURN;
         return sto;
       }
-    } catch (error) { 
+    } catch (error) {
       // ignore
     }
     const typeStringInfoArray = Types.BOOLEAN.stringInfo();
     const typeInfo = typeStringInfoArray[0];
-    throw ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim);
-  }
+    throw ProcessorErrorFactory.invalid_type_conversion(
+      value,
+      typeInfo.type,
+      typeInfo.dim
+    );
+  };
 
-  const block = new Commands.CommandBlock([],  [new Commands.SysCall(castBoolFun)]);
-  const func = new Commands.Function('$castBool', Types.BOOLEAN,
-    [new Commands.FormalParameter(Types.STRING, 'str', false)],
-    block);
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(castBoolFun)]
+  );
+  const func = new Commands.Function(
+    "$castBool",
+    Types.BOOLEAN,
+    [new Commands.FormalParameter(Types.STRING, "str", false)],
+    block
+  );
   return func;
 }
 
 export function createCastStringFun () {
   const castStringFun = async function (store, _) {
-    const val = store.applyStore('str');
+    const val = store.applyStore("str");
     const result = Parsers.convertToString(val.get(), val.type);
     const temp = new StoreValue(Types.STRING, result);
     store.insertStore("$", temp);
     store.mode = Modes.RETURN;
     return store;
-  }
-  const block = new Commands.CommandBlock([], [new Commands.SysCall(castStringFun)]);
-  const func = new Commands.Function('$castString', Types.STRING,
-    [new Commands.FormalParameter(Types.ALL, 'str', false)],
-    block);
+  };
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(castStringFun)]
+  );
+  const func = new Commands.Function(
+    "$castString",
+    Types.STRING,
+    [new Commands.FormalParameter(Types.ALL, "str", false)],
+    block
+  );
   return func;
 }
 
 export function createCastCharFun () {
   const castCharFun = (store, _) => {
-    const valSV = store.applyStore('charCode');
+    const valSV = store.applyStore("charCode");
     // Force the int value to the range [0, 255]
-    const value = valSV.get().toNumber() & 0xFF;
+    const value = valSV.get().toNumber() & 0xff;
     const result = String.fromCharCode(value);
     const temp = new StoreValue(Types.CHAR, result);
     store.insertStore("$", temp);
     store.mode = Modes.RETURN;
     return store;
-  }
-  const block = new Commands.CommandBlock([], [new Commands.SysCall(castCharFun)]);
-  const func = new Commands.Function('$castChar', Types.CHAR,
-    [new Commands.FormalParameter(Types.INTEGER, 'charCode', false)],
-    block);
+  };
+  const block = new Commands.CommandBlock(
+    [],
+    [new Commands.SysCall(castCharFun)]
+  );
+  const func = new Commands.Function(
+    "$castChar",
+    Types.CHAR,
+    [new Commands.FormalParameter(Types.INTEGER, "charCode", false)],
+    block
+  );
   return func;
-}
+}
+

+ 7 - 4
js/processor/semantic/semanticAnalyser.js

@@ -573,8 +573,8 @@ export class SemanticAnalyser {
       const access_type = typeInfo.type;
 
       let compatible = false;
+      let type = access_type;
       if (exp_type instanceof MultiType) {
-        let type = access_type;
         if (access_type.dimensions - used_dims == 0) {
           type = access_type.innerType;
         } else {
@@ -588,9 +588,12 @@ export class SemanticAnalyser {
         compatible = access_type.canAccept(exp_type, used_dims);
       }
       if (!compatible) {
+        if (0 === access_type.dimensions - used_dims) {
+          type = access_type.innerType; // enable a valid attempt to cast real <--> integer
+        }
         if (
           !Config.enable_type_casting ||
-          !Store.canImplicitTypeCast(access_type, exp_type)
+          !Store.canImplicitTypeCast(type, exp_type)
         ) {
           const access_type_string_info = access_type.stringInfo();
           const access_type_info = access_type_string_info[0];
@@ -918,7 +921,7 @@ export class SemanticAnalyser {
             (!resultType.isCompatible(Types.INTEGER) &&
               !resultType.isCompatible(Types.REAL)) ||
             formalParam.type.isCompatible(Types.INTEGER) ||
-              formalParam.type.isCompatible(Types.REAL)
+            formalParam.type.isCompatible(Types.REAL)
           ) {
             throw ProcessorErrorFactory.invalid_parameter_type_full(
               fun.name,
@@ -935,7 +938,7 @@ export class SemanticAnalyser {
             (!resultType.isCompatible(Types.INTEGER) &&
               !resultType.isCompatible(Types.REAL)) ||
             formalParam.type.isCompatible(Types.INTEGER) ||
-              formalParam.type.isCompatible(Types.REAL)
+            formalParam.type.isCompatible(Types.REAL)
           ) {
             throw ProcessorErrorFactory.invalid_parameter_type_full(
               fun.name,

+ 5 - 6
js/util/config.ts

@@ -2,8 +2,7 @@ interface ConfigInterface {
   [id: string]: unknown;
 }
 
-class ConfigObject implements ConfigInterface{
-
+class ConfigObject implements ConfigInterface {
   public decimalPlaces: number;
   public intConvertRoundMode: number;
   public default_lang: string;
@@ -16,10 +15,10 @@ class ConfigObject implements ConfigInterface{
   constructor () {
     this.decimalPlaces = 8;
     this.intConvertRoundMode = 2;
-    this.default_lang = 'pt';
+    this.default_lang = "pt";
     this.enable_type_casting = true;
     this.idle_input_interval = 5000;
-    this.suspend_threshold = 100;
+    this.suspend_threshold = 1000;
     // this.max_instruction_count = 350250; - automated evaluation limit
     this.max_instruction_count = Number.MAX_SAFE_INTEGER;
   }
@@ -27,7 +26,7 @@ class ConfigObject implements ConfigInterface{
   setConfig (opts: object): void {
     const otherConfig = opts as ConfigInterface;
     for (const key in otherConfig) {
-      if(Object.prototype.hasOwnProperty.call(this, key)){
+      if (Object.prototype.hasOwnProperty.call(this, key)) {
         this[key] = otherConfig[key];
       }
     }
@@ -35,4 +34,4 @@ class ConfigObject implements ConfigInterface{
 }
 
 const config = new ConfigObject();
-export const Config = config;
+export const Config = config;

+ 11 - 2
js/visualUI/code_generator.js

@@ -650,7 +650,7 @@ export function elementExpressionCode (expression_obj) {
           ret += " <= ";
           break;
         case Models.EXPRESSION_TYPES.write_sep:
-          ret += ", ";
+          ret += ', " ", ';
           break;
       }
     } else {
@@ -719,10 +719,16 @@ export function variableValueMenuCode (variable_obj, is_return = false) {
         variable_obj.content.dimensions == 1 &&
         variable_obj.dimensions != 1
       ) {
-        ret += " [ " + variableValueMenuCode(variable_obj.column) + " ] ";
+          ret += " [ " + variableValueMenuCode(variable_obj.column) + " ] ";
       }
 
       if (
+        variable_obj.content.dimensions == 2 &&
+        variable_obj.dimensions != 2 && 
+        variable_obj.reference_dimensions == 1
+      ) {
+        ret += " [ " + variableValueMenuCode(variable_obj.row) + " ] ";
+      } else if (
         variable_obj.content.dimensions == 2 &&
         variable_obj.dimensions != 2
       ) {
@@ -819,6 +825,9 @@ function parametersCode (parameter_obj) {
       ret += " " + LocalizedStrings.getUI("type_char") + " ";
       break;
   }
+  if (parameter_obj.reference)
+    ret += "&";
+
   ret += parameter_obj.name + "";
 
   if (parameter_obj.dimensions == 1) {

+ 108 - 19
js/visualUI/commands/variable_value_menu.js

@@ -21,6 +21,7 @@ export function renderMenu (
   size_field = 2,
   expression_element
 ) {
+
   // Verificar se o objeto atual trata-se de uma chamada de função e conferir se possui a quantidade correta de parâmetros
   // Caso não possua, tem que adicionar as variáveis que servirão de parâmetros:
   if (ref_object.function_called) {
@@ -49,6 +50,35 @@ export function renderMenu (
     }
   }
 
+  // Verificar agora, quando trata-se de chamada de função, se a passagem de parâmetro é
+  // por referência ou por cópia:
+  var index_references = [];
+  if (ref_object.function_called) {
+    if (ref_object.function_called.parameters_list) {
+      for (var i = 0; i < ref_object.function_called.parameters_list.length; i++) {
+        if (ref_object.function_called.parameters_list[i].reference) {
+          index_references.push(i)
+          ref_object.parameters_list[i].reference = true
+          ref_object.parameters_list[i].variable_and_value = VAR_OR_VALUE_TYPES.only_variable;
+          if (ref_object.parameters_list[i].column)
+            ref_object.parameters_list[i].column.reference_parent = true
+          if (ref_object.parameters_list[i].row)
+            ref_object.parameters_list[i].row.reference_parent = true
+        }
+        else {
+          ref_object.parameters_list[i].reference = false;
+          ref_object.parameters_list[i].variable_and_value = VAR_OR_VALUE_TYPES.all;
+          if (ref_object.parameters_list[i].column)
+            ref_object.parameters_list[i].column.reference_parent = false
+          if (ref_object.parameters_list[i].row)
+            ref_object.parameters_list[i].row.reference_parent = false
+        }
+
+        ref_object.parameters_list[i].reference_dimensions = ref_object.function_called.parameters_list[i].dimensions
+      } 
+    }
+  }
+
   let menu_var_or_value =
     '<div class="ui dropdown menu_var_or_value_dom" data-varmenu="true"><div class="text"></div><i class="dropdown icon"></i><div class="menu">';
 
@@ -227,6 +257,12 @@ export function renderMenu (
 }
 
 function appendSelectText (ref_object, menu_var_or_value) {
+  // if (ref_object.reference_parent) {
+  //   menu_var_or_value
+  //       .find(".text")
+  //       .append("<i>Opcional</i>");
+  //   return;
+  // }
   switch (ref_object.variable_and_value) {
     case VAR_OR_VALUE_TYPES.only_variable:
       menu_var_or_value
@@ -620,8 +656,11 @@ function variableValueMenuCode (
         variable_obj.content.name +
         "</span>";
 
-      variable_render +=
-        ' <span>[ </span> <div class="column_container"></div> <span> ]</span>';
+      if (variable_obj.reference_dimensions >= 1)
+        variable_render += '';
+      else
+        variable_render +=
+          ' <span>[ </span> <div class="column_container"></div> <span> ]</span>';
 
       variable_render += "</div>";
 
@@ -688,13 +727,16 @@ function variableValueMenuCode (
       });
 
       if (!variable_obj.column) {
-        variable_obj.column = new Models.VariableValueMenu(
+        var temp = new Models.VariableValueMenu(
           VAR_OR_VALUE_TYPES.all,
           null,
           null,
           null,
           true
         );
+        if (variable_obj.reference)
+          temp.reference_parent = true
+        variable_obj.column = temp;
       }
 
       variableValueMenuCode(
@@ -713,11 +755,13 @@ function variableValueMenuCode (
         '<div class="variable_rendered"> <span class="var_name">' +
         variable_obj.content.name +
         "</span>";
-
+      
       variable_render +=
         ' <span>[ </span> <div class="row_container"></div> <span> ]</span>';
-      variable_render +=
-        ' <span>[ </span> <div class="column_container"></div> <span> ] </span>';
+
+      if (variable_obj.reference_dimensions == 0)
+        variable_render +=
+          ' <span>[ </span> <div class="column_container"></div> <span> ] </span>';
 
       variable_render += "</div>";
 
@@ -784,22 +828,32 @@ function variableValueMenuCode (
       });
 
       if (!variable_obj.column) {
-        variable_obj.column = new Models.VariableValueMenu(
+        var temp = new Models.VariableValueMenu(
           VAR_OR_VALUE_TYPES.all,
           null,
           null,
           null,
           true
         );
+
+        if (variable_obj.reference)
+          temp.reference_parent = true
+
+        variable_obj.column = temp
       }
       if (!variable_obj.row) {
-        variable_obj.row = new Models.VariableValueMenu(
+        var temp = new Models.VariableValueMenu(
           VAR_OR_VALUE_TYPES.all,
           null,
           null,
           null,
           true
         );
+
+        if (variable_obj.reference)
+          temp.reference_parent = true
+
+        variable_obj.row = temp
       }
 
       variableValueMenuCode(
@@ -810,14 +864,19 @@ function variableValueMenuCode (
         menu_var_or_value,
         expression_element
       );
-      variableValueMenuCode(
-        command,
-        variable_obj.column,
-        $(variable_render.find(".column_container")),
-        function_obj,
-        menu_var_or_value,
-        expression_element
-      );
+
+      if (variable_obj.reference_dimensions == 1) {
+        variable_obj.column = null
+      } else {
+        variableValueMenuCode(
+          command,
+          variable_obj.column,
+          $(variable_render.find(".column_container")),
+          function_obj,
+          menu_var_or_value,
+          expression_element
+        );
+      }
     } else {
       variable_render =
         '<div class="variable_rendered"> <span class="var_name">' +
@@ -1346,6 +1405,16 @@ function openInputToFunction (
           true
         );
       }
+
+      if (function_selected.parameters_list[j].reference == true) {
+        temp.reference = true;
+        temp.variable_and_value = VAR_OR_VALUE_TYPES.only_variable;
+      } else {
+        temp.reference = false;
+        temp.variable_and_value = VAR_OR_VALUE_TYPES.all;
+      }
+      temp.reference_dimensions = function_selected.parameters_list[j].dimensions
+      
       ref_object.parameters_list.push(temp);
       renderMenu(
         command,
@@ -1525,14 +1594,17 @@ function openInputToVariable (
     "</span>";
 
   if (variable_selected.dimensions == 1 && ref_object.dimensions != 1) {
+    
     variable_render +=
       ' <span>[ </span> <div class="column_container"></div> <span> ]</span>';
   }
   if (variable_selected.dimensions == 2 && ref_object.dimensions != 2) {
     variable_render +=
       ' <span>[ </span> <div class="row_container"></div> <span> ]</span> ';
+    
     variable_render +=
       ' <span>[ </span> <div class="column_container"></div> <span> ]</span>';
+    
   }
 
   variable_render += "</div>";
@@ -1542,13 +1614,18 @@ function openInputToVariable (
   dom_object.append(variable_render);
 
   if (variable_selected.dimensions == 1 && ref_object.dimensions != 1) {
-    ref_object.column = new Models.VariableValueMenu(
+    var temp = new Models.VariableValueMenu(
       VAR_OR_VALUE_TYPES.all,
       null,
       null,
       null,
       true
     );
+    if (ref_object.reference)
+          temp.reference_parent = true
+
+    ref_object.column = temp
+
     renderMenu(
       command,
       ref_object.column,
@@ -1559,13 +1636,19 @@ function openInputToVariable (
     );
   }
   if (variable_selected.dimensions == 2 && ref_object.dimensions != 2) {
-    ref_object.row = new Models.VariableValueMenu(
+    var temp = new Models.VariableValueMenu(
       VAR_OR_VALUE_TYPES.all,
       null,
       null,
       null,
       true
     );
+
+    if (ref_object.reference)
+          temp.reference_parent = true
+
+    ref_object.row = temp
+
     renderMenu(
       command,
       ref_object.row,
@@ -1575,13 +1658,19 @@ function openInputToVariable (
       expression_element
     );
 
-    ref_object.column = new Models.VariableValueMenu(
+    var temp = new Models.VariableValueMenu(
       VAR_OR_VALUE_TYPES.all,
       null,
       null,
       null,
       true
     );
+
+    if (ref_object.reference)
+          temp.reference_parent = true
+
+    ref_object.column = temp
+    
     renderMenu(
       command,
       ref_object.column,

+ 201 - 3
js/visualUI/functions.js

@@ -395,7 +395,8 @@ export function renderFunction (function_obj) {
   for (var j = 0; j < function_obj.commands.length; j++) {
     CommandsManagement.renderCommand(function_obj.commands[j], $(appender.find('.commands_list_div')[0]), 3, function_obj);
   }
-  $('.minimize_function_button').popup({
+
+  appender.find('.minimize_function_button').popup({
     content : LocalizedStrings.getUI("tooltip_hide_function"),
     delay: {
       show: 750,
@@ -403,6 +404,129 @@ export function renderFunction (function_obj) {
     }
   });
 
+  appender.find('.move_function').popup({
+    content : LocalizedStrings.getUI("btn_drag_and_drop_function"),
+    delay: {
+      show: 1000,
+      hide: 0
+    }
+  });
+
+  appender.find('.remove_function_button').popup({
+    content : LocalizedStrings.getUI("btn_delete_function"),
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+  
+  appender.find('.add_var_button_function').popup({
+    content : LocalizedStrings.getUI("btn_add_var"),
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="attribution"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_attribution"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="functioncall"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_call_function"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="iftrue"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_if_else"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="comment"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_comments"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="reader"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_read"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="writer"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_write"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="repeatNtimes"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_repeat_n_times"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="whiletrue"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_repeat_whiletrue"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="dowhiletrue"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_repeat_dowhiletrue"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="switch"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_repeat_switch"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  appender.find('a[data-command="return"]').popup({
+    content : LocalizedStrings.getUI("tooltip_menu_repeat_return"),
+    position: 'right center',
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
   var function_index = program.functions.indexOf(function_obj);
 
   Sortable.create(appender.find(".variables_list_div")[0], {
@@ -740,6 +864,14 @@ export function initVisualUI () {
     runCode();
   });
 
+  $('#download_file_button').on('click', function () {
+    downloadFile();
+  });
+
+  $('#upload_file_button').on('click', function () {
+    $('#ivph_file').click().off('change').change(uploadFile);
+  });
+
   $('#stop_button').on('click', function () {
     showRunButton();
     stopExecution();
@@ -1127,6 +1259,11 @@ function renderParameter (function_obj, parameter_obj, function_container) {
 
   ret += '<div class="ui label function_name_parameter pink"><i class="ui icon ellipsis vertical inverted"></i>';
 
+  if (parameter_obj.reference)
+    ret += '<input type="checkbox" checked class="by_reference">';
+  else 
+    ret += '<input type="checkbox" class="by_copy">';
+
   ret += '<div class="ui dropdown parameter_type">';
 
   if (parameter_obj.dimensions > 0) {
@@ -1151,7 +1288,6 @@ function renderParameter (function_obj, parameter_obj, function_container) {
       ret += '<div class="item ' + (parameter_obj.type == tm.toLowerCase() && parameter_obj.dimensions == 0 ? ' selected ' : '') + '" data-type="'+tm+'" >'+LocalizedStrings.getUI(`type_${tm.toLowerCase()}`)+'</div>';
   }
 
-
   ret += '<div class="item ' + (parameter_obj.dimensions == 1 ? ' selected ' : '') + '">'
     + '<i class="dropdown icon"></i>' + LocalizedStrings.getUI('vector')
     +  '<div class="menu">';
@@ -1209,6 +1345,27 @@ function renderParameter (function_obj, parameter_obj, function_container) {
     enableNameParameterUpdate(parameter_obj, ret, function_obj);
   });
 
+  ret.find('input:checkbox').change(function() {
+    parameter_obj.reference = this.checked
+    AlgorithmManagement.renderAlgorithm();
+  });
+
+  ret.find('.by_reference').popup({
+    content : LocalizedStrings.getUI("text_parameter_reference"),
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+  ret.find('.by_copy').popup({
+    content : LocalizedStrings.getUI("text_parameter_copy"),
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
   return ret;
 }
 
@@ -1479,4 +1636,45 @@ function stopExecution () {
     return;
   }
   proc.mode = Modes.ABORT;
-}
+}
+
+function downloadFile() {
+  
+  var contentToSend = '{}\n::algorithm::';
+
+  if (settingsProgrammingTypes == "textual") {
+    contentToSend +=  ivprogCore.CodeEditor.getCode();
+  } else {
+    contentToSend += JSON.stringify(window.program_obj, function(key, value) {
+      if (key == 'dom_object') {
+          return;
+      }
+      return value;
+    });
+  }
+
+  var date = new Date(); 
+  var temp = date.toISOString().split('T')[0] + "_" + date.toTimeString().split(' ')[0].replaceAll(':', '-');
+  var blob = new Blob([contentToSend],
+                { type: "text/plain;charset=utf-8" });
+  
+  saveAs(blob, "ivprog-exported_" + temp + ".ivph");
+}
+
+function uploadFile (evt) {
+    var oFReader = new FileReader();
+    oFReader.readAsText(document.getElementById("ivph_file").files[0]);
+    oFReader.onload = function (oFREvent) {
+      var txt = oFREvent.target.result;
+      try {
+
+        previousContent = txt;
+        prepareActivityToStudent(txt);
+        window.renderAlgorithm();
+        $('.assessment_button').addClass('disabled');
+      }
+      catch (e) {
+        showInvalidFile();
+      }
+    };
+  }

+ 16 - 0
js/visualUI/globals.js

@@ -490,6 +490,22 @@ function addHandlers (global_container) {
 		removeGlobal(global_var, global_container);
 	});
 
+	global_container.find( ".ellipsis" ).popup({
+    content : LocalizedStrings.getUI("tooltip_move_var"),
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+	global_container.find( ".remove_global" ).popup({
+    content : LocalizedStrings.getUI("tooltip_remove_var"),
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
 }
 
 function updateColumnsAndRowsText (global_container, global_var) {

+ 3 - 1
js/visualUI/ivprog_elements.js

@@ -74,7 +74,8 @@ export class Variable {
     dimensions = 0,
     is_constant = false,
     rows = 0,
-    columns = 0
+    columns = 0,
+    reference = false
   ) {
     this.type = type;
     this.name = name;
@@ -83,6 +84,7 @@ export class Variable {
     this.is_constant = is_constant;
     this.rows = rows;
     this.columns = columns;
+    this.reference = reference;
   }
 }
 

+ 17 - 1
js/visualUI/variables.js

@@ -5,7 +5,7 @@ import * as Utils from './utils';
 import { registerUserEvent, registerSystemEvent, ActionTypes } from "./../services/userLog";
 import { isValidIdentifier } from "./../util/utils";
 
-var counter_new_variables = 0;
+var counter_new_variables = 0;	
 
 export function addVariable (function_obj, function_container, is_in_click = false) {
 	var new_var = new Models.Variable(Types.INTEGER, LocalizedStrings.getUI('new_variable') + '_' + counter_new_variables, 0);
@@ -120,6 +120,22 @@ function addHandlers (variable_obj, variable_container, function_obj) {
 		removeVariable(variable_obj, variable_container, function_obj.name);
 	});
 
+	variable_container.find( ".ellipsis" ).popup({
+    content : LocalizedStrings.getUI("tooltip_move_var"),
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
+	variable_container.find( ".remove_variable" ).popup({
+    content : LocalizedStrings.getUI("tooltip_remove_var"),
+    delay: {
+      show: 750,
+      hide: 0
+    }
+  });
+
 }
 
 export function renderVariable (function_container, new_var, function_obj) {

File diff suppressed because it is too large
+ 465 - 476
package-lock.json


+ 1 - 1
package.json

@@ -47,7 +47,7 @@
   "dependencies": {
     "@babel/runtime": "^7.10.2",
     "antlr4": "^4.7.2",
-    "codemirror": "^5.54.0",
+    "codemirror": "^5.64.0",
     "decimal.js": "^10.2.0",
     "line-i18n": "git+http://200.144.254.107/git/LInE/line-i18n.git",
     "melanke-watchjs": "^1.5.0"

+ 8 - 3
templates/index.html

@@ -2,6 +2,7 @@
 <html>
   <head>
     <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <meta http-equiv="Pragma" content="no-cache">
     <title></title>
     <link href="css/roboto.css" type="text/css" rel="stylesheet">
     <link rel="stylesheet" href="css/semantic.min.css"/>
@@ -15,10 +16,14 @@
     <script src="js/jquery-ui.min.js"></script>
     <script src="js/semantic.min.js"></script>
     <script src="js/Sortable.js"></script>
+    <script src="js/filesaver.min.js"></script>
     <script src="js/iassign-integration-functions.js"></script>
+
   </head>
   <body>
 
+    <input type="file" name="ivph_file" id="ivph_file" style="position:absolute;margin-top: -500px !important;">
+
     <div class="ui height_100 add_accordion" id="ui_main_div">
 
       <div class="title default_visual_title">
@@ -40,10 +45,10 @@
           <a class="item textual_coding_button">
             <i class="code icon"></i>
           </a>
-          <a class="item upload_file_button disabled">
+          <a class="item upload_file_button" id="upload_file_button">
             <i class="upload icon"></i>
           </a>
-          <a class="item download_file_button disabled">
+          <a class="item download_file_button" id="download_file_button">
             <i class="download icon"></i>
           </a>
           <a class="item undo_button disabled">
@@ -111,7 +116,7 @@
     </div>
     <div class="dimmer_content_message">
       <h3>Aconteceu um erro ao processar a atividade. <br> Recarregue a página para tentar novamente.</h3>
-      <button class="positive ui button" onclick="window.parent.location.reload()">Recarregar</button>
+      <button class="positive ui button">Recarregar</button>
     </div>
     <script src="js/iassign-integration-functions.js"></script>
   </div>

+ 1 - 0
webpack.config.js

@@ -100,6 +100,7 @@ module.exports = {
       { from: "js/jquery.min.js", to: path.resolve(__dirname, "build/js") },
       { from: "js/jquery-ui.min.js", to: path.resolve(__dirname, "build/js") },
       { from: "js/semantic.min.js", to: path.resolve(__dirname, "build/js") },
+      { from: "js/filesaver.min.js", to: path.resolve(__dirname, "build/js") },
       {
         from: "css/semantic.min.css",
         to: path.resolve(__dirname, "build/css"),