Bläddra i källkod

Implement type cast during eval of Mod and relational operators

Lucas de Souza 5 år sedan
förälder
incheckning
937b382f23
4 ändrade filer med 110 tillägg och 33 borttagningar
  1. 33 0
      js/processor/compatibilityTable.js
  2. 68 14
      js/processor/ivprogProcessor.js
  3. 2 12
      js/processor/lib/io.js
  4. 7 7
      js/typeSystem/parsers.js

+ 33 - 0
js/processor/compatibilityTable.js

@@ -1,6 +1,7 @@
 import { Types } from './../typeSystem/types';
 import { Operators } from './../ast/operators';
 import { MultiType } from '../typeSystem/multiType';
+import { Config } from '../util/config';
 
 function buildInfixAddTable () {
   const table = [[], [], [], []];
@@ -133,6 +134,13 @@ export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpre
         }
       }
       if(newMulti.length <= 0) {
+        if(Config.enable_type_casting) {
+          if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
+            if(rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
+              return new MultiType([Types.INTEGER, Types.REAL]);
+            }
+          }
+        }
         return Types.UNDEFINED;
       } else {
         return new MultiType(newMulti)
@@ -141,17 +149,42 @@ export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpre
       if(leftExpressionType.isCompatible(rightExpressionType)) {
         return rightExpressionType;
       } else {
+        if(Config.enable_type_casting) {
+          if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
+            if(rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
+              return rightExpressionType;
+            }
+          }
+        }
         return Types.UNDEFINED;
       }
     } else if(rightExpressionType instanceof MultiType) {
       if(rightExpressionType.isCompatible(leftExpressionType)) {
         return leftExpressionType;
       } else {
+        if(Config.enable_type_casting) {
+          if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
+            if(rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
+              return leftExpressionType;
+            }
+          }
+        }
         return Types.UNDEFINED;
       }
     }
     const resultType = infixMap.get(operator)[leftExpressionType.ord][rightExpressionType.ord];
     if (resultType === null || resultType === undefined) {
+      if(Config.enable_type_casting) {
+        if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
+          if(rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
+            if(operator === Operators.MOD) {
+              return Types.INTEGER;
+            } else if (operator.ord >= 5 && operator.ord <= 10){
+              return Types.BOOLEAN;
+            }
+          }
+        }
+      }
       return Types.UNDEFINED
     }
     return resultType;

+ 68 - 14
js/processor/ivprogProcessor.js

@@ -866,16 +866,21 @@ export class IVProgProcessor {
     const $left = this.evaluateExpression(store, infixApp.left);
     const $right = this.evaluateExpression(store, infixApp.right);
     return Promise.all([$left, $right]).then(values => {
+      let shouldImplicitCast = false;
       const left = values[0];
       const right = values[1];
-      const resultType = resultTypeAfterInfixOp(infixApp.op, left.type, right.type);
+      let resultType = resultTypeAfterInfixOp(infixApp.op, left.type, right.type);
       if (Types.UNDEFINED.isCompatible(resultType)) {
-        const stringInfoLeft = left.type.stringInfo();
-        const infoLeft = stringInfoLeft[0];
-        const stringInfoRight = right.type.stringInfo();
-        const infoRight = stringInfoRight[0];
-        return Promise.reject(ProcessorErrorFactory.invalid_infix_op_full(infixApp.op, infoLeft.type, infoLeft.dim,
-          infoRight.type,infoRight.dim,infixApp.sourceInfo));
+        if (Config.enable_type_casting && Store.canImplicitTypeCast(left.type, right.type)) {
+          shouldImplicitCast = true;
+        } else {
+          const stringInfoLeft = left.type.stringInfo();
+          const infoLeft = stringInfoLeft[0];
+          const stringInfoRight = right.type.stringInfo();
+          const infoRight = stringInfoRight[0];
+          return Promise.reject(ProcessorErrorFactory.invalid_infix_op_full(infixApp.op, infoLeft.type, infoLeft.dim,
+            infoRight.type,infoRight.dim,infixApp.sourceInfo));
+        }
       }
       let result = null;
       switch (infixApp.op.ord) {
@@ -910,55 +915,104 @@ export class IVProgProcessor {
           return new StoreObject(resultType, result);
         }
         case Operators.MOD.ord: {
-          result = left.value.modulo(right.value);
+          let leftValue = left.value;
+          let rightValue = right.value;
+          if(shouldImplicitCast) {
+            resultType = Types.INTEGER;
+            leftValue = leftValue.trunc();
+            rightValue = rightValue.trunc();
+          }
+          result = leftValue.modulo(rightValue);
           if(result.dp() > Config.decimalPlaces) {
             result = new Decimal(result.toFixed(Config.decimalPlaces));
           }
           return new StoreObject(resultType, result);
         }          
         case Operators.GT.ord: {
+          let leftValue = left.value;
+          let rightValue = right.value;
           if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length > right.value.length;
           } else {
-            result = left.value.gt(right.value);
+            if (shouldImplicitCast) {
+              resultType = Types.BOOLEAN;
+              leftValue = leftValue.trunc();
+              rightValue = rightValue.trunc();
+            }
+            result = leftValue.gt(rightValue);
           }
           return new StoreObject(resultType, result);
         }
         case Operators.GE.ord: {
+          let leftValue = left.value;
+          let rightValue = right.value;
           if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length >= right.value.length;
           } else {
-            result = left.value.gte(right.value);
+            if (shouldImplicitCast) {
+              resultType = Types.BOOLEAN;
+              leftValue = leftValue.trunc();
+              rightValue = rightValue.trunc();
+            }
+            result = leftValue.gte(rightValue);
           }
           return new StoreObject(resultType, result);
         }
         case Operators.LT.ord: {
+          let leftValue = left.value;
+          let rightValue = right.value;
           if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length < right.value.length;
           } else {
-            result = left.value.lt(right.value);
+            if (shouldImplicitCast) {
+              resultType = Types.BOOLEAN;
+              leftValue = leftValue.trunc();
+              rightValue = rightValue.trunc();
+            }
+            result = leftValue.lt(rightValue);
           }
           return new StoreObject(resultType, result);
         }
         case Operators.LE.ord: {
+          let leftValue = left.value;
+          let rightValue = right.value;
           if (Types.STRING.isCompatible(left.type)) {
             result = left.value.length <= right.value.length;
           } else {
-            result = left.value.lte(right.value);
+            if (shouldImplicitCast) {
+              resultType = Types.BOOLEAN;
+              leftValue = leftValue.trunc();
+              rightValue = rightValue.trunc();
+            }
+            result = leftValue.lte(rightValue);
           }
           return new StoreObject(resultType, result);
         }
         case Operators.EQ.ord: {
+          let leftValue = left.value;
+          let rightValue = right.value;
           if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
-            result = left.value.eq(right.value);
+            if (shouldImplicitCast) {
+              resultType = Types.BOOLEAN;
+              leftValue = leftValue.trunc();
+              rightValue = rightValue.trunc();
+            }
+            result = leftValue.eq(rightValue);
           } else {
             result = left.value === right.value;
           }
           return new StoreObject(resultType, result);
         }
         case Operators.NEQ.ord: {
+          let leftValue = left.value;
+          let rightValue = right.value;
           if (Types.INTEGER.isCompatible(left.type) || Types.REAL.isCompatible(left.type)) {
-            result = !left.value.eq(right.value);
+            if (shouldImplicitCast) {
+              resultType = Types.BOOLEAN;
+              leftValue = leftValue.trunc();
+              rightValue = rightValue.trunc();
+            }
+            result = !leftValue.eq(rightValue);
           } else {
             result = left.value !== right.value;
           }

+ 2 - 12
js/processor/lib/io.js

@@ -1,22 +1,12 @@
 import { StoreObject } from './../store/storeObject';
 import * as Commands from './../../ast/commands';
-import {toInt, toString, toBool, toReal} from './../../typeSystem/parsers';
+import {toInt, toString, toBool, toReal, convertToString} from './../../typeSystem/parsers';
 import { Types } from './../../typeSystem/types';
 
 export function createOutputFun () {
   const writeFunction = function (store, _) {
     const val = store.applyStore('p1');
-    if(val.type.isCompatible(Types.INTEGER)) {
-      this.output.sendOutput(val.value.toString());
-    } else if (val.type.isCompatible(Types.REAL)) {
-      if (val.value.dp() <= 0) {
-        this.output.sendOutput(val.value.toFixed(1));  
-      } else {
-        this.output.sendOutput(val.value.toString());
-      }
-    } else {
-      this.output.sendOutput(val.value);
-    }
+    this.output.sendOutput(convertToString(val.value, val.type));
     return Promise.resolve(store);
   }
   const block = new Commands.CommandBlock([], [new Commands.SysCall(writeFunction)]);

+ 7 - 7
js/typeSystem/parsers.js

@@ -47,20 +47,20 @@ function convertBoolToString (bool) {
   }
 }
 
-export function convertToString(stoObj, type) {
+export function convertToString(value, type) {
   switch (type.ord) {
     case Types.INTEGER.ord:
-      return stoObj.toString();
+      return value.toString();
     case Types.REAL.ord: {
-      if (stoObj.dp() <= 0) {
-        return stoObj.toFixed(1);  
+      if (value.dp() <= 0) {
+        return value.toFixed(1);  
       } else {
-        return stoObj.toNumber();
+        return value.toNumber();
       }
     }
     case Types.BOOLEAN.ord:
-      return convertBoolToString(stoObj);
+      return convertBoolToString(value);
     default:
-      return stoObj;
+      return value;
   }
 }