Ver Fonte

Rework the way the special return variable is inserted in the store to deal with array objects

Implement a function that converts from an ord to a type and the Maybe monad
Lucas de Souza há 4 anos atrás
pai
commit
47157b8ddf
4 ficheiros alterados com 109 adições e 64 exclusões
  1. 3 3
      js/memory/location.ts
  2. 53 61
      js/processor/ivprogProcessor.js
  3. 16 0
      js/typeSystem/types.ts
  4. 37 0
      js/util/maybe.ts

+ 3 - 3
js/memory/location.ts

@@ -18,7 +18,7 @@ class LocationHolder {
    */
   allocate (value:any) : number {
     const id = this.address_id;
-    console.log("Allocation address "+ id);
+    // console.log("Allocation address "+ id);
     const address = new Address(id, value);
     this.data.push(address);
     this.address_id += 1;
@@ -31,7 +31,7 @@ class LocationHolder {
    */
   deallocate (id: number) : boolean {
     const index = this.findIndex(id);
-    console.log("Deallocation address "+ id);
+    // console.log("Deallocation address "+ id);
     if(index !== -1) {
       this.data.splice(index, 1);
       return true;
@@ -47,7 +47,7 @@ class LocationHolder {
   find (id: number): Address | undefined {
     let beg = 0
     let end = this.data.length;
-    console.log("Finding address "+id);
+    // console.log("Finding address "+id);
     while (beg < end) {
       const med = Math.floor((beg + end)/2);
       const address = this.getAddressAt(med);

+ 53 - 61
js/processor/ivprogProcessor.js

@@ -1,15 +1,12 @@
 import { Store } from './store/store';
-import { StoreObjectArray } from './store/storeObjectArray';
 import { Modes } from './modes';
 import { Context } from './context';
-import { Types } from './../typeSystem/types';
+import { Types, fromOrdToType } from './../typeSystem/types';
 import { Operators } from './../ast/operators';
 import { LanguageDefinedFunction } from './definedFunctions';
 import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from './compatibilityTable';
 import * as Commands from './../ast/commands/';
 import * as Expressions from './../ast/expressions/';
-import { StoreObjectArrayAddress } from './store/storeObjectArrayAddress';
-import { StoreObjectArrayAddressRef } from './store/storeObjectArrayAddressRef';
 import { ArrayType } from './../typeSystem/array_type';
 import { convertToString } from '../typeSystem/parsers';
 import { Config } from '../util/config';
@@ -130,26 +127,25 @@ export class IVProgProcessor {
     const funcName = func.isMain ? IVProgProcessor.MAIN_INTERNAL_ID : func.name;
     const funcStore = new Store(funcName);
     funcStore.extendStore(this.globalStore);
-    let returnStoreObject = null;
+    let dimensions = 0;
+    let type_ord = 0;
     if(func.returnType instanceof ArrayType) {
-      if(func.returnType.dimensions > 1) {
-        returnStoreObject = new StoreObjectArray(func.returnType,-1,-1,[[]]);
-      } else {
-        returnStoreObject = new StoreObjectArray(func.returnType,-1,null,[]);
-      }
+      // multi dimensional return...
+      dimensions = func.returnType.dimensions;
+      type_ord = func.returnType.innerType.ord;
     } else {
-      returnStoreObject = new StoreValue(func.returnType, null, null);//new StoreObject(func.returnType, Location.allocate(null));
+      type_ord = func.returnType.ord;
     }
-    funcStore.insertStore('$', returnStoreObject);
+    funcStore.insertStore("$dim", new StoreValue(Types.INTEGER, dimensions));
+    funcStore.insertStore("$type", new StoreValue(Types.INTEGER, type_ord));
     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 => outerRef.executeCommands(stoWithVars, func.commands)).then(finalSto => {
-          outerRef.stores.pop();
-          outerRef.context.pop();
+        .then(stoWithVars => this.executeCommands(stoWithVars, func.commands)).then(finalSto => {
+          this.stores.pop();
+          this.context.pop();
           return finalSto;
         });
     });
@@ -219,10 +215,9 @@ export class IVProgProcessor {
 
   executeCommands (store, cmds) {
     // helper to partially apply a function, in this case executeCommand
-    const outerRef = this;
     const partial = (fun, cmd) => (sto) => fun(sto, cmd);
     return cmds.reduce((lastCommand, next) => {
-      const nextCommand = partial(outerRef.executeCommand.bind(outerRef), next);
+      const nextCommand = partial(this.executeCommand.bind(this), next);
       return lastCommand.then(nextCommand);
     }, Promise.resolve(store));
   }
@@ -293,18 +288,17 @@ export class IVProgProcessor {
 
   executeSwitch (store, cmd) {
     this.context.push(Context.BREAKABLE);
-    const outerRef = this;
     const caseSequence = cmd.cases.reduce( (prev,next) => {
       return prev.then( tuple => {
-        if(outerRef.ignoreSwitchCases(tuple[1])) {
+        if(this.ignoreSwitchCases(tuple[1])) {
           return Promise.resolve(tuple);
         } else if(tuple[0] || next.isDefault) {
-          return outerRef.executeCommands(tuple[1], next.commands)
+          return this.executeCommands(tuple[1], next.commands)
             .then(nSto => Promise.resolve([true, nSto]));
         } else {
           const equalityInfixApp = new Expressions.InfixApp(Operators.EQ, cmd.expression, next.expression);
           equalityInfixApp.sourceInfo = next.sourceInfo;
-          return outerRef.evaluateExpression(tuple[1],equalityInfixApp).then(stoObj => stoObj.get())
+          return this.evaluateExpression(tuple[1],equalityInfixApp).then(stoObj => stoObj.get())
             .then(isEqual => {
               if (isEqual) {
                 return this.executeCommands(tuple[1], next.commands)
@@ -317,7 +311,7 @@ export class IVProgProcessor {
       });
     }, Promise.resolve([false, store]));
     return caseSequence.then(tuple => {
-      outerRef.context.pop();
+      this.context.pop();
       const newStore = tuple[1];
       if (newStore.mode === Modes.BREAK) {
         newStore.mode = Modes.RUN;
@@ -345,36 +339,35 @@ export class IVProgProcessor {
   }
 
   executeDoWhile (store, cmd) {
-    const outerRef = this;
     try {
-      outerRef.loopTimers.push(Date.now());
-      outerRef.context.push(Context.BREAKABLE);
-      const $newStore = outerRef.executeCommands(store, cmd.commands);
+      this.loopTimers.push(Date.now());
+      this.context.push(Context.BREAKABLE);
+      const $newStore = this.executeCommands(store, cmd.commands);
       return $newStore.then(sto => {
         if(sto.mode === Modes.BREAK) {
-          outerRef.context.pop();
+          this.context.pop();
           sto.mode = Modes.RUN;
-          outerRef.loopTimers.pop();
+          this.loopTimers.pop();
           return sto;
         }
-        const $value = outerRef.evaluateExpression(sto, cmd.expression);
+        const $value = this.evaluateExpression(sto, cmd.expression);
         return $value.then(vl => {
           if (!vl.type.isCompatible(Types.BOOLEAN)) {
             return Promise.reject(ProcessorErrorFactory.loop_condition_type_full(cmd.sourceInfo));
           }
           if (vl.get()) {
-            outerRef.context.pop();
-            if(outerRef.loopTimers.length > 0) {
-              const time = outerRef.loopTimers[0];
+            this.context.pop();
+            if(this.loopTimers.length > 0) {
+              const time = this.loopTimers[0];
               if(Date.now() - time >= IVProgProcessor.LOOP_TIMEOUT) {
-                outerRef.forceKill = true;
+                this.forceKill = true;
                 return Promise.reject(ProcessorErrorFactory.endless_loop_full(cmd.sourceInfo));
               }
             }
-            return outerRef.executeCommand(sto, cmd);
+            return this.executeCommand(sto, cmd);
           } else {
-            outerRef.context.pop();
-            outerRef.loopTimers.pop();
+            this.context.pop();
+            this.loopTimers.pop();
             return sto;
           }
         })
@@ -385,34 +378,33 @@ export class IVProgProcessor {
   }
 
   executeWhile (store, cmd) {
-    const outerRef = this;
     try {
-      outerRef.loopTimers.push(Date.now());
-      outerRef.context.push(Context.BREAKABLE);
-      const $value = outerRef.evaluateExpression(store, cmd.expression);
+      this.loopTimers.push(Date.now());
+      this.context.push(Context.BREAKABLE);
+      const $value = this.evaluateExpression(store, cmd.expression);
       return $value.then(vl => {
         if(vl.type.isCompatible(Types.BOOLEAN)) {
           if(vl.get()) {
-            const $newStore = outerRef.executeCommands(store, cmd.commands);
+            const $newStore = this.executeCommands(store, cmd.commands);
             return $newStore.then(sto => {
-              outerRef.context.pop();
+              this.context.pop();
               if (sto.mode === Modes.BREAK) {
-                outerRef.loopTimers.pop();
+                this.loopTimers.pop();
                 sto.mode = Modes.RUN;
                 return sto;
               }
-              if (outerRef.loopTimers.length > 0) {
-                const time = outerRef.loopTimers[0];
+              if (this.loopTimers.length > 0) {
+                const time = this.loopTimers[0];
                 if(Date.now() - time >= IVProgProcessor.LOOP_TIMEOUT) {
-                  outerRef.forceKill = true;
+                  this.forceKill = true;
                   return Promise.reject(ProcessorErrorFactory.endless_loop_full(cmd.sourceInfo));
                 }
               }
-              return outerRef.executeCommand(sto, cmd);
+              return this.executeCommand(sto, cmd);
             });
           } else {
-            outerRef.context.pop();
-            outerRef.loopTimers.pop();
+            this.context.pop();
+            this.loopTimers.pop();
             return store;
           }
         } else {
@@ -452,24 +444,28 @@ export class IVProgProcessor {
 
   executeReturn (store, cmd) {
     try {
-      const funcType = store.applyStore('$').type;
+      const return_type_ord = store.applyStore('$type').get();
+      const return_dim = store.applyStore('$dim').get();
+      let funcType = fromOrdToType(return_type_ord).getOrElse(Types.UNDEFINED);
+      if(return_dim > 0) {
+        funcType = new ArrayType(funcType, return_dim);
+      }
       const $value = this.evaluateExpression(store, cmd.expression);
       const funcName = store.name === IVProgProcessor.MAIN_INTERNAL_ID ? 
         LanguageDefinedFunction.getMainFunctionName() : store.name;
-      return $value.then(vl => {
+      return $value.then(value => {
 
-        if(vl === null && funcType.isCompatible(Types.VOID)) {
+        if(value === null && funcType.isCompatible(Types.VOID)) {
           store.mode = Modes.RETURN;
           return Promise.resolve(store);
         }
 
-        if (vl === null || !funcType.isCompatible(vl.type)) {
+        if (value === null || !funcType.isCompatible(value.type)) {
           const stringInfo = funcType.stringInfo();
           const info = stringInfo[0];
           return Promise.reject(ProcessorErrorFactory.invalid_return_type_full(funcName, info.type, info.dim, cmd.sourceInfo));
         } else {
-          const realValue = vl;
-          store.updateStore('$', realValue);
+          store.insertStore('$', value);
           store.mode = Modes.RETURN;
           return Promise.resolve(store);
         }
@@ -720,11 +716,7 @@ export class IVProgProcessor {
       }
       const val = sto.applyStore('$');
       sto.destroy();
-      if (val instanceof StoreObjectArray) {
-        return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null,null), val));
-      } else {
-        return val;
-      }
+      return Promise.resolve(val);
     });
   }
 

+ 16 - 0
js/typeSystem/types.ts

@@ -1,5 +1,7 @@
 import { Type } from "./type";
 import { MultiType } from "./multiType";
+import { IType } from "./itype";
+import { Maybe } from "../util/maybe";
 
 const INTEGER = new Type("integer", 0);
 const REAL = new Type("real", 1);
@@ -9,6 +11,10 @@ const VOID = new Type("void", 4);
 const UNDEFINED = new Type("undefined", 5);
 const ALL = new MultiType([INTEGER, REAL, STRING, BOOLEAN]);
 
+interface TypeMap {
+  [key: string]: IType
+}
+
 export const Types = Object.freeze({
   INTEGER: INTEGER,
   REAL: REAL,
@@ -18,3 +24,13 @@ export const Types = Object.freeze({
   UNDEFINED: UNDEFINED,
   ALL: ALL
 });
+
+export function fromOrdToType (ord:number): Maybe<IType> {
+  const typeMap = Types as TypeMap;
+  for(let t in typeMap) {
+    if(typeMap[t].ord! === ord){
+      return Maybe.some<IType>(typeMap[t]);
+    }
+  }
+  return Maybe.none<IType>();
+}

+ 37 - 0
js/util/maybe.ts

@@ -0,0 +1,37 @@
+/**
+*
+*  Maybe Monad
+*  @Source: https://codewithstyle.info/advanced-functional-programming-in-typescript-maybe-monad/
+*  @Modified by: @lucascalion - 28/08/2019
+*
+**/
+export class Maybe<T> {
+  private constructor(private value: T | null) {}
+
+  static some<T>(value: T) {
+      if (!value) {
+          throw Error("Provided value must not be empty");
+      }
+      return new Maybe(value);
+  }
+
+  static none<T>() {
+      return new Maybe<T>(null);
+  }
+
+  static fromValue<T>(value: T) {
+      return value ? Maybe.some(value) : Maybe.none<T>();
+  }
+
+  getOrElse(defaultValue: T) {
+      return this.value === null ? defaultValue : this.value;
+  }
+
+  map<R>(f: (wrapped: T) => R): Maybe<R> {
+    if (this.value === null) {
+        return Maybe.none<R>();
+    } else {
+        return Maybe.fromValue(f(this.value));
+    }
+}
+}