Переглянути джерело

feat; implement fuction call visual UI parser

Implement a parser from text to visual UI for function call command
Fix a bug with expressionOR funcion by adding a EOF_TOKEN
Fix a bug with array declaration not accesing the literal value
Fix a bug with boolean value parsers
Fix a bug with variable initial values by creating a special expression walker (variableInitialWalker)
Lucas de Souza 2 роки тому
батько
коміт
f0b7e3aaa0
3 змінених файлів з 110 додано та 51 видалено
  1. 17 1
      js/ast/ivprogParser.js
  2. 1 2
      js/typeSystem/parsers.js
  3. 92 48
      js/util/parseFromVisual.js

+ 17 - 1
js/ast/ivprogParser.js

@@ -33,6 +33,18 @@ export class IVProgParser {
     return 4;
   }
   // </ END scope consts>
+  //
+  static get EOF_TOKEN () {
+    return {
+      text: null,
+      line: -1,
+      col: -1,
+      value: null,
+      offset: -1,
+      lineBreaks: false,
+      type: "EOF",
+    }
+  }
 
   /**
    * @param {string} input
@@ -90,6 +102,9 @@ export class IVProgParser {
   getToken (index = this.pos) {
     // if(index === null)
     //   index = this.pos;
+    if (index >= this.tokenStream.length) {
+      return IVProgParser.EOF_TOKEN
+    }
     return this.tokenStream[index];
   }
 
@@ -122,7 +137,7 @@ export class IVProgParser {
   }
 
   isEOF () {
-    return this.getToken(this.pos) == null;
+    return this.getToken(this.pos).type === IVProgParser.EOF_TOKEN.type;
   }
 
   parseProgram () {
@@ -158,6 +173,7 @@ export class IVProgParser {
       this.pos++;
       this.consumeNewLines();
       if (!this.isEOF()) {
+        console.log(this.getToken())
         throw SyntaxErrorFactory.extra_lines();
       }
       this.popVariableStack();

+ 1 - 2
js/typeSystem/parsers.js

@@ -39,9 +39,8 @@ export function toReal (value) {
 }
 
 export function toBool (str) {
-  const val = "'" + str + "'";
+  const val = str;
   const lexer = LanguageService.getCurrentLexer();
-
   if (lexer.getReservedKeys()[lexer.getRules().RK_TRUE] === val) {
     return true;
   } else if (lexer.getReservedKeys()[lexer.getRules().RK_FALSE] === val) {

+ 92 - 48
js/util/parseFromVisual.js

@@ -5,6 +5,7 @@ import { Types } from "../typeSystem/types";
 import { convertBoolToString } from "../typeSystem/parsers";
 import * as Commands from "../ast/commands";
 import { ArrayType } from "../typeSystem/array_type";
+import { Literal } from "../ast/expressions/literal";
 
 const TYPES = {
   VARIABLE: "var",
@@ -54,33 +55,33 @@ function getOpType (op) {
 }
 
 /**
-  * @param {Commands.IfThenElse} ifthenelse
-  * */
+ * @param {Commands.IfThenElse} ifthenelse
+ * */
 function ifThenElseWalker (ifthenelse) {
   //ifthenelse.
   const expression = expressionWalker(ifthenelse.condition);
-  const ifTrue = ifthenelse.ifTrue.commands.map(commandWalker)
+  const ifTrue = ifthenelse.ifTrue.commands.map(commandWalker);
   let ifFalse = [];
   if (ifthenelse.ifFalse) {
     if (ifthenelse.ifFalse instanceof Commands.CommandBlock) {
-      ifFalse = ifthenelse.ifFalse.commands.map(commandWalker)
+      ifFalse = ifthenelse.ifFalse.commands.map(commandWalker);
     } else {
-      ifFalse = [ifThenElseWalker(ifthenelse.ifFalse)]
+      ifFalse = [ifThenElseWalker(ifthenelse.ifFalse)];
     }
   }
   return {
     type: "iftrue",
     expression,
     ifTrue,
-    ifFalse
-  }
+    ifFalse,
+  };
 }
 
 /**
-  * @param {Commands.Assign} assingment
-  * */
+ * @param {Commands.Assign} assingment
+ * */
 function assignmentWalker (assingment) {
-  let variable = null
+  let variable = null;
   if (assingment instanceof Commands.ArrayIndexAssign) {
     const line = expressionWalker(assingment.line);
     let arrayClass = "vector";
@@ -102,57 +103,63 @@ function assignmentWalker (assingment) {
   } else {
     variable = [
       { instance: "expression", type: TYPES.VARIABLE, value: assingment.id },
-    ]
+    ];
   }
-  const expression = expressionWalker(assingment.expression)
+  const expression = expressionWalker(assingment.expression);
   return {
     type: "attribution",
     variable,
-    expression
-  }
+    expression,
+  };
 }
 
 /**
  * @param {Command} command
-  * */
+ * */
 function commandWalker (command) {
   if (command instanceof Commands.FunctionCall) {
-    return functionCallWalker(command)
+    return functionCallWalker(command);
   } else if (command instanceof Commands.Assign) {
-    return assignmentWalker(command)
+    return assignmentWalker(command);
   } else if (command instanceof Commands.IfThenElse) {
-    return ifThenElseWalker(command)
+    return ifThenElseWalker(command);
   }
-  throw new Error("not implemented")
+  throw new Error("not implemented");
 }
 
 /**
  * @param {Commands.FunctionCall} functionCall
-  * */
+ * */
 function functionCallWalker (functionCall) {
   let name = functionCall.id;
   if (name.indexOf(".") !== -1) {
-    name = name.split(".")[1]
-  }
-  if (name === "$read") {
-    const variable = functionCall.actualParameters.map(expressionWalker)[0]
-    return {
-      type:"reader",
-      variable
-    }
+    name = name.split(".")[1];
   }
+  const parameters = functionCall.actualParameters.map(expressionWalker);
   if (name === "$write") {
-    const content = functionCall.actualParameters.map(expressionWalker)
-    const lastInput = content[content.length - 1][0];
+    const lastInput = parameters[parameters.length - 1][0];
     // if lastInput is an object with value === '\n', newLine is true
-    const newLine = lastInput.value && lastInput.value.match(/\n/) !== null
+    const newLine = lastInput.value && lastInput.value.match(/^\n$/) !== null;
+    const content = newLine
+      ? parameters.slice(0, parameters.length - 1)
+      : parameters;
     return {
-      type:"writer",
+      type: "writer",
       newLine,
-      content
-    }
+      content,
+    };
   }
-  throw new Error("not implemented")
+  if (name === "$read") {
+    return {
+      type: "reader",
+      variable: parameters[0],
+    };
+  }
+  return {
+    type: "functioncall",
+    parameters_list: parameters,
+    name: functionCall.id,
+  };
 }
 /**
  * @param {Commands.Function} func
@@ -178,7 +185,7 @@ function functionWalker (func) {
   funcDeclaration.variables_list = func.variablesDeclarations.map(
     variableDeclarationWalker
   );
-  funcDeclaration.commands = func.commands.map(commandWalker)
+  funcDeclaration.commands = func.commands.map(commandWalker);
   return funcDeclaration;
 }
 
@@ -225,11 +232,10 @@ function variableDeclarationWalker (command, global = false) {
     const lines = expressionWalker(command.lines).pop();
     variable.type = command.type.innerType.value;
     if (command.isVector) {
-      variable.rows = 1;
       variable.columns = lines.value;
       variable.dimension = 1;
-      const values = command.initial.map(
-        (exp) => expressionWalker(exp).pop().value
+      const values = command.initial.value.map((exp) =>
+        variableInitialWalker(exp)
       );
       variable.value = values;
     } else {
@@ -237,19 +243,52 @@ function variableDeclarationWalker (command, global = false) {
       variable.dimension = 2;
       variable.rows = lines.value;
       variable.columns = columns.value;
-      const values = command.initial.map((rows) =>
-        rows.map((exp) => expressionWalker(exp).pop().value)
+      const values = command.initial.value.map((rows) =>
+        rows.value.map((exp) => variableInitialWalker(exp))
       );
       variable.value = values;
     }
   } else {
     // atomic
     variable.type = command.type.value;
-    variable.value = expressionWalker(command.initial).pop().value;
+    variable.value = variableInitialWalker(command.initial);
   }
   return variable;
 }
 
+/**
+ * @param {any} expression
+ * */
+function variableInitialWalker (expression) {
+  if (expression instanceof Expressions.UnaryApp) {
+    const left = variableInitialWalker(expression.left);
+    const opType = getOpType(expression.op);
+    if (opType !== TYPES.ARITHMETIC) {
+      throw new Error(
+        "invalid variable initial value: " + expression.toString()
+      );
+    }
+    return `${expression.op.value}${left}`;
+  } else if (expression instanceof Expressions.BoolLiteral) {
+    const value = expression.value;
+    return convertBoolToString(value);
+  } else if (expression instanceof Literal) {
+    let value = expression.value;
+    if (expression.value.toNumber) {
+      if (
+        Types.REAL.isCompatible(expression.type) &&
+        expression.value.decimalPlaces() == 0
+      ) {
+        value = expression.value.toFixed(2);
+      } else {
+        value = expression.value.toNumber();
+      }
+    }
+    return value;
+  }
+  throw new Error("invalid variable initial value: " + expression.toString());
+}
+
 /**
  *
  * @return {[]}
@@ -273,6 +312,7 @@ function expressionWalker (expression) {
     funcObj.params = paramsList;
     result = [funcObj];
   } else if (expression instanceof Expressions.UnaryApp) {
+    console.log(expression);
     const left = expressionWalker(expression.left);
     const opType = getOpType(expression.op);
     const opValue = translateOp(opType, expression.op);
@@ -371,10 +411,14 @@ export function parseCode (text) {
     }
   }
   parser.fill(tokenStream);
-  const program = parser.parseTree();
-  const globals = program.global.map((decl) =>
-    variableDeclarationWalker(decl, true)
-  );
-  const functions = program.functions.map(functionWalker);
-  return { globals, functions };
+  try {
+    const program = parser.parseTree();
+    const globals = program.global.map((decl) =>
+      variableDeclarationWalker(decl, true)
+    );
+    const functions = program.functions.map(functionWalker);
+    return { globals, functions };
+  } catch {
+    return null;
+  }
 }