Procházet zdrojové kódy

Language Processor cont.

-formal parameter as a class
-language defined functions: read and write
-type ALL for overloaded system functions
-type Array and Undefined for array literals and varible literals respectively
-Input I/O template to abstract input source types
-Implement DOMInput to use a given input/textarea as a input source
-Fix a problem where VariableLiteral wasn't being instantianed during code parse
-Implement an internal StoreObjectRef to pass variable as reference to internal functions
-Removing array validity checks for the time being
Lucas de Souza před 5 roky
rodič
revize
854efe80ff

+ 3 - 1
grammar/pt-br/ivprog.g4

@@ -3,6 +3,8 @@ lexer grammar ivprog;
 @lexer::members{
   //Translate to fit your language
   ivprog.MAIN_FUNCTION_NAME = "inicio";
+  ivprog.READ_FUNCTION_NAME = "leia";
+  ivprog.WRITE_FUNCTION_NAME = "escreva";
 }
 
 // BEGIN i18n Lexical rules
@@ -154,7 +156,7 @@ OR_OPERATOR
   ;
 
 RELATIONAL_OPERATOR
-  : ('>='|'=='|'<='|'>'|'<')
+  : ('>='|'=='|'<='|'>'|'<'|'!=')
   ;
 
 COLON

+ 2 - 1
js/ast/commands/arrayDeclaration.js

@@ -1,9 +1,10 @@
 import { Declaration } from './declaration';
+import { Types } from './../types';
 
 export class ArrayDeclaration extends Declaration {
 
   constructor (id, subtype, lines, columns, initial, isConst)   {
-    super(id, 'array', initial, isConst);
+    super(id, Types.ARRAY, initial, isConst);
     this.subtype = subtype;
     this.lines = lines;
     this.columns = columns;

+ 9 - 0
js/ast/commands/formalParameter.js

@@ -0,0 +1,9 @@
+export class FormalParameter {
+
+  constructor (type, id, dimensions, byRef = false) {
+    this.type = type;
+    this.id = id;
+    this.dimensions = dimensions;
+    this.byRef = byRef;
+  }
+}

+ 5 - 1
js/ast/commands/index.js

@@ -11,6 +11,8 @@ import { CommandBlock } from './commandBlock';
 import { DoWhile } from './doWhile';
 import { Switch } from './switch';
 import { Case } from './case';
+import { SysCall } from './sysCall';
+import { FormalParameter } from './formalParameter';
 
 export {
   Break,
@@ -25,5 +27,7 @@ export {
   CommandBlock,
   DoWhile,
   Switch,
-  Case
+  Case,
+  SysCall,
+  FormalParameter
 };

+ 12 - 0
js/ast/commands/sysCall.js

@@ -0,0 +1,12 @@
+/**
+ * This class represents all the language defined functions.
+ * The language processor uses the id provided here to properly execute the desired function.
+ * The function is actually implemented inside the language processor.
+ * All the functions can be found at: js/processor/definedFunctions.js
+ */
+export class SysCall {
+
+  constructor (id) {
+    this.id = id;
+  }
+}

+ 8 - 2
js/ast/expressions/arrayLiteral.js

@@ -1,8 +1,10 @@
 import { Literal } from './literal';
+import { Types } from './../types';
+
 export class ArrayLiteral extends Literal {
   
   constructor(value) {
-    super('array');
+    super(Types.ARRAY);
     this.value = value;
   }
 
@@ -28,8 +30,12 @@ export class ArrayLiteral extends Literal {
     }
   }
 
+  get isVector () {
+    return this.columns === null;
+  }
+
   get isValid () {
-    return this.validateType() && this.validateSize();
+    return true;//this.validateType() && this.validateSize();
   }
 
   validateType () {

+ 5 - 3
js/ast/expressions/variableLiteral.js

@@ -1,8 +1,10 @@
 import { Literal } from './literal';
+import { Types } from './../types';
+
 export class VariableLiteral extends Literal {
   
-  constructor(value) {
-    super('variable');
-    this.value = value;
+  constructor(id) {
+    super(Types.UNDEFINED);
+    this.id = id;
   }
 }

+ 10 - 25
js/ast/ivprogParser.js

@@ -1,7 +1,7 @@
 import { CommonTokenStream, InputStream } from 'antlr4/index';
 import * as Expressions from './expressions/';
 import * as Commands from './commands/';
-import { Types } from './types';
+import { Types, toInt, toString } from './types';
 import { convertFromString } from './operators';
 import { SyntaxError } from './SyntaxError';
 
@@ -319,15 +319,7 @@ export class IVProgParser {
   **/
   getIntLiteral (token) {
     const text = token.text;
-    let val = null;
-    if(text.match('^0b|^0B')) {
-      val = parseInt(text.substring(2), 2);
-    } else if (text.match('^0x|^0X')) {
-      val = parseInt(text.substring(2), 16);
-    } else {
-      val = parseInt(text);
-    }
-    return new Expressions.IntLiteral(val);
+    return new Expressions.IntLiteral(toInt(text));
   }
 
   getRealLiteral (token) {
@@ -336,14 +328,7 @@ export class IVProgParser {
 
   getStringLiteral (token) {
     const text = token.text;
-    let value = text.replace("\\b", "\b");
-    value = value.replace("\\t", "\t");
-    value = value.replace("\\n", "\n");
-    value = value.replace("\\r", "\r");
-    value = value.replace("\\\"", "\"");
-    value = value.replace("\\\'", "\'");
-    value = value.replace("\\\\", "\\");
-    return new Expressions.StringLiteral(value);
+    return new Expressions.StringLiteral(toString(text));
   }
 
   getBoolLiteral (token) {
@@ -367,11 +352,11 @@ export class IVProgParser {
     this.pos++;
     this.parsingArrayDimension--;
     if (this.parsingArrayDimension === 0) {
-      if (!data.isValid) {
-      // TODO: better error message
-      console.log('invalid array');
-      throw new Error(`Invalid array at line ${beginArray.line}`);
-    }
+      // if (!data.isValid) {
+      //   // TODO: better error message
+      //   console.log('invalid array');
+      //   throw new Error(`Invalid array at line ${beginArray.line}`);
+      // }
     }
     return new Expressions.ArrayLiteral(data);
   }
@@ -444,7 +429,7 @@ export class IVProgParser {
           this.pos++;
         }
       }
-      list.push({type: typeString, id: idString, dimensions: dimensions});
+      list.push(new Commands.FormalParameter(typeString, idString, dimensions));
       const commaToken = this.getToken();
       if (commaToken.type !== this.lexerClass.COMMA)
         break;
@@ -940,7 +925,7 @@ export class IVProgParser {
       return new Expressions.FunctionCall(id, actualParameters);
     } else {
       this.pos = last;
-      return id;
+      return new Expressions.VariableLiteral(id);
     }
   }
 

+ 34 - 6
js/ast/types.js

@@ -1,7 +1,35 @@
 export const Types = Object.freeze({
-  INTEGER: Symbol("int"),
-  REAL: Symbol("real"),
-  STRING: Symbol("string"),
-  BOOLEAN: Symbol("bool"),
-  VOID: Symbol("void")
-});
+  INTEGER: "int",
+  REAL: "real",
+  STRING: "string",
+  BOOLEAN: "bool",
+  VOID: "void",
+  ARRAY: 'array',
+  UNDEFINED: 'undefined',
+  ALL: 'all'
+});
+
+export function toInt (str) {
+  if(str.match('^0b|^0B')) {
+    return parseInt(str.substring(2), 2);
+  } else if (str.match('^0x|^0X')) {
+    return parseInt(str.substring(2), 16);
+  } else {
+    return parseInt(str);
+  }
+}
+
+export function toString (str) {
+  let value = str.replace("\\b", "\b");
+  value = value.replace("\\t", "\t");
+  value = value.replace("\\n", "\n");
+  value = value.replace("\\r", "\r");
+  value = value.replace("\\\"", "\"");
+  value = value.replace("\\\'", "\'");
+  value = value.replace("\\\\", "\\");
+  return value;
+}
+
+export function toBool (str) {
+  return true;
+}

+ 47 - 0
js/io/domInput.js

@@ -0,0 +1,47 @@
+import {Input} from './input';
+import $ from 'jquery';
+
+export class DOMInput extends Input{
+
+  constructor (element) {
+    this.el = $(element);
+    this.listeners = [];
+    this.setupEvents();
+  }
+
+  setupEvents () {
+    this.el.on('keydown', (e) => {
+      const code = e.keyCode || e.which;
+      if (code === 13) {
+        let text = this.el.val();
+        text = text.replace('[\n\r]+', '');
+        this.notifyInput(text);
+        this.el.val('');
+      }
+    });
+  }
+
+  registerListener (listener) {
+    if(!listener.notify) {
+      throw new Error("InternalError: Input listener must implement a notify function.");
+    }
+    this.listeners.push(listener);
+  }
+
+  requestInput () {
+    this.el.focus();
+  }
+
+  removeListener (listener) {
+    const idx = this.listeners.indexOf(listener);
+    if (idx)
+      this.listeners.splice(idx, 1);
+  }
+
+  notifyInput (text) {
+    this.listeners.forEach(l => {
+      l.notify(text);
+    })
+  }
+
+}

+ 18 - 0
js/io/input.js

@@ -0,0 +1,18 @@
+export class Input {
+
+  registerListener (listener) {
+    throw new Error("Must be implemented");
+  }
+
+  notifyInput (text) {
+    throw new Error("Must be implemented");
+  }
+
+  requestInput () {
+    throw new Error("Must be implemented");
+  }
+
+  removeListener (listener) {
+    throw new Error("Must be implemented");
+  }
+}

+ 25 - 31
js/main.js

@@ -5,28 +5,18 @@ import {
 import * as Commands from './ast/commands';
 import { IVProgParser } from './ast/ivprogParser';
 import Lexers from '../grammar/';
+import { IVProgProcessor } from './processor/ivprogProcessor';
 
 const lang = 'pt_br';
 
 const ivprogLexer = Lexers[lang];
 
 const input = `programa {
-
-  const real C = 6.8-5.8+1
              
-  funcao abc() {
-     inteiro a = 8
-     se (a * C > 80) {
-        a = 0
-     } senao se(verdadeiro) {
-        a = -1
-       fun()
-     }
+  funcao inicio() {
+     inteiro a[2] = {1,2}
   }
 
-  funcao real fun() {
-    retorne 3
-  }
 }`;
 
 // const lexer = new ivprogLexer(new InputStream(input));
@@ -40,22 +30,26 @@ const input = `programa {
 //     i++;
 // }
 const anaSin = new IVProgParser(input, ivprogLexer);
-try {
-  const data = anaSin.parseTree();
-  console.log(data);
-  var editor = new JsonEditor('#json-renderer', data);
-  $('#btn').click( () => {
-    const input = $('#input').val();
-    const analiser = new IVProgParser(input, ivprogLexer);
-    try {
-      const data = analiser.parseTree();
-      console.log(data);
-      editor.load(data);  
-    } catch (error) {
-      alert(error);
-    }
+const proc = new IVProgProcessor(anaSin.parseTree());
+proc.interpretAST().then( sto => {
+  console.log(sto.applyStore('a'));
+}).catch(e => console.log(e));
+// try {
+//   const data = anaSin.parseTree();
+//   console.log(data);
+//   var editor = new JsonEditor('#json-renderer', data);
+//   $('#btn').click( () => {
+//     const input = $('#input').val();
+//     const analiser = new IVProgParser(input, ivprogLexer);
+//     try {
+//       const data = analiser.parseTree();
+//       console.log(data);
+//       editor.load(data);  
+//     } catch (error) {
+//       alert(error);
+//     }
     
-  });
-} catch(a) {
-  console.log(a);
-}
+//   });
+// } catch(a) {
+//   console.log(a);
+// }

+ 28 - 0
js/processor/definedFunctions.js

@@ -0,0 +1,28 @@
+import * as Commands from './../ast/commands';
+import {Types} from './../ast/types';
+
+function createOutputFun () {
+  const block = new Commands.CommandBlock([], [new Commands.SysCall('$write')]);
+  const func = new Commands.Function('$write', Types.VOID,
+    [new Commands.FormalParameter(Types.ALL, 'p1', 0, true)],
+    block);
+  return func;
+}
+
+function createInputFun () {
+  const block = new Commands.CommandBlock([],  [new Commands.SysCall('$read')]);
+  const func = new Commands.Function('$read', Types.VOID,
+    [new Commands.FormalParameter(Types.ALL, 'p1', 0, true)],
+    block);
+  return func;
+}
+
+export const LanguageDefinedFunction = Object.freeze({
+  $write: createOutputFun(),
+  $read: createInputFun()
+});
+
+export const NAMES = Object.freeze({
+  WRITE: '$write',
+  READ: '$read'
+});

+ 112 - 28
js/processor/ivprogProcessor.js

@@ -1,10 +1,12 @@
 import { Store } from './store/store';
 import { StoreObject } from './store/storeObject';
 import { StoreObjectArray } from './store/storeObjectArray';
+import { StoreObjectRef } from './store/storeObjectRef';
 import { Modes } from './modes';
 import { Context } from './context';
-import { Types } from './../ast/types';
+import { Types, toInt } from './../ast/types';
 import { Operators } from './../ast/operators';
+import { NAMES } from './definedFunctions';
 import { canApplyInfixOp, canApplyUnaryOp } from './compatibilityTable';
 import * as Commands from './../ast/commands/';
 import * as Expressions from './../ast/expressions/';
@@ -29,7 +31,7 @@ export class IVProgProcessor {
   }
 
   checkContext(context) {
-    return this.context[this.context.length] === context;
+    return this.context[this.context.length - 1] === context;
   }
 
   ignoreSwitchCases (store) {
@@ -85,7 +87,9 @@ export class IVProgProcessor {
     funcStore = this.associateParameters(func.formalParameters, actualParameters, store, funcStore);
     this.context.push(Context.FUNCTION);
     this.stores.push(funcStore);
-    const result = this.executeCommands(funcStore, func.commands);
+    const result = this.executeCommands(funcStore, func.variablesDeclarations).then(sto => {
+      return this.executeCommands(sto, func.commands)
+    });
     this.stores.pop();
     this.context.pop();
     return result;
@@ -102,8 +106,16 @@ export class IVProgProcessor {
         switch (v.dimensions) {
           case 1: {
             if (vl.lines > 0 && vl.columns === null
-              && vl.subtype === v.subtype) {
-              calleeStore.insertStore(v.id, vl);
+              && vl.subtype === v.type) {
+              if(v.byRef && !vl.inStore) {
+                throw new Error('You must inform a variable as parameter');
+              }
+              if(v.byRef) {
+                const ref = new StoreObjectRef(vl.id, callerStore);
+                calleeStore.insertStore(v.id, ref);
+              } else {
+                calleeStore.insertStore(v.id, vl);
+              }
             } else {
               // TODO: Better error message
               throw new Error(`Parameter ${v.id} is not compatible with the value given.`);
@@ -112,8 +124,13 @@ export class IVProgProcessor {
           }
           case 2: {
             if (vl.lines > 0 && vl.columns > 0
-              && vl.subtype === v.subtype) {
-              calleeStore.insertStore(v.id, vl);
+              && vl.subtype === v.type) {
+                if(v.byRef) {
+                  const ref = new StoreObjectRef(vl.id, callerStore);
+                  calleeStore.insertStore(v.id, ref);
+                } else {
+                  calleeStore.insertStore(v.id, vl);
+                }
             } else {
               // TODO: Better error message
               throw new Error(`Parameter ${v.id} is not compatible with the value given.`);
@@ -121,11 +138,18 @@ export class IVProgProcessor {
             break;
           }
           case 0: {
-            if (vl.type !== v.type) {
+            if(v.byRef && !vl.inStore) {
+              throw new Error('You must inform a variable as parameter');
+            } else if (v.type !== Types.ALL && vl.type !== v.type) {
               // TODO: Better error message
               throw new Error(`Parameter ${v.id} is not compatible with ${vl.type}.`);
             } else {
-              calleeStore.insertStore(v.id, vl);
+              if(v.byRef) {
+                const ref = new StoreObjectRef(vl.id, callerStore);
+                calleeStore.insertStore(v.id, ref);
+              } else {
+                calleeStore.insertStore(v.id, vl);
+              }
             }
           }
         }
@@ -186,11 +210,58 @@ export class IVProgProcessor {
       return this.executeSwitch(store, cmd);
     } else if (cmd instanceof Commands.FunctionCall) {
       return this.executeFunctionCall(store, cmd);
+    } else if (cmd instanceof Commands.SysCall) {
+      return this.executeSysCall(store, cmd);
     } else {
       throw new Error("!!!CRITICAL A unknown command was found!!!\n" + cmd);
     }
   }
 
+  executeSysCall (store, cmd) {
+    if (cmd.id === NAMES.WRITE) {
+      this.runWriteFunction(store)
+    }
+  }
+
+  runWriteFunction (store) {
+    const val = store.applyStore('p1');
+    this.output.appendText(val.val);
+    return Promise.resolve(store);
+  }
+
+  runReadFunction (store) {
+    const typeToConvert = store.applyStore('p1').type;
+    const listenInput = (text) => {
+      if (typeToConvert === Types.INTEGER) {
+        const val = toInt(text);
+        return new StoreObject(Types.INTEGER, val);
+      } else if (typeToConvert === Types.REAL) {
+        return new StoreObject(Types.REAL, parseFloat(text));
+      } else if (typeToConvert === Types.BOOLEAN) {
+        
+      } else if (typeToConvert === Types.STRING) {
+        return new StoreObject(Types.STRING, text);
+      }
+    }
+
+    return Promise.resolve(store).then( sto => {
+      let received = false;
+      const notify = (text) => {
+        received = true;
+        const result = listenInput(text);
+        sto.updateStore('p1', result);
+      }
+      const obj = {notify: notify.bind(this)}
+      this.input.registerListener(obj);
+      this.input.requestInput();
+      while(!received) {
+        continue;
+      }
+      this.input.removeListener(obj);
+      return sto;
+    });
+  }
+
   executeFunctionCall (store, cmd) {
     const func = this.findFunction(cmd.id);
     this.runFunction(func, cmd.actualParameters, store);
@@ -210,7 +281,7 @@ export class IVProgProcessor {
           });
         } else {
           const $value = this.evaluateExpression(sto,
-            new Expressions.InfixApp('==', switchExp, aCase.expression));
+            new Expressions.InfixApp(Operators.EQ, switchExp, aCase.expression));
           return $value.then(vl => {
             if (vl.value) {
               const $newSto = this.executeCommand(result.sto,aCase.commands);
@@ -228,7 +299,6 @@ export class IVProgProcessor {
     try {
       this.context.push(Context.BREAKABLE);
       let breakLoop = false;
-      const case0 = cmd.cases[0];
       let $result = Promise.resolve({wasTrue: false, sto: store});
       for (let index = 0; index < cmd.cases.length && !breakLoop; index++) {
         const aCase = cmd.cases[index];
@@ -236,7 +306,12 @@ export class IVProgProcessor {
         $result.then( r => breakLoop = this.ignoreSwitchCases(r.sto));
       }
       this.context.pop();
-      return result.then(r => r.sto);
+      return result.then(r => {
+        if(r.sto.mode === Modes.BREAK) {
+          r.sto.mode = Modes.RUN;
+        }
+        return r.sto;
+      });
     } catch (error) {
       return Promise.reject(error);
     }
@@ -264,6 +339,11 @@ export class IVProgProcessor {
       this.context.push(Context.BREAKABLE);
       const $newStore = this.executeCommands(store, cmd.commands);
       return $newStore.then(sto => {
+        if(sto.mode === Modes.BREAK) {
+          this.context.pop();
+          sto.mode = Modes.RUN;
+          return Promise.resolve(sto);
+        }
         const $value = this.evaluateExpression(sto, cmd.expression);
         return $value.then(vl => {
           if (vl.type !== Types.BOOLEAN) {
@@ -295,6 +375,10 @@ export class IVProgProcessor {
             const $newStore = this.executeCommands(store, cmd.commands);
             return $newStore.then(sto => {
               this.context.pop();
+              if (sto.mode === Modes.BREAK) {
+                sto.mode = Modes.RUN;
+                return Promise.resolve(sto);
+              }
               return this.executeCommand(sto, cmd);
             });
           } else {
@@ -379,19 +463,13 @@ export class IVProgProcessor {
     try {
       const $value = this.evaluateExpression(store, cmd.initial);
       if(cmd instanceof Commands.ArrayDeclaration) {
-        const temp = new StoreObjectArray(decl.subtype, decl.lines, decl.columns, null, decl.isConst);
-        store.insertStore(decl.id, temp);
-        return $value.then(vl => {
-          store.updateStore(decl.id, vl)
-          return store;
-        });
+        const temp = new StoreObjectArray(cmd.subtype, cmd.lines, cmd.columns, null, cmd.isConst);
+        store.insertStore(cmd.id, temp);
+        return $value.then(vl => store.updateStore(cmd.id, vl));
       } else {
-        const temp = new StoreObject(decl.type, null, decl.isConst);
-        store.insertStore(decl.id, temp);
-        return $value.then(vl => {
-          store.updateStore(decl.id, vl)
-          return store;
-        });
+        const temp = new StoreObject(cmd.type, null, cmd.isConst);
+        store.insertStore(cmd.id, temp);
+        return $value.then(vl => store.updateStore(cmd.id, vl));
       }
     } catch (e) {
       return Promise.reject(e);
@@ -434,7 +512,7 @@ export class IVProgProcessor {
   }
 
   evaluateArrayLiteral (store, exp) {
-    if(exp.columns !== null) {
+    if(!exp.isVector) {
       let column = [];
       for (let i = 0; i < exp.lines; i++) {
         const line = [];
@@ -446,15 +524,21 @@ export class IVProgProcessor {
         column.push(stoArray);
       }
       const arr = new StoreObjectArray(column[0].subtype, column.length, column[0].lines, column);
-      return Promise.resolve(arr);
+      if(arr.isValid)
+        return Promise.resolve(arr);
+      else
+        return Promise.reject(new Error(`Invalid array`))
     } else {
       let line = [];
       for (let i = 0; i < exp.lines; i++) {
-        const $value = this.evaluateExpression(store, exp.value[i].value[j]);
+        const $value = this.evaluateExpression(store, exp.value[i]);
         $value.then(value => line.push(value));
       }
       const stoArray = new StoreObjectArray(line[0].type, line.length, null, line);
-      return Promise.resolve(stoArray);
+      if(stoArray.isValid)
+        return Promise.resolve(stoArray);
+      else
+        return Promise.reject(new Error(`Invalid array`))
     }
   }
 

+ 12 - 2
js/processor/store/store.js

@@ -20,6 +20,10 @@ export class Store {
         throw new Error(`Variable ${id} not found.`);
       }
     }
+    const val = this.store[id];
+    if (val.isRef) {
+      return val.getRefObj();
+    }
     return this.store[id];
   }
 
@@ -32,12 +36,17 @@ export class Store {
         throw new Error(`Variable ${id} not found.`);
       }
     } else {
-      const oldObj = this.applyStore(id);
+      const oldObj = this.store[id];
       if(oldObj.readOnly) {
         // 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;
+        }
+        stoObj.setID(id);
         this.store[id] = Object.freeze(stoObj);
         return this;
       } else {
@@ -52,7 +61,8 @@ export class Store {
       // TODO: better error message
       throw new Error(`${id} is already defined`);
     }
-    this.store[id] = stoObj;
+    stoObj.setID(id);
+    this.store[id] = Object.freeze(stoObj);
     return this;
   }
 }

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

@@ -1,9 +1,34 @@
 export class StoreObject {
 
-  constructor (type, value, readOnly) {
-    this.type = type;
-    this.value = value;
-    this.readOnly = readOnly;
+  constructor (type, value, readOnly = false) {
+    this._type = type;
+    this._value = value;
+    this._readOnly = readOnly;
+    this._id = null;
+  }
+
+  setID (id) {
+    this._id = id;
+  }
+
+  get id () {
+    return this._id;
+  }
+
+  get inStore () {
+    return this.id !== null;
+  }
+
+  get type () {
+    return this._type;
+  }
+
+  get value () {
+    return this._value;
+  }
+
+  get readOnly () {
+    return this._readOnly;
   }
 
   isCompatible (another) {

+ 53 - 4
js/processor/store/storeObjectArray.js

@@ -1,12 +1,25 @@
 import { Types } from './../../ast/types';
 import { StoreObject } from './storeObject';
+
 export class StoreObjectArray extends StoreObject {
 
   constructor (subtype, lines, columns, value, readOnly) {
     super(Types.ARRAY, value, readOnly);
-    this.lines = lines;
-    this.columns = columns;
-    this.subtype = subtype;
+    this._lines = lines;
+    this._columns = columns;
+    this._subtype = subtype;
+  }
+
+  get lines () {
+    return this._lines;
+  }
+
+  get columns () {
+    return this._columns;
+  }
+
+  get subtype () {
+    return this._subtype;
   }
 
   isCompatible (another) {
@@ -19,4 +32,40 @@ export class StoreObjectArray extends StoreObject {
     }
     return false;
   }
-}
+
+  get isVector () {
+    return this.columns === null;
+  }
+
+  get isValid () {
+    if (this.value !== null) {
+      if( this.isVector()) {
+        if(this.value.length !== this.lines) {
+          return false;
+        }
+        const mustBeNull = this.value.find(v => v.type !== this.subtype);
+        if(!!mustBeNull) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+    if(this.lines !== this.value.length) {
+      return false;
+    }
+    for (let i = 0; i < this.lines; i++) {
+      for (let j = 0; j < this.columns; j++) {
+        const arr = this.value[i];
+        if(arr.length !== this.columns) {
+          return false;
+        }
+        const mustBeNull = arr.find(v => v.type !== this.subtype);
+        if(!!mustBeNull) {
+          return false;
+        }            
+      }
+    }
+      return true;
+    }
+  }
+}

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

@@ -0,0 +1,34 @@
+import { StoreObject } from './storeObject';
+
+export class StoreObjectRef extends StoreObject {
+
+  constructor (id, store) {
+    super(null, null, false);
+    this.setID(id);
+    this.store = store;
+  }
+
+  get isRef () {
+    return true;
+  }
+
+  get type () {
+    return this.store.applyStore(this.id).type;
+  }
+
+  get value () {
+    return this.store.applyStore(this.id).value;
+  }
+
+  getRefObj () {
+    return this.store.applyStore(this.id);
+  }
+
+  updateRef (stoObj) {
+    this.store.updateStore(this.id, stoObj);
+  }
+
+  isCompatible (another) {
+    return this.store.applyStore(this.id).isCompatible(another);
+  }
+}

+ 5 - 0
package-lock.json

@@ -4279,6 +4279,11 @@
       "integrity": "sha512-pa9tbBWgU0EE4SWgc85T4sa886ufuQdsgruQANhECYjwqgV4z7Vw/499aCaP8ZH79JDS4vhm8doDG9HO4+e4sA==",
       "dev": true
     },
+    "jquery": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
+      "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
+    },
     "js-tokens": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",

+ 2 - 1
package.json

@@ -43,6 +43,7 @@
     "webpack-cli": "^3.1.0"
   },
   "dependencies": {
-    "antlr4": "^4.7.1"
+    "antlr4": "^4.7.1",
+    "jquery": "^3.3.1"
   }
 }

+ 5 - 1
tests/test17.spec.js

@@ -1,6 +1,7 @@
 import Lexers from './../grammar/';
 import * as Expressions from './../js/ast/expressions/';
 import * as Commands from './../js/ast/commands/';
+import { Operators } from './../js/ast/operators';
 import {Types} from './../js/ast/types';
 import {
     IVProgParser
@@ -11,6 +12,7 @@ describe('Variable declaration inside a function', () => {
 
       funcao inicio() {
         inteiro a
+        a = a + 1
       }
     }`;
     const lexer = Lexers['pt_br'];
@@ -20,7 +22,9 @@ describe('Variable declaration inside a function', () => {
       functions: [
         new Commands.Function(null,Types.VOID,[],
         new Commands.CommandBlock([
-          new Commands.Declaration('a',Types.INTEGER,null,false)],[]))
+          new Commands.Declaration('a',Types.INTEGER,null,false)],[
+            new Commands.Assign('a',
+              new Expressions.InfixApp(Operators.ADD, new Expressions.VariableLiteral('a'), new Expressions.IntLiteral(1)))]))
       ]
     }