Bladeren bron

Implement initial stop execution button. Still requires some changes at IVProgProcessor

Implement i18n index file as a typescript file and a type definition module to .csv files
Lucas de Souza 4 jaren geleden
bovenliggende
commit
95de2da474
9 gewijzigde bestanden met toevoegingen van 187 en 79 verwijderingen
  1. 5 0
      i18n/csv.d.ts
  2. 0 14
      i18n/index.js
  3. 21 0
      i18n/index.ts
  4. 1 1
      i18n/ui.csv
  5. 37 14
      js/io/domConsole.js
  6. 41 36
      js/processor/ivprogProcessor.js
  7. 2 2
      js/util/config.js
  8. 76 11
      js/visualUI/functions.js
  9. 4 1
      templates/index.html

+ 5 - 0
i18n/csv.d.ts

@@ -0,0 +1,5 @@
+declare module "*.csv" {
+  const content: {[id:string]:any};
+  export default content;
+}
+

+ 0 - 14
i18n/index.js

@@ -1,14 +0,0 @@
-import Messages from './message.csv';
-import UI from './ui.csv';
-import Errors from './error.csv';
-
-const i18n_data = {};
-for(const key in UI) {
-  const data = {};
-  data['error'] = Errors[key];
-  data['message'] = Messages[key];
-  data['ui'] = UI[key];
-  i18n_data[key] = data;
-}
-
-export default i18n_data;

+ 21 - 0
i18n/index.ts

@@ -0,0 +1,21 @@
+/// <reference path="csv.d.ts" />
+import * as Messages from './message.csv';
+import * as UI from './ui.csv';
+import * as Errors from './error.csv';
+
+type Dict =  {[id:string]:any};
+
+const MessagesObj = Messages as Dict;
+const UIObj = UI as Dict;
+const ErrorsObj = Errors as Dict;
+const i18n_data = {} as Dict;
+
+for(const key in UIObj) {
+  const data = {} as Dict;
+  data['error'] = ErrorsObj[key];
+  data['message'] = MessagesObj[key];
+  data['ui'] = UIObj[key];
+  i18n_data[key] = data;
+}
+
+export default i18n_data;

+ 1 - 1
i18n/ui.csv

@@ -112,7 +112,7 @@ var_menu_select_function,Selecione uma função,Select a function,
 expression_menu_select,Construir uma expressão lógica,Construct a logic expression,
 inform_valid_content,Informe o conteúdo!,Provide some data,
 inform_valid_expression,Construa uma expressão lógica!,Construct a logic expression,
-tooltip_terminal_clear,Limpa o terminal removendo todos os textos,Clears the terminal by removing all text,
+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.,
 tooltip_terminal_show,Exibe o terminal caso esteja escondido,Shows the terminal if it is hidden,
 tooltip_terminal_hide,Esconde o terminal caso não esteja escondido,Hides the terminal if it is not on display,
 text_ivprog_version,Versão,Version,

+ 37 - 14
js/io/domConsole.js

@@ -62,7 +62,8 @@ export class DOMConsole {
     this.setup();
     this.inputListeners = [];
     this.hideInput();
-    this.was_waiting_input = false;
+    this.pending_writes = [];
+    this.last_clear = -1;
   }
 
   setup () {
@@ -139,12 +140,11 @@ export class DOMConsole {
       return;
     }
     this.input.focus();
-    const that = this;
-    this.cursorInterval = window.setInterval(function() {
-      if (that.cursorRef.style.visibility === 'visible') {
-        that.cursorRef.style.visibility = 'hidden';
+    this.cursorInterval = window.setInterval(() => {
+      if (this.cursorRef.style.visibility === 'visible') {
+        this.cursorRef.style.visibility = 'hidden';
       } else {
-        that.cursorRef.style.visibility = 'visible';
+        this.cursorRef.style.visibility = 'visible';
       }
     }, 500);
   }
@@ -182,23 +182,37 @@ export class DOMConsole {
   }
 
   _appendText (text, type) {
-    setTimeout(() => {
+    const write_time = Date.now();
+    const pending_write = setTimeout(() => {
+      this.pending_writes.shift();
+      if(this.last_clear >= write_time) {
+        return;
+      }
       const divClass = this.getClassForType(type);
       const textDiv = document.createElement('div');
       textDiv.classList.add(divClass);
       textDiv.innerHTML = this.getOutputText(text);
       this.termDiv.insertBefore(textDiv, this.inputDiv);
       this.scrollTerm();
-    }, 50)
+    }, 50);
+    this.pending_writes.push(pending_write);
   }
 
   _appendUserInput (text) {
-    const divClass = this.getClassForType(DOMConsole.INPUT);
-    const textDiv = document.createElement('div');
-    textDiv.innerHTML = this.getUserInputText(text);
-    textDiv.classList.add(divClass);
-    this.termDiv.insertBefore(textDiv, this.inputDiv);
-    this.scrollTerm();
+    const write_time = Date.now();
+    const pending_write = setTimeout(() => {
+      this.pending_writes.shift();
+      if(this.last_clear >= write_time) {
+        return;
+      }
+      const divClass = this.getClassForType(DOMConsole.INPUT);
+      const textDiv = document.createElement('div');
+      textDiv.innerHTML = this.getUserInputText(text);
+      textDiv.classList.add(divClass);
+      this.termDiv.insertBefore(textDiv, this.inputDiv);
+      this.scrollTerm();
+    }, 50);
+    this.pending_writes.push(pending_write);
   }
 
   getOutputText (text) {
@@ -320,7 +334,16 @@ export class DOMConsole {
     });
   }
 
+  clearPendingWrites () {
+    this.last_clear = Date.now();
+    for(const id in this.pending_writes) {
+      clearTimeout(id);
+    }
+  }
+
   clear () {
+    this.clearPendingWrites();
+    this.pending_writes = [];
     while(this.inputDiv.parentElement.childNodes.length > 1) {
       this.inputDiv.parentElement.removeChild(this.inputDiv.parentElement.firstChild);
     }

+ 41 - 36
js/processor/ivprogProcessor.js

@@ -220,42 +220,47 @@ export class IVProgProcessor {
   }
 
   executeCommand (store, cmd) {
-    if(this.forceKill) {
-      return Promise.reject("FORCED_KILL!");
-    } else if (store.mode === Modes.PAUSE) {
-      return Promise.resolve(this.executeCommand(store, cmd));
-    } else if(store.mode === Modes.RETURN) {
-      return Promise.resolve(store);
-    } else if(this.checkContext(Context.BREAKABLE) && store.mode === Modes.BREAK) {
-      return Promise.resolve(store);
-    }
-    if (cmd instanceof Commands.Declaration) {
-      return this.executeDeclaration(store, cmd);
-    } else if (cmd instanceof Commands.ArrayIndexAssign) {
-      return this.executeArrayIndexAssign(store, cmd);
-    } else if (cmd instanceof Commands.Assign) {
-      return this.executeAssign(store, cmd);
-    } else if (cmd instanceof Commands.Break) {
-      return this.executeBreak(store, cmd);
-    } else if (cmd instanceof Commands.Return) {
-      return this.executeReturn(store, cmd);
-    } else if (cmd instanceof Commands.IfThenElse) {
-      return this.executeIfThenElse(store, cmd);
-    } else if (cmd instanceof Commands.RepeatUntil) {
-      return this.executeRepeatUntil(store, cmd);
-    } else if (cmd instanceof Commands.While) {
-      return this.executeWhile(store, cmd);
-    } else if (cmd instanceof Commands.For) {
-      return this.executeFor(store, cmd);
-    } else if (cmd instanceof Commands.Switch) {
-      return this.executeSwitch(store, cmd);
-    } else if (cmd instanceof Expressions.FunctionCall) {
-      return this.executeFunctionCall(store, cmd);     
-    } else if (cmd instanceof Commands.SysCall) {
-      return this.executeSysCall(store, cmd);
-    } else {
-      return Promise.reject(ProcessorErrorFactory.unknown_command(cmd.sourceInfo))
-    }
+    return new Promise((resolve, reject) => {
+      setTimeout(() => {
+        if(this.forceKill) {
+          return reject("FORCED_KILL!");
+        } else if (store.mode === Modes.PAUSE) {
+          return resolve(this.executeCommand(store, cmd));
+        } else if(store.mode === Modes.RETURN) {
+          return resolve(store);
+        } else if(this.checkContext(Context.BREAKABLE) && store.mode === Modes.BREAK) {
+          return resolve(store);
+        }
+        if (cmd instanceof Commands.Declaration) {
+          return resolve(this.executeDeclaration(store, cmd));
+        } else if (cmd instanceof Commands.ArrayIndexAssign) {
+          return resolve(this.executeArrayIndexAssign(store, cmd));
+        } else if (cmd instanceof Commands.Assign) {
+          return resolve(this.executeAssign(store, cmd));
+        } else if (cmd instanceof Commands.Break) {
+          return resolve(this.executeBreak(store, cmd));
+        } else if (cmd instanceof Commands.Return) {
+          return resolve(this.executeReturn(store, cmd));
+        } else if (cmd instanceof Commands.IfThenElse) {
+          return resolve(this.executeIfThenElse(store, cmd));
+        } else if (cmd instanceof Commands.RepeatUntil) {
+          return resolve(this.executeRepeatUntil(store, cmd));
+        } else if (cmd instanceof Commands.While) {
+          return resolve(this.executeWhile(store, cmd));
+        } else if (cmd instanceof Commands.For) {
+          return resolve(this.executeFor(store, cmd));
+        } else if (cmd instanceof Commands.Switch) {
+          return resolve(this.executeSwitch(store, cmd));
+        } else if (cmd instanceof Expressions.FunctionCall) {
+          return resolve(this.executeFunctionCall(store, cmd));     
+        } else if (cmd instanceof Commands.SysCall) {
+          return resolve(this.executeSysCall(store, cmd));
+        } else {
+          return reject(ProcessorErrorFactory.unknown_command(cmd.sourceInfo))
+        }
+      }, 5);
+    })
+    
   }
 
   executeSysCall (store, cmd) {

+ 2 - 2
js/util/config.js

@@ -1,13 +1,13 @@
 class ConfigObject {
 
   constructor () {
-    this.loopTimeout = 5000;
+    this.loopTimeout = Number.MAX_SAFE_INTEGER;
     this.decimalPlaces = 8;
     this.intConvertRoundMode = 2;
     this.default_lang = 'pt';
     this.enable_type_casting = true;
     this.idle_input_interval = 5000;
-    this.max_call_stack = 100;
+    this.max_call_stack = 10000;
   }
 
   setConfig (opts) {

+ 76 - 11
js/visualUI/functions.js

@@ -17,6 +17,7 @@ import { registerUserEvent, ActionTypes } from "./../services/userLog";
 import VersionInfo from './../../.ima_version.json';
 import * as TextEditor from "./text_editor";
 import { isValidIdentifier } from "./../util/utils";
+import { Modes } from '../processor/modes';
 
 var counter_new_functions = 0;
 var counter_new_parameters = 0;
@@ -24,6 +25,7 @@ var ivprog_version = VersionInfo.version;
 
 const globalChangeListeners = [];
 const functionsChangeListeners = [];
+let proc = null;
 let domConsole = null;
 let _testCases = [];
 let isRunning = false;
@@ -737,10 +739,16 @@ export function initVisualUI () {
     GlobalsManagement.addGlobal(program, true);
   });
 
-  $('.run_button').on('click', () => {
+  $('#run_button').on('click', function () {
+    showStopButton();
     runCode();
   });
 
+  $('#stop_button').on('click', function () {
+    showRunButton();
+    stopExecution();
+  });
+
   $('.visual_coding_button').on('click', () => {
     toggleVisualCoding();
   });
@@ -970,24 +978,48 @@ function runCode () {
   //$("#ivprog-term").slideDown(500);
   try {
     const data = SemanticAnalyser.analyseFromSource(strCode);
-    const proc = new IVProgProcessor(data);
+    proc = new IVProgProcessor(data);
     proc.registerInput(domConsole);
     proc.registerOutput(domConsole);
     $("#ivprog-term").addClass('ivprog-term-active');
     isRunning = true;
     proc.interpretAST().then( _ => {
-      domConsole.info(LocalizedStrings.getMessage("success_execution"));
-      $("#ivprog-term").removeClass('ivprog-term-active');
-      isRunning = false;
+      scheduleCall(() => {
+        if(domConsole.pending_writes.length == 0) {
+          domConsole.info(LocalizedStrings.getMessage("success_execution"));
+          $("#ivprog-term").removeClass('ivprog-term-active');
+          isRunning = false;
+          proc = null;
+          showRunButton();
+          return true;
+        }
+        return false;
+      },100);
     }).catch(err => {
-      domConsole.err(err.message);
-      $("#ivprog-term").removeClass('ivprog-term-active');
-      isRunning = false;
+      scheduleCall(() => {
+        if(domConsole.pending_writes.length == 0) {
+          domConsole.err(err.message);
+          $("#ivprog-term").removeClass('ivprog-term-active');
+          isRunning = false;
+          proc = null;
+          showRunButton();
+          return true;
+        }
+        return false;
+      },100);
     }) 
   } catch (error) {
-    isRunning = false;
-    domConsole.err(error.message);
-    console.log(error);
+    scheduleCall(() => {
+      if(domConsole.pending_writes.length == 0) {
+        isRunning = false;
+        proc = null;
+        showRunButton();
+        domConsole.err(error.message);
+        console.log(error);
+        return true;
+      }
+      return false;
+    },100);
   }
   
 }
@@ -1412,4 +1444,37 @@ export function removeGlobalListener (index) {
 
 export function removeFunctionListener (index) {
   functionsChangeListeners.splice(index);
+}
+
+function scheduleCall (callback, time) {
+  const scheduled_call = () => {
+    const id = setInterval(() => {
+      if(callback()) {
+        clearInterval(id);
+      }
+    }, time)
+  }
+  scheduled_call();
+}
+
+function showRunButton () {
+  document.getElementById('run_button').style.display = 'inline';
+  document.getElementById('stop_button').style.display = 'none';
+}
+
+function showStopButton () {
+  document.getElementById('run_button').style.display = 'none';
+  document.getElementById('stop_button').style.display = 'inline';
+}
+
+function stopExecution () {
+  domConsole.clearPendingWrites();
+  if(!isRunning) {
+    return;
+  }
+  proc.stores.forEach( sto => {
+    sto.mode = Modes.RETURN;
+  });
+  proc = null;
+  isRunning = false;
 }

+ 4 - 1
templates/index.html

@@ -52,9 +52,12 @@
           <a class="item redo_button disabled">
             <i class="redo icon"></i>
           </a>
-          <a class="item run_button">
+          <a id="run_button" class="item run_button">
             <i class="play icon"></i>
           </a>
+          <a id="stop_button" class="item stop_button" style="display: none">
+            <i class="stop icon"></i>
+          </a>
           <a class="item assessment assessment_button">
             <i class="check icon"></i>
           </a>