ソースを参照

Fix #14

-Implement the array address  store objects

-Refactor semantic analysis to properly check for valid ref values

-Refactor the processor to handle the new types
Lucas de Souza 6 年 前
コミット
359191aae4

+ 12 - 11
js/processor/ivprogProcessor.js

@@ -10,6 +10,8 @@ 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';
 
 export class IVProgProcessor {
 
@@ -125,7 +127,7 @@ export class IVProgProcessor {
               }
 
               if(formalParameter.byRef) {
-                const ref = new StoreObjectRef(stoObj.id, callerStore);
+                const ref = new StoreObjectArrayAddressRef(stoObj);
                 calleeStore.insertStore(formalParameter.id, ref);
               } else {
                 calleeStore.insertStore(formalParameter.id, stoObj);
@@ -146,7 +148,7 @@ export class IVProgProcessor {
               }
 
               if(formalParameter.byRef) {
-                const ref = new StoreObjectRef(stoObj.id, callerStore);
+                const ref = new StoreObjectArrayAddressRef(stoObj);
                 calleeStore.insertStore(formalParameter.id, ref);
               } else {
                 calleeStore.insertStore(formalParameter.id, stoObj);
@@ -169,7 +171,12 @@ export class IVProgProcessor {
             } else {
 
               if(formalParameter.byRef) {
-                const ref = new StoreObjectRef(stoObj.id, callerStore);
+                let ref = null;
+                if (stoObj instanceof StoreObjectArrayAddress) {
+                  ref = new StoreObjectArrayAddressRef(stoObj);
+                } else {
+                  ref = new StoreObjectRef(stoObj.id, callerStore);
+                }
                 calleeStore.insertStore(formalParameter.id, ref);
               } else {
                 calleeStore.insertStore(formalParameter.id, stoObj);
@@ -506,13 +513,12 @@ export class IVProgProcessor {
           reject(new Error("Invalid operation. This must be a vector: line "+cmd.sourceInfo.line));
           return;
          }
+         newArray.value[line] = value;
          store.updateStore(cmd.id, newArray);
         }
         resolve(store);
       }).catch(err => reject(err));
     });
-    const $value = this.evaluateExpression(store, cmd.expression);
-    return $value.then( vl => store.updateStore(cmd.id, vl));
   }
 
   executeDeclaration (store, cmd) {
@@ -694,12 +700,7 @@ export class IVProgProcessor {
         // TODO: better error message
         return Promise.reject(new Error(`${exp.id}: index out of bounds: ${column}`));
       }
-  
-      if (column !== null) {
-        return Promise.resolve(mustBeArray.value[line].value[column]);
-      } else {
-        return Promise.resolve(mustBeArray.value[line]);
-      }
+      return Promise.resolve(new StoreObjectArrayAddress(mustBeArray.id, line, column, store));
     });
   }
 

+ 4 - 2
js/processor/semantic/semanticAnalyser.js

@@ -379,8 +379,10 @@ export class SemanticAnalyser {
     for (let i = 0; i < actualParametersList.length; i++) {
       const param = actualParametersList[i];
       const formalParam = fun.formalParameters[i];
-      if(formalParam.byRef && !(param instanceof VariableLiteral)) {
-        throw new Error("Invalid param type");
+      if(formalParam.byRef) {
+        if (!(param instanceof VariableLiteral || param instanceof ArrayAccess)) {
+          throw new Error("Invalid param type");
+        }
       }
       const resultType = this.evaluateExpressionType(param);
       switch (formalParam.dimensions) {

+ 4 - 5
js/processor/store/store.js

@@ -43,11 +43,10 @@ export class Store {
         // TODO: better error message
         throw new Error("Cannot change value of a read only variable: " + id);
       }
-      if(oldObj.isCompatible(stoObj)) {
-        if(oldObj.isRef) {
-          oldObj.updateRef(stoObj);
-          return this;
-        }
+      if(oldObj.isRef) {
+        oldObj.updateRef(stoObj);
+        return this;
+      } else if(oldObj.isCompatible(stoObj)) {
         stoObj.setID(id);
         this.store[id] = Object.freeze(stoObj);
         return this;

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

@@ -23,7 +23,7 @@ export class StoreObjectArray extends StoreObject {
   }
 
   isCompatible (another) {
-    if(another instanceof StoreObjectArray) {
+    if(another instanceof StoreObject) {
       if(this.lines === another.lines &&
         this.columns === another.columns &&
         this.subtype === another.subtype) {

+ 95 - 0
js/processor/store/storeObjectArrayAddress.js

@@ -0,0 +1,95 @@
+import { StoreObject } from './storeObject';
+import { StoreObjectArray } from './storeObjectArray';
+import { Types } from '../../ast/types';
+
+export class StoreObjectArrayAddress extends StoreObject {
+
+  constructor (refID, line, column, store) {
+    super(null, null, false);
+    this.refID = refID;
+    this.store = store;
+    this.line = line;
+    this.column = column;
+  }
+
+  get isRef () {
+    return false;
+  }
+
+  get inStore () {
+    return true;
+  }
+
+  get refValue () {
+    const refLine = this.store.applyStore(this.refID).value[this.line];
+    if (this.column !== null) {
+      return refLine.value[this.column];
+    }
+    return refLine;
+  }
+
+  get value () {
+    return this.refValue.value;
+  }
+
+  get type () {
+    return this.refValue.type;
+  }
+
+  get lines () {
+    if(this.type !== Types.ARRAY) {
+      return null;
+    }
+    return this.refValue.value.length;
+  }
+
+  get columns () {
+    if(this.lines <= 0) {
+      return null;
+    } else if (this.refValue.value[0].type !== Types.ARRAY) {
+      return null;
+    }
+    // this.refValue is StoreObject
+    //this.refValue.value[0] is another StoreObject
+    return this.refValue.value[0].value.length;
+  }
+
+  get subtype () {
+    return this.refValue.subtype;
+  }
+
+  getArrayObject () {
+    return this.store.applyStore(this.refID);
+  }
+
+  updateArrayObject (stoObj) {
+    const anArray =  this.getArrayObject();
+    const newArray = Object.assign(new StoreObjectArray(null,null,null), anArray);
+    if (this.column !== null) {
+     if (stoObj.type === Types.ARRAY) {
+       throw new Error(`Invalid operation: cannot assign the value given to ${this.refID}`);
+     }
+     newArray.value[this.line].value[this.column] = stoObj;
+     return newArray;
+    } else {
+     if(anArray.columns !== null && stoObj.type !== Types.ARRAY) {
+      throw new Error(`Invalid operation: cannot assign the value given to ${this.refID}`);
+     }
+     newArray.value[this.line] = stoObj;
+     return newArray;
+    }
+  }
+
+  isCompatible (another) {
+    if(this.type === Types.ARRAY) {
+      if(another.type !== Types.ARRAY) {
+        return false;
+      }
+      if(another.subtype !== this.subtype) {
+        return false;
+      }
+      return this.lines === another.lines && this.columns === another.columns;
+    }
+    return this.refValue.isCompatible(another);
+  }
+}

+ 42 - 0
js/processor/store/storeObjectArrayAddressRef.js

@@ -0,0 +1,42 @@
+import { StoreObject } from './storeObject';
+
+export class StoreObjectArrayAddressRef extends StoreObject {
+
+  constructor (address) {
+    super(null, null, false);
+    this.address = address;
+  }
+
+  get isRef () {
+    return true;
+  }
+
+  get type () {
+    return this.address.type;
+  }
+
+  get value () {
+    return this.address.value;
+  }
+
+  get number () {
+    if (this.value instanceof BigNumber) {
+      return this.value.toNumber();
+    } else {
+      return null;
+    }
+  }
+
+  getRefObj () {
+    return this.address.refValue;
+  }
+
+  updateRef (stoObj) {
+    const newArray = this.address.updateArrayObject(stoObj);
+    this.address.store.updateStore(this.address.refID, newArray);
+  }
+
+  isCompatible (another) {
+    return this.address.isCompatible(another);
+  }
+}

+ 8 - 0
js/processor/store/storeObjectRef.js

@@ -20,6 +20,14 @@ export class StoreObjectRef extends StoreObject {
     return this.store.applyStore(this.refID).value;
   }
 
+  get number () {
+    if (this.value instanceof BigNumber) {
+      return this.value.toNumber();
+    } else {
+      return null;
+    }
+  }
+
   getRefObj () {
     return this.store.applyStore(this.refID);
   }

+ 36 - 0
tests/test60.spec.js

@@ -0,0 +1,36 @@
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { SemanticAnalyser } from './../js/processor/semantic/semanticAnalyser';
+import { LanguageService } from './../js/services/languageService';
+import { OutputTest } from './../js/util/outputTest';
+import { InputTest } from './../js/util/inputTest';
+import { IVProgProcessor } from './../js/processor/ivprogProcessor';
+
+describe('Reading a single value into a vector/matrix position', function () {
+
+  const code = `programa {
+
+    funcao inicio() {
+      inteiro a[2] = {0,0}
+      leia(a[0])
+      escreva(a[0])
+    }
+  }`;
+
+  localStorage.setItem('ivprog.lang', 'pt');
+
+  const lexer = LanguageService.getCurrentLexer();
+  const out = new OutputTest();
+  const inPut = new InputTest(['1'])
+
+  it(`should produce a valid state`, function (done) {
+    const parser = new IVProgParser(code, lexer);
+    const sem = new SemanticAnalyser(parser.parseTree());
+    const exec = new IVProgProcessor(sem.analyseTree());
+    exec.registerOutput(out);
+    exec.registerInput(inPut);
+    exec.interpretAST().then(sto => {
+      expect(out.list).toEqual(['1']);
+      done();
+    }).catch(err => done(err));
+  });
+});