Przeglądaj źródła

Implement reference operator for parameters

Remove special vars  and , now the return command recovers the function type information from the function declaration block
Lucas de Souza 5 lat temu
rodzic
commit
8df8e73a6d

+ 4 - 0
grammar/en/ivprog.g4

@@ -96,6 +96,10 @@ fragment RK_LOGICAL_AND
 fragment RK_LOGICAL_OR
   : 'OR'
   ;
+
+RK_REFERENCE
+  : '&'
+  ;
 // END i18n Lexical rules
 
 // GAMBIARRA   : '.' |'á'| 'à'| 'ã'|'â'|'é'|'ê'|'í'|'ó'|'ô'|'õ'|'ú'|'ü'|'ç'|'Ä'|'À'|'Ã'|'Â'|'É'|'Ê'|'Ë'|'Ó'|'Ô'|'Õ'|'Ú'|'Ü'|'Ç'|'#'|'$'|'"'|'§'|'?'|'¹'|'²'|'³'|'£'|'¢'|'¬'|'ª'|'º'|'~'|'\''|'`'|'\\'|'@';

+ 4 - 0
grammar/es/ivprog.g4

@@ -96,6 +96,10 @@ fragment RK_LOGICAL_AND
 fragment RK_LOGICAL_OR
   : 'OU'
   ;
+
+RK_REFERENCE
+  : '&'
+  ;
 // END i18n Lexical rules
 
 // GAMBIARRA   : '.' |'á'| 'à'| 'ã'|'â'|'é'|'ê'|'í'|'ó'|'ô'|'õ'|'ú'|'ü'|'ç'|'Ä'|'À'|'Ã'|'Â'|'É'|'Ê'|'Ë'|'Ó'|'Ô'|'Õ'|'Ú'|'Ü'|'Ç'|'#'|'$'|'"'|'§'|'?'|'¹'|'²'|'³'|'£'|'¢'|'¬'|'ª'|'º'|'~'|'\''|'`'|'\\'|'@';

+ 4 - 0
grammar/pt/ivprog.g4

@@ -96,6 +96,10 @@ fragment RK_LOGICAL_AND
 fragment RK_LOGICAL_OR
   : 'OU'
   ;
+
+RK_REFERENCE
+  : '&'
+  ;
 // END i18n Lexical rules
 
 // GAMBIARRA   : '.' |'á'| 'à'| 'ã'|'â'|'é'|'ê'|'í'|'ó'|'ô'|'õ'|'ú'|'ü'|'ç'|'Ä'|'À'|'Ã'|'Â'|'É'|'Ê'|'Ë'|'Ó'|'Ô'|'Õ'|'Ú'|'Ü'|'Ç'|'#'|'$'|'"'|'§'|'?'|'¹'|'²'|'³'|'£'|'¢'|'¬'|'ª'|'º'|'~'|'\''|'`'|'\\'|'@';

+ 19 - 11
js/ast/ivprogParser.js

@@ -320,7 +320,7 @@ export class IVProgParser {
         this.pos++;
         initial = this.parseExpressionOR();
       }
-      let declaration =  declaration = new Commands.Declaration(idString, typeString, initial, isConst);
+      const declaration = new Commands.Declaration(idString, typeString, initial, isConst);
       declaration.sourceInfo = sourceInfo;
       const commaToken = this.getToken();
       if(commaToken.type === this.lexerClass.COMMA) {
@@ -515,7 +515,7 @@ export class IVProgParser {
    * Returns a list of ArrayLiterals. Helper function for parsing matrices
   */
   parseVectorList (typeString) {
-    let list = [];
+    const list = [];
     let lastSize = null;
     for(;;) {
       this.checkOpenCurly();
@@ -636,20 +636,26 @@ export class IVProgParser {
     const list = [];
     for(;;) {
       let dimensions = 0;
+      let reference = false;
       const typeString = this.parseType();
-      const idToken = this.getToken();
+      let maybeIDToken = this.getToken();
+      if(maybeIDToken.type === this.lexerClass.RK_REFERENCE) {
+        reference = true;
+        this.pos += 1;
+        maybeIDToken = this.getToken();
+      }
       const idString = this.parseID();
-      this.checkVariableDuplicate(idString, idToken);
+      this.checkVariableDuplicate(idString, maybeIDToken);
       if (this.checkOpenBrace(true)) {
-        this.pos++;
-        dimensions++;
+        this.pos += 1;
+        dimensions += 1;
         this.checkCloseBrace();
-        this.pos++;
+        this.pos += 1;
         if(this.checkOpenBrace(true)) {
-          this.pos++;
-          dimensions++;
+          this.pos += 1;
+          dimensions += 1;
           this.checkCloseBrace();
-          this.pos++;
+          this.pos += 1;
         }
       }
       let type = null;
@@ -658,7 +664,9 @@ export class IVProgParser {
       } else {
         type = typeString;
       }
-      list.push(new Commands.FormalParameter(type, idString));
+      const parameter = new Commands.FormalParameter(type, idString, reference);
+      parameter.sourceInfo = SourceInfo.createSourceInfo(maybeIDToken);
+      list.push(parameter);
       const commaToken = this.getToken();
       if (commaToken.type !== this.lexerClass.COMMA)
         break;

+ 11 - 21
js/processor/ivprogProcessor.js

@@ -1,7 +1,7 @@
 import { Store } from './store/store';
 import { Modes } from './modes';
 import { Context } from './context';
-import { Types, fromOrdToType } from './../typeSystem/types';
+import { Types } from './../typeSystem/types';
 import { Operators } from './../ast/operators';
 import { LanguageDefinedFunction } from './definedFunctions';
 import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from './compatibilityTable';
@@ -127,17 +127,6 @@ export class IVProgProcessor {
     const funcName = func.isMain ? IVProgProcessor.MAIN_INTERNAL_ID : func.name;
     const funcStore = new Store(funcName);
     funcStore.extendStore(this.globalStore);
-    let dimensions = 0;
-    let type_ord = 0;
-    if(func.returnType instanceof ArrayType) {
-      // multi dimensional return...
-      dimensions = func.returnType.dimensions;
-      type_ord = func.returnType.innerType.ord;
-    } else {
-      type_ord = func.returnType.ord;
-    }
-    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);
     return newFuncStore$.then(sto => {
       this.context.push(Context.FUNCTION);
@@ -445,28 +434,29 @@ export class IVProgProcessor {
 
   executeReturn (store, cmd) {
     try {
-      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;
+      const func = this.findFunction(funcName);
+      const funcType = func.returnType;
+      const $value = this.evaluateExpression(store, cmd.expression);
+      
       return $value.then(value => {
 
+        let real_value = value;
         if(value === null && funcType.isCompatible(Types.VOID)) {
           store.mode = Modes.RETURN;
           return Promise.resolve(store);
         }
 
         if (value === null || !funcType.isCompatible(value.type)) {
-          const stringInfo = funcType.stringInfo();
+          if(!Config.enable_type_casting || !Store.canImplicitTypeCast(funcType, 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));
+          }
+          real_value = Store.doImplicitCasting(funcType, value);
         } else {
-          store.insertStore('$', value);
+          store.insertStore('$', real_value);
           store.mode = Modes.RETURN;
           return Promise.resolve(store);
         }

+ 14 - 12
js/processor/store/store.ts

@@ -16,7 +16,7 @@ import { StoreObjectArrayRef } from './store_object_array_ref';
 
 export class Store {
 
-  static canImplicitTypeCast (castType: IType, sourceType: IType) {
+  static canImplicitTypeCast (castType: IType, sourceType: IType): boolean {
     if (castType.isCompatible(Types.INTEGER) || castType.isCompatible(Types.REAL)) {
       if (sourceType.isCompatible(Types.INTEGER) || sourceType.isCompatible(Types.REAL)) {
         return true;
@@ -25,7 +25,7 @@ export class Store {
     return false;
   }
 
-  static doImplicitCasting (castType: IType, stoObj: IStoreValue) {
+  static doImplicitCasting (castType: IType, stoObj: IStoreValue): IStoreValue {
     if(!Store.canImplicitTypeCast(castType, stoObj.type)) {
       throw new Error("!!!Critical error: attempted to type cast invalid types");
     }
@@ -36,12 +36,12 @@ export class Store {
     }
   }
 
-  private store: Map<String, StoreObject>;
+  private store: Map<string, StoreObject>;
   public nextStore?: Store
   public mode: Symbol;
 
-  constructor(public name: String) {
-    this.store = new Map<String, StoreObject>();
+  constructor(public name: string) {
+    this.store = new Map<string, StoreObject>();
     this.mode = Modes.RUN; 
   }
 
@@ -49,7 +49,7 @@ export class Store {
     this.nextStore = nextStore;
   }
 
-  applyStore (id: String): IStoreValue {
+  applyStore (id: string): IStoreValue {
     if (!this.store.has(id)) {
       if (this.nextStore != null) {
         return this.nextStore.applyStore(id);
@@ -192,11 +192,13 @@ export class Store {
     }
   }
 
-  //In case of future use of ref, it needs to have a special function to update the storeRefObject
-  // and no the StoreObject refferenced by it
-  // updateStoreRef(id, stoObjAddress) {...}
-
-  insertStore (id: String, stoValue: IStoreValue) {
+  /**
+   * Inserts a new variable into the Store. This method should be used when declaring a new variable,
+   * including the special return variable $.
+   * @param id variable id
+   * @param stoValue the value to be used as the initial value of id
+   */
+  insertStore (id: string, stoValue: IStoreValue) {
     if (this.store.has(id)) {
       // TODO: better error message
       throw new Error(`${id} is already defined`);
@@ -236,7 +238,7 @@ export class Store {
    * Helper function similar to applyStore. But it returns the actual object in the store be it ref or not
    * applyStore will return the refferenced object if the object in the store is a ref
    */
-  getStoreObject (id: String): StoreObject {
+  getStoreObject (id: string): StoreObject {
     if (!this.store.has(id)) {
       if (this.nextStore != null) {
         return this.nextStore.getStoreObject(id);