Prechádzať zdrojové kódy

Implement array as return - Fix #11

Lucas de Souza 5 rokov pred
rodič
commit
c872bc157b

+ 18 - 1
js/ast/ivprogParser.js

@@ -432,7 +432,20 @@ export class IVProgParser {
       return null;
     }
     this.pos++;
-    const returnType = this.parseType();
+    const funType = this.parseType();
+    let dimensions = 0;
+    if(this.checkOpenBrace(true)) {
+      this.pos++;
+      this.checkCloseBrace();
+      this.pos++;
+      dimensions++;
+      if(this.checkOpenBrace(true)) {
+        this.pos++;
+        this.checkCloseBrace();
+        this.pos++;
+        dimensions++;
+      }
+    }
     const functionID = this.parseID();
     this.checkOpenParenthesis();
     this.pos++;
@@ -447,6 +460,10 @@ export class IVProgParser {
     }
     this.consumeNewLines();
     const commandsBlock = this.parseCommandBlock();
+    let returnType = funType;
+    if(dimensions > 0) {
+      returnType = new CompoundType(funType, dimensions);
+    }
     const func = new Commands.Function(functionID, returnType, formalParams, commandsBlock);
     if (functionID === null && !func.isMain) {
       // TODO: better error message

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

@@ -196,7 +196,25 @@ export class SemanticAnalyser {
       return typeInfo.type;
     } else {
       console.warn("Evaluating type only for an array literal...");
-      return Types.UNDEFINED;
+      let last = null;
+      if(literal.value.length === 1) {
+        last = this.evaluateExpressionType(literal.value[0]);
+      } else {
+        for (let i = 0; i < literal.value.length; i++) {
+          const e = this.evaluateExpressionType(literal.value[i]);
+          if(last === null) {
+            last = e;
+          } else if(!last.isCompatible(e)) {
+            throw new Error("invalid value type for array");
+          } else {
+            last = e;
+          }
+        }
+      }
+      if(last instanceof CompoundType) {
+        return new CompoundType(last.innerType, last.dimensions + 1);
+      }
+      return new CompoundType(last, 1);
     }
   }
 
@@ -236,10 +254,10 @@ export class SemanticAnalyser {
     } else {
 
       const resultType = this.evaluateExpressionType(literal);
-      if (!(resultType.type instanceof CompoundType)) {
+      if (!(resultType instanceof CompoundType)) {
         throw new Error("initial must be of type array");
       }
-      if (!type.isCompatible(resultType.type)) {
+      if (!type.isCompatible(resultType)) {
         throw new Error("invalid array type");
       }
       return true;
@@ -363,7 +381,8 @@ export class SemanticAnalyser {
         throw new Error('invalid return type');
       } else if (cmd.expression !== null) {
         const resultType = this.evaluateExpressionType(cmd.expression);
-        if (!resultType.isCompatible(type)) {
+        if (!type.isCompatible(resultType)) {
+          console.log(resultType);
           throw new Error('invalid return type');
         } else {
           return true;

+ 36 - 0
tests/test64.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 { IVProgProcessor } from '../js/processor/ivprogProcessor';
+
+describe('Defining a return type as array', function () {
+
+  const code = `programa {
+
+    funcao inicio() {
+      inteiro a[2] = retArr()
+      escreva(a[0])
+    }
+
+    funcao inteiro[] retArr () {
+      retorne {0,0}
+    }
+  }`;
+
+  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).toEqual(['0']);
+      done()
+    }).catch( err => done(err));
+  });
+});