Browse Source

Merge branch 'newWriteFunction' of LInE/iVProg into master

GitAdmin 4 years ago
parent
commit
e422592f42

+ 2 - 2
.eslintignore

@@ -1,3 +1,3 @@
-/js/visualUI/
+# /js/visualUI/
 /js/Sortable.js
-/js/iassign-integration-functions.js
+/js/iassign-integration-functions.js

+ 36 - 32
.eslintrc.json

@@ -1,34 +1,38 @@
 {
-    "env": {
-        "browser": true,
-        "es6": true,
-        "node": true
-    },
-    "parser": "@typescript-eslint/parser",
-    "plugins": ["@typescript-eslint"],
-    "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
-    "globals": {
-        "Atomics": "readonly",
-        "SharedArrayBuffer": "readonly"
-    },
-    "parserOptions": {
-        "ecmaVersion": 2018,
-        "sourceType": "module"
-    },
-    "rules": {
-        "camelcase": "off",
-        "no-unused-vars": "off",
-        "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
-        "@typescript-eslint/camelcase": "off"
+  "env": {
+    "browser": true,
+    "es6": true,
+    "node": true
+  },
+  "parser": "@typescript-eslint/parser",
+  "plugins": ["@typescript-eslint"],
+  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
+  "globals": {
+    "Atomics": "readonly",
+    "SharedArrayBuffer": "readonly"
+  },
+  "parserOptions": {
+    "ecmaVersion": 2018,
+    "sourceType": "module"
+  },
+  "rules": {
+    "camelcase": "off",
+    "no-unused-vars": "off",
+    "@typescript-eslint/no-unused-vars": [
+      "error",
+      { "argsIgnorePattern": "^_" }
+    ],
+    "@typescript-eslint/camelcase": "off",
+    "space-before-function-paren": ["error", "always"]
+  },
+  "overrides": [
+    {
+      "files": ["*.js", "*.jsx"],
+      "rules": {
+        "@typescript-eslint/explicit-member-accessibility": 0,
+        "@typescript-eslint/explicit-function-return-type": 0
+      }
     }
-    ,
-    "overrides": [
-        {
-            "files": ["*.js", "*.jsx"],
-            "rules": {
-                "@typescript-eslint/explicit-member-accessibility": 0,
-                "@typescript-eslint/explicit-function-return-type": 0
-            }
-        }
-    ]    
-}
+  ]
+}
+

+ 6 - 0
css/ivprog-visual-1.0.css

@@ -1078,3 +1078,9 @@ div.ui.checkbox.transition.visible {
 .pass_button button {
 	padding-bottom: 2px;
 }
+
+/* Write newline button*/
+.ivprog_newline_btn {
+  position: absolute;
+  height: 32px;
+}

+ 4 - 4
grammar/pt/ivprog.g4

@@ -27,7 +27,7 @@ RK_INTEGER
 
 RK_CHARACTER
   : 'caractere'
-  ;    
+  ;
 
 RK_SWITCH
   : 'escolha'
@@ -51,7 +51,7 @@ RK_FUNCTION
 
 RK_RETURN
   : 'devolva'
-  ;  
+  ;
 
 RK_FOR
   : 'para'
@@ -215,7 +215,7 @@ fragment ExponentPart
 STRING
   : '"' STRING_CHARACTER* '"'
   ;
-    
+
 fragment STRING_CHARACTER //String as defined at https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
   : ~["\\\r\n]
   | ESC_SEQ
@@ -225,7 +225,7 @@ CHARACTER //Character as defined at https://github.com/antlr/grammars-v4/blob/ma
   : '\'' ( ESC_SEQ | ~['\\\r\n]) '\''
   ;
 
-WHITESPACE 
+WHITESPACE
   : ( ' ' | '\t') -> skip
   ;
 

+ 1 - 1
i18n/message.csv

@@ -7,6 +7,6 @@ assessment-empty-expected-tooltip,A saída gerada foi além do esperado,The gene
 assessment-empty-generated-tooltip,O programa não gerou saídas suficientes,The program did not generate enough outputs," "
 testcase_autogen_unused_input,O caso de teste $0 possui mais entradas do que as leituras feitas no programa.,The test case $0 has more inputs than output than the number of reads present in the algorithm.," "
 testcase_autogen_empty,O caso de teste $0 não gerou qualquer saída.,The test case $0 did not generate any output.," "
-success_execution,Programa executado com sucesso!,Program executed successfully!,
+success_execution,Execução do programa finalizada!,Program execution finished!,
 aborted_execution,A execução do programa foi interrompida!,Program execution was aborted!,
 unexpected_execution_error,Erro inesperado durante a execução do programa.,Unexpected error during program execution.,

+ 4 - 1
i18n/ui.csv

@@ -137,6 +137,9 @@ text_for_from,de,from,
 text_for_to,até,to,
 text_for_pass,passo,pass,
 text_relational_expression,Relacionais,Relational,
+write_command_newline_on,Quebra de linha ativada, Line break is on,
+write_command_newline_off, Quebra de linha desativada, Line break is off,
+write_seprator_menu_text,Vírgula,Comma,
 initial_program_code,programa {\n\n\t\tfuncao vazio inicio () {\n\t\t\t// Inicie seu codigo aqui!\n\t\t}\n},program {\n\n\t\tfunction void main () {\n\t\t\t// Start your code here!\n\t\t}\n},
 type_char,caractere,char,""
-charvar_default_value,A,A,A
+charvar_default_value,A,A,A

File diff suppressed because it is too large
+ 1 - 0
img/new_line.svg


File diff suppressed because it is too large
+ 1 - 0
img/no_new_line.svg


+ 2 - 1
js/ast/commands/formalParameter.js

@@ -1,9 +1,10 @@
 export class FormalParameter {
 
-  constructor (type, id, byRef = false) {
+  constructor (type, id, byRef = false, variadic = false) {
     this.type = type;
     this.id = id;
     this.byRef = byRef;
+    this.variadic = variadic;
     this._sourceInfo = null;
   }
 

+ 12 - 1
js/ast/commands/function.js

@@ -2,6 +2,13 @@ import { Types } from './../../typeSystem/types';
 
 export class Function {
 
+  /**
+   * 
+   * @param {string} name 
+   * @param {import('./../../typeSystem/itype').IType} returnType 
+   * @param {import('./formalParameter').FormalParameter[]} formalParameters 
+   * @param {import('./commandBlock').CommandBlock} commandBlock 
+   */
   constructor(name, returnType, formalParameters, commandBlock) {
     this.name = name;
     this.returnType = returnType;
@@ -28,5 +35,9 @@ export class Function {
 
 	get sourceInfo () {
 		return this._sourceInfo;
-	}
+  }
+  
+  hasVariadic () {
+    return this.formalParameters.some( p => p.variadic);
+  }
 }

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

@@ -3,6 +3,11 @@ import { LanguageDefinedFunction } from '../../processor/definedFunctions';
 
 export class FunctionCall extends Expression {
 
+	/**
+	 * 
+	 * @param {string} id 
+	 * @param {Expression[]} actualParameters 
+	 */
 	constructor (id, actualParameters) {
 		super();
 		this.id = id;

+ 61 - 10
js/io/domConsole.js

@@ -94,6 +94,7 @@ export class DOMConsole {
       this._appendUserInput(text);
       this.input.value = '';
       this.inputSpan.innerHTML = '';
+      this.currentLine = null;
     }
   }
 
@@ -169,19 +170,43 @@ export class DOMConsole {
     this.anyKey = false;
   }
 
-  write (text) {
-    this._appendText(text, DOMConsole.USER);
+  write (text, newLine = false) {
+    this._appendText(text, DOMConsole.USER, newLine);
   }
 
   info (text) {
-    this._appendText(text, DOMConsole.INFO, false);
+    this._appendTextLn(text, DOMConsole.INFO);
   }
 
   err (text) {
-    this._appendText(text, DOMConsole.ERR, false);
+    this._appendTextLn(text, DOMConsole.ERR);
   }
 
-  async _appendText (text, type, filter = true) {
+  async _appendText (text, type, newLine = false) {
+    const write_time = Date.now();
+    this.pending_writes.push(0);
+    await Utils.sleep(5);
+    this.pending_writes.pop();
+    if (this.last_clear >= write_time) {
+      return;
+    }
+    
+    if (this.currentLine == null) {
+      const divClass = this.getClassForType(type);
+      const textDiv = document.createElement('div');
+      textDiv.classList.add(divClass);
+      this.termDiv.insertBefore(textDiv, this.inputDiv);
+      this.currentLine = textDiv
+    }
+    this.currentLine.innerHTML += this.getOutputText(text);
+    if (newLine) {
+      console.debug("append newline");
+      this.currentLine = null;
+    }
+    this.scrollTerm();
+  }
+
+  async _appendTextLn (text, type, filter = true) {
     const write_time = Date.now();
     this.pending_writes.push(0);
     await Utils.sleep(5);
@@ -197,6 +222,7 @@ export class DOMConsole {
     else
       textDiv.innerHTML = `<span>${text}</span>`;
     this.termDiv.insertBefore(textDiv, this.inputDiv);
+    this.currentLine = null;
     this.scrollTerm();
   }
 
@@ -213,6 +239,7 @@ export class DOMConsole {
     textDiv.innerHTML = this.getUserInputText(text);
     textDiv.classList.add(divClass);
     this.termDiv.insertBefore(textDiv, this.inputDiv);
+    this.currentLine = null;
     this.scrollTerm();
   }
 
@@ -291,6 +318,7 @@ export class DOMConsole {
     this.clearBtn = null;
     this.hideBtn = null;
     this.showBtn = null;
+    this.currentLine = null;
     const cNode = this.parent.cloneNode(false);
     this.parent.parentNode.replaceChild(cNode, this.parent);
     if (this.cursorInterval != null) {
@@ -328,12 +356,33 @@ export class DOMConsole {
   }
 
   sendOutput (text) {
-    const output = ""+text;
-    output.split("\n").forEach(t => {
+    console.debug(text);
+    let output = ""+text;
+    if (output.indexOf('\n') !== -1) {
+      console.debug("newline");
+      const outputList = output.split('\n');
+      let i = 0;
+      for ( ; i < outputList.length - 1; i += 1) {
+        console.debug("newline write");
+        let t = outputList[i];
+        t = t.replace(/\t/g,'&#x0020;&#x0020;');
+        t = t.replace(/\s/g,"&#x0020;");
+        if (t.length == 0)
+          t = "&nbsp;"
+        this.write(t, true);
+      }
+      let t = outputList[i];
       t = t.replace(/\t/g,'&#x0020;&#x0020;');
       t = t.replace(/\s/g,"&#x0020;");
-      this.write(t)
-    });
+      if (t.length != 0)
+        this.write(t);
+    } else {
+      console.debug("no newline");
+      output = output.replace(/\t/g,'&#x0020;&#x0020;');
+      output = output.replace(/\s/g,"&#x0020;");
+      this.write(output);
+    }
+    
   }
 
   clearPendingWrites () {
@@ -345,8 +394,9 @@ export class DOMConsole {
     while (this.inputDiv.parentElement.childNodes.length > 1) {
       this.inputDiv.parentElement.removeChild(this.inputDiv.parentElement.firstChild);
     }
-    this.input.value = "";
+    this.input.value = '';
     this.inputSpan.innerHTML = '';
+    this.currentLine = null;
   }
 
   clearBtnClick () {
@@ -379,6 +429,7 @@ export class DOMConsole {
     }
     this.input.value = '';
     this.inputSpan.innerHTML = '';
+    this.currentLine = null;
     this.hideInput();
     this.anyKey = false;
   }

+ 33 - 6
js/io/domOutput.js

@@ -9,18 +9,45 @@ export class DOMOutput extends Output {
       id = selector.substring(1);
     }
     this.el = document.getElementById(id);
+    this.currentLine = null;
+  }
+
+  write (text, newLine = false) {
+    if (this.currentLine == null) {
+      const span = document.createElement('span');
+      span.classList.add('ivprog-io-output-text');
+      this.el.append(span);
+      this.currentLine = span;
+    }
+    this.currentLine.innerHTML += text;
+    if (newLine) {
+      this.currentLine = null;
+    }
   }
 
   sendOutput (text) {
-    text = text.replace("\n", '</br>');
-    text = text.replace(/\t/g,'&#9;');
-    const span = document.createElement('span');
-    span.classList.add('ivprog-io-output-text');
-    span.innerHTML = text;
-    this.el.append(span);
+    let output = '' + text;
+    if (output.indexOf('\n') !== -1) {
+      const outputList = output.split('\n');
+      let last = outputList.pop();
+      outputList.forEach( t => {
+        t = t.replace(/\t/g,'&#x0020;&#x0020;');
+        t = t.replace(/\s/g,"&#x0020;");
+        if (t.length == 0)
+          t = "&nbsp;";
+        this.write(t, true);
+      });
+      last = last.replace(/\t/g, '&#x0020;&#x0020;');
+      if (last.length != 0)
+        this.write(last);
+    } else {
+      output = output.replace(/\t/g, '&#x0020;&#x0020;');
+      this.write(output);
+    }
   }
 
   clear () {
+    this.currentLine = null;
     while(this.el.childNodes.length > 0) {
       this.el.removeChild(this.el.firstChild);
     }

+ 167 - 69
js/processor/ivprogProcessor.js

@@ -29,11 +29,11 @@ import { StoreValueAddress } from "./store/value/store_value_address";
 import { LocalizedStrings } from "../services/localizedStringsService";
 
 export class IVProgProcessor {
-  static get MAIN_INTERNAL_ID() {
+  static get MAIN_INTERNAL_ID () {
     return "$main";
   }
 
-  constructor(ast) {
+  constructor (ast) {
     this.ast = ast;
     this.globalStore = new Store("$global");
     this.stores = [this.globalStore];
@@ -152,6 +152,13 @@ export class IVProgProcessor {
     return finalSto;
   }
 
+  /**
+   *
+   * @param {import('./../ast/commands/formalParameter').FormalParameter[]} formal_params
+   * @param {Expression[]} effective_params
+   * @param {Store} caller_store
+   * @param {Store} callee_store
+   */
   async associateParameters (
     formal_params,
     effective_params,
@@ -163,90 +170,181 @@ export class IVProgProcessor {
         ? LanguageDefinedFunction.getMainFunctionName()
         : callee_store.name;
 
-    if (formal_params.length != effective_params.length) {
+    const hasVariadic = formal_params.some((p) => p.variadic);
+
+    if (
+      (formal_params.length != effective_params.length && !hasVariadic) ||
+      formal_params.length > effective_params.length
+    ) {
       throw ProcessorErrorFactory.invalid_parameters_size(
         funcName,
         formal_params.length,
         effective_params.length
       );
     }
-    for (let i = 0; i < effective_params.length; i += 1) {
+    for (
+      let i = 0, j = 0;
+      i < formal_params.length && j < effective_params.length;
+      i += 1, j += 1
+    ) {
+      const formalParameter = formal_params[i];
+      if (formalParameter.variadic) {
+        [j, callee_store] = await this.associateVariadicParameter(
+          funcName,
+          formalParameter,
+          j,
+          effective_params,
+          caller_store,
+          callee_store
+        );
+      } else {
+        const actualParam = effective_params[i];
+        callee_store = await this.associateParameter(
+          funcName,
+          formalParameter,
+          actualParam,
+          caller_store,
+          callee_store
+        );
+      }
+    }
+    return callee_store;
+  }
+
+  /**
+   *
+   * @param {string} funcName
+   * @param {import('./../ast/commands/formalParameter').FormalParameter} formalParameter
+   * @param {number} index
+   * @param {Expression[]} effective_params
+   * @param {Store} caller_store
+   * @param {Store} callee_store
+   */
+  async associateVariadicParameter (
+    funcName,
+    formalParameter,
+    index,
+    effective_params,
+    caller_store,
+    callee_store
+  ) {
+    let i;
+    let count = 1;
+    for (i = index; i < effective_params.length; i += 1) {
       const actualParam = effective_params[i];
-      const actualValue = await this.evaluateExpression(
+      callee_store = await this.associateParameter(
+        funcName,
+        formalParameter,
+        actualParam,
         caller_store,
-        actualParam
+        callee_store,
+        count
       );
-      const exp = effective_params[i];
-      let shouldTypeCast = false;
-      const formalParameter = formal_params[i];
-      if (!formalParameter.type.isCompatible(actualValue.type)) {
-        if (
-          Config.enable_type_casting &&
-          !formalParameter.byRef &&
-          Store.canImplicitTypeCast(formalParameter.type, actualValue.type)
-        ) {
-          shouldTypeCast = true;
-        } else {
-          throw ProcessorErrorFactory.invalid_parameter_type(
-            funcName,
-            exp.toString()
-          );
-        }
-      }
+      count += 1;
+    }
+    const variadicCount = new StoreValue(Types.INTEGER, count, undefined, true);
+    callee_store.insertStore(`${formalParameter.id}.0`, variadicCount);
+    return [i - 1, callee_store];
+  }
 
-      if (formalParameter.byRef && !actualValue.inStore()) {
-        throw ProcessorErrorFactory.invalid_ref(funcName, exp.toString());
+  /**
+   *
+   * @param {string} funcName
+   * @param {import('./../ast/commands/formalParameter').FormalParameter} formalParameter
+   * @param {Expression} actualParameter
+   * @param {Store} callerStore
+   * @param {Store} calleeStore
+   * @param {number} variadicCount The number of the current value being assigned to the variadic parameter, default 0
+   */
+  async associateParameter (
+    funcName,
+    formalParameter,
+    actualParameter,
+    callerStore,
+    calleeStore,
+    variadicCount = 0
+  ) {
+    const actualValue = await this.evaluateExpression(
+      callerStore,
+      actualParameter
+    );
+
+    let shouldTypeCast = false;
+
+    if (!formalParameter.type.isCompatible(actualValue.type)) {
+      if (
+        Config.enable_type_casting &&
+        !formalParameter.byRef &&
+        Store.canImplicitTypeCast(formalParameter.type, actualValue.type)
+      ) {
+        shouldTypeCast = true;
+      } else {
+        throw ProcessorErrorFactory.invalid_parameter_type(
+          funcName,
+          actualParameter.toString()
+        );
       }
+    }
 
-      if (formalParameter.byRef) {
-        const realObj = caller_store.getStoreObject(actualValue.id);
-        let ref = null;
-        if (actualValue instanceof ArrayStoreValue) {
-          // it's a vector or matrix...
-          const values = actualValue.get();
-          const array_type = actualValue.type;
-          const addresses = values.map((v) =>
-            realObj.getLocAddressOf(v.line, v.column)
-          );
-          const columns = actualValue.isVector() ? 0 : actualValue.columns;
-          ref = new ArrayStoreValueRef(
-            array_type,
-            values,
-            addresses,
-            actualValue.lines,
-            columns,
+    if (formalParameter.byRef && !actualValue.inStore()) {
+      throw ProcessorErrorFactory.invalid_ref(
+        funcName,
+        actualParameter.toString()
+      );
+    }
+
+    if (formalParameter.byRef) {
+      const realObj = callerStore.getStoreObject(actualValue.id);
+      let ref = null;
+      if (actualValue instanceof ArrayStoreValue) {
+        // it's a vector or matrix...
+        const values = actualValue.get();
+        const array_type = actualValue.type;
+        const addresses = values.map((v) =>
+          realObj.getLocAddressOf(v.line, v.column)
+        );
+        const columns = actualValue.isVector() ? 0 : actualValue.columns;
+        ref = new ArrayStoreValueRef(
+          array_type,
+          values,
+          addresses,
+          actualValue.lines,
+          columns,
+          realObj.id
+        );
+      } else {
+        if (actualValue instanceof StoreValueAddress) {
+          const line = actualValue.line;
+          const column = actualValue.column;
+          ref = new StoreValueRef(
+            actualValue.type,
+            actualValue.get(),
+            realObj.getLocAddressOf(line, column),
             realObj.id
           );
+          ref.setReferenceDimension(realObj.type.dimensions);
         } else {
-          if (actualValue instanceof StoreValueAddress) {
-            const line = actualValue.line;
-            const column = actualValue.column;
-            ref = new StoreValueRef(
-              actualValue.type,
-              actualValue.get(),
-              realObj.getLocAddressOf(line, column),
-              realObj.id
-            );
-            ref.setReferenceDimension(realObj.type.dimensions);
-          } else {
-            ref = new StoreValueRef(
-              actualValue.type,
-              actualValue.get(),
-              realObj.locAddress,
-              realObj.id
-            );
-          }
-        }
-        callee_store.insertStore(formalParameter.id, ref);
-      } else {
-        let realValue = actualValue;
-        if (shouldTypeCast) {
-          realValue = Store.doImplicitCasting(formalParameter.type, realValue);
+          ref = new StoreValueRef(
+            actualValue.type,
+            actualValue.get(),
+            realObj.locAddress,
+            realObj.id
+          );
         }
-        callee_store.insertStore(formalParameter.id, realValue);
       }
+      let varID = formalParameter.id;
+      if (formalParameter.variadic) varID = `${varID}.${variadicCount}`;
+      calleeStore.insertStore(varID, ref);
+    } else {
+      let realValue = actualValue;
+      if (shouldTypeCast) {
+        realValue = Store.doImplicitCasting(formalParameter.type, realValue);
+      }
+      let varID = formalParameter.id;
+      if (formalParameter.variadic) varID = `${varID}.${variadicCount}`;
+      calleeStore.insertStore(varID, realValue);
     }
-    return callee_store;
+    return calleeStore;
   }
 
   /**
@@ -978,7 +1076,7 @@ export class IVProgProcessor {
     return null;
   }
 
-  async evaluateFunctionCall(store, exp) {
+  async evaluateFunctionCall (store, exp) {
     if (exp.isMainCall) {
       throw ProcessorErrorFactory.void_in_expression_full(
         LanguageDefinedFunction.getMainFunctionName(),

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

@@ -7,14 +7,18 @@ import { StoreValue } from '../store/value/store_value';
 
 export function createOutputFun () {
   const writeFunction = async function (store, _) {
-    const val = store.applyStore('p1');
-    this.output.sendOutput(convertToString(val.get(), val.type));
+    const totalSV = store.applyStore('p1.0');
+    const total = totalSV.get();
+    for (let i = 1; i < total; i += 1) {
+      const val = store.applyStore(`p1.${i}`);
+      this.output.sendOutput(convertToString(val.get(), val.type));
+    }
     store.mode = Modes.RETURN;
     return store;
   }
   const block = new Commands.CommandBlock([], [new Commands.SysCall(writeFunction)]);
   const func = new Commands.Function('$write', Types.VOID,
-    [new Commands.FormalParameter(Types.ALL, 'p1', false)],
+    [new Commands.FormalParameter(Types.ALL, 'p1', false, true)],
     block);
   return func;
 }

File diff suppressed because it is too large
+ 539 - 197
js/processor/semantic/semanticAnalyser.js


+ 17 - 5
js/processor/store/store.ts

@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { Modes } from '../modes';
 import { Types } from "../../typeSystem/types";
 import { StoreObject } from './storeObject';
@@ -38,14 +39,14 @@ export class Store {
 
   private store: Map<string, StoreObject>;
   public nextStore?: Store
-  public mode: Symbol;
+  public mode: symbol;
 
   constructor(public name: string) {
     this.store = new Map<string, StoreObject>();
     this.mode = Modes.RUN; 
   }
 
-  extendStore (nextStore: Store) {
+  extendStore (nextStore: Store): void {
     this.nextStore = nextStore;
   }
 
@@ -140,7 +141,7 @@ export class Store {
    * @param {number} line the line address of the vector/matrix
    * @param {number} column the matrix column, which can be undefined
    */
-  updateStoreArray (id:string, sto_value: IStoreValue, line:number, column?:number): Store {
+  updateStoreArray (id: string, sto_value: IStoreValue, line: number, column?: number): Store {
     if (!this.store.has(id)) {
       if (this.nextStore != null) {
         this.nextStore.updateStoreArray(id, sto_value, line, column);
@@ -198,13 +199,13 @@ export class Store {
    * @param id variable id
    * @param stoValue the value to be used as the initial value of id
    */
-  insertStore (id: string, stoValue: IStoreValue) {
+  insertStore (id: string, stoValue: IStoreValue): Store {
     if (this.store.has(id)) {
       // TODO: better error message
       throw new Error(`${id} is already defined`);
     }
     // TODO check for array....
-    let newObj:StoreObject;
+    let newObj: StoreObject;
     if(stoValue instanceof StoreValueRef) {
       newObj = new StoreObjectRef(stoValue);
     } else if (stoValue instanceof ArrayStoreValueRef) {
@@ -252,4 +253,15 @@ export class Store {
   destroy (): void {
     this.store.forEach(sto => sto.destroy(), this);
   }
+
+  isDefined (id: string): boolean {
+    if (!this.store.has(id)) {
+      if (this.nextStore != null) {
+        return this.nextStore.isDefined(id);
+      } else {
+        return false;
+      }
+    }
+    return true;
+  }
 }

+ 32 - 7
js/util/outputTest.js

@@ -5,15 +5,40 @@ export class OutputTest extends Output {
   constructor () {
     super();
     this.list = [];
+    this.currentLine = null;
   }
 
-  sendOutput (text) {
-    const output = ''+text;
-    output.split("\n").forEach(t => {
-      t = t.replace(/\t/g,'  ');
-      t = t.replace(/\s/g,"\u0020");
-      this.list.push(t);
-    },this);
+  write (text, newLine = false) {
+    if (this.currentLine == null) {
+      this.currentLine = this.list.push('') - 1;
+    }
+
+    this.list[this.currentLine] += text;
+    if (newLine) {
+      this.currentLine = null;
+    }
+  }
 
+  sendOutput (text) {
+    let output = '' + text;
+    if (output.indexOf('\n') !== -1) {
+      const outputList = output.split('\n');
+      let last = outputList.pop();
+      outputList.forEach( t => {
+        t = t.replace(/\t/g, '&#x0020;&#x0020;');
+        t = t.replace(/\s/g, "&#x0020;");
+        if (t.length == 0)
+          t = "&nbsp;";
+        this.write(t, true);
+      });
+      last = last.replace(/\t/g, '&#x0020;&#x0020;');
+      last = last.replace(/\s/g, "&#x0020;");
+      if (last.length != 0)
+        this.write(last);
+    } else {
+      output = output.replace(/\t/g, '&#x0020;&#x0020;');
+      output = output.replace(/\s/g, "&#x0020;");
+      this.write(output);
+    }
   }
 }

+ 38 - 11
js/util/testConsole.js

@@ -10,24 +10,36 @@ export class TestConsole {
     this.index = 0;
     this.inputList = inputList;
     this.list = [];
+    this.currentLine = null;
   }
 
-  write (text) {
-    this._appendText(text, DOMConsole.USER);
+  write (text, newLine = false) {
+    this._appendText(text, DOMConsole.USER, newLine);
   }
 
   info (text) {
-    this._appendText(text, DOMConsole.INFO);
+    this._appendTextLn(text, DOMConsole.INFO);
   }
 
   err (text) {
-    this._appendText(text, DOMConsole.ERR);
+    this._appendTextLn(text, DOMConsole.ERR);
   }
 
-  _appendText (text) {
-    this.list.push(text);
+  _appendText (text, type, newLine = false) {
+    if (this.currentLine == null) {
+      this.currentLine = this.list.push('') - 1;
+    }
+
+    this.list[this.currentLine] += text;
+    if (newLine) {
+      this.currentLine = null;
+    }
   }
 
+  _appendTextLn (text) {
+    this.list.push(text);
+    this.currentLine = null;
+  }
 
   getClassForType (type) {
     switch (type) {
@@ -53,10 +65,25 @@ export class TestConsole {
   }
 
   sendOutput (text) {
-    const output = ""+text;
-    output.split("\n").forEach(t => {
-      t = t.replace(/\t/g,'&#9;');
-      this.write(t)
-    });
+    let output = '' + text;
+    if (output.indexOf('\n') !== -1) {
+      const outputList = output.split('\n');
+      let last = outputList.pop();
+      outputList.forEach( t => {
+        t = t.replace(/\t/g, '&#x0020;&#x0020;');
+        t = t.replace(/\s/g, "&#x0020;");
+        if (t.length == 0)
+          t = "&nbsp;";
+        this.write(t, true);
+      });
+      last = last.replace(/\t/g, '&#x0020;&#x0020;');
+      last = last.replace(/\s/g, "&#x0020;");
+      if (last.length != 0)
+        this.write(last);
+    } else {
+      output = output.replace(/\t/g, '&#x0020;&#x0020;');
+      output = output.replace(/\s/g, "&#x0020;");
+      this.write(output);
+    }
   }
 }

File diff suppressed because it is too large
+ 1146 - 1141
js/visualUI/code_generator.js


File diff suppressed because it is too large
+ 1244 - 794
js/visualUI/commands/generic_expression.js


+ 250 - 125
js/visualUI/commands/writer.js

@@ -1,26 +1,44 @@
-import * as Models from '../ivprog_elements';
-import { LocalizedStrings } from '../../services/localizedStringsService';
-import * as VariableValueMenu from './variable_value_menu';
-import * as VariableValueMenuManagement from './variable_value_menu';
-import * as CommandsManagement from '../commands';
-import * as GenericExpressionManagement from './generic_expression';
+import * as Models from "../ivprog_elements";
+import { LocalizedStrings } from "../../services/localizedStringsService";
+import * as VariableValueMenu from "./variable_value_menu";
+import * as VariableValueMenuManagement from "./variable_value_menu";
+import * as CommandsManagement from "../commands";
+import * as GenericExpressionManagement from "./generic_expression";
 
 export function createFloatingCommand () {
-	return $('<div class="ui writer created_element"> <i class="ui icon small upload"></i> <span> '+LocalizedStrings.getUI('text_command_write')+' var </span></div>');
+  return $(
+    '<div class="ui writer created_element"> <i class="ui icon small upload"></i> <span> ' +
+      LocalizedStrings.getUI("text_command_write") +
+      " var </span></div>"
+  );
 }
 
 export function renderCommand (command, function_obj) {
-	var ret = '';
-	ret += '<div class="ui writer command_container"> <i class="ui icon small upload command_drag"></i> <i class="ui icon times red button_remove_command"></i> <span class="span_command_spec">'+LocalizedStrings.getUI('text_command_write')+' ( </span><div class="all_elements_write"></div> <span class="close_parentheses span_command_spec">)</span> </div>';
-
-	var el = $(ret);
-	el.data('command', command);
-
-	//renderExpression (command, function_obj, div_to_render, expression_array)
-
-	GenericExpressionManagement.renderExpression(command, function_obj, el.find('.all_elements_write'), command.content);
-
-	/*for (var i = 0; i < command.content.length; i ++) {
+  const ret = `<div class="ui writer command_container">
+      <i class="ui icon small upload command_drag"></i>
+      <i class="ui icon times red button_remove_command"></i>
+      <span class="span_command_spec">${LocalizedStrings.getUI(
+        "text_command_write"
+      )}
+      ( </span><div class="all_elements_write"></div>
+      <span class="close_parentheses span_command_spec">)</span>
+    <img data-state="${command.newline ? "on" : "false"}" src="${
+    command.newline ? "img/new_line.svg" : "img/no_new_line.svg"
+  }" class="ivprog_newline_btn"/>
+    </div>`;
+  const el = $(ret);
+  el.data("command", command);
+
+  //renderExpression (command, function_obj, div_to_render, expression_array)
+
+  GenericExpressionManagement.renderExpression(
+    command,
+    function_obj,
+    el.find(".all_elements_write"),
+    command.content
+  );
+
+  /*for (var i = 0; i < command.content.length; i ++) {
 		var new_div_item = $( '<div class="var_value_menu_div"></div>' );
 		var div_parent_with_handler = $( '<div class="div_parent_handler"></div>' );
 		div_parent_with_handler.append($('<i class="ui icon ellipsis vertical inverted handler"></i>'));
@@ -39,121 +57,228 @@ export function renderCommand (command, function_obj) {
 		addHandlerIconAdd(el.find('.all_elements_write'), command, function_obj);
 	}*/
 
-	addHandlers(command, function_obj, el);
-	return el;
+  addHandlers(command, function_obj, el);
+  return el;
 }
 
-function addHandlersManager (command, function_obj, writer_dom, item_div, content_element) {
-
-	item_div.find('.times').on('click', function() {
-		for (var i = 0; i < command.content.length; i++) {
-			if (command.content[i] == content_element) {
-				delete command.content[i];
-	  			command.content.splice(i, 1);
-				
-				item_div.children().off();
-				item_div.off();
-				item_div.fadeOut();
-
-				if (command.content.length > 0) {
-					item_div.next('.icon_add_item_to_writer').fadeOut();
-				}
-				break;
-			}
-		}
-	});
+function addHandlersManager (
+  command,
+  _function_obj,
+  _writer_dom,
+  item_div,
+  content_element
+) {
+  item_div.find(".times").on("click", function () {
+    for (let i = 0; i < command.content.length; i++) {
+      if (command.content[i] == content_element) {
+        delete command.content[i];
+        command.content.splice(i, 1);
+
+        item_div.children().off();
+        item_div.off();
+        item_div.fadeOut();
+
+        if (command.content.length > 0) {
+          item_div.next(".icon_add_item_to_writer").fadeOut();
+        }
+        break;
+      }
+    }
+  });
 }
 
 function addHandlers (command, function_obj, writer_dom) {
-
-	writer_dom.find('.button_remove_command').on('click', function() {
-		if (CommandsManagement.removeCommand(command, function_obj, writer_dom)) {
-			writer_dom.fadeOut(400, function() {
-				writer_dom.remove();
-			});
-		}
-	});
-
-	Sortable.create(writer_dom.find(".all_elements_write")[0], {
-	    handle: '.ellipsis',
-	    animation: 100,
-	    ghostClass: 'ghost',
-	    group: 'writer_' + Math.floor(Math.random() * 10000000),
-	    draggable: '.div_parent_handler',
-	    onEnd: function (evt) {
-	    	
-	    	command.content.splice(evt.newIndex, 0, command.content.splice(evt.oldIndex, 1)[0]);
-
-	    	writer_dom.empty();
-	    	writer_dom.replaceWith(renderCommand(command, function_obj));
-	    }
-	  });
-
-
+  writer_dom.find(".button_remove_command").on("click", function () {
+    if (CommandsManagement.removeCommand(command, function_obj, writer_dom)) {
+      writer_dom.fadeOut(400, function () {
+        writer_dom.remove();
+      });
+    }
+  });
+
+  Sortable.create(writer_dom.find(".all_elements_write")[0], {
+    handle: ".ellipsis",
+    animation: 100,
+    ghostClass: "ghost",
+    group: "writer_" + Math.floor(Math.random() * 10000000),
+    draggable: ".div_parent_handler",
+    onEnd: function (evt) {
+      command.content.splice(
+        evt.newIndex,
+        0,
+        command.content.splice(evt.oldIndex, 1)[0]
+      );
+
+      writer_dom.empty();
+      writer_dom.replaceWith(renderCommand(command, function_obj));
+    },
+  });
+  // Attach event handles for the newline button
+  const newlineBtn = writer_dom.find(".ivprog_newline_btn");
+  newlineBtn.on("click", function () {
+    const state = this.dataset.state;
+    if (state === "on") {
+      this.dataset.state = "off";
+      command.newline = false;
+      this.setAttribute("src", "img/no_new_line.svg");
+    } else {
+      this.dataset.state = "on";
+      command.newline = true;
+      this.setAttribute("src", "img/new_line.svg");
+    }
+    writer_dom.data("command", command);
+    setPopup(newlineBtn, command.newline);
+  });
+  // Attach jquery popup
+  setPopup(newlineBtn, command.newline);
 }
 
-function addHandlerIconAdd (dom_object, command, function_obj, insert_after = false, after_which = null) {
-	var icon_add_item = $( '<i class="ui icon plus square outline icon_add_item_to_writer"></i> ' );
-	if (!insert_after) {
-		dom_object.append(icon_add_item);
-	} else {
-		icon_add_item.insertAfter(after_which);
-	}
-	
-	icon_add_item.on('click', function(e) {
-		var div_parent_with_handler = $( '<div class="div_parent_handler" style="display:none;"></div>' );
-		var new_div_item = $( '<div class="var_value_menu_div"></div>' );
-		div_parent_with_handler.append($('<i class="ui icon ellipsis vertical inverted handler"></i>'));
-		div_parent_with_handler.append(new_div_item);
-		div_parent_with_handler.append($('<i class="white inverted icon times handler"></i>'));
-		div_parent_with_handler.insertAfter(icon_add_item);
-
-		var new_related_menu = new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.all, null, null, null, true);
-
-		VariableValueMenu.renderMenu(command, new_related_menu, new_div_item, function_obj);
-
-		addHandlerIconAdd(dom_object, command, function_obj, true, div_parent_with_handler);
-
-		addHandlersManager(command, function_obj, dom_object, div_parent_with_handler, new_related_menu);
-		var pos = 1;
-		dom_object.find('.icon_add_item_to_writer').each(function() {
-			if ($(this).get(0) === icon_add_item.get(0)) {
-				command.content.splice(pos, 0, new_related_menu);
-			} else {
-				pos ++;
-			}
-		});
-		if (command.content.length == 1) {
-			icon_add_item.remove();
-		}
-		div_parent_with_handler.fadeIn();
-	});
+function setPopup (element, state) {
+  if (element.popup("exists")) {
+    element.popup("destroy");
+  }
+  const content = state
+    ? LocalizedStrings.getUI("write_command_newline_on")
+    : LocalizedStrings.getUI("write_command_newline_off");
+  element.popup({
+    content: content,
+    delay: {
+      show: 750,
+      hide: 0,
+    },
+  });
 }
 
-export function addContent (command, ref_object, dom_object, menu_var_or_value, function_obj, ref_object_content) {
-	
-	if (dom_object.hasClass('var_value_menu_div')) {
-		var icon_add_item = $( '<i class="ui icon plus square outline icon_add_item_to_writer"></i> ' );
-		icon_add_item.insertAfter(dom_object);
-
-		icon_add_item.on('click', function(e) {
-			var div_parent_with_handler = $( '<div class="div_parent_handler"></div>' );
-			div_parent_with_handler.append($('<i class="ui icon ellipsis vertical inverted handler"></i>'));
-			div_parent_with_handler.append(new_div_item);
-			div_parent_with_handler.append($('<i class="white inverted icon times handler"></i>'));
-
-			div_parent_with_handler.insertAfter(icon_add_item);
-			var new_related_menu = new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.all, null, null, null, true);
-
-			VariableValueMenu.renderMenu(command, new_related_menu, new_div_item, function_obj);
-
-			addHandlersManager(command, function_obj, dom_object, div_parent_with_handler, new_related_menu);
-
-			command.content.push(new_related_menu);
+function _addHandlerIconAdd (
+  dom_object,
+  command,
+  function_obj,
+  insert_after = false,
+  after_which = null
+) {
+  const icon_add_item = $(
+    '<i class="ui icon plus square outline icon_add_item_to_writer"></i> '
+  );
+  if (!insert_after) {
+    dom_object.append(icon_add_item);
+  } else {
+    icon_add_item.insertAfter(after_which);
+  }
+
+  icon_add_item.on("click", function (_event) {
+    const div_parent_with_handler = $(
+      '<div class="div_parent_handler" style="display:none;"></div>'
+    );
+    const new_div_item = $('<div class="var_value_menu_div"></div>');
+    div_parent_with_handler.append(
+      $('<i class="ui icon ellipsis vertical inverted handler"></i>')
+    );
+    div_parent_with_handler.append(new_div_item);
+    div_parent_with_handler.append(
+      $('<i class="white inverted icon times handler"></i>')
+    );
+    div_parent_with_handler.insertAfter(icon_add_item);
+
+    const new_related_menu = new Models.VariableValueMenu(
+      VariableValueMenuManagement.VAR_OR_VALUE_TYPES.all,
+      null,
+      null,
+      null,
+      true
+    );
+
+    VariableValueMenu.renderMenu(
+      command,
+      new_related_menu,
+      new_div_item,
+      function_obj
+    );
+
+    addHandlerIconAdd(
+      dom_object,
+      command,
+      function_obj,
+      true,
+      div_parent_with_handler
+    );
+
+    addHandlersManager(
+      command,
+      function_obj,
+      dom_object,
+      div_parent_with_handler,
+      new_related_menu
+    );
+    let pos = 1;
+    dom_object.find(".icon_add_item_to_writer").each(function () {
+      if ($(this).get(0) === icon_add_item.get(0)) {
+        command.content.splice(pos, 0, new_related_menu);
+      } else {
+        pos++;
+      }
+    });
+    if (command.content.length == 1) {
+      icon_add_item.remove();
+    }
+    div_parent_with_handler.fadeIn();
+  });
+}
 
-			if (command.content.length == 1) {
-				icon_add_item.remove();
-			}
-		});
-	}
+export function addContent (
+  command,
+  _ref_object,
+  dom_object,
+  _menu_var_or_value,
+  function_obj,
+  _ref_object_content
+) {
+  if (dom_object.hasClass("var_value_menu_div")) {
+    const icon_add_item = $(
+      '<i class="ui icon plus square outline icon_add_item_to_writer"></i> '
+    );
+    icon_add_item.insertAfter(dom_object);
+
+    icon_add_item.on("click", function (_event) {
+      const div_parent_with_handler = $(
+        '<div class="div_parent_handler"></div>'
+      );
+      div_parent_with_handler.append(
+        $('<i class="ui icon ellipsis vertical inverted handler"></i>')
+      );
+      div_parent_with_handler.append(new_div_item);
+      div_parent_with_handler.append(
+        $('<i class="white inverted icon times handler"></i>')
+      );
+
+      div_parent_with_handler.insertAfter(icon_add_item);
+      const new_related_menu = new Models.VariableValueMenu(
+        VariableValueMenuManagement.VAR_OR_VALUE_TYPES.all,
+        null,
+        null,
+        null,
+        true
+      );
+
+      VariableValueMenu.renderMenu(
+        command,
+        new_related_menu,
+        new_div_item,
+        function_obj
+      );
+
+      addHandlersManager(
+        command,
+        function_obj,
+        dom_object,
+        div_parent_with_handler,
+        new_related_menu
+      );
+
+      command.content.push(new_related_menu);
+
+      if (command.content.length == 1) {
+        icon_add_item.remove();
+      }
+    });
+  }
 }

+ 146 - 71
js/visualUI/ivprog_elements.js

@@ -1,26 +1,81 @@
-import { Types } from './types';
-import WatchJS from 'melanke-watchjs';
-import * as AlgorithmManagement from './algorithm';
-
-export const COMMAND_TYPES = Object.freeze({function:"function", comment:"comment", reader:"reader", writer:"writer", attribution:"attribution", iftrue:"iftrue",
- repeatNtimes:"repeatNtimes", whiletrue:"whiletrue", dowhiletrue:"dowhiletrue", switch:"switch", switchcase:"switchcase", functioncall:"functioncall", break:"break",
- return:"return"});
-
-export const ARITHMETIC_TYPES = Object.freeze({plus:"plus", minus:"minus", multiplication:"multiplication", division:"division", module:"module", none:"none"});
-
-export const EXPRESSION_ELEMENTS = Object.freeze({exp_op_exp:"exp_op_exp", op_exp:"op_exp", par_exp_par:"par_exp_par", start_point:"start_point"});
-
-export const EXPRESSION_TYPES = Object.freeze({exp_conditional:"exp_conditional", exp_logic:"exp_logic", exp_arithmetic:"exp_arithmetic"});
-
-export const ARITHMETIC_COMPARISON = Object.freeze({greater_than:"greater_than", less_than:"less_than", equals_to:"equals_to", not_equals_to:"not_equals_to", greater_than_or_equals_to:"greater_than_or_equals_to", less_than_or_equals_to:"less_than_or_equals_to"});
-
-export const LOGIC_COMPARISON = Object.freeze({equals_to:"equals_to", not_equals_to:"not_equals_to", and:"and", or:"or", not:"not"});
-
-export const SYSTEM_FUNCTIONS_CATEGORIES = Object.freeze({math:'$mathLib', text:'$strLib', arrangement:'$arrayLib', conversion:'$langLib'});
+import { Types } from "./types";
+import WatchJS from "melanke-watchjs";
+import * as AlgorithmManagement from "./algorithm";
+
+export const COMMAND_TYPES = Object.freeze({
+  function: "function",
+  comment: "comment",
+  reader: "reader",
+  writer: "writer",
+  attribution: "attribution",
+  iftrue: "iftrue",
+  repeatNtimes: "repeatNtimes",
+  whiletrue: "whiletrue",
+  dowhiletrue: "dowhiletrue",
+  switch: "switch",
+  switchcase: "switchcase",
+  functioncall: "functioncall",
+  break: "break",
+  return: "return",
+});
+
+export const ARITHMETIC_TYPES = Object.freeze({
+  plus: "plus",
+  minus: "minus",
+  multiplication: "multiplication",
+  division: "division",
+  module: "module",
+  none: "none",
+});
+
+export const EXPRESSION_ELEMENTS = Object.freeze({
+  exp_op_exp: "exp_op_exp",
+  op_exp: "op_exp",
+  par_exp_par: "par_exp_par",
+  start_point: "start_point",
+});
+
+export const EXPRESSION_TYPES = Object.freeze({
+  exp_conditional: "exp_conditional",
+  exp_logic: "exp_logic",
+  exp_arithmetic: "exp_arithmetic",
+  write_sep: "write_separator",
+});
+
+export const ARITHMETIC_COMPARISON = Object.freeze({
+  greater_than: "greater_than",
+  less_than: "less_than",
+  equals_to: "equals_to",
+  not_equals_to: "not_equals_to",
+  greater_than_or_equals_to: "greater_than_or_equals_to",
+  less_than_or_equals_to: "less_than_or_equals_to",
+});
+
+export const LOGIC_COMPARISON = Object.freeze({
+  equals_to: "equals_to",
+  not_equals_to: "not_equals_to",
+  and: "and",
+  or: "or",
+  not: "not",
+});
+
+export const SYSTEM_FUNCTIONS_CATEGORIES = Object.freeze({
+  math: "$mathLib",
+  text: "$strLib",
+  arrangement: "$arrayLib",
+  conversion: "$langLib",
+});
 
 export class Variable {
-
-  constructor (type, name, value, dimensions = 0, is_constant = false, rows = 0, columns = 0) {
+  constructor (
+    type,
+    name,
+    value,
+    dimensions = 0,
+    is_constant = false,
+    rows = 0,
+    columns = 0
+  ) {
     this.type = type;
     this.name = name;
     this.value = value;
@@ -32,8 +87,17 @@ export class Variable {
 }
 
 export class Function {
-
-  constructor (name, return_type = Types.VOID, return_dimensions = 0, parameters_list = [], is_main = false, is_hidden = false, variables_list = [], function_comment = null, commands = []) {
+  constructor (
+    name,
+    return_type = Types.VOID,
+    return_dimensions = 0,
+    parameters_list = [],
+    is_main = false,
+    is_hidden = false,
+    variables_list = [],
+    function_comment = null,
+    commands = []
+  ) {
     this.type = COMMAND_TYPES.function;
     this.name = name;
     this.return_type = return_type;
@@ -48,8 +112,14 @@ export class Function {
 }
 
 export class SystemFunction {
-
-  constructor (identifier, return_type, return_dimensions, parameters_list, function_comment = null, category) {
+  constructor (
+    identifier,
+    return_type,
+    return_dimensions,
+    parameters_list,
+    function_comment = null,
+    category
+  ) {
     this.type = COMMAND_TYPES.function;
     this.identifier = identifier;
     this.return_type = return_type;
@@ -61,7 +131,6 @@ export class SystemFunction {
 }
 
 export class Comment {
-  
   constructor (comment_text) {
     this.type = COMMAND_TYPES.comment;
     this.comment_text = comment_text;
@@ -69,14 +138,12 @@ export class Comment {
 }
 
 export class Break {
-  
   constructor () {
     this.type = COMMAND_TYPES.break;
   }
 }
 
 export class Reader {
-  
   constructor (variable_value_menu = new VariableValueMenu()) {
     this.type = COMMAND_TYPES.reader;
     this.variable_value_menu = variable_value_menu;
@@ -84,15 +151,14 @@ export class Reader {
 }
 
 export class Writer {
-
-  constructor (content) {
+  constructor (content, newline = true) {
     this.type = COMMAND_TYPES.writer;
     this.content = content;
+    this.newline = newline;
   }
 }
 
 export class Attribution {
-
   constructor (variable, expression = []) {
     this.type = COMMAND_TYPES.attribution;
     this.variable = variable;
@@ -101,7 +167,6 @@ export class Attribution {
 }
 
 export class ExpressionOperator {
-
   constructor (type_op, item) {
     this.type_op = type_op; // Logic, Arithmetic OR Relational
     this.item = item;
@@ -109,7 +174,6 @@ export class ExpressionOperator {
 }
 
 export class ExpressionElement {
-
   constructor (type_exp, itens = []) {
     this.type_exp = type_exp;
     this.itens = itens;
@@ -117,7 +181,6 @@ export class ExpressionElement {
 }
 
 export class ConditionalExpression {
-
   constructor (expression) {
     this.type = EXPRESSION_TYPES.exp_conditional;
     this.expression = expression;
@@ -125,7 +188,6 @@ export class ConditionalExpression {
 }
 
 export class LogicExpression {
-
   constructor (has_neg, first_operand, second_operand, operator) {
     this.type = EXPRESSION_TYPES.exp_logic;
     this.has_neg = has_neg;
@@ -136,7 +198,6 @@ export class LogicExpression {
 }
 
 export class ArithmeticExpression {
-
   constructor (first_operand, second_operand, operator) {
     this.type = EXPRESSION_TYPES.exp_arithmetic;
     this.first_operand = first_operand;
@@ -146,7 +207,6 @@ export class ArithmeticExpression {
 }
 
 export class IfTrue {
-
   constructor (expression, commands_block, commands_else) {
     this.type = COMMAND_TYPES.iftrue;
     this.expression = expression;
@@ -156,8 +216,14 @@ export class IfTrue {
 }
 
 export class RepeatNTimes {
-
-  constructor (var_attribution, var_incrementation, expression1, expression2, expression3, commands_block) {
+  constructor (
+    var_attribution,
+    var_incrementation,
+    expression1,
+    expression2,
+    expression3,
+    commands_block
+  ) {
     this.type = COMMAND_TYPES.repeatNtimes;
     this.var_attribution = var_attribution;
     this.var_incrementation = var_incrementation;
@@ -169,7 +235,6 @@ export class RepeatNTimes {
 }
 
 export class WhileTrue {
-
   constructor (expression, commands_block) {
     this.type = COMMAND_TYPES.whiletrue;
     this.expression = expression;
@@ -178,7 +243,6 @@ export class WhileTrue {
 }
 
 export class DoWhileTrue {
-
   constructor (expression, commands_block) {
     this.type = COMMAND_TYPES.dowhiletrue;
     this.expression = expression;
@@ -187,7 +251,6 @@ export class DoWhileTrue {
 }
 
 export class Switch {
-
   constructor (variable, cases = []) {
     this.type = COMMAND_TYPES.switch;
     this.variable = variable;
@@ -196,24 +259,21 @@ export class Switch {
 }
 
 export class Return {
-
- constructor (variable_value_menu) {
+  constructor (variable_value_menu) {
     this.type = COMMAND_TYPES.return;
     this.variable_value_menu = variable_value_menu;
-  } 
+  }
 }
 
 export class SwitchCase {
-
- constructor (variable_value_menu, commands_block = []) {
+  constructor (variable_value_menu, commands_block = []) {
     this.type = COMMAND_TYPES.switchcase;
     this.variable_value_menu = variable_value_menu;
     this.commands_block = commands_block;
-  } 
+  }
 }
 
 export class FunctionCall {
-
   constructor (function_called, parameters_list) {
     this.type = COMMAND_TYPES.functioncall;
     this.function_called = function_called;
@@ -222,8 +282,14 @@ export class FunctionCall {
 }
 
 export class VariableValueMenu {
-
-  constructor (variable_and_value = 7, content = null, row = null, column = null, include_constant = true, dimensions = 0) {
+  constructor (
+    variable_and_value = 7,
+    content = null,
+    row = null,
+    column = null,
+    include_constant = true,
+    dimensions = 0
+  ) {
     this.type = "var_value";
     this.variable_and_value = variable_and_value;
     this.content = content;
@@ -235,7 +301,6 @@ export class VariableValueMenu {
 }
 
 export class FunctionCallMenu {
-  
   constructor (function_called = null, parameters_list = []) {
     this.type = "function_call";
     this.function_called = function_called;
@@ -244,31 +309,41 @@ export class FunctionCallMenu {
 }
 
 export class Program {
-
   constructor () {
     this.functions = [];
     this.globals = [];
   }
 
   addFunction (function_to_add) {
-
-    WatchJS.watch(function_to_add.parameters_list, function(){
-      if (window.insertContext) {
-        setTimeout(function(){ AlgorithmManagement.renderAlgorithm(); }, 300);
-        window.insertContext = false;
-      } else {
-        AlgorithmManagement.renderAlgorithm();
-      }
-    }, 1);
-
-    WatchJS.watch(function_to_add.variables_list, function(){
-      if (window.insertContext) {
-        setTimeout(function(){ AlgorithmManagement.renderAlgorithm(); }, 300);
-        window.insertContext = false;
-      } else {
-        AlgorithmManagement.renderAlgorithm();
-      }
-    }, 1);
+    WatchJS.watch(
+      function_to_add.parameters_list,
+      function () {
+        if (window.insertContext) {
+          setTimeout(function () {
+            AlgorithmManagement.renderAlgorithm();
+          }, 300);
+          window.insertContext = false;
+        } else {
+          AlgorithmManagement.renderAlgorithm();
+        }
+      },
+      1
+    );
+
+    WatchJS.watch(
+      function_to_add.variables_list,
+      function () {
+        if (window.insertContext) {
+          setTimeout(function () {
+            AlgorithmManagement.renderAlgorithm();
+          }, 300);
+          window.insertContext = false;
+        } else {
+          AlgorithmManagement.renderAlgorithm();
+        }
+      },
+      1
+    );
 
     this.functions.push(function_to_add);
   }

+ 2 - 2
package.json

@@ -41,13 +41,13 @@
     "ts-loader": "^5.4.5",
     "typescript": "^3.8.3",
     "webpack": "4.x",
-    "webpack-cli": "3.x"
+    "webpack-cli": "3.x",
+    "csv-parser": "^2.3.1"
   },
   "dependencies": {
     "@babel/runtime": "^7.9.2",
     "antlr4": "^4.7.2",
     "codemirror": "^5.49.0",
-    "csv-parser": "^2.3.1",
     "decimal.js": "^10.2.0",
     "line-i18n": "git+http://200.144.254.107/git/LInE/line-i18n.git",
     "melanke-watchjs": "^1.5.0"

+ 35 - 34
webpack.config.js

@@ -11,10 +11,10 @@ module.exports = {
     path: path.resolve(__dirname, "build", "js"),
     filename: "[name].[contenthash].js",
     library: "ivprogCore",
-    libraryTarget: "umd"
+    libraryTarget: "umd",
   },
   node: {
-    fs: "empty"
+    fs: "empty",
   },
   module: {
     rules: [
@@ -24,71 +24,71 @@ module.exports = {
         use: {
           loader: "babel-loader",
           options: {
-            presets: ["@babel/preset-env"]
-          }
-        }
+            presets: ["@babel/preset-env"],
+          },
+        },
       },
       {
         test: /\.g4$/,
         exclude: /(node_modules)/,
         use: {
-          loader: "antlr4-webpack-loader"
-        }
+          loader: "antlr4-webpack-loader",
+        },
       },
       {
         test: /\.tsx?$/,
         use: "ts-loader",
-        exclude: /node_modules/
+        exclude: /node_modules/,
       },
       {
         test: /\.csv$/,
         use: [
           {
-            loader: path.resolve(__dirname, "i18n_csv_loader")
-          }
+            loader: path.resolve(__dirname, "i18n_csv_loader"),
+          },
         ],
-        exclude: /node_modules/
-      }
-    ]
+        exclude: /node_modules/,
+      },
+    ],
   },
   resolve: {
-    extensions: [".tsx", ".ts", ".js", ".csv"]
+    extensions: [".tsx", ".ts", ".js", ".csv"],
   },
   stats: {
-    colors: true
+    colors: true,
   },
   plugins: [
     new CleanWebpackPlugin({
       cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, "build/**/*")],
-      watch: true
+      watch: true,
     }),
     new UpdateVersionPlugin(),
     new HtmlWebpackPlugin({
       template: "templates/index.html",
-      filename: path.resolve(__dirname, "build", "index.html")
+      filename: path.resolve(__dirname, "build", "index.html"),
     }),
     new HtmlWebpackPlugin({
       template: "templates/runner.html",
-      filename: path.resolve(__dirname, "build", "runner.html")
+      filename: path.resolve(__dirname, "build", "runner.html"),
     }),
     /*new ChangeScriptSourcePlugin(),*/
     new CopyPlugin([
       {
         from: "js/iassign-integration-functions.js",
-        to: path.resolve(__dirname, "build/js")
+        to: path.resolve(__dirname, "build/js"),
       },
       {
         from: "css/ivprog-visual-1.0.css",
-        to: path.resolve(__dirname, "build/css")
+        to: path.resolve(__dirname, "build/css"),
       },
       { from: "css/ivprog-term.css", to: path.resolve(__dirname, "build/css") },
       {
         from: "css/ivprog-assessment.css",
-        to: path.resolve(__dirname, "build/css")
+        to: path.resolve(__dirname, "build/css"),
       },
       {
         from: "css/ivprog-editor.css",
-        to: path.resolve(__dirname, "build/css")
+        to: path.resolve(__dirname, "build/css"),
       },
       { from: "css/roboto.css", to: path.resolve(__dirname, "build/css") },
       { from: "css/fonts/", to: path.resolve(__dirname, "build/css/fonts") },
@@ -98,39 +98,40 @@ module.exports = {
       { from: "js/semantic.min.js", to: path.resolve(__dirname, "build/js") },
       {
         from: "css/semantic.min.css",
-        to: path.resolve(__dirname, "build/css")
+        to: path.resolve(__dirname, "build/css"),
       },
       { from: "css/themes/", to: path.resolve(__dirname, "build/css/themes") },
       { from: "img/trash-icon.png", to: path.resolve(__dirname, "build/img") },
       { from: "img/empty.svg", to: path.resolve(__dirname, "build/img") },
+      { from: "img/new_line.svg", to: path.resolve(__dirname, "build/img") },
+      { from: "img/no_new_line.svg", to: path.resolve(__dirname, "build/img") },
       {
         from: "js/jquery.json-editor.min.js",
-        to: path.resolve(__dirname, "build/js")
+        to: path.resolve(__dirname, "build/js"),
       },
       {
         from: "node_modules/codemirror/lib/codemirror.css",
-        to: path.resolve(__dirname, "build/css")
+        to: path.resolve(__dirname, "build/css"),
       },
       {
         from: "node_modules/codemirror/addon/hint/show-hint.css",
-        to: path.resolve(__dirname, "build/css")
+        to: path.resolve(__dirname, "build/css"),
       },
       {
         from: "node_modules/codemirror/theme/ttcn.css",
-        to: path.resolve(__dirname, "build/css")
-      }
+        to: path.resolve(__dirname, "build/css"),
+      },
       /*{from:'index.html', to:path.resolve(__dirname, 'build')},
         {from:'runner.html', to:path.resolve(__dirname, 'build')},*/
-    ])
+    ]),
   ],
   optimization: {
     splitChunks: {
-      chunks: "all"
-    }
+      chunks: "all",
+    },
   },
   devtool: "source-map",
   watchOptions: {
-    ignored: [path.resolve(__dirname, ".ima_version.json")]
-  }
+    ignored: [path.resolve(__dirname, ".ima_version.json")],
+  },
 };
-