Bläddra i källkod

Merge branch 'fixAssessment' of LInE/ivprog into master

Lucas de Souza 5 år sedan
förälder
incheckning
6ef750c4ab

+ 1 - 1
.ima_version.json

@@ -1 +1 @@
-{ "version":"2019_03_04 11_07" }
+{ "version":"2019_03_08 15_22" }

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 129 - 71
build/ivprog.bundle.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
build/ivprog.bundle.js.map


+ 1 - 1
i18n/pt/error.json

@@ -84,7 +84,7 @@
   "invalid_array_literal_column": "Esperava-se $0 colunas mas encontrou $1.",
   "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": "Caso de teste $0 falhou: <ul> <li>entrada(s): $1</li> <li>saída(s) esperada(s): $2</li> <li>saída(s): $3</li></ul>",
   "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"
 }

+ 2 - 1
i18n/pt/message.json

@@ -1,4 +1,5 @@
 {
   "test_case_success": "Caso de teste $0: OK",
-  "test_case_duration": "Levou $0ms"
+  "test_case_duration": "Levou $0ms",
+  "test_suite_grade": "A sua solução alcançou $0% da nota."
 }

+ 88 - 51
js/assessment/ivprogAssessment.js

@@ -1,14 +1,18 @@
-import { IVProgParser } from "./../ast/ivprogParser";
+import { Decimal } from 'decimal.js';
+import line_i18n from 'line-i18n'
 import { SemanticAnalyser } from "./../processor/semantic/semanticAnalyser";
 import { IVProgProcessor } from "./../processor/ivprogProcessor";
 import { InputTest } from "./../util/inputTest";
 import { OutputTest } from "./../util/outputTest";
+import { DOMConsole} from "./../io/domConsole";
 import * as LocalizedStringsService from "../services/localizedStringsService";
-import { Decimal } from 'decimal.js';
 import { Config } from "../util/config";
 
+
 const LocalizedStrings = LocalizedStringsService.getInstance();
 
+const StringTypes = line_i18n.StringTypes;
+
 export class IVProgAssessment {
 
   constructor (textCode, testCases, domConsole) {
@@ -19,29 +23,30 @@ export class IVProgAssessment {
 
   runTest () {
     try {
-      // try and show error messages through domconsole
-      const parser = IVProgParser.createParser(this.textCode);
-      const semantic = new SemanticAnalyser(parser.parseTree());
-      const validTree = semantic.analyseTree();
+      const validTree = SemanticAnalyser.analyseFromSource(this.textCode);
       // loop test cases and show messages through domconsole
       const partialTests = this.testCases.map( (t, name) => {
         return this.partialEvaluateTestCase(new IVProgProcessor(validTree), t.input, t.output, name);
       });
       const testResult = partialTests.reduce((acc, curr) => acc.then(curr), Promise.resolve(0));
-      return testResult.then(total => Promise.resolve(total / this.testCases.length))
-        .catch(err => {
-          this.domConsole.err("Erro durante a execução do programa");// try and show error messages through domconsole
+      return testResult.then(total => {
+        const grade = total / this.testCases.length;
+        const channel = grade == 1 ? DOMConsole.INFO : DOMConsole.ERR;
+        this.writeToConsole(channel, StringTypes.MESSAGE, "test_suite_grade", grade * 100);
+        return Promise.resolve(grade)
+      }).catch(err => {
+          this.domConsole.err("Erro inesperado durante o cálculo da nota.");// try and show error messages through domconsole
           this.domConsole.err(err.message);
           return Promise.resolve(0);
       });
     } catch (error) {
-      this.domConsole.err("Erro durante a execução do programa");// try and show error messages through domconsole
+      this.domConsole.err("Erro inesperado durante a execução do programa");// try and show error messages through domconsole
       this.domConsole.err(error.message);
       return Promise.resolve(0);
     }
   }
 
-  evaluateTestCase (prog, inputList, outputList, name, accumulator) {
+  evaluateTestCase (prog, inputList, expectedOutputs, name, accumulator) {
     const outerThis = this;
     const input = new InputTest(inputList);
     const output = new OutputTest();
@@ -52,28 +57,33 @@ export class IVProgAssessment {
       const millis = Date.now() - startTime;
       if (input.inputList.length !== input.index) {
         outerThis.showErrorMessage('test_case_few_reads', name+1);
-        outerThis.showMessage('test_case_duration', millis);
-        return Promise.resolve(accumulator + 1 * (input.index/inputList.length));
-      } else if (output.list.length < outputList.length) {
-        outerThis.showErrorMessage('test_case_failed', name + 1, inputList.join(','),
-          outputList.join(','), output.list.join(','));
-        outerThis.showMessage('test_case_duration', millis);
-        return Promise.resolve(accumulator + 1 * (output.list.length/outputList.length));
-      } else if (output.list.length > outputList.length) {
+        outerThis.showInfoMessage('test_case_duration', millis);
+        return Promise.resolve(accumulator + (input.index/inputList.length));
+      } else if (output.list.length != expectedOutputs.length) {
         outerThis.showErrorMessage('test_case_failed', name + 1, inputList.join(','),
-          outputList.join(','), output.list.join(','));
-        outerThis.showMessage('test_case_duration', millis);
-        return Promise.resolve(accumulator + 1 * (outputList.length/output.list.length));
+          expectedOutputs.join(','), output.list.join(','));
+        outerThis.showInfoMessage('test_case_duration', millis);
+        // must check for a partial match of the generated output
+        const numMatchedOutputs = output.list.reduce((acc, actualOutput, index) => {
+          if(outerThis.checkOutputValues(actualOutput, expectedOutputs[index])) {
+            return acc + 1;
+          } else {
+            return acc;
+          }
+        }, 0);
+        const maxLength = Math.max(expectedOutputs.length, output.list.length);
+        return Promise.resolve(accumulator + (numMatchedOutputs/maxLength));
       } else {
-        const isOk = outerThis.checkOutput(output.list, outputList);
+        const isOk = outerThis.checkOutputLists(output.list, expectedOutputs);
         if(!isOk) {
+          console.log("not ok.");
           outerThis.showErrorMessage('test_case_failed', name + 1, inputList.join(','),
-            outputList.join(','), output.list.join(','));
-          outerThis.showMessage('test_case_duration', millis);
+            expectedOutputs.join(','), output.list.join(','));
+          outerThis.showInfoMessage('test_case_duration', millis);
           return Promise.resolve(accumulator);
         } else {
-          outerThis.showMessage('test_case_success', name + 1);
-          outerThis.showMessage('test_case_duration', millis);
+          outerThis.showInfoMessage('test_case_success', name + 1);
+          outerThis.showInfoMessage('test_case_duration', millis);
           return Promise.resolve(accumulator + 1);
         }
       }
@@ -83,42 +93,69 @@ export class IVProgAssessment {
     });
   }
 
-  partialEvaluateTestCase (prog, inputList, outputList, name) {
-    return this.evaluateTestCase.bind(this, prog, inputList, outputList, name);
+  partialEvaluateTestCase (prog, inputList, expectedOutputs, name) {
+    return this.evaluateTestCase.bind(this, prog, inputList, expectedOutputs, name);
   }
 
-  checkOutput (aList, bList) {
-    for (let i = 0; i < aList.length; i++) {
-      const outValue = aList[i];
-      let castNumberA = parseFloat(outValue);
-      if(!Number.isNaN(castNumberA)) {
-        let castNumberB = parseFloat(bList[i]);
-        if(Number.isNaN(castNumberB)) {
-          return false;
-        }
-        castNumberA = new Decimal(castNumberA);
-        castNumberB = new Decimal(castNumberB);
-        const decimalPlaces = Math.min(castNumberB.dp(), Config.decimalPlaces);
-        Decimal.set({ rounding: Decimal.ROUND_FLOOR});
-        castNumberA = new Decimal(castNumberA.toFixed(decimalPlaces));
-        castNumberB = new Decimal(castNumberB.toFixed(decimalPlaces));
-        const aEqualsB = castNumberA.eq(castNumberB);
-        Decimal.set({ rounding: Decimal.ROUND_HALF_UP});
-        if (!aEqualsB) {
-          return false;
-        }
-      } else if(outValue != bList[i]) {
+  checkOutputLists (actualOutputs, expectedOutputs) {
+    for (let i = 0; i < actualOutputs.length; i++) {
+      const outValue = actualOutputs[i];
+      const expectedValue = expectedOutputs[i];
+      if(!this.checkOutputValues(outValue, expectedValue)) {
         return false;
       }
     }
     return true;
   }
 
+  checkOutputValues (actualValue, expectedValue) {
+    let castNumberA = parseFloat(actualValue);
+    if(!Number.isNaN(castNumberA)) {
+      let castNumberB = parseFloat(expectedValue);
+      if(Number.isNaN(castNumberB)) {
+        return false;
+      }
+      castNumberA = new Decimal(castNumberA);
+      castNumberB = new Decimal(castNumberB);
+      const decimalPlaces = Math.min(castNumberB.dp(), Config.decimalPlaces);
+      Decimal.set({ rounding: Decimal.ROUND_FLOOR});
+      castNumberA = new Decimal(castNumberA.toFixed(decimalPlaces));
+      castNumberB = new Decimal(castNumberB.toFixed(decimalPlaces));
+      const aEqualsB = castNumberA.eq(castNumberB);
+      Decimal.set({ rounding: Decimal.ROUND_HALF_UP});
+      if (!aEqualsB) {
+        return false;
+      }
+    } else if(actualValue != expectedValue) {
+      return false;
+    }
+    return true;
+  }
+
   showErrorMessage (errorID, ...args) {
     this.domConsole.err(LocalizedStrings.getError(errorID, args));
   }
 
-  showMessage (msgID, ...args) {
+  showInfoMessage (msgID, ...args) {
     this.domConsole.info(LocalizedStrings.getMessage(msgID, args));
   }
+
+  writeToConsole (channel, msgType, msgID, ...args) {
+    let msg = LocalizedStrings.getString(msgID, msgType);
+    msg = LocalizedStrings.processString(msg, args);
+    switch(channel) {
+      case DOMConsole.ERR: {
+        this.domConsole.err(msg);
+        break;
+      }
+      case DOMConsole.INFO: {
+        this.domConsole.info(msg);
+        break;
+      }
+      case DOMConsole.USER: {
+        this.domConsole.write(msg);
+        break;
+      }
+    }
+  }
 }

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

@@ -10,9 +10,16 @@ import { CompoundType } from '../../typeSystem/compoundType';
 import { MultiType } from '../../typeSystem/multiType';
 import { Config } from '../../util/config';
 import { Store } from '../store/store';
+import { IVProgParser } from '../../ast/ivprogParser';
 
 export class SemanticAnalyser {
 
+  static analyseFromSource (stringCode) {
+    const parser = IVProgParser.createParser(stringCode);
+    const semantic = new SemanticAnalyser(parser.parseTree());
+    return semantic.analyseTree();
+  }
+
   constructor(ast) {
     this.ast = ast;
     this.lexerClass = LanguageService.getCurrentLexer();

+ 1 - 4
js/visualUI/functions.js

@@ -8,7 +8,6 @@ import * as CommandsManagement from './commands';
 import * as CodeManagement from './code_generator';
 import * as VariableValueMenu from './commands/variable_value_menu';
 import { DOMConsole } from './../io/domConsole';
-import { IVProgParser } from './../ast/ivprogParser';
 import { IVProgProcessor } from './../processor/ivprogProcessor';
 import WatchJS from 'melanke-watchjs';
 import { SemanticAnalyser } from '../processor/semantic/semanticAnalyser';
@@ -884,9 +883,7 @@ function runCode () {
     domConsole = new DOMConsole("#ivprog-term");
   $("#ivprog-term").slideDown(500);
   try {
-    const parser = IVProgParser.createParser(strCode);
-    const analyser = new SemanticAnalyser(parser.parseTree());
-    const data = analyser.analyseTree();
+    const data = SemanticAnalyser.analyseFromSource(strCode);
     const proc = new IVProgProcessor(data);
     proc.registerInput(domConsole);
     proc.registerOutput(domConsole);