Browse Source

Fix issue where non initialized array would throw an error

-Fix semanticAnalyser not inserting parameters in symbolMap

-Refactor castString function
Lucas de Souza 6 years ago
parent
commit
e517bd6e08

+ 63 - 11
index.html

@@ -30,19 +30,71 @@
     <div class="four wide column">
       <div class="row">
         <textarea class="ui form control" name="input" id="input" cols="100" rows="30">
-            programa {
+          programa {
 
-              const real C = 5.5
-             
-              funcao inteiro inicio() {
-               inteiro a = 8
-               se (a * C > 80) {
-                a = 0
-               } senao {
-                 a = -1
-               }
+            funcao inicio() {
+              inteiro a[16] = {1,8,3,5,7,4,2,1,8,3,5,7,-4,2,10,-1}
+              inteiro tam = numero_elementos(a) -1
+              inteiro i
+              a = mergeSort(a,0,tam)
+              para(i = 0; i< tam; i = i + 1) {
+                escreva(a[i]+", ")
               }
-             }
+              escreva(a[i])
+            }
+        
+            funcao inteiro[] mergeSort(inteiro a[], inteiro init, inteiro end) {
+              inteiro meio = (init+end)/2
+              inteiro size1 = meio - init + 1, size2 = end - meio, sizeF = end - init + 1
+              inteiro p1[size1]
+              inteiro p2[size2]
+              inteiro f[sizeF]
+              se (init < end) {
+                p1 = mergeSort(a, init, meio)
+                p2 = mergeSort(a, meio+1, end)
+                f = merge(p1,p2)
+                retorne f
+              } senao {
+                retorne {a[init]}
+              }
+            }
+        
+            funcao inteiro[] merge(inteiro p1[], inteiro p2[]) {
+              inteiro lenp1 = numero_elementos(p1)
+              inteiro lenp2 = numero_elementos(p2)
+              inteiro sizeF = lenp1 + lenp2
+              inteiro f[sizeF]
+              inteiro i = 0, a = 0, b =0
+              enquanto(i < lenp1+lenp2) {
+                se(a < lenp1) {
+                  se(b <lenp2) {
+                    se(p1[a] <= p2[b]) {
+                      f[i] = p1[a]
+                      a = a + 1
+                      i = i + 1
+                    } senao {
+                      f[i] = p2[b]
+                      b = b + 1
+                      i = i + 1
+                    }
+                  } senao {
+                    enquanto(a < lenp1) {
+                      f[i] = p1[a]
+                      a = a + 1
+                      i = i + 1
+                    }
+                  }
+                } senao {
+                  enquanto(b < lenp2) {
+                    f[i] = p2[b]
+                    b = b + 1
+                    i = i + 1
+                  }
+                }
+              }
+              retorne f
+            }
+          }
         </textarea>
       </div>
       <div class="row">

+ 3 - 2
js/main.js

@@ -35,10 +35,11 @@ try {
       proc.registerInput(domIn);
       domOut.clear();
       proc.registerOutput(domOut);
-      proc.interpretAST().then(sto => editor.load(sto.store))
-        .catch( e => alert(e));
+      proc.interpretAST().then(_ => editor.load({}))
+        .catch( e => {alert(e);console.log(e);});
     } catch (error) {
       alert(error);
+      console.log(error);
     }
     
   });

+ 39 - 10
js/processor/ivprogProcessor.js

@@ -13,6 +13,7 @@ import * as Expressions from './../ast/expressions/';
 import { StoreObjectArrayAddress } from './store/storeObjectArrayAddress';
 import { StoreObjectArrayAddressRef } from './store/storeObjectArrayAddressRef';
 import { CompoundType } from './../typeSystem/compoundType';
+import { convertToString } from '../typeSystem/parsers';
 
 export class IVProgProcessor {
 
@@ -90,7 +91,16 @@ export class IVProgProcessor {
   runFunction (func, actualParameters, store) {
     let funcStore = new Store();
     funcStore.extendStore(this.globalStore);
-    const returnStoreObject = new StoreObject(func.returnType, null);
+    let returnStoreObject = null;
+    if(func.returnType instanceof CompoundType) {
+      if(func.returnType.dimensions > 1) {
+        returnStoreObject = new StoreObjectArray(func.returnType,-1,-1,[[]]);
+      } else {
+        returnStoreObject = new StoreObjectArray(func.returnType,-1,null,[]);
+      }
+    } 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);
@@ -498,10 +508,10 @@ export class IVProgProcessor {
             column = columnSO.number;
           }
           const value = values[2];
-          const temp = new StoreObjectArray(cmd.type, line, column, null, cmd.isConst);
+          const temp = new StoreObjectArray(cmd.type, line, column, null);
           store.insertStore(cmd.id, temp);
+          let realValue = value;
           if (value !== null) {
-            let realValue = value;
             if(value instanceof StoreObjectArrayAddress) {
               if(value.type instanceof CompoundType) {
                 realValue = Object.assign(new StoreObjectArray(null,null,null), value.refValue);
@@ -509,17 +519,25 @@ export class IVProgProcessor {
                 realValue = Object.assign(new StoreObject(null,null), value.refValue);
               }
             }
-            store.updateStore(cmd.id, realValue)
+          } else {
+            realValue = new StoreObjectArray(cmd.type, line, column, [])
+            if(column !== null) {
+              for (let i = 0; i < column; i++) {
+                realValue.value.push([]);
+              }
+            }
           }
+          realValue.readOnly = cmd.isConst;
+          store.updateStore(cmd.id, realValue);
           return store;
         });
         
       } else {
-        const temp = new StoreObject(cmd.type, null, cmd.isConst);
+        const temp = new StoreObject(cmd.type, null);
         store.insertStore(cmd.id, temp);
         return $value.then(vl => {
+          let realValue = vl;
           if (vl !== null) {
-            let realValue = vl;
             if(vl instanceof StoreObjectArrayAddress) {
               if(vl.type instanceof CompoundType) {
                 realValue = Object.assign(new StoreObjectArray(null,null,null), vl.refValue);
@@ -527,8 +545,11 @@ export class IVProgProcessor {
                 realValue = Object.assign(new StoreObject(null,null), vl.refValue);
               }
             }
-            store.updateStore(cmd.id, realValue)
+          } else {
+            realValue = new StoreObject(cmd.type,0);
           }
+          realValue.readOnly = cmd.isConst;
+          store.updateStore(cmd.id, realValue);
           return store;
         });
       }
@@ -560,7 +581,6 @@ export class IVProgProcessor {
     } else if (exp instanceof Expressions.FunctionCall) {
       return this.evaluateFunctionCall(store, exp);
     }
-    console.log('null exp');
     return Promise.resolve(null);
   }
 
@@ -713,8 +733,17 @@ export class IVProgProcessor {
       }
       let result = null;
       switch (infixApp.op.ord) {
-        case Operators.ADD.ord:
-          return new StoreObject(resultType, left.value.plus(right.value));
+        case Operators.ADD.ord: {
+          if(Types.STRING.isCompatible(left.type)) {
+            const rightStr = convertToString(right.value, right.type);
+            return new StoreObject(resultType, left.value + rightStr);
+          } else if (Types.STRING.isCompatible(right.type)) {
+            const leftStr = convertToString(left.value, left.type);
+            return new StoreObject(resultType, leftStr + right.value);
+          } else {
+            return new StoreObject(resultType, left.value.plus(right.value));
+          }
+        }
         case Operators.SUB.ord:
           return new StoreObject(resultType, left.value.minus(right.value));
         case Operators.MULT.ord:

+ 2 - 32
js/processor/lib/lang.js

@@ -1,7 +1,7 @@
 import { StoreObject } from '../store/storeObject';
 import * as Commands from './../../ast/commands';
 import { Types } from './../../typeSystem/types';
-import { toReal, convertBoolToString } from "./../../typeSystem/parsers";
+import { toReal, convertToString } from "./../../typeSystem/parsers";
 import { IVProgParser } from '../../ast/ivprogParser';
 import { RealLiteral, IntLiteral, BoolLiteral } from '../../ast/expressions';
 
@@ -166,37 +166,7 @@ export function createCastBoolFun () {
 export function createCastStringFun () {
   const castStringFun = function (store, _) {
     const val = store.applyStore('str');
-    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);
-    }
-    let result = null;
-    switch (val.type.ord) {
-      case Types.INTEGER.ord:
-        result = val.value.toString();  
-        break;
-      case Types.REAL.ord: {
-        if (val.value.dp() <= 0) {
-          result = val.value.toFixed(1);  
-        } else {
-          result = val.number;
-        }
-        break;
-      }
-      case Types.BOOLEAN.ord:
-        result = convertBoolToString(val.value);
-        break;
-      default:
-        result = val.value;
-        break;
-    }
+    let result = convertToString(val)
     const temp = new StoreObject(Types.STRING, result);
     return Promise.resolve(sto.updateStore("$", temp));
   }

+ 13 - 1
js/processor/semantic/semanticAnalyser.js

@@ -43,7 +43,7 @@ export class SemanticAnalyser {
       if(symMap.next) {
         return this.findSymbol(id, symMap.next);
       }
-      throw new Error("variable not defined");
+      throw new Error("variable not defined "+id);
     } else {
       return symMap.map[id];
     }
@@ -267,6 +267,17 @@ export class SemanticAnalyser {
 
   assertFunction (fun) {
     this.pushMap();
+    fun.formalParameters.forEach(formalParam => {
+      if(formalParam.type instanceof CompoundType) {
+        if(formalParam.type.dimensions > 1) {
+          this.insertSymbol(formalParam.id, {id: formalParam.id, lines: -1, columns: -1, type: formalParam.type});
+        } else {
+          this.insertSymbol(formalParam.id, {id: formalParam.id, lines: -1, columns: null, type: formalParam.type});
+        }
+      } else {
+        this.insertSymbol(formalParam.id, {id: formalParam.id, type: formalParam.type});
+      }
+    })
     this.assertDeclarations(fun.variablesDeclarations);
     const optional = fun.returnType.isCompatible(Types.VOID);
     const valid = this.assertReturn(fun, optional);
@@ -434,6 +445,7 @@ export class SemanticAnalyser {
         console.log(formalParam.type);
         throw new Error(`Parameter ${formalParam.id} is not compatible with the value given.`);
       }
+
     }
   }
 }

+ 4 - 0
js/processor/store/storeObject.js

@@ -41,6 +41,10 @@ export class StoreObject {
     return this._readOnly;
   }
 
+  set readOnly (value) {
+    this._readOnly = value;
+  }
+
   isCompatible (another) {
     if( another instanceof StoreObject) {
       return this.type.isCompatible(another.type);

+ 6 - 3
js/processor/store/storeObjectArray.js

@@ -18,9 +18,12 @@ export class StoreObjectArray extends StoreObject {
 
   isCompatible (another) {
     if(another instanceof StoreObject) {
-      if(this.lines === another.lines &&
-        this.columns === another.columns) {
-          return super.isCompatible(another);
+      if(((this.lines === -1 && another.lines > 0) ||
+        (this.lines === another.lines))) {
+          if ((this.columns === -1 && another.columns > 0) ||
+            (this.columns === another.columns)) {
+              return super.isCompatible(another);
+          }
         }
     }
     return false;

+ 20 - 1
js/typeSystem/parsers.js

@@ -1,4 +1,5 @@
 import { LanguageService } from "../services/languageService";
+import { Types } from "./types";
 import { BigNumber } from 'bignumber.js'
 
 export function toInt (str) {
@@ -36,7 +37,7 @@ export function toBool (str) {
   }
 }
 
-export function convertBoolToString (bool) {
+function convertBoolToString (bool) {
   const lexer = LanguageService.getCurrentLexer();
   const instance = new lexer(null);
   if (bool) {
@@ -44,4 +45,22 @@ export function convertBoolToString (bool) {
   } else {
     return instance.literalNames[lexer.RK_FALSE];
   }
+}
+
+export function convertToString(stoObj, type) {
+  switch (type.ord) {
+    case Types.INTEGER.ord:
+      return stoObj.toString();
+    case Types.REAL.ord: {
+      if (stoObj.dp() <= 0) {
+        return stoObj.toFixed(1);  
+      } else {
+        return stoObj.toNumber();
+      }
+    }
+    case Types.BOOLEAN.ord:
+      return convertBoolToString(stoObj);
+    default:
+      return stoObj;
+  }
 }

+ 91 - 0
tests/test65.spec.js

@@ -0,0 +1,91 @@
+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 { IVProgProcessor } from '../js/processor/ivprogProcessor';
+
+describe('Non initialized vector/matrix', function () {
+
+  const code = `programa {
+
+    funcao inicio() {
+      inteiro a[16] = {1,8,3,5,7,4,2,1,8,3,5,7,-4,2,10,-1}
+      inteiro tam = numero_elementos(a) - 1
+      inteiro i
+      a = mergeSort(a, 0, tam)
+      para(i = 0; i< tam; i = i + 1) {
+        escreva(a[i] + ", ")
+      }
+      escreva(a[i])
+    }
+  
+    funcao inteiro[] mergeSort(inteiro a[], inteiro init, inteiro end) {
+      inteiro meio = (init + end) / 2
+      inteiro size1 = meio - init + 1, size2 = end - meio, sizeF = end - init + 1
+      inteiro p1[size1]
+      inteiro p2[size2]
+      inteiro f[sizeF]
+      se (init < end) {
+        p1 = mergeSort(a, init, meio)
+        p2 = mergeSort(a, meio+1, end)
+        f = merge(p1, p2)
+        retorne f
+      } senao {
+        retorne { a[init] }
+      }
+    }
+  
+    funcao inteiro[] merge(inteiro p1[], inteiro p2[]) {
+      inteiro lenp1 = numero_elementos(p1)
+      inteiro lenp2 = numero_elementos(p2)
+      inteiro sizeF = lenp1 + lenp2
+      inteiro f[sizeF]
+      inteiro i = 0, a = 0, b =0
+      enquanto(i < lenp1+lenp2) {
+        se(a < lenp1) {
+          se(b <lenp2) {
+            se(p1[a] <= p2[b]) {
+              f[i] = p1[a]
+              a = a + 1
+              i = i + 1
+            } senao {
+              f[i] = p2[b]
+              b = b + 1
+              i = i + 1
+            }
+          } senao {
+            enquanto(a < lenp1) {
+              f[i] = p1[a]
+              a = a + 1
+              i = i + 1
+            }
+          }
+        } senao {
+          enquanto(b < lenp2) {
+            f[i] = p2[b]
+            b = b + 1
+            i = i + 1
+          }
+        }
+      }
+      retorne f
+    }
+  }
+  `;
+
+  localStorage.setItem('ivprog.lang', 'pt');
+
+  const lexer = LanguageService.getCurrentLexer();
+  const out = new OutputTest();
+
+  it(`should not throw an exception`, function (done) {
+    const parser = new IVProgParser(code, lexer);
+    const sem = new SemanticAnalyser(parser.parseTree());
+    const exec = new IVProgProcessor(sem.analyseTree());
+    exec.registerOutput(out);
+    exec.interpretAST().then(_ => {
+      expect(out.list.length).toEqual(16);
+      done()
+    }).catch( err => done(err));
+  });
+});