Explorar o código

Include fixes and test cases for the bugs bellow:

-Fix a bug while parsing actual parameters list
-Fix a bug which cause returning a single value from the store(variable access or return) would not allow the resulting StoreObject to be save in the new store. This happened due to the StoreObject being frozen.
-Fix a bug which would go back a token while parsing an array access expression
-Fix executeSwitch using .executeCommand instead of .executeCommands
Lucas de Souza %!s(int64=6) %!d(string=hai) anos
pai
achega
cdea95a29c

+ 2 - 2
js/ast/commands/for.js

@@ -1,6 +1,6 @@
 export class For {
-  constructor (attribution, condition, increment, commandBlock) {
-    this.attribution = attribution;
+  constructor (assignment, condition, increment, commandBlock) {
+    this.assignment = assignment;
     this.condition = condition;
     this.increment = increment;
     this.commandBlock = commandBlock;

+ 1 - 13
js/ast/ivprogParser.js

@@ -904,24 +904,12 @@ export class IVProgParser {
         this.consumeNewLines();
         this.checkCloseBrace();
         this.pos++;
-      } else {
-        this.pos--;
       }
 
       return new Expressions.ArrayAccess(id, firstIndex, secondIndex);
 
     } else if (this.checkOpenParenthesis(true)) {
-      this.pos++;
-      this.consumeNewLines();
-      let actualParameters = [];
-      if(!this.checkCloseParenthesis(true)) {
-        actualParameters = this.parseActualParameters();
-        this.consumeNewLines();
-        this.checkCloseParenthesis();
-        this.pos++;
-      } else {
-        this.pos++;
-      }
+      const actualParameters = this.parseActualParameters();
       return new Expressions.FunctionCall(id, actualParameters);
     } else {
       this.pos = last;

+ 30 - 11
js/processor/ivprogProcessor.js

@@ -272,13 +272,14 @@ export class IVProgProcessor {
   }
 
   executeSwitch (store, cmd) {
+    this.context.push(Context.BREAKABLE);
     const auxCaseFun = (promise, switchExp, aCase) => {
       return promise.then( result => {
         const sto = result.sto;
         if (this.ignoreSwitchCases(sto)) {
           return Promise.resolve(result);
         } else if (result.wasTrue || aCase.isDefault) {
-          const $newSto = this.executeCommand(result.sto,aCase.commands);
+          const $newSto = this.executeCommands(result.sto,aCase.commands);
           return $newSto.then(nSto => {
             return Promise.resolve({wasTrue: true, sto: nSto});
           });
@@ -287,7 +288,7 @@ export class IVProgProcessor {
             new Expressions.InfixApp(Operators.EQ, switchExp, aCase.expression));
           return $value.then(vl => {
             if (vl.value) {
-              const $newSto = this.executeCommand(result.sto,aCase.commands);
+              const $newSto = this.executeCommands(result.sto,aCase.commands);
               return $newSto.then(nSto => {
                 return Promise.resolve({wasTrue: true, sto: nSto});
               });
@@ -300,7 +301,6 @@ export class IVProgProcessor {
     }
 
     try {
-      this.context.push(Context.BREAKABLE);
       let breakLoop = false;
       let $result = Promise.resolve({wasTrue: false, sto: store});
       for (let index = 0; index < cmd.cases.length && !breakLoop; index++) {
@@ -308,8 +308,8 @@ export class IVProgProcessor {
         $result = auxCaseFun($result, cmd.expression, aCase);
         $result.then( r => breakLoop = this.ignoreSwitchCases(r.sto));
       }
-      this.context.pop();
-      return result.then(r => {
+      return $result.then(r => {
+        this.context.pop();
         if(r.sto.mode === Modes.BREAK) {
           r.sto.mode = Modes.RUN;
         }
@@ -489,13 +489,21 @@ export class IVProgProcessor {
           const value = values[2];
           const temp = new StoreObjectArray(cmd.subtype, line, column, null, cmd.isConst);
           store.insertStore(cmd.id, temp);
-          return  store.updateStore(cmd.id, value);
+          if(value !== null)
+            return  store.updateStore(cmd.id, value);
+          else
+            return store;
         });
         
       } else {
         const temp = new StoreObject(cmd.type, null, cmd.isConst);
         store.insertStore(cmd.id, temp);
-        return $value.then(vl => store.updateStore(cmd.id, vl));
+        return $value.then(vl => {
+          if (vl !== null)
+            return store.updateStore(cmd.id, vl)
+          else
+            return store;
+        });
       }
     } catch (e) {
       return Promise.reject(e);
@@ -535,7 +543,14 @@ export class IVProgProcessor {
       return Promise.reject(new Error(`Function ${exp.id} cannot be used inside an expression`));
     }
     const $newStore = this.runFunction(func, exp.actualParameters, store);
-    return $newStore.then( sto => sto.applyStore('$'));
+    return $newStore.then( sto => {
+      const val = sto.applyStore('$');
+      if (val.type === Types.ARRAY) {
+        return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null,null), val));
+      } else {
+        return Promise.resolve(Object.assign(new StoreObject(null,null), val));
+      }
+    });
   }
 
   evaluateArrayLiteral (store, exp) {
@@ -577,7 +592,11 @@ export class IVProgProcessor {
   evaluateVariableLiteral (store, exp) {
     try {
       const val = store.applyStore(exp.id);
-      return Promise.resolve(val);
+      if (val.type === Types.ARRAY) {
+        return Promise.resolve(Object.assign(new StoreObjectArray(null,null,null,null), val));
+      } else {
+        return Promise.resolve(Object.assign(new StoreObject(null,null), val));
+      }
     } catch (error) {
       return Promise.reject(error);
     }
@@ -632,9 +651,9 @@ export class IVProgProcessor {
   }
 
   evaluateUnaryApp (store, unaryApp) {
-    const $left = this.evaluateExpression(store, infixApp.left);
+    const $left = this.evaluateExpression(store, unaryApp.left);
     return $left.then( left => {
-      if (!canApplyUnaryOp(infixApp.op, left)) {
+      if (!canApplyUnaryOp(unaryApp.op, left)) {
         // TODO: better urgent error message
         return Promise.reject(new Error(`Cannot use this op to ${left.type}`));
       }

+ 5 - 5
tests/test19.spec.js

@@ -3,24 +3,24 @@ import {Types} from './../js/ast/types';
 import { IVProgParser } from './../js/ast/ivprogParser';
 import { IVProgProcessor} from './../js/processor/ivprogProcessor'
 
-describe('Multi(*) operation', function (done) {
+describe('Multi(*) operation', function () {
 
   let input = `programa {
 
     funcao inicio() {
       inteiro a
-      a = -2 + 2 * 4
+      a = -2 + 2 * 4 + 2
     }
   }`;
 
   const lexer = Lexers['pt_br'];
 
-  it(`should have higher priority than Sum(+)`, function () {
+  it(`should have higher priority than Sum(+)`, function (done) {
     const parser = new IVProgParser(input, lexer);
     const exec = new IVProgProcessor(parser.parseTree());
     exec.interpretAST().then(sto => {
-      expect(sto.applyStore('a').value).toEqual(6);
+      expect(sto.applyStore('a').value).toEqual(8);
       done();
-    });
+    }).catch( err => done(err));
   });
 });

+ 2 - 2
tests/test20.spec.js

@@ -3,7 +3,7 @@ import {Types} from './../js/ast/types';
 import { IVProgParser } from './../js/ast/ivprogParser';
 import { IVProgProcessor} from './../js/processor/ivprogProcessor'
 
-describe('An Array initialization with expressions', function (done) {
+describe('An Array initialization with expressions', function () {
 
   const input = `programa {
 
@@ -15,7 +15,7 @@ describe('An Array initialization with expressions', function (done) {
   const lexer = Lexers['pt_br'];
   const result = [4,15];
 
-  it(`should produce a valid state`, function () {
+  it(`should produce a valid state`, function (done) {
     const parser = new IVProgParser(input, lexer);
     const exec = new IVProgProcessor(parser.parseTree());
     exec.interpretAST().then(sto => {

+ 3 - 3
tests/test21.spec.js

@@ -3,7 +3,7 @@ import {Types} from './../js/ast/types';
 import { IVProgParser } from './../js/ast/ivprogParser';
 import { IVProgProcessor} from './../js/processor/ivprogProcessor'
 
-describe('A call to a function that returns a valid type', function (done) {
+describe('A call to a function that returns a valid type', function () {
 
   const input = `programa {
 
@@ -20,12 +20,12 @@ describe('A call to a function that returns a valid type', function (done) {
   const lexer = Lexers['pt_br'];
   const result = 2;
 
-  it(`should produce a valid state`, function () {
+  it(`should produce a valid state`, function (done) {
     const parser = new IVProgParser(input, lexer);
     const exec = new IVProgProcessor(parser.parseTree());
     exec.interpretAST().then(sto => {
       expect(sto.applyStore('a').value).toEqual(result);
       done();
-    });
+    }).catch(err => done(err));
   });
 });

+ 2 - 4
tests/test22.spec.js

@@ -1,9 +1,8 @@
 import Lexers from './../grammar/';
-import {Types} from './../js/ast/types';
 import { IVProgParser } from './../js/ast/ivprogParser';
 import { IVProgProcessor} from './../js/processor/ivprogProcessor'
 
-describe('An assignment to a variable', function (done) {
+describe('An assignment to a variable', function () {
 
   const input = `programa {
 
@@ -14,9 +13,8 @@ describe('An assignment to a variable', function (done) {
   }`;
 
   const lexer = Lexers['pt_br'];
-  const result = 2;
 
-  it(`should respect the variable type`, function () {
+  it(`should respect the variable type`, function (done) {
     const parser = new IVProgParser(input, lexer);
     const exec = new IVProgProcessor(parser.parseTree());
     exec.interpretAST().then(sto => {

+ 24 - 0
tests/test23.spec.js

@@ -0,0 +1,24 @@
+import Lexers from './../grammar/';
+import {
+    IVProgParser
+} from './../js/ast/ivprogParser';
+
+describe('Variable initialization with a function call', () => {
+    let input = `programa {
+
+      funcao inicio() {
+        inteiro a = func(5)
+      }
+
+      funcao inteiro fun(inteiro a) {
+        retorne a * 2
+      }
+    }`;
+    const lexer = Lexers['pt_br'];
+
+    it(`should not throw an Error`, () => {
+        const as = new IVProgParser(input, lexer);
+        const fun = as.parseTree.bind(as);
+        expect(fun).not.toThrow();
+    });
+});

+ 26 - 0
tests/test25.spec.js

@@ -0,0 +1,26 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('Assigning an ID to another variable', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 5
+      inteiro b = a
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should result in a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('b').value).toEqual(5);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 26 - 0
tests/test26.spec.js

@@ -0,0 +1,26 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('Assigning a line from a matrix to another vector', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a[2][2] = {{5,2},{8,6}}
+      inteiro b[2] = a[0]
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should result in a valid state`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('b')).toBeTruthy();
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 30 - 0
tests/test27.spec.js

@@ -0,0 +1,30 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A finite while loop', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      inteiro b = 0
+      enquanto (a < 5) {
+        a = a + 1
+      }
+      b = 8
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should terminate`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(5);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 32 - 0
tests/test28.spec.js

@@ -0,0 +1,32 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A break command inside a inner while loop', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      inteiro b = 0
+      enquanto (a < 5) {
+        a = a + 1
+        enquanto (b < 1) {
+          pare
+        }
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should terminate the inner while only`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(5);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 28 - 0
tests/test29.spec.js

@@ -0,0 +1,28 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A break command inside a for loop', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      para(a = 0;a < 5; a = a + 1) {
+        pare
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should terminate it`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(0);
+      done();
+    }).catch( err => done(err));
+  });
+});

+ 38 - 0
tests/test30.spec.js

@@ -0,0 +1,38 @@
+import Lexers from './../grammar/';
+import {Types} from './../js/ast/types';
+import { IVProgParser } from './../js/ast/ivprogParser';
+import { IVProgProcessor} from './../js/processor/ivprogProcessor'
+
+describe('A break command inside a for loop', function () {
+
+  let input = `programa {
+
+    funcao inicio() {
+      inteiro a = 0
+      escolha (a) {
+        caso 2:
+          a = a + 1
+          pare
+        caso 1:
+          a = a + 2
+          pare
+        caso 0:
+          a = -5
+          pare
+        caso contrario:
+          a = 5 + 8
+      }
+    }
+  }`;
+
+  const lexer = Lexers['pt_br'];
+
+  it(`should terminate it`, function (done) {
+    const parser = new IVProgParser(input, lexer);
+    const exec = new IVProgProcessor(parser.parseTree());
+    exec.interpretAST().then(sto => {
+      expect(sto.applyStore('a').value).toEqual(-5);
+      done();
+    }).catch( err => done(err));
+  });
+});