Browse Source

Merge branch 'text_to_visual' of LInE/iVProg into master

GitAdmin 1 year ago
parent
commit
193c473411

+ 2 - 1
.eslintrc.json

@@ -23,7 +23,8 @@
       { "argsIgnorePattern": "^_" }
     ],
     "@typescript-eslint/camelcase": "off",
-    "space-before-function-paren": ["error", "always"]
+    "space-before-function-paren": "off",
+    "@typescript-eslint/space-before-function-paren": ["error", "always"]
   },
   "overrides": [
     {

+ 2 - 2
changeScriptSourcePlugin.js

@@ -6,7 +6,7 @@ function ChangeScriptSourcePlugin () {}
 ChangeScriptSourcePlugin.prototype.apply = function (compiler) {
   compiler.hooks.compilation.tap('ChangeScriptSourcePlugin', function (compilation) {
     console.log('The compiler is starting a new compilation...')
-    // Staic Plugin interface |compilation |HOOK NAME | register listener 
+    // Staic Plugin interface |compilation |HOOK NAME | register listener
     HtmlWebpackPlugin.getHooks(compilation).alterAssetTags.tapAsync(
       'ChangeScriptSourcePlugin', // <-- Set a meaningful name here for stacktraces
       function (data, cb) {
@@ -26,4 +26,4 @@ ChangeScriptSourcePlugin.prototype.apply = function (compiler) {
   })
 }
 
-module.exports = ChangeScriptSourcePlugin
+module.exports = ChangeScriptSourcePlugin

+ 0 - 268
grammar/en/ivprog.g4

@@ -1,268 +0,0 @@
-lexer grammar ivprog;
-
-// BEGIN i18n Lexical rules
-RK_PROGRAM
-  : 'program'
-  ;
-
-RK_REAL
-  : 'real'
-  ;
-
-RK_VOID
-  : 'void'
-  ;
-
-RK_BOOLEAN
-  : 'bool'
-  ;
-
-RK_STRING
-  : 'string'
-  ;
-
-RK_INTEGER
-  : 'int'
-  ;
-
-RK_CHARACTER
-  : 'char'
-  ;
-
-RK_SWITCH
-  : 'switch'
-  ;
-
-RK_CASE
-  : 'case'
-  ;
-
-RK_DEFAULT
-  : 'otherwise'
-  ;
-
-RK_CONST
-  : 'const'
-  ;
-
-RK_FUNCTION
-  : 'function'
-  ;
-
-RK_RETURN
-  : 'return'
-  ;
-
-RK_FOR
-  : 'for'
-  ;
-
-RK_FOR_ALT
-  : 'repeat_for'
-  ;
-
-RK_FOR_FROM
-  : 'from'
-  ;
-
-RK_FOR_TO
-  : 'to'
-  ;
-
-RK_FOR_PASS
-  : 'pass'
-  ;
-
-RK_BREAK
-  : 'break'
-  ;
-
-RK_DO
-  : 'repeat'
-  ;
-
-RK_DO_UNTIL
-  : 'until'
-  ;
-
-RK_WHILE
-  : 'while'
-  ;
-
-RK_WHILE_ALT
-  : 'repeat_while'
-  ;
-
-RK_IF
-  : 'if'
-  ;
-
-RK_ELSE
-  : 'else'
-  ;
-
-RK_FALSE
-  : 'false'
-  ;
-
-RK_TRUE
-  : 'true'
-  ;
-
-fragment RK_LOGICAL_NOT
-  : 'not'
-  ;
-
-fragment RK_LOGICAL_AND
-  : 'AND'
-  ;
-
-fragment RK_LOGICAL_OR
-  : 'OR'
-  ;
-
-RK_REFERENCE
-  : '&'
-  ;
-// END i18n Lexical rules
-
-// GAMBIARRA   : '.' |'á'| 'à'| 'ã'|'â'|'é'|'ê'|'í'|'ó'|'ô'|'õ'|'ú'|'ü'|'ç'|'Ä'|'À'|'Ã'|'Â'|'É'|'Ê'|'Ë'|'Ó'|'Ô'|'Õ'|'Ú'|'Ü'|'Ç'|'#'|'$'|'"'|'§'|'?'|'¹'|'²'|'³'|'£'|'¢'|'¬'|'ª'|'º'|'~'|'\''|'`'|'\\'|'@';
-
-OPEN_PARENTHESIS
-  : '('
-  ;
-
-CLOSE_PARENTHESIS
-  : ')'
-  ;
-
-OPEN_BRACE
-  : '['
-  ;
-
-CLOSE_BRACE
-  : ']'
-  ;
-
-OPEN_CURLY
-  : '{'
-  ;
-
-CLOSE_CURLY
-  : '}'
-  ;
-
-COMMA
-  : ','
-  ;
-
-EQUAL
-  : '<-'
-  | '←'
-  ;
-
-SUM_OP
-  : ('+'|'-')
-  ;
-
-MULTI_OP
-  : ('*'|'/'|'%')
-  ;
-
-AND_OPERATOR
-  : RK_LOGICAL_AND
-  ;
-
-OR_OPERATOR
-  : RK_LOGICAL_OR
-  ;
-
-RELATIONAL_OPERATOR
-  : ('>='|'=='|'<='|'>'|'<'|'!=')
-  ;
-
-COLON
-  : ':'
-  ;
-
-NOT_OPERATOR
-  : RK_LOGICAL_NOT
-  ;
-
-ID
-  : [a-zA-Z_] [a-zA-Z0-9_]*
-  ;
-
-LIB_ID
-  : ID '.' ID
-  ;
-
-INTEGER
-  : [0-9]+
-  | ('0x'|'0X')(HEX_DIGIT)+
-  | ('0b'|'0B')[0-1]+
-  ;
-
-REAL
-  : [0-9]+ '.' [0-9]+
-  | [0-9]+ '.' [0-9]* ExponentPart
-  ;
-
-fragment ExponentPart
-  : [eE] [+-]? [0-9]+
-  ;
-
-STRING
-  : '"' STRING_CHARACTER* '"'
-  ;
-
-fragment STRING_CHARACTER //String as defined at https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
-  : ~["\\\r\n]
-  | ESC_SEQ
-  ;
-
-CHARACTER //Character as defined at https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
-  : '\'' ( ESC_SEQ | ~['\\\r\n]) '\''
-  ;
-
-WHITESPACE
-  : ( ' ' | '\t') -> skip
-  ;
-
-fragment SEMICOLON
-  : ';'
-  ;
-
-EOS
-  : [\r\n]+
-  | SEMICOLON
-  ;
-
-fragment HEX_DIGIT
-  : [0-9a-fA-F]
-  ;
-
-fragment OCTAL_DIGIT
-  : [0-7]
-  ;
-
-fragment ESC_SEQ
-  : '\\' ('b'|'t'|'n'|'f'|'r'|'"'|'\''|'\\')
-  | ESC_UNICODE
-  | ESC_OCTAL
-  ;
-
-fragment ESC_OCTAL
-  : '\\' [0-3] OCTAL_DIGIT OCTAL_DIGIT
-  | '\\' OCTAL_DIGIT OCTAL_DIGIT
-  | '\\' OCTAL_DIGIT
-  ;
-
-fragment ESC_UNICODE
-  : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
-  ;
-
-COMMENTS
-  : ('//' ~('\n'|'\r')* '\r'? '\n'
-    | '/*' .*? '*/') -> channel(HIDDEN)
-  ;

+ 105 - 0
grammar/en/ivprog.ts

@@ -0,0 +1,105 @@
+import {
+  I18N_LEXER_TYPES,
+  I18N_LEXER_COMMANDS,
+  I18N_LEXER_BOOLVAL,
+  I18N_LEXER_LOGICOP,
+  makeLexer,
+  I18N_LANG_LIBS,
+  I18N_LANG_FUNCS,
+} from "../lexer";
+
+// i18n lexer strings for the language.
+const types: I18N_LEXER_TYPES = {
+  // types
+  RK_REAL: "real",
+  RK_INTEGER: "int",
+  RK_BOOLEAN: "bool",
+  RK_CHARACTER: "char",
+  RK_STRING: "string",
+};
+const commands: I18N_LEXER_COMMANDS = {
+  // RK_VOID is not formally part of Types since it doesn't have a valid value/instance
+  RK_VOID: "vazio",
+  // commands
+  RK_PROGRAM: "program",
+  RK_SWITCH: "switch",
+  RK_CASE: "case",
+  RK_DEFAULT: "otherwise",
+  RK_CONST: "const",
+  RK_FUNCTION: "function",
+  RK_RETURN: "return",
+  RK_FOR: "for",
+  RK_FOR_ALT: "repeat_for",
+  RK_FOR_FROM: "from",
+  RK_FOR_TO: "to",
+  RK_FOR_PASS: "pass",
+  RK_BREAK: "break",
+  RK_DO: "repeat",
+  RK_DO_UNTIL: "until",
+  RK_WHILE: "while",
+  RK_WHILE_ALT: "repeat_while",
+  RK_IF: "if",
+  RK_ELSE: "else",
+  RK_REFERENCE: "&",
+};
+const boolVal: I18N_LEXER_BOOLVAL = {
+  RK_FALSE: "false",
+  RK_TRUE: "true",
+};
+
+const logicOp: I18N_LEXER_LOGICOP = {
+  RK_LOGICAL_NOT: "not",
+  RK_LOGICAL_AND: "AND",
+  RK_LOGICAL_OR: "OR",
+};
+
+const langLibs: I18N_LANG_LIBS = {
+  $mathLib: "Mathematics",
+  $ioLib: "IO",
+  $strLib: "Text",
+  $arrayLib: "Array",
+  $langLib: "Conversion",
+};
+
+const langFuncs: I18N_LANG_FUNCS = {
+  main_function: "main",
+  $read: "read",
+  $write: "write",
+  $numElements: "total_of_elements",
+  $matrixLines: "total_of_lines",
+  $matrixColumns: "total_of_columns",
+  $substring: "substring",
+  $length: "length",
+  $uppercase: "uppercase",
+  $lowercase: "lowercase",
+  $charAt: "char_at",
+  $isReal: "is_real",
+  $isInt: "is_integer",
+  $isBool: "is_logic",
+  $castReal: "to_real",
+  $castInt: "to_integer",
+  $castBool: "to_logic",
+  $castString: "to_string",
+  $castChar: "to_char",
+  $sin: "sin",
+  $cos: "cos",
+  $tan: "tan",
+  $sqrt: "sqrt",
+  $pow: "pow",
+  $log: "log",
+  $abs: "abs",
+  $negate: "negate",
+  $invert: "invert",
+  $max: "maximum",
+  $min: "minimum",
+  $rand: "random",
+};
+// END i18n lexer strings
+export const enLexer = makeLexer({
+  commands,
+  boolVal,
+  logicOp,
+  types,
+  langLibs,
+  langFuncs,
+});

+ 0 - 36
grammar/en/langFunctions.js

@@ -1,36 +0,0 @@
-/* This is a dictionary of the language defined functions
-**/
-export default {
-  main_function: "main",
-  $read: "read",
-  $write: "write",
-  $numElements: "total_of_elements",
-  $matrixLines: "total_of_lines",
-  $matrixColumns: "total_of_columns",
-  $substring: "substring",
-  $length: "length",
-  $uppercase: "uppercase",
-  $lowercase: "lowercase",
-  $charAt: "char_at",
-  $isReal: "is_real",
-  $isInt: "is_integer",
-  $isBool: "is_logic",
-  $castReal: "to_real",
-  $castInt: "to_integer",
-  $castBool: "to_logic",
-  $castString: "to_string",
-  $castChar: "to_char",
-  $sin: "sin",
-  $cos: "cos",
-  $tan: "tan",
-  $sqrt: "sqrt",
-  $pow: "pow",
-  $log: "log",
-  $abs: "abs",
-  $negate: "negate",
-  $invert: "invert",
-  $max: "maximum",
-  $min: "minimum",
-  $rand: "random"
-
-}

+ 0 - 10
grammar/en/langLibs.js

@@ -1,10 +0,0 @@
-/**
- * This is the dictionary of the language defined libraries
- */
-export default {
-  $mathLib: "Mathematic",
-  $ioLib: "IO",
-  $strLib: "Text",
-  $arrayLib: "Array",
-  $langLib: "Conversion"
-}

+ 10 - 0
grammar/helper.ts

@@ -0,0 +1,10 @@
+export function combineRegex(strings: TemplateStringsArray, ...pieces: any[]) {
+  return new RegExp(
+    strings.raw
+      .map(
+        (r, i) =>
+          r + (pieces[i] === undefined ? "" : "(?:" + pieces[i].source + ")")
+      )
+      .join("")
+  );
+}

+ 0 - 15
grammar/index.js

@@ -1,15 +0,0 @@
-import * as PT from "./pt/ivprog.g4";
-import PTFuncs from "./pt/langFunctions";
-import PTLibs from "./pt/langLibs";
-import * as EN from "./en/ivprog.g4";
-import ENFuncs from "./en/langFunctions";
-import ENLibs from "./en/langLibs";
-/*import * as ES from "./es/ivprog.g4";
-import ESFuncs from "./es/langFunctions";
-import ESLibs from "./es/langLibs";*/
-
-export default {
-  pt: { lexer: PT.ivprog, langFuncs: PTFuncs, langLibs: PTLibs },
-  en: { lexer: EN.ivprog, langFuncs: ENFuncs, langLibs: ENLibs },
-  //es: {lexer: ES.ivprog, langFuncs: ESFuncs, langLibs: ESLibs}
-};

+ 11 - 0
grammar/index.ts

@@ -0,0 +1,11 @@
+import { ptLexer as pt } from "./pt/ivprog";
+import { enLexer as en } from "./en/ivprog";
+import { IVProgLexer } from "./lexer";
+/*import * as ES from "./es/ivprog.g4";
+import ESFuncs from "./es/langFunctions";
+import ESLibs from "./es/langLibs";*/
+const lexers: Record<string, IVProgLexer> = {};
+lexers["pt"] = pt;
+lexers["en"] = en;
+
+export default lexers;

+ 224 - 0
grammar/lexer.ts

@@ -0,0 +1,224 @@
+import * as moo from "moo";
+import { combineRegex } from "./helper";
+
+export interface I18N_LEXER_TYPES {
+  RK_INTEGER: string;
+  RK_REAL: string;
+  RK_CHARACTER: string;
+  RK_STRING: string;
+  RK_BOOLEAN: string;
+}
+
+export interface I18N_LEXER_BOOLVAL {
+  RK_FALSE: string;
+  RK_TRUE: string;
+}
+
+export interface I18N_LEXER_LOGICOP {
+  RK_LOGICAL_NOT: string;
+  RK_LOGICAL_AND: string;
+  RK_LOGICAL_OR: string;
+}
+
+export interface I18N_LEXER_COMMANDS {
+  RK_PROGRAM: string;
+  RK_VOID: string;
+  RK_SWITCH: string;
+  RK_CASE: string;
+  RK_DEFAULT: string;
+  RK_CONST: string;
+  RK_FUNCTION: string;
+  RK_RETURN: string;
+  RK_FOR: string;
+  RK_FOR_ALT: string;
+  RK_FOR_FROM: string;
+  RK_FOR_TO: string;
+  RK_FOR_PASS: string;
+  RK_BREAK: string;
+  RK_DO: string;
+  RK_DO_UNTIL: string;
+  RK_WHILE: string;
+  RK_WHILE_ALT: string;
+  RK_IF: string;
+  RK_ELSE: string;
+  RK_REFERENCE: string;
+}
+
+export interface I18N_LANG_LIBS {
+  $ioLib: string;
+  $strLib: string;
+  $mathLib: string;
+  $langLib: string;
+  $arrayLib: string;
+}
+
+export interface I18N_LANG_FUNCS {
+  main_function: string;
+  $read: string;
+  $write: string;
+  $numElements: string;
+  $matrixLines: string;
+  $matrixColumns: string;
+  $substring: string;
+  $length: string;
+  $uppercase: string;
+  $lowercase: string;
+  $charAt: string;
+  $isReal: string;
+  $isInt: string;
+  $isBool: string;
+  $castReal: string;
+  $castInt: string;
+  $castBool: string;
+  $castString: string;
+  $castChar: string;
+  $sin: string;
+  $cos: string;
+  $tan: string;
+  $sqrt: string;
+  $pow: string;
+  $log: string;
+  $abs: string;
+  $negate: string;
+  $invert: string;
+  $max: string;
+  $min: string;
+  $rand: string;
+}
+
+export interface I18nLexer {
+  commands: I18N_LEXER_COMMANDS;
+  logicOp: I18N_LEXER_LOGICOP;
+  boolVal: I18N_LEXER_BOOLVAL;
+  types: I18N_LEXER_TYPES;
+  langLibs: I18N_LANG_LIBS;
+  langFuncs: I18N_LANG_FUNCS;
+}
+
+export class IVProgLexer {
+  constructor (
+    private RKs: Record<string, string>,
+    public lexer: moo.Lexer,
+    private rules: I18N_LEXER_RULES,
+    private i18nLexer: I18nLexer
+  ) {}
+
+  getReservedKeys (): Record<string, string> {
+    return this.RKs;
+  }
+
+  getRules (): I18N_LEXER_RULES {
+    return this.rules;
+  }
+
+  getTypeKeys (): I18N_LEXER_TYPES {
+    return this.i18nLexer.types;
+  }
+
+  getLangLibs (): I18N_LANG_LIBS {
+    return this.i18nLexer.langLibs;
+  }
+
+  getLangFuncs (): I18N_LANG_FUNCS {
+    return this.i18nLexer.langFuncs;
+  }
+}
+
+export interface I18N_LEXER_RULES
+  extends I18N_LEXER_TYPES,
+    I18N_LEXER_COMMANDS,
+    I18N_LEXER_BOOLVAL,
+    I18N_LEXER_LOGICOP {
+  OPEN_BRACE: string;
+  CLOSE_BRACE: string;
+  OPEN_PARENTHESIS: string;
+  CLOSE_PARENTHESIS: string;
+  OPEN_CURLY: string;
+  CLOSE_CURLY: string;
+  COMMA: string;
+  ASSIGNMENT: string;
+  REAL: string;
+  INTEGER: string;
+  SUM_OP: string;
+  MULTI_OP: string;
+  RELATIONAL_OPERATOR: string;
+  COLON: string;
+  STRING: string;
+  CHARACTER: string;
+  EOS: string;
+  WHITESPACE: string;
+  COMMENTS: string;
+  RK_REFERENCE: string;
+  ID: string;
+  DOT: string;
+  ERROR: string;
+}
+
+// General Regex Rules
+const ID = "[a-zA-Z_][a-zA-Z0-9_]*";
+const HEX_DIGIT = "[0-9a-fA-F]";
+const OCTAL_DIGIT = "[0-7]";
+const ESC_OCTAL = RegExp(
+  `\\\\[0-3]${OCTAL_DIGIT}${OCTAL_DIGIT}|\\\\${OCTAL_DIGIT}${OCTAL_DIGIT}|\\\\${OCTAL_DIGIT}`
+);
+const ESC_UNICODE = RegExp(
+  `\\\\u${HEX_DIGIT}${HEX_DIGIT}${HEX_DIGIT}${HEX_DIGIT}`
+);
+const ESC_SEQ_BASE = /\\[b,t,n,f,r,",',\\]|/;
+const ESC_SEQ = combineRegex`${ESC_SEQ_BASE}|${ESC_UNICODE}|${ESC_OCTAL}`;
+const STRING_CHARACTER = combineRegex`${ESC_SEQ}|[^"\\\\]`;
+
+export function makeLexer (lexer: I18nLexer): IVProgLexer {
+  const RKs: Record<string, string> = {};
+  const rules: Record<string, string> = {};
+  Object.entries(lexer.types).forEach(([key, value]) => {
+    RKs[key] = value;
+    rules[key] = key;
+  });
+  Object.entries(lexer.boolVal).forEach(([key, value]) => {
+    RKs[key] = value;
+    rules[key] = key;
+  });
+  Object.entries(lexer.commands).forEach(([key, value]) => {
+    RKs[key] = value;
+    rules[key] = key;
+  });
+  RKs["RK_LOGICAL_AND"] = lexer.logicOp.RK_LOGICAL_AND;
+  RKs["RK_LOGICAL_OR"] = lexer.logicOp.RK_LOGICAL_OR;
+  RKs["RK_LOGICAL_NOT"] = lexer.logicOp.RK_LOGICAL_NOT;
+
+  rules["RK_LOGICAL_AND"] = "RK_LOGICAL_AND";
+  rules["RK_LOGICAL_OR"] = "RK_LOGICAL_OR";
+  rules["RK_LOGICAL_NOT"] = "RK_LOGICAL_NOT";
+
+  const RESERVED_KEYS = moo.keywords(RKs);
+
+  const lexerRules: moo.Rules = {
+    COMMENTS: { match: /\/\/[^$]*?$|\/\*[^$]*?\*\//, lineBreaks: true },
+    OPEN_BRACE: /\[/,
+    CLOSE_BRACE: /\]/,
+    OPEN_PARENTHESIS: /\(/,
+    CLOSE_PARENTHESIS: /\)/,
+    OPEN_CURLY: /\{/,
+    CLOSE_CURLY: /\}/,
+    COMMA: /,/,
+    ASSIGNMENT: /<-|←/,
+    REAL: /[0-9]+\.[0-9]*[eE][+-]?[0-9]+|[0-9]+\.[0-9]+/,
+    INTEGER: RegExp(`(?:0x|0X)${HEX_DIGIT}+|(?:0b|0B)[0-1]+|[0-9]+`),
+    SUM_OP: /[+-]/,
+    MULTI_OP: /[*/%]/,
+    RELATIONAL_OPERATOR: />=|==|<=|>|<|!=/,
+    COLON: /:/,
+    STRING: combineRegex`"(?:${STRING_CHARACTER})*?"`,
+    CHARACTER: combineRegex`'(?:${ESC_SEQ}|[^'\\\\])'`,
+    EOS: { match: /;\r?\n?|[\r\n]+/, lineBreaks: true },
+    WHITESPACE: /(?: |\t)+/,
+    RK_REFERENCE: RegExp(lexer.commands.RK_REFERENCE),
+    ID: { match: RegExp(ID), type: RESERVED_KEYS },
+    DOT: /\./,
+    ERROR: { match: /[\$?`]/, error: true },
+  };
+  Object.entries(lexerRules).forEach(([key, _]) => (rules[key] = key));
+  const moolexer = moo.compile(lexerRules);
+  return new IVProgLexer(RKs, moolexer, rules as unknown as I18N_LEXER_RULES, lexer);
+}

+ 0 - 268
grammar/pt/ivprog.g4

@@ -1,268 +0,0 @@
-lexer grammar ivprog;
-
-// BEGIN i18n Lexical rules
-RK_PROGRAM
-  : 'programa'
-  ;
-
-RK_REAL
-  : 'real'
-  ;
-
-RK_VOID
-  : 'vazio'
-  ;
-
-RK_BOOLEAN
-  : 'logico'
-  ;
-
-RK_STRING
-  : 'cadeia'
-  ;
-
-RK_INTEGER
-  : 'inteiro'
-  ;
-
-RK_CHARACTER
-  : 'caractere'
-  ;
-
-RK_SWITCH
-  : 'escolha'
-  ;
-
-RK_CASE
-  : 'caso'
-  ;
-
-RK_DEFAULT
-  : 'contrario'
-  ;
-
-RK_CONST
-  : 'const'
-  ;
-
-RK_FUNCTION
-  : 'funcao'
-  ;
-
-RK_RETURN
-  : 'devolva'
-  ;
-
-RK_FOR
-  : 'para'
-  ;
-
-RK_FOR_ALT
-  : 'repita_para'
-  ;
-
-RK_FOR_FROM
-  : 'de'
-  ;
-
-RK_FOR_TO
-  : 'ate'
-  ;
-
-RK_FOR_PASS
-  : 'passo'
-  ;
-
-RK_BREAK
-  : 'pare'
-  ;
-
-RK_DO
-  : 'repita'
-  ;
-
-RK_DO_UNTIL
-  : 'ate_que'
-  ;
-
-RK_WHILE
-  : 'enquanto'
-  ;
-
-RK_WHILE_ALT
-  : 'repita_enquanto'
-  ;
-
-RK_IF
-  : 'se'
-  ;
-
-RK_ELSE
-  : 'senao'
-  ;
-
-RK_FALSE
-  : 'falso'
-  ;
-
-RK_TRUE
-  : 'verdadeiro'
-  ;
-
-fragment RK_LOGICAL_NOT
-  : 'nao'
-  ;
-
-fragment RK_LOGICAL_AND
-  : 'E'
-  ;
-
-fragment RK_LOGICAL_OR
-  : 'OU'
-  ;
-
-RK_REFERENCE
-  : '&'
-  ;
-// END i18n Lexical rules
-
-// GAMBIARRA   : '.' |'á'| 'à'| 'ã'|'â'|'é'|'ê'|'í'|'ó'|'ô'|'õ'|'ú'|'ü'|'ç'|'Ä'|'À'|'Ã'|'Â'|'É'|'Ê'|'Ë'|'Ó'|'Ô'|'Õ'|'Ú'|'Ü'|'Ç'|'#'|'$'|'"'|'§'|'?'|'¹'|'²'|'³'|'£'|'¢'|'¬'|'ª'|'º'|'~'|'\''|'`'|'\\'|'@';
-
-OPEN_PARENTHESIS
-  : '('
-  ;
-
-CLOSE_PARENTHESIS
-  : ')'
-  ;
-
-OPEN_BRACE
-  : '['
-  ;
-
-CLOSE_BRACE
-  : ']'
-  ;
-
-OPEN_CURLY
-  : '{'
-  ;
-
-CLOSE_CURLY
-  : '}'
-  ;
-
-COMMA
-  : ','
-  ;
-
-EQUAL
-  : '<-'
-  | '←'
-  ;
-
-SUM_OP
-  : ('+'|'-')
-  ;
-
-MULTI_OP
-  : ('*'|'/'|'%')
-  ;
-
-AND_OPERATOR
-  : RK_LOGICAL_AND
-  ;
-
-OR_OPERATOR
-  : RK_LOGICAL_OR
-  ;
-
-RELATIONAL_OPERATOR
-  : ('>='|'=='|'<='|'>'|'<'|'!=')
-  ;
-
-COLON
-  : ':'
-  ;
-
-NOT_OPERATOR
-  : RK_LOGICAL_NOT
-  ;
-
-ID
-  : [a-zA-Z_] [a-zA-Z0-9_]*
-  ;
-
-LIB_ID
-  : ID '.' ID
-  ;
-
-INTEGER
-  : [0-9]+
-  | ('0x'|'0X')(HEX_DIGIT)+
-  | ('0b'|'0B')[0-1]+
-  ;
-
-REAL
-  : [0-9]+ '.' [0-9]+
-  | [0-9]+ '.' [0-9]* ExponentPart
-  ;
-
-fragment ExponentPart
-  : [eE] [+-]? [0-9]+
-  ;
-
-STRING
-  : '"' STRING_CHARACTER* '"'
-  ;
-
-fragment STRING_CHARACTER //String as defined at https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
-  : ~["\\\r\n]
-  | ESC_SEQ
-  ;
-
-CHARACTER //Character as defined at https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
-  : '\'' ( ESC_SEQ | ~['\\\r\n]) '\''
-  ;
-
-WHITESPACE
-  : ( ' ' | '\t') -> skip
-  ;
-
-fragment SEMICOLON
-  : ';'
-  ;
-
-EOS
-  : [\r\n]+
-  | SEMICOLON
-  ;
-
-fragment HEX_DIGIT
-  : [0-9a-fA-F]
-  ;
-
-fragment OCTAL_DIGIT
-  : [0-7]
-  ;
-
-fragment ESC_SEQ
-  : '\\' ('b'|'t'|'n'|'f'|'r'|'"'|'\''|'\\')
-  | ESC_UNICODE
-  | ESC_OCTAL
-  ;
-
-fragment ESC_OCTAL
-  : '\\' [0-3] OCTAL_DIGIT OCTAL_DIGIT
-  | '\\' OCTAL_DIGIT OCTAL_DIGIT
-  | '\\' OCTAL_DIGIT
-  ;
-
-fragment ESC_UNICODE
-  : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
-  ;
-
-COMMENTS
-  : ('//' ~('\n'|'\r')* '\r'? '\n'
-    | '/*' .*? '*/') -> channel(HIDDEN)
-  ;

+ 105 - 0
grammar/pt/ivprog.ts

@@ -0,0 +1,105 @@
+import {
+  I18N_LEXER_TYPES,
+  I18N_LEXER_COMMANDS,
+  I18N_LEXER_BOOLVAL,
+  I18N_LEXER_LOGICOP,
+  makeLexer,
+  I18N_LANG_LIBS,
+  I18N_LANG_FUNCS,
+} from "../lexer";
+
+// i18n lexer strings for the language.
+const types: I18N_LEXER_TYPES = {
+  // types
+  RK_REAL: "real",
+  RK_INTEGER: "inteiro",
+  RK_BOOLEAN: "logico",
+  RK_CHARACTER: "caractere",
+  RK_STRING: "cadeia",
+};
+const commands: I18N_LEXER_COMMANDS = {
+  // RK_VOID is not formally part of Types since it doesn't have a valid value/instance
+  RK_VOID: "vazio",
+  // commands
+  RK_PROGRAM: "programa",
+  RK_SWITCH: "escolha",
+  RK_CASE: "caso",
+  RK_DEFAULT: "contrario",
+  RK_CONST: "const",
+  RK_FUNCTION: "funcao",
+  RK_RETURN: "devolva",
+  RK_FOR: "para",
+  RK_FOR_ALT: "repita_para",
+  RK_FOR_FROM: "de",
+  RK_FOR_TO: "ate",
+  RK_FOR_PASS: "passo",
+  RK_BREAK: "pare",
+  RK_DO: "repita",
+  RK_DO_UNTIL: "ate_que",
+  RK_WHILE: "enquanto",
+  RK_WHILE_ALT: "repita_enquanto",
+  RK_IF: "se",
+  RK_ELSE: "senao",
+  RK_REFERENCE: "&",
+};
+const boolVal: I18N_LEXER_BOOLVAL = {
+  RK_FALSE: "falso",
+  RK_TRUE: "verdadeiro",
+};
+
+const logicOp: I18N_LEXER_LOGICOP = {
+  RK_LOGICAL_NOT: "nao",
+  RK_LOGICAL_AND: "E",
+  RK_LOGICAL_OR: "OU",
+};
+
+const langLibs: I18N_LANG_LIBS = {
+  $mathLib: "Matematica",
+  $ioLib: "ES",
+  $strLib: "Texto",
+  $arrayLib: "Arranjo",
+  $langLib: "Conversao",
+};
+
+const langFuncs: I18N_LANG_FUNCS = {
+  main_function: "inicio",
+  $read: "leia",
+  $write: "escreva",
+  $numElements: "total_de_elementos",
+  $matrixLines: "total_de_linhas",
+  $matrixColumns: "total_de_colunas",
+  $substring: "subcadeia",
+  $length: "comprimento",
+  $uppercase: "caixa_alta",
+  $lowercase: "caixa_baixa",
+  $charAt: "caractere_na_posicao",
+  $isReal: "e_real",
+  $isInt: "e_inteiro",
+  $isBool: "e_logico",
+  $castReal: "como_real",
+  $castInt: "como_inteiro",
+  $castBool: "como_logico",
+  $castString: "como_cadeia",
+  $castChar: "como_caractere",
+  $sin: "seno",
+  $cos: "cosseno",
+  $tan: "tangente",
+  $sqrt: "raiz_quadrada",
+  $pow: "potencia",
+  $log: "logaritmo",
+  $abs: "modulo",
+  $negate: "trocar_sinal",
+  $invert: "inverter_valor",
+  $max: "maximo",
+  $min: "minimo",
+  $rand: "numero_aleatorio",
+};
+// END i18n lexer strings
+export const ptLexer = makeLexer({
+  commands,
+  boolVal,
+  logicOp,
+  types,
+  langLibs,
+  langFuncs,
+});

+ 0 - 35
grammar/pt/langFunctions.js

@@ -1,35 +0,0 @@
-/* This is a dictionary of the language defined functions
-**/
-export default {
-  main_function: "inicio",
-  $read: "leia",
-  $write: "escreva",
-  $numElements: "total_de_elementos",
-  $matrixLines: "total_de_linhas",
-  $matrixColumns: "total_de_colunas",
-  $substring: "subcadeia",
-  $length: "comprimento",
-  $uppercase: "caixa_alta",
-  $lowercase: "caixa_baixa",
-  $charAt: "caractere_na_posicao",
-  $isReal: "e_real",
-  $isInt: "e_inteiro",
-  $isBool: "e_logico",
-  $castReal: "como_real",
-  $castInt: "como_inteiro",
-  $castBool: "como_logico",
-  $castString: "como_cadeia",
-  $castChar: "como_caractere",
-  $sin: "seno",
-  $cos: "cosseno",
-  $tan: "tangente",
-  $sqrt: "raiz_quadrada",
-  $pow: "potencia",
-  $log: "logaritmo",
-  $abs: "modulo",
-  $negate: "trocar_sinal",
-  $invert: "inverter_valor",
-  $max: "maximo",
-  $min: "minimo",
-  $rand: "numero_aleatorio"
-}

+ 0 - 10
grammar/pt/langLibs.js

@@ -1,10 +0,0 @@
-/**
- * This is the dictionary of the language defined libraries
- */
-export default {
-  $mathLib: "Matematica",
-  $ioLib: "ES",
-  $strLib: "Texto",
-  $arrayLib: "Arranjo",
-  $langLib: "Conversao"
-}

File diff suppressed because it is too large
+ 1 - 0
i18n/error.csv


BIN
ivprog_2022_01_13_21_43.zip


+ 32 - 26
js/ast/error/syntaxErrorFactory.js

@@ -13,97 +13,97 @@ function createError (message_id, context = []) {
 export const SyntaxErrorFactory = Object.freeze({
   extra_lines: () => new SyntaxError(LocalizedStrings.getError("extra_lines")),
   token_missing_one: (expected, token) => {
-    const context = [expected, token.text, token.line, token.column];
+    const context = [expected, token.text, token.line, token.col];
     const error = createError("token_missing_one", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   token_missing_list: (expectedList, token) => {
     const line = expectedList.join(LocalizedStrings.getOR());
     const error = SyntaxErrorFactory.token_missing_one(line, token);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   id_missing: (token) => {
-    const context = [token.text, token.line, token.column];
+    const context = [token.text, token.line, token.col];
     const error = createError("id_missing", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   eos_missing: (token) => {
-    const context = [token.line, token.column];
+    const context = [token.line, token.col];
     const error = createError("eos_missing", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_array_dimension: (typeName, token) => {
-    const context = [token.line, token.column, typeName];
+    const context = [token.line, token.col, typeName];
     const error = createError("invalid_array_dimension", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_array_size: (token) => {
     const context = [token.line];
     const error = createError("invalid_array_size", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_main_return: (name, typeName, token) => {
     const context = [name, typeName, token.line];
     const error = createError("invalid_main_return", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_var_declaration: (token) => {
     const context = [token.line];
     const error = createError("invalid_var_declaration", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_break_command: (cmdName, token) => {
     const context = [token.line, cmdName];
     const error = createError("invalid_break_command", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_terminal: (token) => {
-    const context = [token.text, token.line, token.column];
+    const context = [token.text, token.line, token.col];
     const error = createError("invalid_terminal", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_type: (list, token) => {
     const line = list.join(LocalizedStrings.getOR());
-    const context = [token.text, token.line, token.column, line];
+    const context = [token.text, token.line, token.col, line];
     const error = createError("invalid_type", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   const_not_init: (token) => {
-    const context = [token.line, token.column];
+    const context = [token.line, token.col];
     const error = createError("const_not_init", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_id_format: (token) => {
-    const context = [token.text, token.line, token.column];
+    const context = [token.text, token.line, token.col];
     const error = createError("invalid_id_format", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   duplicate_function: (token) => {
-    const context = [token.text, token.line, token.column];
+    const context = [token.text, token.line, token.col];
     const error = createError("duplicate_function", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   main_parameters: () => {
     return createError("main_parameters");
   },
   duplicate_variable: (token) => {
-    const context = [token.text, token.line, token.column];
+    const context = [token.text, token.line, token.col];
     const error = createError("duplicate_variable", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_character: (text, line, column) => {
@@ -115,7 +115,7 @@ export const SyntaxErrorFactory = Object.freeze({
   annonymous_array_literal: (token) => {
     const context = [token.line];
     const error = createError("annonymous_array_literal", context);
-    error.context = { line: token.line, column: token.column };
+    error.context = { line: token.line, column: token.col};
     return error;
   },
   invalid_matrix_literal_line: (exp, sourceInfo) => {
@@ -184,4 +184,10 @@ export const SyntaxErrorFactory = Object.freeze({
     error.context = { line: sourceInfo.line, column: sourceInfo.column };
     return error;
   },
+  invalid_syntax: (text, line, column) => {
+    const context = [text, line];
+    const error = createError("invalid_syntax", context);
+    error.context = { line: line, column: column };
+    return error;
+  }
 });

File diff suppressed because it is too large
+ 228 - 151
js/ast/ivprogParser.js


+ 21 - 4
js/ast/sourceInfo.js

@@ -1,18 +1,35 @@
 export class SourceInfo {
 
+  /**
+    * @param {moo.Token} token
+    *
+    * @return {SourceInfo}
+    * **/
   static createSourceInfo (token) {
-    return new SourceInfo(token.line, token.column, token.text, token.text.length);
+    return new SourceInfo(token.line, token.col, token.text, token.text.length);
   }
 
+  /**
+    * @param {moo.Token} tokenA
+    * @param {moo.Token} tokenB
+    *
+    * @return {SourceInfo}
+    * **/
   static createSourceInfoFromList (tokenA, tokenB) {
     const line = tokenA.line;
-    const column = tokenA.column;
+    const column = tokenA.col;
     // adapted from https://github.com/UNIVALI-LITE/Portugol-Studio/blob/master/core/src/main/java/br/univali/portugol/nucleo/analise/sintatica/Portugol.g
     // No idea why...
-    const size = tokenB.tokenIndex + 1 - tokenA.tokenIndex
+    const size = tokenB.offset + 1 - tokenA.offset
     return new SourceInfo(line, column, "", size);
   }
 
+  /**
+   * @param {number} line
+   * @param {number} column
+   * @param {string} text
+   * @param {number} size
+    * **/
   constructor (line, column, text, size) {
     this.line = line;
     this.column = column;
@@ -20,4 +37,4 @@ export class SourceInfo {
     this.size = size;
   }
 
-}
+}

+ 118 - 99
js/iassign-integration-functions.js

@@ -43,103 +43,115 @@ function removeCollapseValue (command) {
   }
 }
 
+function configAuxiliar (form_element) {
+  var _array = form_element.serializeArray();
+  var temp = _array.reduce(function(map, obj) {
+    map[obj.name] = obj.value == "on";
+    return map;
+  }, {});
+
+  return temp;
+}
+
+function configAuxiliarProgrammingType (form_element) {
+  var _array = form_element.serializeArray();
+  var temp = _array.reduce(function(map, obj) {
+    map[obj.name] = obj.value;
+    return map;
+  }, {});
+
+  return temp;
+}
+
 // Função chamada pelo iTarefa quando o professor finaliza a criação da atividade
 // ou quando o aluno finaliza a resolução do exercício
 // O retorno é um JSON com os dados do exercício ou da resolução
 // Esse retorno será armazenado no banco de dados do Moodle, pelo iTarefa
 function getAnswer () {
-  // Remover o colapsar usado localmente:
-  if (window.program_obj) {
-    for (var i = 0; i < window.program_obj.functions.length; i++) {
-      for (var j = 0; j < window.program_obj.functions[i].commands.length; j++) {
-        removeCollapseValue(window.program_obj.functions[i].commands[j]);
-      }
-    }
-  }
+
+  var objAnswer = new Object();
+  objAnswer.version = '1.0';
+
   // Se o parâmetro "iLM_PARAM_SendAnswer" for false,
   // então trata-se de resolução de atividade
   if (iLMparameters.iLM_PARAM_SendAnswer == 'false') {
     // Montar o retorno com a resposta do aluno
-    var contentToSend = previousContent.split("\n::algorithm::")[0];
-    contentToSend += '\n::algorithm::';
 
-    if (settingsProgrammingTypes == "textual") {
-      contentToSend +=  ivprogCore.CodeEditor.getCode();
-    } else {
-      contentToSend += JSON.stringify(window.program_obj, function(key, value) {
-        if (key == 'dom_object') {
-            return;
-        }
-        return value;
-      });
+    objAnswer.code = generator();
+    objAnswer.test_cases = ivprogCore.getTestCases();
+    objAnswer.logs = ivprogCore.getLogs();
+    try {
+      objAnswer.settings = {
+        "programming": Object.fromEntries(ivprogCore.Config.activity_programming_type),
+        "functions": Object.fromEntries(ivprogCore.Config.activity_functions),
+        "datatypes": Object.fromEntries(ivprogCore.Config.activity_datatypes),
+        "commands": Object.fromEntries(ivprogCore.Config.activity_commands),
+        "filter": Object.fromEntries(ivprogCore.Config.activity_filter)
+      };
+    }
+    catch(e) {
+      objAnswer.settings = {
+        "programming": [],
+        "functions": [],
+        "datatypes": [],
+        "commands": [],
+        "filter": []
+      };
     }
 
-    contentToSend += '\n::logs::';
-    contentToSend += getTrackingLogs();
-
-    return contentToSend;
+    return JSON.stringify(objAnswer, null, 4);
 
   } else {
-    // Montar o retorno com a criação da atividade do professor
-    var ret = ' { ' + prepareTestCases()
-        + ',\n"settings_programming_type": \n' + JSON.stringify($('form[name="settings_programming_type"]').serializeArray())
-        + ',\n"settings_data_types": \n' + JSON.stringify($('form[name="settings_data_types"]').serializeArray())
-        + ',\n"settings_commands": \n' + JSON.stringify($('form[name="settings_commands"]').serializeArray())
-        + ',\n"settings_functions": \n' + JSON.stringify($('form[name="settings_functions"]').serializeArray())
-        + ',\n"settings_filter": \n' + JSON.stringify($('form[name="settings_filter"]').serializeArray())
-        + ' } ';
+
+    objAnswer.test_cases = prepareTestCases();
+
+    objAnswer.settings = {
+      "programming": configAuxiliarProgrammingType($('form[name="settings_programming_type"]')),
+      "functions": configAuxiliar($('form[name="settings_functions"]')),
+      "datatypes": configAuxiliar($('form[name="settings_data_types"]')),
+      "commands": configAuxiliar($('form[name="settings_commands"]')),
+      "filter": configAuxiliar($('form[name="settings_filter"]'))
+    };
 
     if ($("input[name='include_algo']").is(':checked')) {
-      ret += '\n::algorithm::';
-      ret += JSON.stringify(window.program_obj, function(key, value) {
-
-          if (key == 'dom_object') {
-              return;
-          }
-          return value;
-      });
+      objAnswer.algorithm = generator();
     }
 
-    return ret;
+    return JSON.stringify(objAnswer, null, 4);
   }
 }
 
 function prepareTestCases () {
-  var ret = ' \n "testcases" : [ '
+
   var test_cases_array = $('form[name="test_cases"]').serializeArray();
-  console.log(test_cases_array);
+
+  var cases = [];
+
   for (var i = 0; i < test_cases_array.length; i = i + 2) {
-    ret += '\n{ ';
-    ret += '\n "input": [';
+
+    var temp = new Object();
+
+    temp.input = [];
+    temp.output = [];
+
     var inps = test_cases_array[i].value.match(/[^\r\n]+/g);
     if (inps) {
       for (var j = 0; j < inps.length; j++) {
-        ret += '"' + inps[j] + '"';
-        if ((j + 1) < inps.length) {
-          ret += ', ';
-        }
+        temp.input.push(inps[j]);
       }
     }
-    ret += '], \n "output": [';
+    
     var outs = test_cases_array[i+1].value.match(/[^\r\n]+/g);
-    console.log(outs);
     if (outs) {
       for (var j = 0; j < outs.length; j++) {
-        console.log("output -> ",outs[j]);
-        ret += '"' + outs[j] + '"';
-        if ((j + 1) < outs.length) {
-          ret += ', ';
-        }
+        temp.output.push(outs[j]);
       }
     }
-    ret += ']';
-    ret += '\n}'
-    if ((i + 2) < test_cases_array.length) {
-      ret += ',';
-    }
+
+    cases.push(temp);
   }
-  ret += '\n] ';
-  return ret;
+  
+  return cases;
 }
 
 // Função chamada pelo iTarefa para receber a nota do aluno na atividade
@@ -279,13 +291,35 @@ function includePreviousAlgorithm () {
   }, 1);
 }
 
-function prepareActivityToStudent (ilm_cont) {
+function prepareActivityToStudent (ilm_cont, ignore_logs = false) {
+
+    // File version (1.0):
+    try {
+      var jsonObj = JSON.parse(ilm_cont);
+      ivprogCore.prepareActivityToStudentHelperJSON(jsonObj);
+
+      if (ivprogCore.getTestCases())
+        $('.assessment_button').removeClass('disabled');
+
+      renderAlgorithm();
+
+      $('.ivprog_visual_panel').removeClass("loading");
+      return;
+    }
+    catch (e) {
+      console.log('Previous file format!');
+      console.log(e);
+    }
+
+    // Previous file format:
     // Ver arquivo js/util/iassignHelpers.js
-    var content = ivprogCore.prepareActivityToStudentHelper(ilm_cont).getOrElse(null);
+    var content = ivprogCore.prepareActivityToStudentHelper(ilm_cont, ignore_logs).getOrElse(null);
     if(!content) {
+      $('.ivprog_visual_panel').removeClass("loading");
       showInvalidData();
       return;
     }
+    
     // Casos de testes agora são delegados ao tratamento apropriado pela função acima
     // var testCases = content.testcases;
     settingsProgrammingTypes = content.settingsProgrammingType;
@@ -299,6 +333,7 @@ function prepareActivityToStudent (ilm_cont) {
         includePreviousAlgorithm();
     }
     $('.assessment_button').removeClass('disabled');
+    $('.ivprog_visual_panel').removeClass("loading");
     renderAlgorithm();
 
     ivprogTextualOrVisual();
@@ -319,6 +354,8 @@ function prepareEnvironment () {
   // portanto, a "DIV" de resolução é liberada
   if (iLMparameters.iLM_PARAM_SendAnswer == 'false') {
     //$('.resolucao').css("display","block");
+    $('.ivprog_visual_panel').addClass("loading");
+
     getiLMContent();
 
     // $('.div_to_body').mousemove(function(e) {
@@ -512,6 +549,9 @@ function prepareTableTestCases (div_el) {
   $('.button_generate_outputs').on('click', function(e) {
     generateOutputs();
   });
+
+  if (!iLMparameters.iLM_PARAM_Assignment)
+    addTestCase();
 }
 
 function showAlert (msg) {
@@ -527,7 +567,7 @@ function generateOutputs () {
   // código:
   var code_teacher = window.generator();
   // array com as entradas já inseridas:
-  var test_cases = JSON.parse(prepareTestCases().replace('"testcases" :', ''));
+  var test_cases = prepareTestCases();
   ivprogCore.autoGenerateTestCaseOutput(code_teacher, test_cases).catch(function (error) {
     showAlert("Houve um erro durante a execução do seu programa: "+error.message);
   });
@@ -692,40 +732,6 @@ function prepareTableSettings (div_el) {
 
 }
 
-function getTrackingLogs () {
-  return ivprogCore.getLogsAsString();
-  // var ret = "";
-  // for (var i = 0; i < trackingMatrix.length; ++i) {
-  //   ret += "\n" + trackingMatrix[i][0] + "," + trackingMatrix[i][1] + "," + trackingMatrix[i][2];
-  //   if (trackingMatrix[i][3] === 1) {
-  //     ret += ',' + trackingMatrix[i][3] + ',"' + trackingMatrix[i][4] + '"';
-  //   }
-  // }
-  // return ret;
-}
-
-// Tracking mouse movements
-// var trackingMatrix = [];
-
-/* function adCoords(e, code){
-  var x = e.pageX;
-  var y = e.pageY;
-  if (code === 1) {
-    return [new Date().getTime(), x, y, code, e.target.classList['value']];
-  } else {
-    return [x, y, code];
-  }
-} */
-
-// $( document ).ready(function() {
-
-//     if (inIframe()) {
-//         orderIcons();
-//         orderWidth();
-//     }
-//     renderAlgorithm();
-// });
-
 function orderWidth() {
   $('.ui.raised.container.segment.div_to_body').css('width', '100%');
   $('.ui.one.column.container.segment.ivprog_visual_panel').css('width', '100%');
@@ -823,6 +829,19 @@ function showInvalidData () {
   })
 }
 
+function showMessageDialog (msg = "") {
+  $('.ui.height_100.add_accordion').dimmer({
+    closable: false
+  });
+  $('.dimmer_content_message h3').html(msg);
+  $('.dimmer_content_message button').text("OK");
+  $('.dimmer_content_message').css('display', 'block');
+  $('.ui.height_100.add_accordion').dimmer('add content', '.dimmer_content_message');
+  $('.ui.height_100.add_accordion').dimmer('show');
+  $('.dimmer_content_message button').on('click', function(e) {
+    $('.ui.height_100.add_accordion').dimmer('hide');
+  })
+}
 
 function showInvalidFile () {
   $('.ui.height_100.add_accordion').dimmer({

+ 15 - 1
js/main.js

@@ -19,12 +19,14 @@ import {
 } from "./services/userLog";
 import {
   prepareActivityToStudentHelper,
+  prepareActivityToStudentHelperJSON,
   autoEval,
+  setPreviousAlgorithm
 } from "./util/iassignHelpers";
 import { openAssessmentDetail, levenshteinDistance } from "./util/utils";
 import { Config } from "./util/config";
 import { processData } from "./util/dataProcess";
-import { parseExpression } from "./util/parseFromVisual";
+import { parseExpression, parseCode } from "./util/parseFromVisual";
 import * as CodeEditorAll from "./visualUI/text_editor";
 import { autoGenerateTestCaseOutput } from "./util/auto_gen_output";
 import { generate } from "./visualUI/code_generator";
@@ -37,6 +39,14 @@ const CodeEditor = {
   disable: CodeEditorAll.disable,
 };
 
+const Settings = {
+  programming: [],
+  functions: [],
+  datatypes: [],
+  commands: [],
+  filter: []
+}
+
 const i18n = i18nHelper.i18n;
 const LocalizedStrings = LocalizedStringsService.getInstance();
 
@@ -50,6 +60,7 @@ export {
   getTestCases,
   autoEval,
   prepareActivityToStudentHelper,
+  prepareActivityToStudentHelperJSON,
   LocalizedStrings,
   i18n,
   getLogs,
@@ -63,7 +74,10 @@ export {
   autoGenerateTestCaseOutput,
   Config,
   parseExpression,
+  parseCode,
   generate as generateCode,
   levenshteinDistance,
   processData,
+  Settings,
+  setPreviousAlgorithm
 };

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

@@ -1,6 +1,5 @@
 import { ProcessorErrorFactory } from "./../error/processorErrorFactory";
 import { LanguageDefinedFunction } from "./../definedFunctions";
-import { LanguageService } from "./../../services/languageService";
 import {
   ArrayDeclaration,
   While,
@@ -47,9 +46,6 @@ export class SemanticAnalyser {
 
   constructor (ast) {
     this.ast = ast;
-    this.lexerClass = LanguageService.getCurrentLexer();
-    const lexer = new this.lexerClass(null);
-    this.literalNames = lexer.literalNames;
     this.symbolMap = null;
     this.currentFunction = null;
   }

+ 4 - 4
js/runner.js

@@ -1,12 +1,10 @@
 import { IVProgParser } from './ast/ivprogParser';
 import { IVProgProcessor } from './processor/ivprogProcessor';
 import {DOMConsole} from './io/domConsole';
-import { LanguageService } from './services/languageService';
 import { SemanticAnalyser } from './processor/semantic/semanticAnalyser';
 import { Location } from "./memory/location";
 
 export function runner () {
-const ivprogLexer = LanguageService.getCurrentLexer();
 
 
 // const lexer = new ivprogLexer(new InputStream(input));
@@ -29,8 +27,10 @@ domConsole.hide();
 try {
   window.$('#btn').click( () => {
     const input = window.$('#input').val();
-    const analiser = new IVProgParser(input, ivprogLexer);
+    const analiser = IVProgParser.createParser(input);
     try {
+      analiser.fill();
+      //console.debug(analiser.tokenStream)
       const data = analiser.parseTree();
       const semAna = new SemanticAnalyser(data);
       const proc = new IVProgProcessor(semAna.analyseTree());
@@ -51,7 +51,7 @@ try {
       console.log(error);
       console.log(Location.size());
     }
-    
+
   });
 } catch(a) {
   console.log(a);

+ 52 - 0
js/services/languageService.ts

@@ -0,0 +1,52 @@
+declare const iLMparameters: any; // Tell Typescript iLMparameters is a global
+
+import Lexers from "./../../grammar/";
+import line_i18n from "line-i18n";
+import { Config } from "./../util/config";
+import {
+  IVProgLexer,
+  I18N_LANG_FUNCS,
+  I18N_LANG_LIBS,
+} from "../../grammar/lexer";
+
+class LanguageServiceExtended extends line_i18n.LanguageServiceNoLS {
+  constructor () {
+    super(
+      typeof iLMparameters === "undefined"
+        ? Config.default_lang
+        : iLMparameters.lang
+    );
+  }
+
+  getDefaultLang (): string {
+    return "en";
+  }
+
+  getCurrentLexer (): IVProgLexer {
+    const langLexer = Lexers[this.getLang()];
+    if (langLexer === null || langLexer === undefined) {
+      return Lexers[this.getDefaultLang()];
+    } else {
+      return langLexer;
+    }
+  }
+
+  getCurrentLangFuncs (): I18N_LANG_FUNCS {
+    const langInfo = Lexers[this.getLang()];
+    if (langInfo === null || langInfo === undefined) {
+      return Lexers[this.getDefaultLang()].getLangFuncs();
+    } else {
+      return langInfo.getLangFuncs();
+    }
+  }
+
+  getCurrentLangLibs (): I18N_LANG_LIBS {
+    const langInfo = Lexers[this.getLang()];
+    if (langInfo === null || langInfo === undefined) {
+      return Lexers[this.getDefaultLang()].getLangLibs();
+    }
+    return langInfo.getLangLibs();
+  }
+}
+
+export const LanguageService = new LanguageServiceExtended();

+ 7 - 8
js/typeSystem/parsers.js

@@ -21,7 +21,7 @@ export function toString (str) {
 }
 
 export function toChar (str) {
-  console.debug(str, str.length);
+  //console.debug(str, str.length);
   let value = str.replace(/^'/, "");
   value = value.replace(/'$/, "");
   value = value.replace(/\\b/g, "\b");
@@ -39,12 +39,11 @@ export function toReal (value) {
 }
 
 export function toBool (str) {
-  const val = "'" + str + "'";
+  const val = str;
   const lexer = LanguageService.getCurrentLexer();
-  const instance = new lexer(null);
-  if (instance.literalNames[lexer.RK_TRUE] === val) {
+  if (lexer.getReservedKeys()[lexer.getRules().RK_TRUE] === val) {
     return true;
-  } else if (instance.literalNames[lexer.RK_FALSE] === val) {
+  } else if (lexer.getReservedKeys()[lexer.getRules().RK_FALSE] === val) {
     return false;
   } else {
     // TODO: better error message
@@ -54,13 +53,13 @@ export function toBool (str) {
 
 export function convertBoolToString (bool) {
   const lexer = LanguageService.getCurrentLexer();
-  const instance = new lexer(null);
   let result = null;
   if (bool) {
-    result = instance.literalNames[lexer.RK_TRUE];
+    result = lexer.getReservedKeys()[lexer.getRules().RK_TRUE];
   } else {
-    result = instance.literalNames[lexer.RK_FALSE];
+    result = lexer.getReservedKeys()[lexer.getRules().RK_FALSE];
   }
+  //console.debug(result)
   return result.replace(/'/g, "");
 }
 

+ 1 - 2
js/typeSystem/type.ts

@@ -1,11 +1,10 @@
 import { IType } from "./itype";
 
 export class Type implements IType {
-
   public value: string;
   public ord: number;
 
-  constructor(value: string, ord: number) {
+  constructor (value: string, ord: number) {
     this.value = value;
     this.ord = ord;
   }

+ 351 - 0
js/util/codeParser.js

@@ -0,0 +1,351 @@
+
+import * as Models from '../visualUI/ivprog_elements';
+import { LocalizedStrings } from "./../services/localizedStringsService";
+import * as VariableValueMenuManagement from '../visualUI/commands/variable_value_menu';
+import * as CodeParser from '../visualUI/commands/generic_expression';
+
+function parseBoolean (var_value, dimensions) {
+  if (dimensions == 0)
+    return var_value == LocalizedStrings.getUI("logic_value_true");
+  if (dimensions == 1) {
+    var final_array = [];
+    var_value.forEach(function(el){
+      final_array.push(el == LocalizedStrings.getUI("logic_value_true"));
+    });
+    return final_array;
+  }
+  if (dimensions == 2) {
+    var final_array = [];
+    var_value.forEach(function(row){
+      var temp = [];
+      row.forEach(function(el){
+        temp.push(el == LocalizedStrings.getUI("logic_value_true"));
+      });
+      final_array.push(temp);
+    });
+    return final_array;
+  }
+}
+
+function parseGlobal (global_obj) {
+
+  var new_global = new Models.Variable(
+    global_obj.type, 
+    global_obj.name, 
+    global_obj.value);
+  
+  new_global.is_constant = global_obj.is_const;
+  new_global.columns = global_obj.columns;
+  new_global.dimensions = global_obj.dimension;
+  new_global.rows = global_obj.rows;
+
+  if (global_obj.type == "boolean")
+    new_global.value = parseBoolean(global_obj.value, global_obj.dimension);
+	
+	window.program_obj.addGlobal(new_global);
+}
+
+function parseParameter (parameter_obj) {
+
+  const new_parameter = new Models.Variable(
+    parameter_obj.type,
+    parameter_obj.name,
+    null,
+    parameter_obj.dimension,
+    parameter_obj.is_const,
+    parameter_obj.rows,
+    parameter_obj.columns,
+    parameter_obj.reference
+  );
+
+  new_parameter.value = parameter_obj.value;
+
+  if (parameter_obj.type == "boolean" && parameter_obj.value)
+    new_parameter.value = parseBoolean(parameter_obj.value, parameter_obj.dimension);
+
+  return new_parameter;
+}
+
+function parseFunction (function_obj) {
+
+  const new_function = new Models.Function(
+    function_obj.name, 
+    function_obj.return_type, 
+    function_obj.return_dimensions, 
+    [], 
+    false, 
+    false, 
+    []);
+  
+  if (!new_function.name) {
+    new_function.name = LocalizedStrings.getUI("start");
+    new_function.is_main = true;
+  }
+
+  if (function_obj.parameters_list) {
+    function_obj.parameters_list.forEach(function(el){
+      new_function.parameters_list.push(parseParameter(el));
+    });
+  }
+
+  if (function_obj.variables_list) {
+    function_obj.variables_list.forEach(function(el){
+      new_function.variables_list.push(parseParameter(el));
+    });
+  }
+
+  window.program_obj.addFunction(new_function);
+  
+}
+
+export function parserCodeVisual (code_obj = null) {
+
+  window.conteudo = code_obj
+
+  // Globals:
+  window.program_obj.globals = [];
+  code_obj.globals.forEach(parseGlobal);
+
+  // Functions:
+  window.program_obj.functions = [];
+  code_obj.functions.forEach(parseFunction);
+
+  // Commands: 
+  window.program_obj.functions.forEach(function(preparedFunction) {
+    code_obj.functions.forEach(function(rawFunction) {
+      if ((preparedFunction.name == rawFunction.name) 
+          || 
+          (!rawFunction.name && preparedFunction.name == LocalizedStrings.getUI("start"))) {
+            preparedFunction.commands = parseCommands(rawFunction.commands, preparedFunction);
+          }
+    })
+  });
+
+}
+
+function parseCommands (commands_block, function_obj) {
+
+  if (Array.isArray(commands_block)) {
+    var temp = [];
+    commands_block.forEach(function(command) {
+      temp.push(parseCommands(command, function_obj));
+    });
+    return temp;
+  }
+  else {
+    switch (commands_block.type) {
+      case Models.COMMAND_TYPES.reader:
+        return parseReader(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.return:
+        return parseReturn(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.writer:
+        return parseWriter(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.break:
+        return parseBreak(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.comment:
+        return parseComment(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.attribution:
+        return parseAttribution(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.functioncall:
+        return parseFunctionCall(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.iftrue:
+        return parseIfTrue(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.repeatNtimes:
+        return parseRepeatNTimes(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.whiletrue:
+        return parseWhileTrue(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.dowhiletrue:
+        return parseDoWhileTrue(commands_block, function_obj);
+
+      case Models.COMMAND_TYPES.switch:
+        return parseSwitch(commands_block, function_obj);
+    }
+    return null;
+  }
+  
+}
+
+function parseReader (command, function_obj) {
+  var temp = CodeParser.expressionParserCodeVisual(command.variable, function_obj);
+
+  if (Array.isArray(temp) && temp[0])
+    temp = temp[0];
+
+  return new Models.Reader(
+    temp
+  );
+}
+
+function parseReturn (command, function_obj) {
+
+  var temp = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
+
+  return new Models.Return(
+    temp
+  );
+
+}
+
+function parseWriter (command, function_obj) {
+
+  var temp = CodeParser.expressionParserCodeVisual(command.content[0], function_obj);
+
+  return new Models.Writer(
+    temp,
+    command.newLine
+  );
+}
+
+function parseBreak (command, function_obj) {
+    return new Models.Break();
+}
+
+function parseAttribution (command, function_obj) {
+
+  var variable = CodeParser.expressionParserCodeVisual(command.variable, function_obj);
+  var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
+
+  if (Array.isArray(variable)) 
+    variable = variable[0];
+
+  return new Models.Attribution(
+    variable,
+    expression
+  );
+}
+
+function parseComment (command, function_obj) {
+  // TODO
+  return new Models.Comment(
+    null
+  );
+}
+
+function parseFunctionCall (command, function_obj) {
+
+  var parameters = [];
+  if (command.parameters_list) {
+    command.parameters_list.forEach(function(el) {
+      var temp = CodeParser.expressionParserCodeVisual(el, function_obj);
+      if (temp.content === 0) temp.content = "0";
+      parameters.push(temp[0]);
+    });
+  }
+
+  var function_called = CodeParser.searchFunction(command.name);
+
+  var temp = new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_function, null, null, null, false);
+  temp.function_called = function_called;
+  temp.parameters_list = parameters;
+  
+  return new Models.FunctionCall(
+    temp, 
+    null
+  );
+}
+
+function parseIfTrue(command, function_obj) {
+
+  var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
+  var ifTrueBlock = parseCommands(command.ifTrue, function_obj);
+  var ifFalseBlock = parseCommands(command.ifFalse, function_obj);
+
+  return new Models.IfTrue(expression, ifTrueBlock, ifFalseBlock);
+
+}
+
+function parseRepeatNTimes(command, function_obj) {
+
+  var var_attribution = CodeParser.expressionParserCodeVisual(command.var_attribution, function_obj);
+  var_attribution = var_attribution[0];
+
+  var expression1 = CodeParser.expressionParserCodeVisual(command.var_initial, function_obj);
+  expression1 = expression1[0];
+
+  var expression2 = CodeParser.expressionParserCodeVisual(command.condition, function_obj);
+
+  if (expression2[0].item == 'minus') {
+    expression2 = expression2[1];
+    expression2.content *= -1;
+  } else
+    expression2 = expression2[0];
+
+  var var_step = CodeParser.expressionParserCodeVisual(command.step_expression, function_obj);
+
+  var commands_block = parseCommands(command.commands, function_obj);
+
+  var operator = command.step_expression[0].value == '+' 
+                  ? Models.ARITHMETIC_TYPES.plus
+                  : Models.ARITHMETIC_TYPES.minus;
+
+  var expression3 = new Models.ExpressionElement(
+    Models.EXPRESSION_ELEMENTS.exp_op_exp, 
+    [ 
+      null,
+      operator, 
+      var_step[1]
+    ]);
+
+  return new Models.RepeatNTimes(
+    var_attribution,
+    new Models.VariableValueMenu(VariableValueMenuManagement.VAR_OR_VALUE_TYPES.only_variable, null, null, null, false),
+    expression1,
+    expression2,
+    expression3, 
+    commands_block);
+
+}
+
+function parseWhileTrue (command, function_obj) {
+
+  var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
+  var commands = parseCommands(command.commands, function_obj);
+
+  return new Models.WhileTrue(
+    expression, 
+    commands
+  );
+}
+
+function parseDoWhileTrue (command, function_obj) {
+  
+  var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
+  var commands = parseCommands(command.commands, function_obj);
+
+  return new Models.DoWhileTrue(
+    expression, 
+    commands
+  );
+}
+
+function parseSwitch (command, function_obj) {
+
+  var expression = CodeParser.expressionParserCodeVisual(command.expression, function_obj);
+
+  var sc = [];
+  if (command.cases) {
+    command.cases.forEach(function(case_el) {
+
+      var temp_exp = CodeParser.expressionParserCodeVisual(case_el.expression, function_obj);
+      var temp_commands = parseCommands(case_el.commands, function_obj);
+      var temp_case = new Models.SwitchCase(temp_exp[0], temp_commands);
+
+      sc.push(temp_case);
+    })
+  }
+
+	return new Models.Switch(
+    expression[0], 
+    sc
+  );
+}

+ 10 - 0
js/util/config.ts

@@ -10,6 +10,11 @@ class ConfigObject implements ConfigInterface {
   public idle_input_interval: number;
   public suspend_threshold: number;
   public max_instruction_count: number;
+  public activity_programming_type: Map<string, string>;
+  public activity_functions: Map<string, boolean>;
+  public activity_datatypes: Map<string, boolean>;
+  public activity_commands: Map<string, boolean>;
+  public activity_filter: Map<string, boolean>;
   [id: string]: unknown;
 
   constructor () {
@@ -21,6 +26,11 @@ class ConfigObject implements ConfigInterface {
     this.suspend_threshold = 1000;
     // this.max_instruction_count = 350250; - automated evaluation limit
     this.max_instruction_count = Number.MAX_SAFE_INTEGER;
+    this.activity_programming_type = new Map<string, string>();
+    this.activity_functions = new Map<string, boolean>();
+    this.activity_datatypes = new Map<string, boolean>();
+    this.activity_commands = new Map<string, boolean>();
+    this.activity_filter = new Map<string, boolean>();
   }
 
   setConfig (opts: object): void {

+ 4 - 4
js/util/dataProcess.js

@@ -42,10 +42,10 @@ export function processData () {
     const files = Array.from(folderInput.files);
     const idx = files.find((f) => f.name == "index.csv");
     const folderName = idx.webkitRelativePath.replace(idx.name, "");
-    console.debug(idx);
-    console.debug(folderName);
+    //console.debug(idx);
+    //console.debug(folderName);
     const data = await idx.text();
-    console.debug(data);
+    //console.debug(data);
     const csvEntries = data
       .split("\n")
       .slice(1)
@@ -56,7 +56,7 @@ export function processData () {
         vec.forEach((val, i) => (obj[header[i]] = val));
         return obj;
       });
-    console.debug(csvEntries);
+    //console.debug(csvEntries);
     const blockExercMap = csvEntries.reduce(prepareData, new Map());
     //console.log(Array.from(blockExercMatrix.entries()));
     const getFilePath = async function (submission) {

+ 58 - 5
js/util/iassignHelpers.js

@@ -5,14 +5,18 @@ import { TestConsole } from "./testConsole";
 import { parseLogs } from "./../services/userLog";
 import { SemanticAnalyser } from "../processor/semantic/semanticAnalyser";
 import { Maybe } from "./maybe";
+import { parserCodeVisual } from "./codeParser";
 
-function parseActivityData (data) {
+function parseActivityData (data, ignore_logs=false) {
   let algorithm_in_ilm = null;
   if (data.split("\n::algorithm::")[1]) {
     algorithm_in_ilm = data.split("\n::algorithm::")[1].split("\n::logs::")[0];
     const logs = data.split("\n::algorithm::")[1].split("\n::logs::")[1];
-    if (logs != null) {
-      parseLogs(logs);
+    if (logs != null && ignore_logs == false) {
+      try {
+        parseLogs(logs);
+      }
+      catch (e) {}
     }
   }
   let content;
@@ -26,8 +30,57 @@ function parseActivityData (data) {
   return Maybe.some(content);
 }
 
-export function prepareActivityToStudentHelper (ilm_cont) {
-  const maybe_content = parseActivityData(ilm_cont);
+function configAuxiliar (obj_config) {
+
+  return new Map(
+      Object
+        .keys(obj_config)
+        .map(
+            key => [key, obj_config[key]]
+        )
+    )
+}
+    
+function setActivityConfig (config_json) {
+
+  ivprogCore.Config.activity_commands = configAuxiliar(config_json.commands);
+  ivprogCore.Config.activity_functions = configAuxiliar(config_json.functions);
+  ivprogCore.Config.activity_datatypes = configAuxiliar(config_json.datatypes);
+  ivprogCore.Config.activity_filter = configAuxiliar(config_json.filter);
+  ivprogCore.Config.activity_programming_type = configAuxiliar(config_json.programming);
+
+}
+
+export function setPreviousAlgorithm (code) {
+  
+  var code_obj = null;
+  try {
+    code_obj = ivprogCore.parseCode(code)
+    parserCodeVisual(code_obj)
+  }
+  catch(e) {
+    showInvalidData()
+    console.log(e)
+    return
+  }
+}
+
+export function prepareActivityToStudentHelperJSON (ilm_cont) {
+  
+  setTestCases(ilm_cont.test_cases)
+
+  setActivityConfig(ilm_cont.settings)
+
+  if (ilm_cont.code)
+    setPreviousAlgorithm(ilm_cont.code)
+  else 
+    if (ilm_cont.algorithm)
+      setPreviousAlgorithm(ilm_cont.algorithm)
+
+}
+
+export function prepareActivityToStudentHelper (ilm_cont, ignore_logs=false) {
+  const maybe_content = parseActivityData(ilm_cont, ignore_logs);
   return maybe_content.map((content) => {
     const testCases = content.testcases;
     setTestCases(testCases);

+ 377 - 1
js/util/parseFromVisual.js

@@ -2,6 +2,9 @@ import { IVProgParser } from "../ast/ivprogParser";
 import * as Expressions from "../ast/expressions";
 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",
@@ -50,6 +53,341 @@ function getOpType (op) {
   }
 }
 
+/**
+ * @param {Commands.Case} switchCase
+ * */
+function switchCaseWalker (switchCase) {
+  const commands = switchCase.commands.map(commandWalker);
+  const expression = switchCase.isDefault
+    ? null
+    : expressionWalker(switchCase.expression);
+  return {
+    type: "switchcase",
+    line: switchCase.sourceInfo.line,
+    expression,
+    commands,
+  };
+}
+
+/**
+ * @param {Commands.Switch} switchCommand
+ * */
+function switchWalker (switchCommand) {
+  const expression = expressionWalker(switchCommand.expression);
+  const cases = switchCommand.cases.map(switchCaseWalker);
+  return {
+    type: "switch",
+    expression,
+    cases,
+  };
+}
+
+/**
+ * @param {Commands.Return} returnCommand
+ * */
+function returnWalker (returnCommand) {
+  const expression = expressionWalker(returnCommand.expression);
+  return {
+    type: "return",
+    expression,
+  };
+}
+
+function breakWalker (_) {
+  return { type: "break" };
+}
+
+/**
+ * @param {Commands.For} forLoop
+ * */
+function forWalker (forLoop) {
+  const var_attribution = expressionWalker(forLoop.for_id);
+  const var_initial = expressionWalker(forLoop.for_from);
+  const condition = expressionWalker(forLoop.for_to);
+  const step_expression = forLoop.for_pass
+    ? expressionWalker(forLoop.for_pass)
+    : [];
+  const commands = forLoop.commands.map(commandWalker);
+  return {
+    type: "repeatNtimes",
+    var_attribution,
+    var_initial,
+    condition,
+    step_expression,
+    commands,
+  };
+}
+
+/**
+ * @param {Commands.While} whileLoop
+ * */
+function whileWalker (whileLoop) {
+  const expression = expressionWalker(whileLoop.expression);
+  const commands = whileLoop.commands.map(commandWalker);
+  let type = whileLoop.testFirst ? "whiletrue" : "dowhiletrue";
+  return {
+    type,
+    expression,
+    commands,
+  };
+}
+
+/**
+ * @param {Commands.IfThenElse} ifthenelse
+ * */
+function ifThenElseWalker (ifthenelse) {
+  //ifthenelse.
+  const expression = expressionWalker(ifthenelse.condition);
+  const ifTrue = ifthenelse.ifTrue.commands.map(commandWalker);
+  let ifFalse = [];
+  if (ifthenelse.ifFalse) {
+    if (ifthenelse.ifFalse instanceof Commands.CommandBlock) {
+      ifFalse = ifthenelse.ifFalse.commands.map(commandWalker);
+    } else {
+      ifFalse = [ifThenElseWalker(ifthenelse.ifFalse)];
+    }
+  }
+  return {
+    type: "iftrue",
+    expression,
+    ifTrue,
+    ifFalse,
+  };
+}
+
+/**
+ * @param {Commands.Assign} assingment
+ * */
+function assignmentWalker (assingment) {
+  let variable = null;
+  if (assingment instanceof Commands.ArrayIndexAssign) {
+    const line = expressionWalker(assingment.line);
+    let arrayClass = "vector";
+    let column = null;
+    if (assingment.column) {
+      arrayClass = "matrix";
+      column = expressionWalker(assingment.column);
+    }
+    variable = [
+      {
+        instance: "expression",
+        type: TYPES.VARIABLE,
+        class: arrayClass,
+        column: column,
+        line: line,
+        value: assingment.id,
+      },
+    ];
+  } else {
+    variable = [
+      { instance: "expression", type: TYPES.VARIABLE, value: assingment.id },
+    ];
+  }
+  const expression = expressionWalker(assingment.expression);
+  return {
+    type: "attribution",
+    variable,
+    expression,
+  };
+}
+
+/**
+ * @param {Command} command
+ * */
+function commandWalker (command) {
+  let parsedCommand = null;
+  if (command instanceof Commands.FunctionCall) {
+    parsedCommand = functionCallWalker(command);
+  } else if (command instanceof Commands.Assign) {
+    parsedCommand = assignmentWalker(command);
+  } else if (command instanceof Commands.IfThenElse) {
+    parsedCommand = ifThenElseWalker(command);
+  } else if (command instanceof Commands.While) {
+    parsedCommand = whileWalker(command);
+  } else if (command instanceof Commands.Break) {
+    parsedCommand = breakWalker(command);
+  } else if (command instanceof Commands.Return) {
+    parsedCommand = returnWalker(command);
+  } else if (command instanceof Commands.Switch) {
+    parsedCommand = switchWalker(command);
+  } else if (command instanceof Commands.For) {
+    parsedCommand = forWalker(command);
+  } else {
+    throw new Error("not implemented");
+  }
+  parsedCommand.line = command.sourceInfo.line;
+  return parsedCommand;
+}
+
+/**
+ * @param {Commands.FunctionCall} functionCall
+ * */
+function functionCallWalker (functionCall) {
+  let name = functionCall.id;
+  if (name.indexOf(".") !== -1) {
+    name = name.split(".")[1];
+  }
+  const parameters = functionCall.actualParameters.map(expressionWalker);
+  if (name === "$write") {
+    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 content = newLine
+      ? parameters.slice(0, parameters.length - 1)
+      : parameters;
+    return {
+      type: "writer",
+      newLine,
+      content,
+    };
+  }
+  if (name === "$read") {
+    return {
+      type: "reader",
+      variable: parameters[0],
+    };
+  }
+  return {
+    type: "functioncall",
+    parameters_list: parameters,
+    name: functionCall.id,
+  };
+}
+/**
+ * @param {Commands.Function} func
+ * */
+function functionWalker (func) {
+  const funcDeclaration = {
+    name: func.name,
+    line: func.sourceInfo.line,
+    return_type: "",
+    return_dimensions: 0,
+    parameters_list: [],
+    variables_list: [],
+    commands: [],
+  };
+  if (func.returnType instanceof ArrayType) {
+    funcDeclaration.return_type = func.returnType.innerType.value;
+    funcDeclaration.return_dimensions = func.returnType.dimensions;
+  } else {
+    funcDeclaration.return_type = func.returnType.value;
+  }
+  funcDeclaration.parameters_list = func.formalParameters.map(
+    functionParameterWalker
+  );
+  funcDeclaration.variables_list = func.variablesDeclarations.map(
+    variableDeclarationWalker
+  );
+  funcDeclaration.commands = func.commands.map(commandWalker);
+  return funcDeclaration;
+}
+
+/**
+ * @param {Commands.FormalParameter} formalParameter
+ * */
+function functionParameterWalker (formalParameter) {
+  const variable = {
+    name: formalParameter.id,
+    line: formalParameter.sourceInfo.line,
+    type: "",
+    rows: 0,
+    columns: 0,
+    dimension: 0,
+    value: 0,
+    is_const: false,
+    reference: formalParameter.byRef,
+  };
+  if (formalParameter.type instanceof ArrayType) {
+    variable.type = formalParameter.type.innerType.value;
+    variable.dimension = formalParameter.type.dimensions;
+  } else {
+    variable.type = formalParameter.type.value;
+  }
+  return variable;
+}
+
+/**
+ * @param {Commands.Declaration} command
+ * @param {boolean} global
+ * */
+function variableDeclarationWalker (command, global = false) {
+  const variable = {
+    name: command.id,
+    line: command.sourceInfo.line,
+    type: "",
+    rows: 0,
+    columns: 0,
+    dimension: 0,
+    value: 0,
+    is_const: false,
+  };
+  variable.is_const = global && command.isConst;
+  if (command instanceof Commands.ArrayDeclaration) {
+    // array
+    const lines = expressionWalker(command.lines).pop();
+    variable.type = command.type.innerType.value;
+    if (command.isVector) {
+      variable.columns = lines.value;
+      variable.dimension = 1;
+      const values = command.initial.value.map((exp) =>
+        variableInitialWalker(exp)
+      );
+      variable.value = values;
+    } else {
+      const columns = expressionWalker(command.columns).pop();
+      variable.dimension = 2;
+      variable.rows = lines.value;
+      variable.columns = columns.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 = 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 = Number(expression.value.toFixed(2));
+      } else {
+        value = expression.value.toNumber();
+      }
+    }
+    return value;
+  }
+  throw new Error("invalid variable initial value: " + expression.toString());
+}
+
+/**
+ *
+ * @return {[]}
+ **/
 function expressionWalker (expression) {
   let result;
   if (expression instanceof Expressions.VariableLiteral) {
@@ -118,7 +456,7 @@ function expressionWalker (expression) {
         Types.REAL.isCompatible(expression.type) &&
         expression.value.decimalPlaces() == 0
       ) {
-        value = expression.value.toFixed(2);
+        value = Number(expression.value.toFixed(2));
       } else {
         value = expression.value.toNumber();
       }
@@ -141,3 +479,41 @@ export function parseExpression (text) {
   const expressionAST = parser.parseExpressionOR();
   return expressionWalker(expressionAST);
 }
+
+/**
+ * @param {string} text
+ * */
+export function parseCode (text) {
+  const parser = IVProgParser.createParser(text, false);
+  const codeLinesMap = new Map();
+  const tokens = Array.from(parser.lexer.reset(text));
+  const tokenStream = [];
+  for (const token of tokens) {
+    if (token.type === parser.ruleNames.ERROR) {
+      return null;
+    }
+    if (token.type === parser.ruleNames.COMMENTS) {
+      for (let i = 0; i <= token.lineBreaks; i++) {
+        if (codeLinesMap.has(i + token.line))
+          codeLinesMap.get(i + token.line).push(token);
+        else codeLinesMap.set(i + token.line, [token]);
+      }
+      continue;
+    }
+    if (token.type !== parser.ruleNames.WHITESPACE) {
+      tokenStream.push(token);
+    }
+  }
+  parser.fill(tokenStream);
+  try {
+    const program = parser.parseTree();
+    const globals = program.global.map((decl) =>
+      variableDeclarationWalker(decl, true)
+    );
+    const functions = program.functions.map(functionWalker);
+    return { globals, functions };
+  } catch (e) {
+    console.error(e);
+    return null;
+  }
+}

+ 189 - 110
js/util/utils.js

@@ -2,63 +2,82 @@ import { LanguageService } from "./../services/languageService";
 import { LocalizedStrings } from "./../services/localizedStringsService";
 import { Operators } from "./../ast/operators";
 
-/** 
- * source: https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/ 
- * 
-*/
-export function scrollIt (destination, duration = 200, easing = 'linear', callback = null) {
-
+/**
+ * source: https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/
+ *
+ */
+export function scrollIt (
+  destination,
+  duration = 200,
+  easing = "linear",
+  callback = null
+) {
   const easings = {
-    linear(t) {
+    linear (t) {
       return t;
     },
-    easeInQuad(t) {
+    easeInQuad (t) {
       return t * t;
     },
-    easeOutQuad(t) {
+    easeOutQuad (t) {
       return t * (2 - t);
     },
-    easeInOutQuad(t) {
+    easeInOutQuad (t) {
       return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
     },
-    easeInCubic(t) {
+    easeInCubic (t) {
       return t * t * t;
     },
-    easeOutCubic(t) {
-      return (--t) * t * t + 1;
+    easeOutCubic (t) {
+      return --t * t * t + 1;
     },
-    easeInOutCubic(t) {
+    easeInOutCubic (t) {
       return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
     },
-    easeInQuart(t) {
+    easeInQuart (t) {
       return t * t * t * t;
     },
-    easeOutQuart(t) {
-      return 1 - (--t) * t * t * t;
+    easeOutQuart (t) {
+      return 1 - --t * t * t * t;
     },
-    easeInOutQuart(t) {
-      return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
+    easeInOutQuart (t) {
+      return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
     },
-    easeInQuint(t) {
+    easeInQuint (t) {
       return t * t * t * t * t;
     },
-    easeOutQuint(t) {
-      return 1 + (--t) * t * t * t * t;
+    easeOutQuint (t) {
+      return 1 + --t * t * t * t * t;
+    },
+    easeInOutQuint (t) {
+      return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
     },
-    easeInOutQuint(t) {
-      return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t;
-    }
   };
 
   const start = window.pageYOffset;
-  const startTime = 'now' in window.performance ? performance.now() : new Date().getTime();
+  const startTime =
+    "now" in window.performance ? performance.now() : new Date().getTime();
 
-  const documentHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
-  const windowHeight = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight;
-  const destinationOffset = typeof destination === 'number' ? destination : destination.offsetTop;
-  const destinationOffsetToScroll = Math.round(documentHeight - destinationOffset < windowHeight ? documentHeight - windowHeight : destinationOffset);
+  const documentHeight = Math.max(
+    document.body.scrollHeight,
+    document.body.offsetHeight,
+    document.documentElement.clientHeight,
+    document.documentElement.scrollHeight,
+    document.documentElement.offsetHeight
+  );
+  const windowHeight =
+    window.innerHeight ||
+    document.documentElement.clientHeight ||
+    document.getElementsByTagName("body")[0].clientHeight;
+  const destinationOffset =
+    typeof destination === "number" ? destination : destination.offsetTop;
+  const destinationOffsetToScroll = Math.round(
+    documentHeight - destinationOffset < windowHeight
+      ? documentHeight - windowHeight
+      : destinationOffset
+  );
 
-  if ('requestAnimationFrame' in window === false) {
+  if ("requestAnimationFrame" in window === false) {
     window.scroll(0, destinationOffsetToScroll);
     if (callback) {
       callback();
@@ -66,11 +85,15 @@ export function scrollIt (destination, duration = 200, easing = 'linear', callba
     return;
   }
 
-  function scroll() {
-    const now = 'now' in window.performance ? performance.now() : new Date().getTime();
-    const time = Math.min(1, ((now - startTime) / duration));
+  function scroll () {
+    const now =
+      "now" in window.performance ? performance.now() : new Date().getTime();
+    const time = Math.min(1, (now - startTime) / duration);
     const timeFunction = easings[easing](time);
-    window.scroll(0, Math.ceil((timeFunction * (destinationOffsetToScroll - start)) + start));
+    window.scroll(
+      0,
+      Math.ceil(timeFunction * (destinationOffsetToScroll - start) + start)
+    );
 
     if (window.pageYOffset === destinationOffsetToScroll) {
       if (callback) {
@@ -86,42 +109,67 @@ export function scrollIt (destination, duration = 200, easing = 'linear', callba
 }
 
 /**
- * 
+ *
  * source: https://stackoverflow.com/a/16270434
  */
 export function isElementInViewport (el) {
   const rect = el.getBoundingClientRect();
 
-  return rect.bottom > 0 &&
+  return (
+    rect.bottom > 0 &&
     rect.right > 0 &&
     rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
-    rect.top < (window.innerHeight || document.documentElement.clientHeight);
+    rect.top < (window.innerHeight || document.documentElement.clientHeight)
+  );
 }
 
 let cacheMainList = null;
 let cacheOp = null;
 
 function fillCache () {
-  if(cacheMainList == null) {
+  if (cacheMainList == null) {
     cacheMainList = [];
-    const mainList = ["RK_PROGRAM","RK_REAL","RK_VOID","RK_BOOLEAN","RK_STRING",
-      "RK_INTEGER","RK_CHARACTER","RK_SWITCH","RK_CASE","RK_DEFAULT","RK_CONST",
-      "RK_FUNCTION","RK_RETURN","RK_FOR","RK_BREAK","RK_DO","RK_WHILE","RK_IF",
-      "RK_ELSE","RK_FALSE","RK_TRUE"];
-    const lexerClass = LanguageService.getCurrentLexer();
-    const nullLexer = new lexerClass();
+    const mainList = [
+      "RK_PROGRAM",
+      "RK_REAL",
+      "RK_VOID",
+      "RK_BOOLEAN",
+      "RK_STRING",
+      "RK_INTEGER",
+      "RK_CHARACTER",
+      "RK_SWITCH",
+      "RK_CASE",
+      "RK_DEFAULT",
+      "RK_CONST",
+      "RK_FUNCTION",
+      "RK_RETURN",
+      "RK_FOR",
+      "RK_BREAK",
+      "RK_DO",
+      "RK_WHILE",
+      "RK_IF",
+      "RK_ELSE",
+      "RK_FALSE",
+      "RK_TRUE",
+    ];
+    const lexer = LanguageService.getCurrentLexer();
+    const names = lexer.getReservedKeys();
     for (let key = 0; key < mainList.length; ++key) {
       const word = mainList[key];
-      const keyword = nullLexer.literalNames[lexerClass[word]];
-      cacheMainList.push(keyword.substring(1, keyword.length-1));
+      const keyword = names[word];
+      cacheMainList.push(keyword);
     }
   }
-  if(cacheOp == null) {
-    cacheOp = []
-    const logicOpList = [Operators.AND.value, Operators.OR.value, Operators.NOT.value];
+  if (cacheOp == null) {
+    cacheOp = [];
+    const logicOpList = [
+      Operators.AND.value,
+      Operators.OR.value,
+      Operators.NOT.value,
+    ];
     for (let op = 0; op < logicOpList.length; ++op) {
       const lOp = `logic_operator_${logicOpList[op]}`;
-      cacheOp.push(LocalizedStrings.getUI(lOp))
+      cacheOp.push(LocalizedStrings.getUI(lOp));
     }
   }
 }
@@ -130,14 +178,14 @@ export function isKeyword (text) {
   fillCache();
   for (let key = 0; key < cacheMainList.length; ++key) {
     const keyword = cacheMainList[key];
-    if(keyword == text) {
+    if (keyword == text) {
       return true;
     }
   }
   // not in main list, check op
   for (let op = 0; op < cacheOp.length; op++) {
     const lOp = cacheOp[op];
-    if(lOp == text) {
+    if (lOp == text) {
       return true;
     }
   }
@@ -146,122 +194,153 @@ export function isKeyword (text) {
 
 export function isValidIdentifier (identifier_str) {
   const validRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(identifier_str);
-  if(!validRegex) {
-    return false;
-  }
-	return !isKeyword(identifier_str);
+  return validRegex && !isKeyword(identifier_str)
 }
 
 export function getCodeEditorModeConfig () {
-  const blockList = ["RK_SWITCH", "RK_PROGRAM","RK_CASE","RK_DEFAULT","RK_FOR","RK_FOR_ALT",
-    "RK_FUNCTION","RK_DO","RK_WHILE","RK_WHILE_ALT","RK_IF","RK_ELSE"]
-  const keywordsList = ["RK_CONST","RK_RETURN","RK_BREAK","RK_FOR_FROM","RK_FOR_TO","RK_FOR_PASS","RK_DO_UNTIL"];
-  const typeList = ["RK_REAL","RK_VOID","RK_BOOLEAN","RK_STRING","RK_INTEGER","RK_CHARACTER"];
+  const blockList = [
+    "RK_SWITCH",
+    "RK_PROGRAM",
+    "RK_CASE",
+    "RK_DEFAULT",
+    "RK_FOR",
+    "RK_FOR_ALT",
+    "RK_FUNCTION",
+    "RK_DO",
+    "RK_WHILE",
+    "RK_WHILE_ALT",
+    "RK_IF",
+    "RK_ELSE",
+  ];
+  const keywordsList = [
+    "RK_CONST",
+    "RK_RETURN",
+    "RK_BREAK",
+    "RK_FOR_FROM",
+    "RK_FOR_TO",
+    "RK_FOR_PASS",
+    "RK_DO_UNTIL",
+  ];
+  const typeList = [
+    "RK_REAL",
+    "RK_VOID",
+    "RK_BOOLEAN",
+    "RK_STRING",
+    "RK_INTEGER",
+    "RK_CHARACTER",
+  ];
   const atomList = ["RK_FALSE", "RK_TRUE"];
 
   const case_default = [];
   const blocks = [];
   const keywords = [];
   const types = [];
-  const atoms = []
+  const atoms = [];
   let switchString = "";
 
   cacheMainList = [];
-  const lexerClass = LanguageService.getCurrentLexer();
-  const nullLexer = new lexerClass();
-  blockList.forEach( v => {
-    const keyword = nullLexer.literalNames[lexerClass[v]];
-    const value = keyword.substring(1, keyword.length-1);
+  const lexer = LanguageService.getCurrentLexer();
+  const names = lexer.getReservedKeys();
+  //console.debug(names);
+  blockList.forEach((v) => {
+    const keyword = names[v];
+    const value = keyword;
     cacheMainList.push(value);
     keywords.push(value);
     blocks.push(value);
-    if(v == "RK_SWITCH") {
+    if (v == "RK_SWITCH") {
       switchString = value;
     } else if (v == "RK_CASE" || v == "RK_DEFAULT") {
       case_default.push(value);
     }
   });
-  keywordsList.forEach( v => {
-    const keyword = nullLexer.literalNames[lexerClass[v]];
-    const value = keyword.substring(1, keyword.length-1);
+  keywordsList.forEach((v) => {
+    const keyword = names[v];
+    const value = keyword;
     cacheMainList.push(value);
     keywords.push(value);
   });
-  typeList.forEach(v => {
-    const keyword = nullLexer.literalNames[lexerClass[v]];
-    const value = keyword.substring(1, keyword.length-1);
+  typeList.forEach((v) => {
+    const keyword = names[v];
+    const value = keyword;
     cacheMainList.push(value);
     types.push(value);
-  })
-  atomList.forEach( v => {
-    const keyword = nullLexer.literalNames[lexerClass[v]];
-    const value = keyword.substring(1, keyword.length-1);
+  });
+  atomList.forEach((v) => {
+    const keyword = names[v];
+    const value = keyword;
     cacheMainList.push(value);
     atoms.push(value);
-  })
-  
-  cacheOp = []
-  const logicOpList = [Operators.AND.value, Operators.OR.value, Operators.NOT.value];
-  for (let op = 0; op < logicOpList.length; ++op) {
-    const lOp = `logic_operator_${logicOpList[op]}`;
-    const value = LocalizedStrings.getUI(lOp);
-    cacheOp.push(value)
+  });
+
+  cacheOp = [];
+  const logicOpList = ["NOT_OPERATOR", "OR_OPERATOR", "AND_OPERATOR"];
+
+  logicOpList.forEach((v) => {
+    const keyword = names[v];
+    const value = keyword;
+    cacheOp.push(value);
     keywords.push(value);
-  }
+  });
+  cacheMainList.push(lexer.getLangFuncs().main_function);
   return {
     case_default: case_default,
     atoms: atoms,
     keywords: keywords,
     switchString: switchString,
     types: types,
-    blocks: blocks
-  }
+    blocks: blocks,
+  };
 }
 
 /**
  * Source: https://gist.github.com/andrei-m/982927
- * @param {string} a 
- * @param {string} b 
+ * @param {string} a
+ * @param {string} b
  */
 export function levenshteinDistance (a, b) {
-  if(a.length == 0) return b.length; 
-  if(b.length == 0) return a.length; 
+  if (a.length == 0) return b.length;
+  if (b.length == 0) return a.length;
 
   const matrix = [];
 
   // increment along the first column of each row
   let i;
-  for(i = 0; i <= b.length; i++){
+  for (i = 0; i <= b.length; i++) {
     matrix[i] = [i];
   }
 
   // increment each column in the first row
   let j;
-  for(j = 0; j <= a.length; j++){
+  for (j = 0; j <= a.length; j++) {
     matrix[0][j] = j;
   }
 
   // Fill in the rest of the matrix
-  for(i = 1; i <= b.length; i++){
-    for(j = 1; j <= a.length; j++){
-      if(b.charCodeAt(i-1) == a.charCodeAt(j-1)){
-        matrix[i][j] = matrix[i-1][j-1];
+  for (i = 1; i <= b.length; i++) {
+    for (j = 1; j <= a.length; j++) {
+      if (b.charCodeAt(i - 1) == a.charCodeAt(j - 1)) {
+        matrix[i][j] = matrix[i - 1][j - 1];
       } else {
-        matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
-                        Math.min(matrix[i][j-1] + 1, // insertion
-                          matrix[i-1][j] + 1)); // deletion
+        matrix[i][j] = Math.min(
+          matrix[i - 1][j - 1] + 1, // substitution
+          Math.min(
+            matrix[i][j - 1] + 1, // insertion
+            matrix[i - 1][j] + 1
+          )
+        ); // deletion
       }
     }
   }
   return matrix[b.length][a.length];
 }
 
-let win = null
+let win = null;
 export function openAssessmentDetail (event) {
   event.preventDefault();
   const page_code = event.currentTarget.dataset.page;
-  if(win != null) {
-    win.close()
+  if (win != null) {
+    win.close();
   }
   win = window.open("", "DetailWindow", "width=550,height=600");
   win.document.open();
@@ -270,13 +349,13 @@ export function openAssessmentDetail (event) {
 }
 
 export function range (size, startAt = 0) {
-  return [...Array(size).keys()].map(i => i + startAt);
+  return [...Array(size).keys()].map((i) => i + startAt);
 }
 
 /**
- * 
- * @param {number} ms 
+ *
+ * @param {number} ms
  */
 export async function sleep (ms) {
-    return new Promise( (res, _) => setTimeout(res, ms));
-  }
+  return new Promise((res, _) => setTimeout(res, ms));
+}

+ 6 - 6
js/visualUI/code_generator.js

@@ -884,7 +884,7 @@ function variablesCode (variable_obj) {
       case Types.REAL:
         ret += "<- {";
         for (let j = 0; j < temp.value.length; j++) {
-          ret += temp.value[j].toFixed(2);
+          ret += parseFloat(temp.value[j]).toFixed(2);
           if (j + 1 < temp.value.length) {
             ret += ", ";
           }
@@ -959,7 +959,7 @@ function variablesCode (variable_obj) {
           ret += "{";
 
           for (let k = 0; k < temp.columns; k++) {
-            ret += temp.value[j][k].toFixed(2);
+            ret += parseFloat(temp.value[j][k]).toFixed(2);
 
             if (k + 1 < temp.columns) {
               ret += ", ";
@@ -1047,7 +1047,7 @@ function variablesCode (variable_obj) {
         ret += "<- " + temp.value;
         break;
       case Types.REAL:
-        ret += "<- " + temp.value.toFixed(2);
+        ret += "<- " + parseFloat(temp.value).toFixed(2);
         break;
       case Types.TEXT:
         ret += '<- "' + temp.value + '"';
@@ -1117,7 +1117,7 @@ function globalsCode () {
           case Types.REAL:
             ret += "<- {";
             for (let j = 0; j < temp.value.length; j++) {
-              ret += temp.value[j].toFixed(2);
+              ret += parseFloat(temp.value[j]).toFixed(2);
               if (j + 1 < temp.value.length) {
                 ret += ", ";
               }
@@ -1192,7 +1192,7 @@ function globalsCode () {
               ret += "{";
 
               for (let k = 0; k < temp.columns; k++) {
-                ret += temp.value[j][k].toFixed(2);
+                ret += parseFloat(temp.value[j][k]).toFixed(2);
 
                 if (k + 1 < temp.columns) {
                   ret += ", ";
@@ -1280,7 +1280,7 @@ function globalsCode () {
             ret += "<- " + temp.value;
             break;
           case Types.REAL:
-            ret += "<- " + temp.value.toFixed(2);
+            ret += "<- " + parseFloat(temp.value).toFixed(2);
             break;
           case Types.TEXT:
             ret += '<- "' + temp.value + '"';

+ 101 - 1
js/visualUI/commands/generic_expression.js

@@ -1628,7 +1628,107 @@ export function expressionParserToVisual (text, function_obj, input_field) {
     exp_obj.push(getVariable(function_obj, parsed[i]));
   }
 
+  return exp_obj;
+}
+
+export function searchFunction (function_name) {
+
+  for (var j = 0; j < program_obj.functions.length; j++) {
+    if (program_obj.functions[j].name == function_name) {
+      return program_obj.functions[j];
+    }
+  }
+
+  // Se ainda não encontrou, procurar na biblioteca do iVProg:
+  for (var j = 0; j < window.system_functions.length; j++) {
+    if (function_name.split(".")[1] && function_name.split(".")[1] 
+        == window.system_functions[j].identifier) {
+      return window.system_functions[j];
+    } else if (function_name == window.system_functions[j].identifier) {
+      return window.system_functions[j];
+    }
+  }
+
+}
+
+
+export function expressionParserCodeVisual (parsed, function_obj) {
+
+  if (!parsed) return null;
+
+  var var_not_found = [];
+  var fun_not_found = [];
+
+  for (var i = 0; i < parsed.length; i++) {
+    var variavel = null;
+    if (parsed[i].instance == "expression"
+          && parsed[i].type == "var") {
+      // 1. Procurar a variável na função:
+      for (var j = 0; j < function_obj.variables_list.length; j++) {
+        if (function_obj.variables_list[j].name == parsed[i].value) {
+          variavel = function_obj.variables_list[j];
+          break;
+        }
+      }
+
+      // 2. Procurar a variável nas globais: 
+      if (!variavel)
+        for (var j = 0; j < program_obj.globals.length; j++) {
+          if (program_obj.globals[j].name == parsed[i].value) {
+            variavel = program_obj.globals[j];
+            break;
+          }
+        }
+
+      // 3. Procurar a variável nos parâmetros:
+      if (!variavel)
+        for (var j = 0; j < function_obj.parameters_list.length; j++) {
+          if (function_obj.parameters_list[j].name == parsed[i].value) {
+            variavel = function_obj.parameters_list[j];
+            break;
+          }
+        }
+      
+      if (!variavel)
+        var_not_found.push(parsed[i].value);
+    }
+
+    var funcao;
+    if (parsed[i].instance == "expression"
+      && parsed[i].type == "function") {
+    
+      // Procurar a função para referência:
+      for (var j = 0; j < program_obj.functions.length; j++) {
+        if (program_obj.functions[j].name == parsed[i].value) {
+          funcao = program_obj.functions[j];
+        }
+      }
+
+      // Se ainda não encontrou, procurar na biblioteca do iVProg:
+      if (!funcao) {
+        for (var j = 0; j < window.system_functions.length; j++) {
+          if (parsed[i].value.split(".")[1] && parsed[i].value.split(".")[1] 
+              == window.system_functions[j].identifier) {
+            funcao = window.system_functions[j];
+          } else if (parsed[i].value == window.system_functions[j].identifier) {
+            funcao = window.system_functions[j];
+          }
+        }
+      }
+
+    if (!funcao) {
+      fun_not_found.push(parsed[i].value);
+    }
+  }
+}
+
+  var exp_obj = [];
+  for (var i = 0; i < parsed.length; i++) {
+    exp_obj.push(getVariable(function_obj, parsed[i]));
+  }
+
   
 
   return exp_obj;
-}
+}
+

+ 86 - 50
js/visualUI/functions.js

@@ -138,6 +138,25 @@ WatchJS.watch(window.program_obj.functions, function(){
 
 function addFunctionHandler () {
 
+  if (window.program_obj.functions) {
+		var in_use = false;
+		do {
+			in_use = false;
+
+			var temp_name = LocalizedStrings.getUI('new_function') + '_' + counter_new_functions;
+
+			window.program_obj.functions.forEach(function(el) {
+				if (temp_name == el.name) {
+					in_use = true;
+				}
+			})
+
+			if (in_use)
+        counter_new_functions++;
+
+		} while (in_use);
+	}
+
 	const new_function = new Models.Function(LocalizedStrings.getUI("new_function") + "_" + counter_new_functions, Types.VOID, 0, [], false, false, [], new Models.Comment(LocalizedStrings.getUI('text_comment_start')));
 	program.addFunction(new_function);
 
@@ -156,6 +175,26 @@ function addParameter (function_obj, function_container/*, is_from_click = false
   if (function_obj.parameters_list == null) {
     function_obj.parameters_list = [];
   }
+
+  if (function_obj.parameters_list) {
+		var in_use = false;
+		do {
+			in_use = false;
+
+			var temp_name = LocalizedStrings.getUI('new_parameter') + '_' + counter_new_parameters;
+
+			function_obj.parameters_list.forEach(function(el) {
+				if (temp_name == el.name) {
+					in_use = true;
+				}
+			})
+
+			if (in_use)
+        counter_new_parameters++;
+
+		} while (in_use);
+	}
+
   const new_parameter = new Models.Variable(Types.INTEGER, LocalizedStrings.getUI("new_parameter") + "_" + counter_new_parameters);
   function_obj.parameters_list.push(new_parameter);
   counter_new_parameters ++;
@@ -248,7 +287,7 @@ function addHandlers (function_obj, function_container) {
         function_container.find(".inline_add_command").toggle();
       });
     }
-    
+
   });
 }
 
@@ -256,7 +295,7 @@ function addHandlers (function_obj, function_container) {
 function renderFunctionReturn (function_obj, function_element) {
 
   var ret = '<div class="ui dropdown function_return">';
-    
+
     if (function_obj.return_dimensions == 1) {
       ret += '<div class="text">'+ LocalizedStrings.getUI("vector") +': '+ LocalizedStrings.getUI(`type_${function_obj.return_type.toLowerCase()}`);
       ret += ' [ ] </div>';
@@ -303,20 +342,20 @@ function renderFunctionReturn (function_obj, function_element) {
     ret += '</div></div>';
 
     ret = $(ret);
-    
+
     function_element.find('.function_return').append(ret);
 }
 
 var cont = 0;
 
 export function renderFunction (function_obj) {
-  
+
   var appender = '<div class="ui secondary segment function_div list-group-item function_cont_'+cont+'">';
 
   if (function_obj.function_comment) {
     //appender += renderComment(function_obj.function_comment, sequence, true, -1);
   }
-    
+
   appender += '<span class="glyphicon glyphicon-move move_function" aria-hidden="true"><i class="icon sort alternate vertical"></i></span>';
 
   appender += (function_obj.is_main ? '<div class="div_start_minimize_v"> </div>' : '<button class="ui icon button large remove_function_button"><i class="red icon times"></i></button>')
@@ -330,10 +369,10 @@ export function renderFunction (function_obj) {
   } else {
       appender += '<div class="ui function_return"></div>';
 
-      appender += '<div class="function_name_div function_name_div_updated"><span class="span_name_function name_function_updated">'+function_obj.name+'</span> </div> ' 
+      appender += '<div class="function_name_div function_name_div_updated"><span class="span_name_function name_function_updated">'+function_obj.name+'</span> </div> '
         + ' <span class="parethesis_function"> ( </span> <i class="ui icon plus square outline add_parameter_button"></i> <div class="ui large labels parameters_list container_parameters_list">';
   }
-    
+
   appender += '</div> <span class="parethesis_function"> ) </span> </div>'
     + (function_obj.is_hidden ? ' <div class="function_area" style="display: none;"> ' : ' <div class="function_area"> ');
 
@@ -382,7 +421,7 @@ export function renderFunction (function_obj) {
 
   addHandlers(function_obj, appender);
 
-  // Rendering parameters: 
+  // Rendering parameters:
   for (var j = 0; j < function_obj.parameters_list.length; j++) {
     renderParameter(function_obj, function_obj.parameters_list[j], appender);
   }
@@ -419,7 +458,7 @@ export function renderFunction (function_obj) {
       hide: 0
     }
   });
-  
+
   appender.find('.add_var_button_function').popup({
     content : LocalizedStrings.getUI("btn_add_var"),
     delay: {
@@ -562,7 +601,7 @@ export function renderFunction (function_obj) {
       offset: 40,
       onStick: function (evt) {
         $(teste).css('top', '20px', 'important');
-      }, 
+      },
       onBottom: function (evt) {
         $(teste).css('top', '20px', 'important');
       },
@@ -583,7 +622,7 @@ export function renderFunction (function_obj) {
       }
     });
   }
-  
+
   cont ++;
 
   appender.find('.add_parameter_button').popup({
@@ -673,7 +712,7 @@ function updateProgramObjDrag () {
   // index_in_block = $(evento_drag.item).parent().find('.command_container').index(evento_drag.item);
 
   const is_in_case_switch = $(evento_drag.item).parent().hasClass('case_commands_block');
-  
+
   // encontrar o elemento na árvore:
 
   var command_start_point = window.program_obj.functions[function_index].commands[indice_na_raiz];
@@ -693,7 +732,7 @@ function updateProgramObjDrag () {
 
   // agora tem que alocar o comando na árvore, mas considerar as quatro situações:
   // (1) se está em um else ou (2) se está em switch ou (3) será um caso padrão ou (4) se será na raiz.
-  
+
   if (path_target.length == 0) { // soltou na raiz:
     window.program_obj.functions[function_index].commands.splice(evento_drag.newIndex - 1, 0, command_in_drag);
   } else if (is_in_else)  {
@@ -717,7 +756,7 @@ function updateProgramObjDrag () {
 
   window.draging = false;
   renderAlgorithm();
-  
+
 
 }
 
@@ -761,7 +800,7 @@ function prepareDragHandler (evt) {
 var command_in_drag;
 
 function addSortableHandler (element, id_function) {
-  
+
   var n_group = 'commands_drag_' + id_function;
   Sortable.create(element, {
     handle: '.command_drag',
@@ -834,7 +873,7 @@ function addSortableHandler (element, id_function) {
       addSortableHandler($(this).find(".case_commands_block")[0], id_function);
     });
 
-  });  
+  });
 }
 
 export function initVisualUI () {
@@ -1009,7 +1048,7 @@ export function setTestCases (testCases) {
 
 export function getTestCases () {
   // Deep clone of test cases to avoid unauthorized modification
-  // TODO: It may be not possible to use this once custom test are fully implemented 
+  // TODO: It may be not possible to use this once custom test are fully implemented
   return JSON.parse(JSON.stringify(_testCases));
 }
 
@@ -1036,7 +1075,7 @@ function runCodeAssessment () {
     // cannot run assessment or it's already running
     return -1;
   }
-  
+
   let strCode = null;
 
   is_iassign = false;
@@ -1099,7 +1138,7 @@ function runCode () {
   if (strCode == null) {
     return;
   }
-  
+
   toggleConsole(true);
 
   // if(domConsole == null)
@@ -1116,7 +1155,7 @@ function runCode () {
       scheduleCall(() => {
         if(domConsole.pending_writes.length == 0) {
           if(proc.mode === Modes.ABORT) {
-            domConsole.info(LocalizedStrings.getMessage("aborted_execution"));  
+            domConsole.info(LocalizedStrings.getMessage("aborted_execution"));
           } else {
             domConsole.info(LocalizedStrings.getMessage("success_execution"));
           }
@@ -1144,7 +1183,7 @@ function runCode () {
         }
         return false;
       },100);
-    }) 
+    })
   } catch (error) {
     scheduleCall(() => {
       if(domConsole.pending_writes.length == 0) {
@@ -1158,7 +1197,7 @@ function runCode () {
       return false;
     },100);
   }
-  
+
 }
 
 function toggleConsole (is_running) {
@@ -1261,7 +1300,7 @@ function renderParameter (function_obj, parameter_obj, function_container) {
 
   if (parameter_obj.reference)
     ret += '<input type="checkbox" checked class="by_reference">';
-  else 
+  else
     ret += '<input type="checkbox" class="by_copy">';
 
   ret += '<div class="ui dropdown parameter_type">';
@@ -1280,7 +1319,7 @@ function renderParameter (function_obj, parameter_obj, function_container) {
 
   ret += '<div class="menu">';
 
-  
+
   for (const tm in Types) {
       if (tm == Types.VOID.toUpperCase()) {
         continue;
@@ -1322,13 +1361,13 @@ function renderParameter (function_obj, parameter_obj, function_container) {
   ret += ' <i class="yellow inverted icon times remove_parameter"></i></div>';
 
   ret = $(ret);
-  
+
   function_container.find('.container_parameters_list').append(ret);
 
   ret.find('.remove_parameter').on('click', function(e){
     removeParameter(function_obj, parameter_obj, ret);
   });
-  
+
   ret.find('.ui.dropdown.parameter_type').dropdown({
     onChange: function(_, __, $selectedItem) {
       if ($selectedItem.data('dimensions')) {
@@ -1370,7 +1409,7 @@ function renderParameter (function_obj, parameter_obj, function_container) {
 }
 
 function updateParameterName (parameter_var, new_name, parameter_obj_dom, function_obj) {
-  
+
   if (parameter_var.name == new_name) {
     return;
   }
@@ -1409,11 +1448,11 @@ function variableNameAlreadyExists (name_var, function_obj) {
 }
 
 function updateFunctionName (function_var, new_name, function_obj_dom) {
-  
+
   if (function_var.name == new_name) {
     return;
   }
-  
+
   if (isValidIdentifier(new_name)) {
     if (functionNameAlreadyExists(new_name)) {
       Utils.renderErrorMessage(function_obj_dom.find('.function_name_div'), LocalizedStrings.getError('inform_valid_function_duplicated', [new_name]));
@@ -1523,7 +1562,7 @@ function enableNameFunctionUpdate (function_obj, parent_node) {
   }
   parent_node.find('.span_name_function').css('padding-left', '0');
   parent_node.find('.span_name_function').css('padding-right', '0');
-  
+
   input_field = $( "<input type='text' class='width-dynamic input_name_function' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' value='"+function_obj.name+"' />" );
   input_field.insertBefore(parent_node.find('.span_name_function'));
 
@@ -1587,7 +1626,7 @@ function enableNameFunctionUpdate (function_obj, parent_node) {
     }
   });
   input_field.select();
-  
+
 }
 
 export function addFunctionChangeListener (callback) {
@@ -1639,42 +1678,39 @@ function stopExecution () {
 }
 
 function downloadFile() {
-  
+
   var contentToSend = '{}\n::algorithm::';
 
-  if (settingsProgrammingTypes == "textual") {
-    contentToSend +=  ivprogCore.CodeEditor.getCode();
-  } else {
-    contentToSend += JSON.stringify(window.program_obj, function(key, value) {
-      if (key == 'dom_object') {
-          return;
-      }
-      return value;
-    });
-  }
+  contentToSend = generator();
 
-  var date = new Date(); 
+  var date = new Date();
   var temp = date.toISOString().split('T')[0] + "_" + date.toTimeString().split(' ')[0].replaceAll(':', '-');
   var blob = new Blob([contentToSend],
                 { type: "text/plain;charset=utf-8" });
-  
+
   saveAs(blob, "ivprog-exported_" + temp + ".ivph");
 }
 
 function uploadFile (evt) {
     var oFReader = new FileReader();
     oFReader.readAsText(document.getElementById("ivph_file").files[0]);
+
     oFReader.onload = function (oFREvent) {
       var txt = oFREvent.target.result;
+
       try {
 
-        previousContent = txt;
-        prepareActivityToStudent(txt);
-        window.renderAlgorithm();
-        $('.assessment_button').addClass('disabled');
+        if (txt.indexOf("::algorithm::") >= 0 || txt.indexOf("\"test_cases\"") >= 0) {
+          //leo/lucas Version with "test-cases": { "version": "x.y",\n "code": ... \n "test_cases":...
+          prepareActivityToStudent(txt, true);
+          console.debug("code=" + txt.code):
+        } else {
+          ivprogCore.setPreviousAlgorithm(txt);
+          window.renderAlgorithm();
+        }
       }
       catch (e) {
-        showInvalidFile();
+        console.log(e)
       }
     };
-  }
+  }

+ 42 - 26
js/visualUI/globals.js

@@ -3,11 +3,31 @@ import * as Models from './ivprog_elements';
 import { LocalizedStrings } from './../services/localizedStringsService';
 import * as Utils from './utils';
 import { registerUserEvent, registerSystemEvent, ActionTypes } from "./../services/userLog";
-
+import { isValidIdentifier } from "./../util/utils";
 var counter_new_globals = 0;
 
 export function addGlobal (program, is_from_click = false) {
 
+	// Verify if the next global name is in use:
+	if (program.globals) {
+		var in_use = false;
+		do {
+			in_use = false;
+			
+			var temp_name = LocalizedStrings.getUI('new_global') + '_' + counter_new_globals;
+
+			program.globals.forEach(function(el) {
+				if (temp_name == el.name) {
+					in_use = true;
+				}
+			})
+
+			if (in_use)
+				counter_new_globals++;
+
+		} while (in_use);
+	}
+
 	var new_global = new Models.Variable(Types.INTEGER, LocalizedStrings.getUI('new_global') + '_' + counter_new_globals, 0);
 	counter_new_globals ++;
 
@@ -42,7 +62,7 @@ function updateName (global_var, new_name, global_obj_dom) {
 			global_var.name = new_name;
 		}
 	} else {
-		Utils.renderErrorMessage(global_obj_dom.find('.editing_name_var'), LocalizedStrings.getUI('inform_valid_name'));
+		Utils.renderErrorMessage(global_obj_dom.find('.editing_name_var'), LocalizedStrings.getError('inform_valid_identifier'));
 	}
 }
 
@@ -55,10 +75,6 @@ function globalNameAlreadyExists (global_name) {
   return false;
 }
 
-function isValidIdentifier (identifier_str) {
-	return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(identifier_str);
-}
-
 function updateType (global_var, new_type, new_dimensions = 0) {
 	global_var.type = new_type;
 	global_var.dimensions = new_dimensions;
@@ -295,7 +311,7 @@ function renderValues (global_var, global_container) {
 
 	if (global_var.dimensions == 0) {
 		if (global_var.type == Types.REAL) {
-			ret += '<div class="created_div_valor_var"><span class="span_value_variable simple_var">'+global_var.value.toFixed(1)+'</span>  </div> ';
+			ret += '<div class="created_div_valor_var"><span class="span_value_variable simple_var">'+parseFloat(global_var.value).toFixed(1)+'</span>  </div> ';
 		} else {
 			if (global_var.type == Types.BOOLEAN) {
 				ret += '<div class="created_div_valor_var"><span class="span_value_variable boolean_simple_type">'+LocalizedStrings.getUI(`logic_value_${global_var.value}`)+'</span>  </div> ';
@@ -310,7 +326,7 @@ function renderValues (global_var, global_container) {
 			ret += '<tr>';
 			if (global_var.type == Types.REAL) {
 				for (var k = 0; k < global_var.columns; k++) {
-					ret += '<td><span class="span_value_variable vector_var" data-index="'+k+'">'+global_var.value[k].toFixed(1)+'</span></td>';
+					ret += '<td><span class="span_value_variable vector_var" data-index="'+k+'">'+parseFloat(global_var.value[k]).toFixed(1)+'</span></td>';
 				}
 			} else {
 				for (var k = 0; k < global_var.columns; k++) {
@@ -334,7 +350,7 @@ function renderValues (global_var, global_container) {
 				for (var l = 0; l < global_var.rows; l++) {
     				ret += '<tr>';
     				for (var k = 0; k < global_var.columns; k++) {
-    					ret += '<td><span class="span_value_variable matrix_var" data-index="'+k+'" data-row="'+l+'">'+global_var.value[l][k].toFixed(1)+'</span>'+'</td>';
+    					ret += '<td><span class="span_value_variable matrix_var" data-index="'+k+'" data-row="'+l+'">'+parseFloat(global_var.value[l][k]).toFixed(1)+'</span>'+'</td>';
     				} 
     				ret += '</tr>';
 				}
@@ -621,7 +637,7 @@ function enableGlobalMatrixValueUpdate (global_var, row, index, parent_node) {
 
 	if (global_var.type == Types.REAL) {
 		input_field = $( "<input type='text' class='width-dynamic input_name_function' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' value='"
-			+ global_var.value[row][index].toFixed(1) + "' />" );
+			+ parseFloat(global_var.value[row][index]).toFixed(1) + "' />" );
 		input_field.insertBefore(parent_node.find('.span_value_variable'));
 	} else {
 		input_field = $( "<input type='text' class='width-dynamic input_name_function' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' value='"
@@ -649,7 +665,7 @@ function enableGlobalMatrixValueUpdate (global_var, row, index, parent_node) {
 			if (global_var.type == Types.REAL) {
 				global_var.value[row][index] = parseFloat(input_field.val().trim());
 
-				parent_node.find('.span_value_variable').text(global_var.value[row][index].toFixed(1));
+				parent_node.find('.span_value_variable').text(parseFloat(global_var.value[row][index]).toFixed(1));
 			} else {
 				if (global_var.type == Types.INTEGER) {
 					global_var.value[row][index] = parseInt(input_field.val().trim());
@@ -685,7 +701,7 @@ function enableGlobalMatrixValueUpdate (global_var, row, index, parent_node) {
 				if (global_var.type == Types.REAL) {
 					global_var.value[row][index] = parseFloat(input_field.val().trim());
 
-					parent_node.find('.span_value_variable').text(global_var.value[row][index].toFixed(1));
+					parent_node.find('.span_value_variable').text(parseFloat(global_var.value[row][index]).toFixed(1));
 				} else {
 					if (global_var.type == Types.INTEGER) {
 						global_var.value[row][index] = parseInt(input_field.val().trim());
@@ -697,7 +713,7 @@ function enableGlobalMatrixValueUpdate (global_var, row, index, parent_node) {
 				registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 			} else {
 				if (global_var.type == Types.REAL) {
-					parent_node.find('.span_value_variable').text(global_var.value[row][index].toFixed(1));
+					parent_node.find('.span_value_variable').text(parseFloat(global_var.value[row][index]).toFixed(1));
 				} else {
 					parent_node.find('.span_value_variable').text(global_var.value[row][index]);
 				}
@@ -716,7 +732,7 @@ function enableGlobalMatrixValueUpdate (global_var, row, index, parent_node) {
 		}
 		if(code == 27) {
 			if (global_var.type == Types.REAL) {
-				parent_node.find('.span_value_variable').text(global_var.value[row][index].toFixed(1));
+				parent_node.find('.span_value_variable').text(parseFloat(global_var.value[row][index]).toFixed(1));
 			} else {
 				parent_node.find('.span_value_variable').text(global_var.value[row][index]);
 			}
@@ -747,7 +763,7 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 
 	if (global_var.type == Types.REAL) {
 		input_field = $( "<input type='text' class='width-dynamic input_name_function' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' value='"
-			+ global_var.value.toFixed(1) + "' />" );
+			+ parseFloat(global_var.value).toFixed(1) + "' />" );
 		input_field.insertBefore(parent_node.find('.span_value_variable'));
 	} else {
 		input_field = $( "<input type='text' class='width-dynamic input_name_function' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' value='"
@@ -775,7 +791,7 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 		if (input_field.val().trim()) {
 			if (global_var.type == Types.REAL) {
 				global_var.value = parseFloat(input_field.val().trim());
-				parent_node.find('.span_value_variable').text(global_var.value.toFixed(1));
+				parent_node.find('.span_value_variable').text(parseFloat(global_var.value).toFixed(1));
 			} else{
 				if (global_var.type == Types.INTEGER) {
 					global_var.value = parseInt(input_field.val().trim());
@@ -790,7 +806,7 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 			changed = true;
 		} else {
 			if (global_var.type == Types.REAL) {
-				parent_node.find('.span_value_variable').text(global_var.value.toFixed(1));
+				parent_node.find('.span_value_variable').text(parseFloat(global_var.value).toFixed(1));
 			} else {
 				parent_node.find('.span_value_variable').text(global_var.value);
 			}
@@ -819,7 +835,7 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 			if (input_field.val().trim()) {
 				if (global_var.type == Types.REAL) {
 					global_var.value = parseFloat(input_field.val().trim());
-					parent_node.find('.span_value_variable').text(global_var.value.toFixed(1));
+					parent_node.find('.span_value_variable').text(parseFloat(global_var.value).toFixed(1));
 				} else {
 					if (global_var.type == Types.INTEGER) {
 						global_var.value = parseInt(input_field.val().trim());
@@ -833,7 +849,7 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 				changed = true;
 			} else {
 				if (global_var.type == Types.REAL) {
-					parent_node.find('.span_value_variable').text(global_var.value.toFixed(1));
+					parent_node.find('.span_value_variable').text(parseFloat(global_var.value).toFixed(1));
 				} else {
 					parent_node.find('.span_value_variable').text(global_var.value);
 				}
@@ -856,7 +872,7 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 		}
 		if(code == 27) {
 			if (global_var.type == Types.REAL) {
-				parent_node.find('.span_value_variable').text(global_var.value.toFixed(1));
+				parent_node.find('.span_value_variable').text(parseFloat(global_var.value).toFixed(1));
 			} else{
 				parent_node.find('.span_value_variable').text(global_var.value);
 			}
@@ -964,7 +980,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 
 	if (global_var.type == Types.REAL) {
 		input_field = $( "<input type='text' class='width-dynamic input_name_function' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' value='"
-			+ global_var.value[index].toFixed(1) + "' />" );
+			+ parseFloat(global_var.value[index]).toFixed(1) + "' />" );
 		input_field.insertBefore(parent_node.find('.span_value_variable'));
 	} else {
 		input_field = $( "<input type='text' class='width-dynamic input_name_function' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' value='"
@@ -993,7 +1009,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 			if (global_var.type == Types.REAL) {
 				global_var.value[index] = parseFloat(input_field.val().trim());
 
-				parent_node.find('.span_value_variable').text(global_var.value[index].toFixed(1));
+				parent_node.find('.span_value_variable').text(parseFloat(global_var.value[index]).toFixed(1));
 			} else {
 
 				if (global_var.type == Types.INTEGER) {
@@ -1008,7 +1024,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 			changed = true;
 		} else {
 			if (global_var.type == Types.REAL) {
-				parent_node.find('.span_value_variable').text(global_var.value[index].toFixed(1));
+				parent_node.find('.span_value_variable').text(parseFloat(global_var.value[index]).toFixed(1));
 			} else {
 				parent_node.find('.span_value_variable').text(global_var.value[index]);
 			}
@@ -1037,7 +1053,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 				if (global_var.type == Types.REAL) {
 					global_var.value[index] = parseFloat(input_field.val().trim());
 
-					parent_node.find('.span_value_variable').text(global_var.value[index].toFixed(1));
+					parent_node.find('.span_value_variable').text(parseFloat(global_var.value[index]).toFixed(1));
 				} else {
 
 					if (global_var.type == Types.INTEGER) {
@@ -1052,7 +1068,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 				changed = true;
 			} else {
 				if (global_var.type == Types.REAL) {
-					parent_node.find('.span_value_variable').text(global_var.value[index].toFixed(1));
+					parent_node.find('.span_value_variable').text(parseFloat(global_var.value[index]).toFixed(1));
 				} else {
 					parent_node.find('.span_value_variable').text(global_var.value[index]);
 				}
@@ -1074,7 +1090,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 		}
 		if(code == 27) {
 			if (global_var.type == Types.REAL) {
-				parent_node.find('.span_value_variable').text(global_var.value[index].toFixed(1));
+				parent_node.find('.span_value_variable').text(parseFloat(global_var.value[index]).toFixed(1));
 			} else {
 				parent_node.find('.span_value_variable').text(global_var.value[index]);
 			}

+ 21 - 0
js/visualUI/variables.js

@@ -8,6 +8,27 @@ import { isValidIdentifier } from "./../util/utils";
 var counter_new_variables = 0;	
 
 export function addVariable (function_obj, function_container, is_in_click = false) {
+
+	// Verify if the next variable name is in use:
+	if (function_obj.variables_list) {
+		var in_use = false;
+		do {
+			in_use = false;
+			
+			var temp_name = LocalizedStrings.getUI('new_variable') + '_' + counter_new_variables;
+
+			function_obj.variables_list.forEach(function(el) {
+				if (temp_name == el.name) {
+					in_use = true;
+				}
+			})
+
+			if (in_use)
+				counter_new_variables++;
+
+		} while (in_use);
+	}
+
 	var new_var = new Models.Variable(Types.INTEGER, LocalizedStrings.getUI('new_variable') + '_' + counter_new_variables, 0);
 	if (function_obj.variables_list == null) {
 		function_obj.variables_list = [];

File diff suppressed because it is too large
+ 9069 - 5624
package-lock.json


+ 11 - 11
package.json

@@ -29,27 +29,27 @@
     "@babel/core": "^7.10.2",
     "@babel/plugin-transform-runtime": "^7.10.1",
     "@babel/preset-env": "^7.10.2",
-    "@typescript-eslint/eslint-plugin": "^2.34.0",
-    "@typescript-eslint/parser": "^2.34.0",
-    "antlr4-webpack-loader": "*",
+    "@types/moo": "^0.5.5",
+    "@typescript-eslint/eslint-plugin": "^5.7.0",
+    "@typescript-eslint/parser": "^5.0.0",
     "babel-loader": "^8.0.6",
     "clean-webpack-plugin": "3.x",
-    "copy-webpack-plugin": "^5.1.1",
+    "copy-webpack-plugin": "10.x",
     "csv-parser": "^2.3.3",
-    "eslint": "^6.5.1",
-    "html-webpack-plugin": "^4.3.0",
-    "server": "^1.0.29",
+    "eslint": "^8.5.0",
+    "html-webpack-plugin": "^5.5.0",
+    "http-server": "^14.0.0",
     "ts-loader": "^5.4.5",
     "typescript": "^3.9.5",
-    "webpack": "^4.43.0",
-    "webpack-cli": "3.x"
+    "webpack": "^5",
+    "webpack-cli": "4.x"
   },
   "dependencies": {
     "@babel/runtime": "^7.10.2",
-    "antlr4": "^4.7.2",
     "codemirror": "^5.64.0",
     "decimal.js": "^10.2.0",
     "line-i18n": "git+http://200.144.254.107/git/LInE/line-i18n.git",
-    "melanke-watchjs": "^1.5.0"
+    "melanke-watchjs": "^1.5.0",
+    "moo": "^0.5.1"
   }
 }

+ 6 - 0
templates/index.html

@@ -161,6 +161,12 @@
       if (iLMparameters.iLM_PARAM_TeacherAutoEval == null) {
         ivprogCore.initVisualUI();
       }
+
+      setTimeout(function() {
+        $('.ivprog_visual_panel').removeClass("loading");
+        renderAlgorithm();
+      },
+      8000)
     });
   </script>
 </html>

+ 10 - 10
templates/runner.html

@@ -16,21 +16,21 @@
 <body>
     <div style="padding-top: 50px;content: ''"></div>
   <div class="ui container grid">
-    
+
     <div class="four wide column">
       <div class="row">
         <textarea class="ui form control" name="input" id="input" cols="100" rows="30">
             programa {
 
-              const real C = 5.5
-             
+              const real C  5.5
+
               funcao inicio() {
 
-               inteiro a = 8
+               inteiro a  8
                se (a * C > 80) {
-                a = 0
+                a  0
                } senao {
-                 a = -1
+                 a  -1
                }
               }
              }
@@ -50,12 +50,12 @@
         </div>
     </div>
   </div>
-  
-  
+
+
 </body>
 <script>
-  ( function () {
+  window.addEventListener('DOMContentLoaded', () => {
     ivprogCore.runner();
-  })();
+  });
 </script>
 </html>

+ 2 - 2
updateVersionPlugin.js

@@ -12,9 +12,9 @@ function writeVersionFile () {
 function UpdateVersionPlugin () { }
 
 UpdateVersionPlugin.prototype.apply  = function (compiler) {
-  compiler.hooks.beforeCompile.tap("UpdateVersionPlugin", function() {
+  compiler.hooks.beforeCompile.tap("UpdateVersionPlugin", function () {
     writeVersionFile();
   });
 }
 
-module.exports = UpdateVersionPlugin;
+module.exports = UpdateVersionPlugin;

+ 78 - 65
webpack.config.js

@@ -13,9 +13,6 @@ module.exports = {
     library: "ivprogCore",
     libraryTarget: "umd",
   },
-  node: {
-    fs: "empty",
-  },
   module: {
     rules: [
       {
@@ -28,13 +25,6 @@ module.exports = {
           },
         },
       },
-      {
-        test: /\.g4$/,
-        exclude: /(node_modules)/,
-        use: {
-          loader: "antlr4-webpack-loader",
-        },
-      },
       {
         test: /\.tsx?$/,
         use: "ts-loader",
@@ -53,6 +43,9 @@ module.exports = {
   },
   resolve: {
     extensions: [".tsx", ".ts", ".js", ".csv"],
+    fallback: {
+      fs: false,
+    },
   },
   stats: {
     colors: true,
@@ -64,71 +57,91 @@ module.exports = {
     }),
     new UpdateVersionPlugin(),
     new HtmlWebpackPlugin({
-      template: "templates/index.html",
+      template: "./templates/index.html",
       filename: path.resolve(__dirname, "build", "index.html"),
     }),
     new HtmlWebpackPlugin({
-      template: "templates/runner.html",
+      template: "./templates/runner.html",
       filename: path.resolve(__dirname, "build", "runner.html"),
     }),
     new HtmlWebpackPlugin({
-      template: "templates/process.html",
+      template: "./templates/process.html",
       filename: path.resolve(__dirname, "build", "process.html"),
     }),
     /*new ChangeScriptSourcePlugin(),*/
-    new CopyPlugin([
-      {
-        from: "js/iassign-integration-functions.js",
-        to: path.resolve(__dirname, "build/js"),
-      },
-      {
-        from: "css/ivprog-visual-1.0.css",
-        to: path.resolve(__dirname, "build/css"),
-      },
-      { from: "css/ivprog-term.css", to: path.resolve(__dirname, "build/css") },
-      {
-        from: "css/ivprog-assessment.css",
-        to: path.resolve(__dirname, "build/css"),
-      },
-      {
-        from: "css/ivprog-editor.css",
-        to: path.resolve(__dirname, "build/css"),
-      },
-      { from: "css/roboto.css", to: path.resolve(__dirname, "build/css") },
-      { from: "css/fonts/", to: path.resolve(__dirname, "build/css/fonts") },
-      { from: "js/Sortable.js", to: path.resolve(__dirname, "build/js") },
-      { from: "js/jquery.min.js", to: path.resolve(__dirname, "build/js") },
-      { from: "js/jquery-ui.min.js", to: path.resolve(__dirname, "build/js") },
-      { from: "js/semantic.min.js", to: path.resolve(__dirname, "build/js") },
-      { from: "js/filesaver.min.js", to: path.resolve(__dirname, "build/js") },
-      {
-        from: "css/semantic.min.css",
-        to: path.resolve(__dirname, "build/css"),
-      },
-      { from: "css/themes/", to: path.resolve(__dirname, "build/css/themes") },
-      { from: "img/trash-icon.png", to: path.resolve(__dirname, "build/img") },
-      { from: "img/empty.svg", to: path.resolve(__dirname, "build/img") },
-      { from: "img/new_line.svg", to: path.resolve(__dirname, "build/img") },
-      { from: "img/no_new_line.svg", to: path.resolve(__dirname, "build/img") },
-      {
-        from: "js/jquery.json-editor.min.js",
-        to: path.resolve(__dirname, "build/js"),
-      },
-      {
-        from: "node_modules/codemirror/lib/codemirror.css",
-        to: path.resolve(__dirname, "build/css"),
-      },
-      {
-        from: "node_modules/codemirror/addon/hint/show-hint.css",
-        to: path.resolve(__dirname, "build/css"),
-      },
-      {
-        from: "node_modules/codemirror/theme/ttcn.css",
-        to: path.resolve(__dirname, "build/css"),
-      },
-      /*{from:'index.html', to:path.resolve(__dirname, 'build')},
+    new CopyPlugin({
+      patterns: [
+        {
+          from: "js/iassign-integration-functions.js",
+          to: path.resolve(__dirname, "build/js"),
+        },
+        {
+          from: "css/ivprog-visual-1.0.css",
+          to: path.resolve(__dirname, "build/css"),
+        },
+        {
+          from: "css/ivprog-term.css",
+          to: path.resolve(__dirname, "build/css"),
+        },
+        {
+          from: "css/ivprog-assessment.css",
+          to: path.resolve(__dirname, "build/css"),
+        },
+        {
+          from: "css/ivprog-editor.css",
+          to: path.resolve(__dirname, "build/css"),
+        },
+        { from: "css/roboto.css", to: path.resolve(__dirname, "build/css") },
+        { from: "css/fonts/", to: path.resolve(__dirname, "build/css/fonts") },
+        { from: "js/Sortable.js", to: path.resolve(__dirname, "build/js") },
+        { from: "js/jquery.min.js", to: path.resolve(__dirname, "build/js") },
+        {
+          from: "js/jquery-ui.min.js",
+          to: path.resolve(__dirname, "build/js"),
+        },
+        { from: "js/semantic.min.js", to: path.resolve(__dirname, "build/js") },
+        {
+          from: "js/filesaver.min.js",
+          to: path.resolve(__dirname, "build/js"),
+        },
+        {
+          from: "css/semantic.min.css",
+          to: path.resolve(__dirname, "build/css"),
+        },
+        {
+          from: "css/themes/",
+          to: path.resolve(__dirname, "build/css/themes"),
+        },
+        {
+          from: "img/trash-icon.png",
+          to: path.resolve(__dirname, "build/img"),
+        },
+        { from: "img/empty.svg", to: path.resolve(__dirname, "build/img") },
+        { from: "img/new_line.svg", to: path.resolve(__dirname, "build/img") },
+        {
+          from: "img/no_new_line.svg",
+          to: path.resolve(__dirname, "build/img"),
+        },
+        {
+          from: "js/jquery.json-editor.min.js",
+          to: path.resolve(__dirname, "build/js"),
+        },
+        {
+          from: "node_modules/codemirror/lib/codemirror.css",
+          to: path.resolve(__dirname, "build/css"),
+        },
+        {
+          from: "node_modules/codemirror/addon/hint/show-hint.css",
+          to: path.resolve(__dirname, "build/css"),
+        },
+        {
+          from: "node_modules/codemirror/theme/ttcn.css",
+          to: path.resolve(__dirname, "build/css"),
+        },
+        /*{from:'index.html', to:path.resolve(__dirname, 'build')},
         {from:'runner.html', to:path.resolve(__dirname, 'build')},*/
-    ]),
+      ],
+    }),
   ],
   optimization: {
     splitChunks: {