Ver código fonte

Implement functions and globals modifications notifier

Fix conversion functions parameter signature

Implement i18n error conversion messages

Remove unnecessary comments
Lucas de Souza 5 anos atrás
pai
commit
075008bac9

+ 2 - 1
i18n/pt/error.json

@@ -85,5 +85,6 @@
   "exceeded_input_request": "A quantidade de leituras requisitadas execedeu a quantidade de entradas disponíveis.",
   "test_case_few_reads": "Caso de teste $0 falhou: ainda restam entradas!",
   "test_case_failed": "Caso de teste $0 falhou: entradas:<$1>; saída esperada:<$2>; saída:<$3>",
-  "test_case_failed_exception": "Caso de teste $0 falhou: $1"
+  "test_case_failed_exception": "Caso de teste $0 falhou: $1",
+  "invalid_type_conversion": "O valor $0 não pode ser convertido para o tipo $1"
 }

+ 7 - 1
js/main.js

@@ -1,5 +1,7 @@
 import { runner } from './runner';
-import { initVisualUI } from './visualUI/functions';
+import { initVisualUI, addFunctionChangeListener,
+  addGlobalChangeListener, removeFunctionListener,
+  removeGlobalListener } from './visualUI/functions';
 import * as LocalizedStringsService from './services/localizedStringsService';
 import { i18nHelper } from "./services/i18nHelper";
 
@@ -9,6 +11,10 @@ const LocalizedStrings = LocalizedStringsService.getInstance();
 export {
   runner,
   initVisualUI,
+  addFunctionChangeListener,
+  addGlobalChangeListener,
+  removeFunctionListener,
+  removeGlobalListener,
   LocalizedStrings,
   i18n
 }

+ 8 - 6
js/processor/compatibilityTable.js

@@ -127,12 +127,14 @@ export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpre
   try {
     if(leftExpressionType instanceof MultiType && rightExpressionType instanceof MultiType) {
       let newMulti = [];
-      for (let i = 0; i < leftExpressionType.types.length; i++) {
-        const element = leftExpressionType.types[i];
-        if(rightExpressionType.types.indexOf(element) !== -1) {
-          newMulti.push(element);
+      for (let i = 0; i < leftExpressionType.types.length; ++i) {
+        const typeA = leftExpressionType.types[i];
+        for(let j = 0; j < rightExpressionType.types.length; ++i) {
+          const typeB = rightExpressionType.types[j];
+          newMulti.push(resultTypeAfterInfixOp(operator, typeA, typeB));
         }
       }
+      newMulti = newMulti.filter(x => !x.isCompatible(Types.UNDEFINED));
       if(newMulti.length <= 0) {
         if(Config.enable_type_casting) {
           if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
@@ -147,7 +149,7 @@ export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpre
       }
     } else if(leftExpressionType instanceof MultiType) {
       if(leftExpressionType.isCompatible(rightExpressionType)) {
-        return rightExpressionType;
+        return resultTypeAfterInfixOp(operator, rightExpressionType, rightExpressionType);
       } else {
         if(Config.enable_type_casting) {
           if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
@@ -160,7 +162,7 @@ export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpre
       }
     } else if(rightExpressionType instanceof MultiType) {
       if(rightExpressionType.isCompatible(leftExpressionType)) {
-        return leftExpressionType;
+        return resultTypeAfterInfixOp(operator, leftExpressionType, leftExpressionType);
       } else {
         if(Config.enable_type_casting) {
           if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {

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

@@ -374,5 +374,9 @@ export const ProcessorErrorFactory  = Object.freeze({
   },
   array_dimension_not_positive: () => {
     return new SemanticError(LocalizedStrings.getError("array_dimension_not_positive"));
+  },
+  invalid_type_conversion: (value, type, dim) => {
+    const context = [value, LocalizedStrings.translateType(type, dim)];
+    return new RuntimeError(LocalizedStrings.getError("invalid_type_conversion", context));
   }
 });

+ 4 - 5
js/processor/ivprogProcessor.js

@@ -116,7 +116,6 @@ export class IVProgProcessor {
     } else {
       const val = this.ast.functions.find( v => v.name === name);
       if (!!!val) {
-        // TODO: better error message;
         throw ProcessorErrorFactory.function_missing(name);
       }
       return val;
@@ -139,13 +138,14 @@ export class IVProgProcessor {
     }
     funcStore.insertStore('$', returnStoreObject);
     const newFuncStore$ = this.associateParameters(func.formalParameters, actualParameters, store, funcStore);
+    const outerRef = this;
     return newFuncStore$.then(sto => {
       this.context.push(Context.FUNCTION);
       this.stores.push(sto);
       return this.executeCommands(sto, func.variablesDeclarations)
-        .then(stoWithVars => this.executeCommands(stoWithVars, func.commands)).then(finalSto => {
-          this.stores.pop();
-          this.context.pop();
+        .then(stoWithVars => outerRef.executeCommands(stoWithVars, func.commands)).then(finalSto => {
+          outerRef.stores.pop();
+          outerRef.context.pop();
           return finalSto;
         });
     });
@@ -694,7 +694,6 @@ export class IVProgProcessor {
     }
     const func = this.findFunction(exp.id);
     if(Types.VOID.isCompatible(func.returnType)) {
-      // TODO: better error message
       return Promise.reject(ProcessorErrorFactory.void_in_expression_full(exp.id, exp.sourceInfo));
     }
     const $newStore = this.runFunction(func, exp.actualParameters, store);

+ 25 - 14
js/processor/lib/lang.js

@@ -5,6 +5,8 @@ import { toReal, convertToString } 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';
 
 /**
  * 
@@ -89,14 +91,16 @@ export function createIsBoolFun () {
 export function createCastRealFun () {
   const castRealFun = (sto, _) => {
     const val = sto.applyStore("val");
+    let value = val.value;
     switch (val.type.ord) {
       case Types.INTEGER.ord: {
-        const temp = new StoreObject(Types.REAL, toReal(val.number));
+        value = value.toNumber();
+        const temp = new StoreObject(Types.REAL, toReal(value));
         sto.mode = Modes.RETURN;
         return Promise.resolve(sto.updateStore("$", temp));
       }
       case Types.STRING.ord: {
-        const parser = IVProgParser.createParser(val.value);
+        const parser = IVProgParser.createParser(value);
         try {
           const result = parser.parseTerm();
           if (result instanceof RealLiteral) {
@@ -104,16 +108,17 @@ export function createCastRealFun () {
             sto.mode = Modes.RETURN;
             return Promise.resolve(sto.updateStore("$", temp));
           }
-        } catch (error) { 
-          return Promise.reject("cannot convert string to real");
-        }
+        } catch (error) { }
       }
     }
+    const typeStringInfoArray = Types.REAL.stringInfo();
+    const typeInfo = typeStringInfoArray[0];
+    return Promise.reject(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(Types.ALL, 'val', false)],
+    [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.STRING]), 'val', false)],
     block);
   return func;
 }
@@ -121,14 +126,16 @@ export function createCastRealFun () {
 export function createCastIntFun () {
   const castIntFun = (sto, _) => {
     const val = sto.applyStore("val");
+    let value = val.value;
     switch (val.type.ord) {
       case Types.REAL.ord: {
-        const temp = new StoreObject(Types.INTEGER, Math.floor(val.number));
+        value = value.toNumber();
+        const temp = new StoreObject(Types.INTEGER, Math.floor(value));
         sto.mode = Modes.RETURN;
         return Promise.resolve(sto.updateStore("$", temp));
       }
       case Types.STRING.ord: {
-        const parser = IVProgParser.createParser(val.value);
+        const parser = IVProgParser.createParser(value);
         try {
           const result = parser.parseTerm();
           if (result instanceof IntLiteral) {
@@ -136,16 +143,17 @@ export function createCastIntFun () {
             sto.mode = Modes.RETURN;
             return Promise.resolve(sto.updateStore("$", temp));
           }
-        } catch (error) { 
-          return Promise.reject("cannot convert string to real");
-        }
+        } catch (error) { }
       }
     }
+    const typeStringInfoArray = Types.INTEGER.stringInfo();
+    const typeInfo = typeStringInfoArray[0];
+    return Promise.reject(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(Types.ALL, 'val', false)],
+    [new Commands.FormalParameter(new MultiType([Types.REAL, Types.STRING]), 'val', false)],
     block);
   return func;
 }
@@ -153,7 +161,8 @@ export function createCastIntFun () {
 export function createCastBoolFun () {
   const castBoolFun = (sto, _) => {
     const str = sto.applyStore("str");
-    const parser = IVProgParser.createParser(str.value);
+    let value = str.value; 
+    const parser = IVProgParser.createParser(value);
     try {
       const val = parser.parseTerm();
       if (val instanceof BoolLiteral) {
@@ -162,7 +171,9 @@ export function createCastBoolFun () {
         return Promise.resolve(sto.updateStore("$", temp));
       }
     } catch (error) { }
-    return Promise.reject("cannot convert " + str.value + " to boolean");
+    const typeStringInfoArray = Types.BOOLEAN.stringInfo();
+    const typeInfo = typeStringInfoArray[0];
+    return Promise.reject(ProcessorErrorFactory.invalid_type_conversion(value, typeInfo.type, typeInfo.dim));
   }
 
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(castBoolFun)]);

+ 2 - 1
js/processor/lib/math.js

@@ -173,8 +173,9 @@ export function createAbsFun () {
     const x = sto.applyStore('x');
     const result = x.value.abs();
     const temp = new StoreObject(x.type, result);
+    sto.updateStore('$', temp)
     sto.mode = Modes.RETURN;
-    return Promise.resolve(sto.updateStore('$', temp));
+    return Promise.resolve(sto);
   };
 
  const block = new Commands.CommandBlock([],  [new Commands.SysCall(absFun)]);

+ 0 - 1
js/processor/semantic/semanticAnalyser.js

@@ -57,7 +57,6 @@ export class SemanticAnalyser {
   }
 
   findFunction (name) {
-    console.log(name);
     if(name.match(/^\$.+$/)) {
       const fun = LanguageDefinedFunction.getFunction(name);
       if(!!!fun) {

+ 3 - 3
js/processor/store/store.js

@@ -17,10 +17,10 @@ export class Store {
     if(!Store.canImplicitTypeCast(castType, stoObj.type)) {
       throw new Error("!!!Critical error: attempted to type cast invalid types");
     }
-    if(Types.INTEGER.isCompatible(castType)) {
-      return new StoreObject(castType, stoObj.value.trunc());
+    if(castType.isCompatible(Types.INTEGER)) {
+      return new StoreObject(Types.INTEGER, stoObj.value.trunc());
     } else {
-      return new StoreObject(castType, stoObj.value);
+      return new StoreObject(Types.REAL, stoObj.value);
     }
   }
 

+ 1 - 1
js/util/config.js

@@ -2,7 +2,7 @@ class ConfigObject {
 
   constructor () {
     this.loopTimeout = 5000;
-    this.decimalPlaces = 6;
+    this.decimalPlaces = 8;
     this.intConvertRoundMode = 2;
     this.default_lang = 'pt';
     this.enable_type_casting = true;

+ 0 - 2
js/visualUI/commands.js

@@ -18,8 +18,6 @@ import * as VariableValueMenuManagement from './commands/variable_value_menu';
 import * as BreaksManagement from './commands/break';
 import * as ReturnsManagement from './commands/return';
 
-import * as nearest from 'jquery-nearest';
-
 var has_element_created_draged = false;
 var which_element_is_draged = null;
 

+ 30 - 3
js/visualUI/functions.js

@@ -23,7 +23,8 @@ var counter_new_functions = 0;
 var counter_new_parameters = 0;
 var ivprog_version = VersionInfo.version;
 
-let studentTemp = null;
+const globalChangeListeners = [];
+const functionsChangeListeners = [];
 let domConsole = null;
 window.studentGrade = null;
 window.LocalizedStrings = LocalizedStrings;
@@ -104,19 +105,27 @@ window.watchW = WatchJS;
 
 WatchJS.watch(window.program_obj.globals, function(){
   if (window.insertContext) {
-    setTimeout(function(){ AlgorithmManagement.renderAlgorithm(); }, 300);
+    setTimeout(function() {
+      AlgorithmManagement.renderAlgorithm();
+      globalChangeListeners.forEach(x => x());
+    }, 300);
     window.insertContext = false;
   } else {
     AlgorithmManagement.renderAlgorithm();
+    globalChangeListeners.forEach(x => x());
   }
 }, 1);
 
 WatchJS.watch(window.program_obj.functions, function(){
   if (window.insertContext) {
-    setTimeout(function(){ AlgorithmManagement.renderAlgorithm(); }, 300);
+    setTimeout(function(){
+      AlgorithmManagement.renderAlgorithm();
+      functionsChangeListeners.forEach( x => x());
+    }, 300);
     window.insertContext = false;
   } else {
     AlgorithmManagement.renderAlgorithm();
+    functionsChangeListeners.forEach( x => x());
   }
 }, 1);
 
@@ -1271,4 +1280,22 @@ function enableNameFunctionUpdate (function_obj, parent_node) {
   });
   input_field.select();
   
+}
+
+export function addFunctionChangeListener (callback) {
+  functionsChangeListeners.push(callback);
+  return functionsChangeListeners.length - 1;
+}
+
+export function addGlobalChangeListener (callback) {
+  globalChangeListeners.push(callback);
+  return globalChangeListeners.length - 1;
+}
+
+export function removeGlobalListener (index) {
+  globalChangeListeners.splice(index, 1);
+}
+
+export function removeFunctionListener (index) {
+  functionsChangeListeners.splice(index);
 }