1
0
Prechádzať zdrojové kódy

Merge branch 'fixTan' of LInE/ivprog into master

Lucas de Souza 6 rokov pred
rodič
commit
3373e9518c

+ 26 - 16
js/processor/ivprogProcessor.js

@@ -14,22 +14,22 @@ import { StoreObjectArrayAddress } from './store/storeObjectArrayAddress';
 import { StoreObjectArrayAddressRef } from './store/storeObjectArrayAddressRef';
 import { CompoundType } from './../typeSystem/compoundType';
 import { convertToString } from '../typeSystem/parsers';
-
-let loopTimeoutMs = 10000
+import { Config } from '../util/config';
+import Decimal from 'decimal.js';
 
 export class IVProgProcessor {
 
   static get LOOP_TIMEOUT () {
-    return loopTimeoutMs;
+    return Config.loopTimeout;
   }
 
   static set LOOP_TIMEOUT (ms) {
-    loopTimeoutMs = ms;
+    Config.setConfig({loopTimeout: ms});
   }
 
   constructor (ast) {
     this.ast = ast;
-    this.globalStore = new Store();
+    this.globalStore = new Store("$global");
     this.stores = [this.globalStore];
     this.context = [Context.BASE];
     this.input = null;
@@ -101,7 +101,8 @@ export class IVProgProcessor {
   }
 
   runFunction (func, actualParameters, store) {
-    let funcStore = new Store();
+    const funcName = func.isMain ? 'main' : func.name;
+    let funcStore = new Store(funcName);
     funcStore.extendStore(this.globalStore);
     let returnStoreObject = null;
     if(func.returnType instanceof CompoundType) {
@@ -113,10 +114,7 @@ export class IVProgProcessor {
     } else {
       returnStoreObject = new StoreObject(func.returnType, null);
     }
-    const funcName = func.isMain ? 'main' : func.name;
-    const funcNameStoreObject = new StoreObject(Types.STRING, funcName, true);
     funcStore.insertStore('$', returnStoreObject);
-    funcStore.insertStore('$name', funcNameStoreObject);
     const newFuncStore$ = this.associateParameters(func.formalParameters, actualParameters, store, funcStore);
     return newFuncStore$.then(sto => {
       this.context.push(Context.FUNCTION);
@@ -420,7 +418,7 @@ export class IVProgProcessor {
     try {
       const funcType = store.applyStore('$');
       const $value = this.evaluateExpression(store, cmd.expression);
-      const funcName = store.applyStore('$name');
+      const funcName = store.name;
       return $value.then(vl => {
 
         if(vl === null && funcType.isCompatible(Types.VOID)) {
@@ -430,7 +428,7 @@ export class IVProgProcessor {
         if (vl === null || !funcType.type.isCompatible(vl.type)) {
           // TODO: Better error message -- Inform line and column from token!!!!
           // THIS IF SHOULD BE IN A SEMANTIC ANALYSER
-          return Promise.reject(new Error(`Function ${funcName.value} must return ${funcType.type} instead of ${vl.type}.`));
+          return Promise.reject(new Error(`Function ${funcName} must return ${funcType.type} instead of ${vl.type}.`));
         } else {
           let realValue = this.parseStoreObjectValue(vl);
           store.updateStore('$', realValue);
@@ -789,18 +787,30 @@ export class IVProgProcessor {
         }
         case Operators.SUB.ord:
           return new StoreObject(resultType, left.value.minus(right.value));
-        case Operators.MULT.ord:
-          return new StoreObject(resultType, left.value.times(right.value));
+        case Operators.MULT.ord: {
+          result = left.value.times(right.value);
+          if(result.dp() > Config.decimalPlaces) {
+            result = new Decimal(result.toFixed(Config.decimalPlaces));
+          }
+          return new StoreObject(resultType, result);
+        }
         case Operators.DIV.ord: {
-          result = left.value / right.value;
           if (Types.INTEGER.isCompatible(resultType))
             result = left.value.divToInt(right.value);
           else
             result = left.value.div(right.value);
+          if(result.dp() > Config.decimalPlaces) {
+            result = new Decimal(result.toFixed(Config.decimalPlaces));
+          }
           return new StoreObject(resultType, result);
         }
-        case Operators.MOD.ord:
-          return new StoreObject(resultType, left.value.modulo(right.value));
+        case Operators.MOD.ord: {
+          result = left.value.modulo(right.value);
+          if(result.dp() > Config.decimalPlaces) {
+            result = new Decimal(result.toFixed(Config.decimalPlaces));
+          }
+          return new StoreObject(resultType, result);
+        }          
         case Operators.GT.ord: {
           if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length > right.value.length;

+ 52 - 7
js/processor/lib/math.js

@@ -6,6 +6,7 @@ import { Decimal } from 'decimal.js';
 import { MultiType } from '../../typeSystem/multiType';
 import { CompoundType } from '../../typeSystem/compoundType';
 import { Modes } from '../modes';
+import { Config } from '../../util/config';
 
 /**
  * sin
@@ -28,7 +29,20 @@ function convertToRadians (degrees) {
 export function createSinFun () {
    const sinFun = (sto, _) => {
      const x = sto.applyStore('x');
-     const result = Decimal.sin(convertToRadians(x.value));
+     const angle = x.value.mod(360);
+     let result = null;
+     if(angle.eq(90)) {
+       result = new Decimal(1);
+     } else if (angle.eq(180)) {
+      result = new Decimal(0);
+     } else if (angle.eq(270)) {
+       result = new Decimal(-1);
+     } else {
+       result = Decimal.sin(convertToRadians(angle));
+     }
+     if(result.dp() > Config.decimalPlaces) {
+      result = new Decimal(result.toFixed(Config.decimalPlaces));
+    }
      const temp = new StoreObject(Types.REAL, result);
      sto.mode = Modes.RETURN;
      return Promise.resolve(sto.updateStore('$', temp));
@@ -44,7 +58,19 @@ export function createSinFun () {
 export function createCosFun () {
   const cosFun = (sto, _) => {
     const x = sto.applyStore('x');
-    const result = Decimal.cos(convertToRadians(x.value));
+    const angle = x.value.mod(360);
+    let result = null;
+    if(angle.eq(90)) {
+      result = new Decimal(0);
+    } else if (angle.eq(180)) {
+      result = new Decimal(-1);
+    } else if (angle.eq(270)) {
+      result = new Decimal(0)
+    }
+    result = Decimal.cos(convertToRadians(angle));
+    if(result.dp() > Config.decimalPlaces) {
+      result = new Decimal(result.toFixed(Config.decimalPlaces));
+    }
     const temp = new StoreObject(Types.REAL, result);
     sto.mode = Modes.RETURN;
     return Promise.resolve(sto.updateStore('$', temp));
@@ -60,7 +86,14 @@ export function createCosFun () {
 export function createTanFun () {
   const tanFun = (sto, _) => {
     const x = sto.applyStore('x');
-    const result = Decimal.tan(convertToRadians(x.value));
+    const angle = x.value.mod(360);
+    if(angle.eq(90) || angle.eq(270)) {
+      return Promise.reject("Tangent of "+x.value.toNumber()+"° is undefined.");
+    }
+    let result = Decimal.tan(convertToRadians(angle));
+    if(result.dp() > Config.decimalPlaces) {
+      result = new Decimal(result.toFixed(Config.decimalPlaces));
+    }
     const temp = new StoreObject(Types.REAL, result);
     sto.mode = Modes.RETURN;
     return Promise.resolve(sto.updateStore('$', temp));
@@ -76,7 +109,10 @@ export function createTanFun () {
 export function createSqrtFun () {
   const sqrtFun = (sto, _) => {
     const x = sto.applyStore('x');
-    const result = x.value.sqrt();
+    let result = x.value.sqrt();
+    if(result.dp() > Config.decimalPlaces) {
+      result = new Decimal(result.toFixed(Config.decimalPlaces));
+    }
     const temp = new StoreObject(Types.REAL, result);
     sto.mode = Modes.RETURN;
     return Promise.resolve(sto.updateStore('$', temp));
@@ -93,7 +129,10 @@ export function createPowFun () {
   const powFun = (sto, _) => {
     const x = sto.applyStore('x');
     const y = sto.applyStore('y');
-    const result = x.value.pow(y.value);
+    let result = x.value.pow(y.value);
+    if(result.dp() > Config.decimalPlaces) {
+      result = new Decimal(result.toFixed(Config.decimalPlaces));
+    }
     const temp = new StoreObject(Types.REAL, result);
     sto.mode = Modes.RETURN;
     return Promise.resolve(sto.updateStore('$', temp));
@@ -113,7 +152,10 @@ export function createLogFun () {
     if (x.value.isNegative()) {
       return Promise.reject("the value passed to log function cannot be negative");
     }
-    const result = Decimal.log10(x.value);
+    let result = Decimal.log10(x.value);
+    if(result.dp() > Config.decimalPlaces) {
+      result = new Decimal(result.toFixed(Config.decimalPlaces));
+    }
     const temp = new StoreObject(Types.REAL, result);
     sto.mode = Modes.RETURN;
     return Promise.resolve(sto.updateStore('$', temp));
@@ -161,7 +203,10 @@ export function createNegateFun () {
 export function createInvertFun () {
   const invertFun = (sto, _) => {
     const x = sto.applyStore('x');
-    const result = toReal(1).dividedBy(x.value);
+    let result = toReal(1).dividedBy(x.value);
+    if(result.dp() > Config.decimalPlaces) {
+      result = new Decimal(result.toFixed(Config.decimalPlaces));
+    }
     const temp = new StoreObject(Types.REAL, result);
     sto.mode = Modes.RETURN;
     return Promise.resolve(sto.updateStore('$', temp));

+ 2 - 1
js/processor/store/store.js

@@ -2,7 +2,8 @@ import { Modes } from './../modes';
 
 export class Store {
 
-  constructor() {
+  constructor(name) {
+    this.name = name;
     this.store = {};
     this.nextStore = null;
     this.mode = Modes.RUN; 

+ 18 - 0
js/util/config.js

@@ -0,0 +1,18 @@
+class ConfigObject {
+
+  constructor () {
+    this.loopTimeout = 5000;
+    this.decimalPlaces = 5;
+    this.intConvertRoundMode = 2;
+  }
+
+  setConfig (opts) {
+    for (const key in opts) {
+      if(this.hasOwnProperty(key)){
+        this[key] = opts[key];
+      }
+    }
+  }
+}
+let config = new ConfigObject();
+export const Config = config;

+ 28 - 0
tests/test68.spec.js

@@ -0,0 +1,28 @@
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+import { SemanticAnalyser } from "./../js/processor/semantic/semanticAnalyser";
+import { LanguageService } from '../js/services/languageService';
+
+describe('Tangent of 90° angles', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      escreva(Matematica.tan(90))
+    }
+  }`;
+
+  const lexer = LanguageService.getCurrentLexer();
+
+  it(`should throw an exception`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const semantic = new SemanticAnalyser(parser.parseTree());
+    const exec = new IVProgProcessor(semantic.analyseTree());
+    exec.interpretAST().then(_ => {
+      done("No error thrown");
+    }).catch( _ => {
+      expect(1).toEqual(1);
+      done();
+    });
+  });
+});