Browse Source

Merge branch 'master' into newWriteFunction

Lucas de Souza 3 years ago
parent
commit
525825fb2a

+ 2 - 2
.eslintignore

@@ -1,3 +1,3 @@
-/js/visualUI/
+# /js/visualUI/
 /js/Sortable.js
-/js/iassign-integration-functions.js
+/js/iassign-integration-functions.js

+ 2 - 1
.vscode/settings.json

@@ -4,5 +4,6 @@
     "**/.git/objects/**": true,
     "**/.git/subtree-cache/**": true,
     "**/node_modules/**": true
-  }
+  },
+  "javascript.format.insertSpaceBeforeFunctionParenthesis": true
 }

+ 2 - 1
grammar/pt/langFunctions.js

@@ -11,7 +11,7 @@ export default {
   $length: "comprimento",
   $uppercase: "caixa_alta",
   $lowercase: "caixa_baixa",
-  $charAt: "texto_na_posicao",
+  $charAt: "caractere_na_posicao",
   $isReal: "e_real",
   $isInt: "e_inteiro",
   $isBool: "e_logico",
@@ -19,6 +19,7 @@ export default {
   $castInt: "como_inteiro",
   $castBool: "como_logico",
   $castString: "como_cadeia",
+  $castChar: "como_caractere",
   $sin: "seno",
   $cos: "cosseno",
   $tan: "tangente",

+ 1 - 1
i18n/csv.d.ts

@@ -1,5 +1,5 @@
 declare module "*.csv" {
-  const content: {[id:string]:any};
+  const content: {[id: string]: unknown};
   export default content;
 }
 

+ 2 - 3
i18n/index.ts

@@ -1,16 +1,15 @@
-/// <reference path="csv.d.ts" />
 import * as Messages from './message.csv';
 import * as UI from './ui.csv';
 import * as Errors from './error.csv';
 
-type Dict =  {[id:string]:any};
+type Dict =  {[id: string]: unknown};
 
 const MessagesObj = Messages as Dict;
 const UIObj = UI as Dict;
 const ErrorsObj = Errors as Dict;
 const i18n_data = {} as Dict;
 
-for(const key in UIObj) {
+for (const key in UIObj) {
   const data = {} as Dict;
   data['error'] = ErrorsObj[key];
   data['message'] = MessagesObj[key];

+ 3 - 1
i18n/ui.csv

@@ -137,7 +137,9 @@ text_for_from,de,from,
 text_for_to,até,to,
 text_for_pass,passo,pass,
 text_relational_expression,Relacionais,Relational,
-initial_program_code,"programa {\n\n\t\tfuncao vazio inicio () {\n\t\t\t// Inicie seu codigo aqui!\n\t\t}\n}","program {\n\n\t\tfunction void main () {\n\t\t\t// Start your code here!\n\t\t}\n}",
 write_command_newline_on,Quebra de linha ativada, Line break is on,
 write_command_newline_off, Quebra de linha desativada, Line break is off,
 write_seprator_menu_text,Vírgula,Comma,
+initial_program_code,programa {\n\n\t\tfuncao vazio inicio () {\n\t\t\t// Inicie seu codigo aqui!\n\t\t}\n},program {\n\n\t\tfunction void main () {\n\t\t\t// Start your code here!\n\t\t}\n},
+type_char,caractere,char,""
+charvar_default_value,A,A,A

+ 19 - 0
js/ast/expressions/charLiteral.js

@@ -0,0 +1,19 @@
+import { Literal } from './literal';
+import { Types } from './../../typeSystem/types';
+
+export class CharLiteral extends Literal {
+  
+  constructor(value) {
+    super(Types.CHAR);
+    this.value = value;
+  }
+
+  toString () {
+    const text = `'${this.value}'`;
+    if(this.parenthesis) {
+      return `(${text})`
+    } else {
+      return text;
+    }
+  }
+}

+ 2 - 0
js/ast/expressions/index.js

@@ -3,6 +3,7 @@ import { FunctionCall } from './functionCall';
 import { IntLiteral } from './intLiteral';
 import { RealLiteral } from './realLiteral';
 import { BoolLiteral } from './boolLiteral';
+import { CharLiteral } from './charLiteral'
 import { StringLiteral } from './stringLiteral';
 import { ArrayLiteral } from './arrayLiteral';
 import { VariableLiteral } from './variableLiteral';
@@ -15,6 +16,7 @@ export {
   IntLiteral,
   RealLiteral,
   BoolLiteral,
+  CharLiteral,
   StringLiteral,
   ArrayLiteral,
   VariableLiteral,

+ 23 - 9
js/ast/ivprogParser.js

@@ -2,7 +2,7 @@ import { CommonTokenStream, InputStream } from 'antlr4/index';
 import * as Expressions from './expressions';
 import * as Commands from './commands';
 import * as AstHelpers from "./ast_helpers";
-import { toInt, toString, toBool, toReal } from '../typeSystem/parsers';
+import * as Parsers from '../typeSystem/parsers';
 import { Types } from "../typeSystem/types";
 import { ArrayType } from "../typeSystem/array_type";
 import { SourceInfo } from './sourceInfo';
@@ -44,7 +44,8 @@ export class IVProgParser {
     this.variableTypes = [this.lexerClass.RK_INTEGER,
       this.lexerClass.RK_REAL,
       this.lexerClass.RK_BOOLEAN,
-      this.lexerClass.RK_STRING
+      this.lexerClass.RK_STRING,
+      this.lexerClass.RK_CHARACTER
     ];
     this.functionTypes = this.variableTypes.concat(this.lexerClass.RK_VOID);
     this.parsingArrayDimension = 0;
@@ -132,7 +133,8 @@ export class IVProgParser {
       this.popVariableStack();
       return {global: globalVars, functions: functions};
     } else {
-      throw SyntaxErrorFactory.token_missing_one(this.lexer.literalNames[this.lexerClass.RK_PROGRAM], token);
+      throw SyntaxErrorFactory.token_missing_one(this.lexer.literalNames[this.lexerClass.RK_PROGRAM],
+        token);
     }
   }
 
@@ -381,13 +383,13 @@ export class IVProgParser {
     }
 
     if(dim1 == null) {
-      n_lines = new Expressions.IntLiteral(toInt(initial.lines));
+      n_lines = new Expressions.IntLiteral(Parsers.toInt(initial.lines));
       n_lines.sourceInfo = sourceInfo;
     }
 
     if (dimensions > 1) {
       if(dim2 == null) {
-        n_columns = new Expressions.IntLiteral(toInt(initial.columns));
+        n_columns = new Expressions.IntLiteral(Parsers.toInt(initial.columns));
         n_columns.sourceInfo = sourceInfo;
       } 
     }
@@ -446,14 +448,14 @@ export class IVProgParser {
   getIntLiteral (token) {
     const text = token.text;
     const sourceInfo = SourceInfo.createSourceInfo(token);
-    const exp = new Expressions.IntLiteral(toInt(text));
+    const exp = new Expressions.IntLiteral(Parsers.toInt(text));
     exp.sourceInfo = sourceInfo;
     return exp;
   }
 
   getRealLiteral (token) {
     const sourceInfo = SourceInfo.createSourceInfo(token);
-    const exp = new Expressions.RealLiteral(toReal(token.text));
+    const exp = new Expressions.RealLiteral(Parsers.toReal(token.text));
     exp.sourceInfo = sourceInfo;
     return exp;
   }
@@ -461,13 +463,20 @@ export class IVProgParser {
   getStringLiteral (token) {
     const text = token.text;
     const sourceInfo = SourceInfo.createSourceInfo(token);
-    const exp = new Expressions.StringLiteral(toString(text));
+    const exp = new Expressions.StringLiteral(Parsers.toString(text));
     exp.sourceInfo = sourceInfo;
     return exp;
   }
 
+  getCharLiteral (token) {
+    const text = token.text;
+    const exp = new Expressions.CharLiteral(Parsers.toChar(text));
+    exp.sourceInfo = SourceInfo.createSourceInfo(token);
+    return exp;
+  }
+
   getBoolLiteral (token) {
-    const val = toBool(token.text);
+    const val = Parsers.toBool(token.text);
     const exp = new Expressions.BoolLiteral(val);
     exp.sourceInfo = SourceInfo.createSourceInfo(token);
     return exp;
@@ -717,6 +726,8 @@ export class IVProgParser {
           return Types.REAL;
         case this.lexerClass.RK_STRING:
           return Types.STRING;
+        case this.lexerClass.RK_CHARACTER:
+          return Types.CHAR;
         default:
           break;
       }
@@ -1214,6 +1225,9 @@ export class IVProgParser {
       case this.lexerClass.STRING:
         this.pos++;
         return this.getStringLiteral(token);
+      case this.lexerClass.CHARACTER:
+        this.pos++;
+        return this.getCharLiteral(token);
       case this.lexerClass.RK_TRUE:
       case this.lexerClass.RK_FALSE:
         this.pos++;

+ 4 - 1
js/ast/operators.js

@@ -1,3 +1,5 @@
+export type Operator = {ord: number; value: string}
+
 export const Operators = Object.freeze({
   ADD: {ord: 0, value: "+"},
   SUB: {ord: 1, value: "-"},
@@ -15,7 +17,7 @@ export const Operators = Object.freeze({
   NOT: {ord: 13, value: 'not'}
 });
 
-export function convertFromString (op) {
+export function convertFromString (op: string): Operator | null  {
   switch (op) {
     case '+' : return Operators.ADD;
     case '-' : return Operators.SUB;
@@ -32,4 +34,5 @@ export function convertFromString (op) {
     case 'or' : return Operators.OR;
     case 'not' : return Operators.NOT;
   }
+  return null;
 }

+ 27 - 24
js/iassign-integration-functions.js

@@ -740,35 +740,38 @@ function full_screen() {
   }
 }
 
+function getAutoEvalOriginalData () {
+  return parent.getAutoEvalOriginalData();
+}
+
 function teacherAutoEval (data) {
   previousContent = data;
-  $.get(iLMparameters.iLM_PARAM_TeacherAutoEval, function (originalData) {
-    // Ver arquivo js/util/iassignHelpers.js
-    var content = ivprogCore.prepareActivityToStudentHelper(data).getOrElse(null);
-    if(!content) {
-      showInvalidData();
-      return;
-    }
-    // Casos de testes agora são delegados ao tratamento apropriado pela função acima
-    // var testCases = content.testcases;
-    settingsProgrammingTypes = content.settingsProgrammingType;
-    settingsDataTypes = content.settingsDataTypes;
-    settingsCommands = content.settingsCommands;
-    settingsFunctions = content.settingsFunctions;
-    settingsFilter = content.settingsFilter;
+  // Ver arquivo js/util/iassignHelpers.js
+  var content = ivprogCore.prepareActivityToStudentHelper(data).getOrElse(null);
+  if(!content) {
+    showInvalidData();
+    return;
+  }
+  // Casos de testes agora são delegados ao tratamento apropriado pela função acima
+  // var testCases = content.testcases;
+  settingsProgrammingTypes = content.settingsProgrammingType;
+  settingsDataTypes = content.settingsDataTypes;
+  settingsCommands = content.settingsCommands;
+  settingsFunctions = content.settingsFunctions;
+  settingsFilter = content.settingsFilter;
 
-    if (content.algorithmInIlm != null) {
-      algorithm_in_ilm = content.algorithmInIlm;
-      parsePreviousAlgorithm();
-      ivprogCore.autoEval(originalData, displayGrade);
-    }
+  if (content.algorithmInIlm != null) {
+    algorithm_in_ilm = content.algorithmInIlm;
+    parsePreviousAlgorithm();
+    var originalData = getAutoEvalOriginalData();
+    ivprogCore.autoEval(originalData, parent.postResultAutoEval);
+  }
 
-    ivprogTextualOrVisual();
-    if (settingsFilter && settingsFilter[0]) {
+  ivprogTextualOrVisual();
+  if (settingsFilter && settingsFilter[0]) {
 
-      blockAllEditingOptions();
-    }
-  });
+    blockAllEditingOptions(); 
+  }
 }
 
 function displayGrade(grade) {

+ 3 - 1
js/main.js

@@ -7,6 +7,7 @@ import { i18nHelper } from "./services/i18nHelper";
 import { ActionTypes, getLogs, getLogsAsString, registerClick, registerUserEvent, parseLogs } from "./services/userLog";
 import { prepareActivityToStudentHelper, autoEval } from "./util/iassignHelpers";
 import { openAssessmentDetail } from "./util/utils";
+import { Config } from './util/config';
 import * as CodeEditorAll from "./visualUI/text_editor";
 import {autoGenerateTestCaseOutput} from './util/auto_gen_output';
 
@@ -41,5 +42,6 @@ export {
   ActionTypes,
   CodeEditor,
   openAssessmentDetail,
-  autoGenerateTestCaseOutput
+  autoGenerateTestCaseOutput,
+  Config
 }

+ 76 - 49
js/processor/compatibilityTable.js

@@ -1,10 +1,12 @@
-import { Types } from './../typeSystem/types';
-import { Operators } from './../ast/operators';
+import { Types } from '../typeSystem/types';
+import { IType } from '../typeSystem/itype';
+import { Type } from '../typeSystem/type';
+import { Operators, Operator } from '../ast/operators';
 import { MultiType } from '../typeSystem/multiType';
 import { Config } from '../util/config';
 
-function buildInfixAddTable () {
-  const table = [[], [], [], []];
+function buildInfixAddTable (): IType[][] {
+  const table: IType[][] = [[], [], [], [], []]
 
   table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
   table[Types.INTEGER.ord][Types.REAL.ord] = Types.REAL;
@@ -18,12 +20,16 @@ function buildInfixAddTable () {
   table[Types.STRING.ord][Types.REAL.ord] = Types.STRING;
   table[Types.STRING.ord][Types.STRING.ord] = Types.STRING;
   table[Types.STRING.ord][Types.BOOLEAN.ord] = Types.STRING;
+  table[Types.STRING.ord][Types.CHAR.ord] = Types.STRING;
+
+  table[Types.CHAR.ord][Types.CHAR.ord] = Types.STRING;
+  table[Types.CHAR.ord][Types.STRING.ord] = Types.STRING;
 
   return table;
 }
 
-function buildInfixMultiDivSubTable () {
-  const table = [[], [], [], []];
+function buildInfixMultiDivSubTable (): IType[][] {
+  const table: IType[][] = [[], []];
 
   table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
   table[Types.INTEGER.ord][Types.REAL.ord] = Types.REAL;
@@ -34,8 +40,8 @@ function buildInfixMultiDivSubTable () {
   return table;
 }
 
-function buildInfixEqualityInequalityTable () {
-  const table = [[], [], [], []];
+function buildInfixEqualityInequalityTable (): IType[][] {
+  const table: IType[][] = [[], [], [], [], []];
 
   table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.BOOLEAN;
 
@@ -45,11 +51,13 @@ function buildInfixEqualityInequalityTable () {
 
   table[Types.STRING.ord][Types.STRING.ord] = Types.BOOLEAN;
 
+  table[Types.CHAR.ord][Types.CHAR.ord] = Types.BOOLEAN;
+
   return table;
 }
 
-function buildInfixRelationalTable () {
-  const table = [[], [], [], []];
+function buildInfixRelationalTable (): IType[][] {
+  const table: IType[][] = [[], [], [], [], []];
 
   table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.BOOLEAN;
 
@@ -57,27 +65,29 @@ function buildInfixRelationalTable () {
 
   table[Types.STRING.ord][Types.STRING.ord] = Types.BOOLEAN;
 
+  table[Types.CHAR.ord][Types.CHAR.ord] = Types.BOOLEAN;
+
   return table;
 }
 
-function buildInfixAndOrTable () {
-  const table = [[], [], [], []];
+function buildInfixAndOrTable (): IType[][] {
+  const table: IType[][] = [[], [], [], []];
 
   table[Types.BOOLEAN.ord][Types.BOOLEAN.ord] = Types.BOOLEAN;
 
   return table;
 }
 
-function buildInfixModTable () {
-  const table = [[], [], [], []];
+function buildInfixModTable (): IType[][] {
+  const table: IType[][] = [[]];
 
   table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
 
   return table;
 }
 
-function buildUnarySumSubList () {
-  const list = [];
+function buildUnarySumSubList (): IType[] {
+  const list: IType[] = [];
 
   list[Types.INTEGER.ord] = Types.INTEGER;
 
@@ -86,15 +96,15 @@ function buildUnarySumSubList () {
   return list;
 }
 
-function buildUnaryNegList () {
-  const list = [];
+function buildUnaryNegList (): IType[] {
+  const list: IType[] = [];
 
   list[Types.BOOLEAN.ord] = Types.BOOLEAN;
 
   return list;
 }
 
-function buildInfixCompatibilityTable () {
+function buildInfixCompatibilityTable (): WeakMap<Operator, IType[][]> {
   const compatibilityMap = new WeakMap();
   compatibilityMap.set(Operators.ADD, buildInfixAddTable());
   compatibilityMap.set(Operators.SUB, buildInfixMultiDivSubTable());
@@ -112,7 +122,7 @@ function buildInfixCompatibilityTable () {
   return compatibilityMap;
 }
 
-function buildUnaryCompatibilityTable () {
+function buildUnaryCompatibilityTable (): WeakMap<Operator, IType[]> {
   const compatibilityMap = new WeakMap();
   compatibilityMap.set(Operators.ADD, buildUnarySumSubList());
   compatibilityMap.set(Operators.SUB, buildUnarySumSubList());
@@ -123,50 +133,54 @@ function buildUnaryCompatibilityTable () {
 const infixMap = buildInfixCompatibilityTable();
 const unaryMap = buildUnaryCompatibilityTable();
 
-export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpressionType) {
+export function resultTypeAfterInfixOp (
+  operator: Operator,
+  leftExpressionType: IType,
+  rightExpressionType: IType
+): IType {
   try {
-    if(leftExpressionType instanceof MultiType && rightExpressionType instanceof MultiType) {
+    if (leftExpressionType instanceof MultiType && rightExpressionType instanceof MultiType) {
       let newMulti = [];
       for (let i = 0; i < leftExpressionType.types.length; ++i) {
         const typeA = leftExpressionType.types[i];
-        for(let j = 0; j < rightExpressionType.types.length; ++i) {
+        for (let j = 0; j < rightExpressionType.types.length; ++i) {
           const typeB = rightExpressionType.types[j];
           newMulti.push(resultTypeAfterInfixOp(operator, typeA, typeB));
         }
       }
       newMulti = newMulti.filter(x => !x.isCompatible(Types.UNDEFINED));
-      if(newMulti.length <= 0) {
-        if(Config.enable_type_casting) {
-          if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
-            if(rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
+      if (newMulti.length <= 0) {
+        if (Config.enable_type_casting) {
+          if (leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
+            if (rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
               return new MultiType([Types.INTEGER, Types.REAL]);
             }
           }
         }
         return Types.UNDEFINED;
       } else {
-        return new MultiType(newMulti)
+        return new MultiType(newMulti as Type[])
       }
-    } else if(leftExpressionType instanceof MultiType) {
-      if(leftExpressionType.isCompatible(rightExpressionType)) {
+    } else if (leftExpressionType instanceof MultiType) {
+      if (leftExpressionType.isCompatible(rightExpressionType as Type)) {
         return resultTypeAfterInfixOp(operator, rightExpressionType, rightExpressionType);
       } else {
-        if(Config.enable_type_casting) {
-          if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
-            if(rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
+        if (Config.enable_type_casting) {
+          if (leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
+            if (rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
               return rightExpressionType;
             }
           }
         }
         return Types.UNDEFINED;
       }
-    } else if(rightExpressionType instanceof MultiType) {
-      if(rightExpressionType.isCompatible(leftExpressionType)) {
+    } else if (rightExpressionType instanceof MultiType) {
+      if (rightExpressionType.isCompatible(leftExpressionType as Type)) {
         return resultTypeAfterInfixOp(operator, leftExpressionType, leftExpressionType);
       } else {
-        if(Config.enable_type_casting) {
-          if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
-            if(rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
+        if (Config.enable_type_casting) {
+          if (leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
+            if (rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
               return leftExpressionType;
             }
           }
@@ -174,14 +188,16 @@ export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpre
         return Types.UNDEFINED;
       }
     }
-    const resultType = infixMap.get(operator)[leftExpressionType.ord][rightExpressionType.ord];
+    const resultTable = infixMap.get(operator) || [];
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    const resultType = resultTable[leftExpressionType.ord!][rightExpressionType.ord!];
     if (resultType === null || resultType === undefined) {
-      if(Config.enable_type_casting) {
-        if(leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
-          if(rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
-            if(operator === Operators.MOD) {
+      if (Config.enable_type_casting) {
+        if (leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
+          if (rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
+            if (operator === Operators.MOD) {
               return Types.INTEGER;
-            } else if (operator.ord >= 5 && operator.ord <= 10){
+            } else if (operator.ord >= 5 && operator.ord <= 10) {
               return Types.BOOLEAN;
             }
           }
@@ -199,12 +215,23 @@ export function resultTypeAfterInfixOp (operator, leftExpressionType, rightExpre
   }
 }
 
-export function resultTypeAfterUnaryOp (operator, leftExpressionType) {
+export function resultTypeAfterUnaryOp (operator: Operator, leftExpressionType: IType): IType {
   try {
-    if(leftExpressionType instanceof MultiType){
-      return leftExpressionType;
+    if (leftExpressionType instanceof MultiType) {
+      let newMulti = [];
+      for (let i = 0; i < leftExpressionType.types.length; ++i) {
+        const type = leftExpressionType.types[i];
+        newMulti.push(resultTypeAfterUnaryOp(operator, type));
+      }
+      newMulti = newMulti.filter(x => !x.isCompatible(Types.UNDEFINED));
+      if (newMulti.length <= 0) {
+        return Types.UNDEFINED;
+      }
+      return new MultiType(newMulti as Type[]);
     }
-    const resultType = unaryMap.get(operator)[leftExpressionType.ord];
+    const resultTable = unaryMap.get(operator) || [];
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    const resultType = resultTable[leftExpressionType.ord!];
     if (resultType == null) {
       return Types.UNDEFINED;
     }
@@ -214,6 +241,6 @@ export function resultTypeAfterUnaryOp (operator, leftExpressionType) {
       return Types.UNDEFINED;
     } else {
       throw e;
-    } 
+    }
   }
 }

+ 4 - 3
js/processor/definedFunctions.js

@@ -8,7 +8,7 @@ import {createMatrixColumnsFun, createMatrixLinesFun,
 import {createCastBoolFun, createCastIntFun,
   createCastRealFun, createCastStringFun,
   createIsBoolFun, createIsIntFun,
-  createIsRealFun} from './lib/lang';
+  createIsRealFun, createCastCharFun} from './lib/lang';
 import {createAbsFun, createCosFun,
   createInvertFun, createLogFun,
   createMaxFun, createMinFun,
@@ -28,7 +28,7 @@ function valueToKey (value, object) {
 }
 
 function concatObjects (...objs) {
-  let result = {};
+  const result = {};
   for (let i = 0; i < objs.length; i++) {
     const obj = objs[i];
     for(const key in obj) {
@@ -78,7 +78,8 @@ const libsObject = {
     $castReal: createCastRealFun(),
     $castInt: createCastIntFun(),
     $castBool: createCastBoolFun(),
-    $castString: createCastStringFun()
+    $castString: createCastStringFun(),
+    $castChar: createCastCharFun()
   }
 }
 

+ 123 - 76
js/processor/ivprogProcessor.js

@@ -29,11 +29,11 @@ import { StoreValueAddress } from "./store/value/store_value_address";
 import { LocalizedStrings } from "../services/localizedStringsService";
 
 export class IVProgProcessor {
-  static get MAIN_INTERNAL_ID() {
+  static get MAIN_INTERNAL_ID () {
     return "$main";
   }
 
-  constructor(ast) {
+  constructor (ast) {
     this.ast = ast;
     this.globalStore = new Store("$global");
     this.stores = [this.globalStore];
@@ -50,21 +50,21 @@ export class IVProgProcessor {
     this.function_call_count = 0;
   }
 
-  registerInput(input) {
+  registerInput (input) {
     if (this.input !== null) this.input = null;
     this.input = input;
   }
 
-  registerOutput(output) {
+  registerOutput (output) {
     if (this.output !== null) this.output = null;
     this.output = output;
   }
 
-  checkContext(context) {
+  checkContext (context) {
     return this.context[this.context.length - 1] === context;
   }
 
-  ignoreSwitchCases(store) {
+  ignoreSwitchCases (store) {
     if (store.mode === Modes.RETURN) {
       return true;
     } else if (store.mode === Modes.BREAK) {
@@ -74,7 +74,7 @@ export class IVProgProcessor {
     }
   }
 
-  prepareState() {
+  prepareState () {
     if (this.stores !== null) {
       for (let i = 0; i < this.stores.length; i++) {
         delete this.stores[i];
@@ -89,7 +89,7 @@ export class IVProgProcessor {
     this.mode = Modes.RUN;
   }
 
-  async interpretAST() {
+  async interpretAST () {
     this.prepareState();
     Location.clear();
     await this.initGlobal();
@@ -100,18 +100,18 @@ export class IVProgProcessor {
     return this.runFunction(mainFunc, [], this.globalStore);
   }
 
-  async initGlobal() {
+  async initGlobal () {
     if (!this.checkContext(Context.BASE)) {
       return ProcessorErrorFactory.invalid_global_var();
     }
     return this.executeCommands(this.globalStore, this.ast.global);
   }
 
-  findMainFunction() {
+  findMainFunction () {
     return this.ast.functions.find((v) => v.isMain);
   }
 
-  findFunction(name) {
+  findFunction (name) {
     if (name.match(/^\$.+$/)) {
       if (name === IVProgProcessor.MAIN_INTERNAL_ID) {
         return this.findMainFunction();
@@ -130,7 +130,7 @@ export class IVProgProcessor {
     }
   }
 
-  async runFunction(func, actualParameters, store) {
+  async runFunction (func, actualParameters, store) {
     const funcName = func.isMain ? IVProgProcessor.MAIN_INTERNAL_ID : func.name;
     const funcStore = new Store(funcName);
     funcStore.extendStore(this.globalStore);
@@ -153,13 +153,13 @@ export class IVProgProcessor {
   }
 
   /**
-   * 
-   * @param {import('./../ast/commands/formalParameter').FormalParameter[]} formal_params 
-   * @param {Expression[]} effective_params 
-   * @param {Store} caller_store 
-   * @param {Store} callee_store 
+   *
+   * @param {import('./../ast/commands/formalParameter').FormalParameter[]} formal_params
+   * @param {Expression[]} effective_params
+   * @param {Store} caller_store
+   * @param {Store} callee_store
    */
-  async associateParameters(
+  async associateParameters (
     formal_params,
     effective_params,
     caller_store,
@@ -170,47 +170,76 @@ export class IVProgProcessor {
         ? LanguageDefinedFunction.getMainFunctionName()
         : callee_store.name;
 
-    const hasVariadic = formal_params.some(p => p.variadic);
+    const hasVariadic = formal_params.some((p) => p.variadic);
 
-    if ((formal_params.length != effective_params.length && !hasVariadic)
-      || formal_params.length > effective_params.length) {
+    if (
+      (formal_params.length != effective_params.length && !hasVariadic) ||
+      formal_params.length > effective_params.length
+    ) {
       throw ProcessorErrorFactory.invalid_parameters_size(
         funcName,
         formal_params.length,
         effective_params.length
       );
     }
-    for (let i = 0, j = 0; i < formal_params.length && j < effective_params.length; i += 1, j += 1) {
+    for (
+      let i = 0, j = 0;
+      i < formal_params.length && j < effective_params.length;
+      i += 1, j += 1
+    ) {
       const formalParameter = formal_params[i];
       if (formalParameter.variadic) {
-       [j, callee_store] = await this.associateVariadicParameter(funcName, formalParameter, j, effective_params, caller_store,
-          callee_store);
+        [j, callee_store] = await this.associateVariadicParameter(
+          funcName,
+          formalParameter,
+          j,
+          effective_params,
+          caller_store,
+          callee_store
+        );
       } else {
         const actualParam = effective_params[i];
-        callee_store = await this.associateParameter(funcName, formalParameter, actualParam, caller_store,
-          callee_store);
+        callee_store = await this.associateParameter(
+          funcName,
+          formalParameter,
+          actualParam,
+          caller_store,
+          callee_store
+        );
       }
-      
     }
     return callee_store;
   }
 
   /**
-   * 
-   * @param {string} funcName 
-   * @param {import('./../ast/commands/formalParameter').FormalParameter} formalParameter 
-   * @param {number} index 
-   * @param {Expression[]} effective_params 
-   * @param {Store} caller_store 
-   * @param {Store} callee_store 
+   *
+   * @param {string} funcName
+   * @param {import('./../ast/commands/formalParameter').FormalParameter} formalParameter
+   * @param {number} index
+   * @param {Expression[]} effective_params
+   * @param {Store} caller_store
+   * @param {Store} callee_store
    */
-  async associateVariadicParameter (funcName, formalParameter, index, effective_params, caller_store, callee_store) {
+  async associateVariadicParameter (
+    funcName,
+    formalParameter,
+    index,
+    effective_params,
+    caller_store,
+    callee_store
+  ) {
     let i;
-    let count = 1
+    let count = 1;
     for (i = index; i < effective_params.length; i += 1) {
       const actualParam = effective_params[i];
-      callee_store = await this.associateParameter(funcName, formalParameter, actualParam, caller_store,
-        callee_store, count);
+      callee_store = await this.associateParameter(
+        funcName,
+        formalParameter,
+        actualParam,
+        caller_store,
+        callee_store,
+        count
+      );
       count += 1;
     }
     const variadicCount = new StoreValue(Types.INTEGER, count, undefined, true);
@@ -219,15 +248,18 @@ export class IVProgProcessor {
   }
 
   /**
-   * 
-   * @param {string} funcName 
-   * @param {import('./../ast/commands/formalParameter').FormalParameter} formalParameter 
-   * @param {Expression} actualParameter 
-   * @param {Store} callerStore 
-   * @param {Store} calleeStore 
+   *
+   * @param {string} funcName
+   * @param {import('./../ast/commands/formalParameter').FormalParameter} formalParameter
+   * @param {Expression} actualParameter
+   * @param {Store} callerStore
+   * @param {Store} calleeStore
    * @param {number} variadicCount The number of the current value being assigned to the variadic parameter, default 0
    */
-  async associateParameter (funcName, formalParameter, actualParameter,
+  async associateParameter (
+    funcName,
+    formalParameter,
+    actualParameter,
     callerStore,
     calleeStore,
     variadicCount = 0
@@ -238,7 +270,7 @@ export class IVProgProcessor {
     );
 
     let shouldTypeCast = false;
-    
+
     if (!formalParameter.type.isCompatible(actualValue.type)) {
       if (
         Config.enable_type_casting &&
@@ -255,7 +287,10 @@ export class IVProgProcessor {
     }
 
     if (formalParameter.byRef && !actualValue.inStore()) {
-      throw ProcessorErrorFactory.invalid_ref(funcName, actualParameter.toString());
+      throw ProcessorErrorFactory.invalid_ref(
+        funcName,
+        actualParameter.toString()
+      );
     }
 
     if (formalParameter.byRef) {
@@ -298,8 +333,7 @@ export class IVProgProcessor {
         }
       }
       let varID = formalParameter.id;
-      if (formalParameter.variadic)
-        varID = `${varID}.${variadicCount}`;
+      if (formalParameter.variadic) varID = `${varID}.${variadicCount}`;
       calleeStore.insertStore(varID, ref);
     } else {
       let realValue = actualValue;
@@ -307,8 +341,7 @@ export class IVProgProcessor {
         realValue = Store.doImplicitCasting(formalParameter.type, realValue);
       }
       let varID = formalParameter.id;
-      if (formalParameter.variadic)
-        varID = `${varID}.${variadicCount}`;
+      if (formalParameter.variadic) varID = `${varID}.${variadicCount}`;
       calleeStore.insertStore(varID, realValue);
     }
     return calleeStore;
@@ -321,7 +354,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeCommands(store, cmds) {
+  async executeCommands (store, cmds) {
     // helper to partially apply a function, in this case executeCommand
     let sto = store;
     for (let i = 0; i < cmds.length; i += 1) {
@@ -337,7 +370,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeCommand(store, cmd) {
+  async executeCommand (store, cmd) {
     this.instruction_count += 1;
     if (this.instruction_count % Config.suspend_threshold == 0) {
       //every Config.suspend_threshold instruction should briefly delay its execution in order to allow the browser to process other things
@@ -398,7 +431,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeSysCall(store, cmd) {
+  async executeSysCall (store, cmd) {
     const func = cmd.langFunc.bind(this);
     return func(store, cmd);
   }
@@ -410,7 +443,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeFunctionCall(store, cmd) {
+  async executeFunctionCall (store, cmd) {
     let func = null;
     if (cmd.isMainCall) {
       func = this.findMainFunction();
@@ -442,7 +475,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeSwitch(store, cmd) {
+  async executeSwitch (store, cmd) {
     this.context.push(Context.BREAKABLE);
     const switchCases = cmd.cases;
     let lastStore = store;
@@ -489,7 +522,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeFor(store, cmd) {
+  async executeFor (store, cmd) {
     //BEGIN for -> while rewrite
     const initCmd = new Commands.Assign(cmd.for_id.id, cmd.for_from);
     initCmd.sourceInfo = cmd.sourceInfo;
@@ -557,7 +590,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeRepeatUntil(store, cmd) {
+  async executeRepeatUntil (store, cmd) {
     this.context.push(Context.BREAKABLE);
     const sto = await this.executeCommands(store, cmd.commands);
     if (sto.mode === Modes.BREAK) {
@@ -584,7 +617,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeWhile(store, cmd) {
+  async executeWhile (store, cmd) {
     this.context.push(Context.BREAKABLE);
     const checkCondition = await this.evaluateExpression(store, cmd.expression);
     if (!checkCondition.type.isCompatible(Types.BOOLEAN)) {
@@ -614,7 +647,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeIfThenElse(store, cmd) {
+  async executeIfThenElse (store, cmd) {
     const isTrue = await this.evaluateExpression(store, cmd.condition);
     if (!isTrue.type.isCompatible(Types.BOOLEAN)) {
       throw ProcessorErrorFactory.if_condition_type_full(
@@ -642,7 +675,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeReturn(store, cmd) {
+  async executeReturn (store, cmd) {
     const funcName =
       store.name === IVProgProcessor.MAIN_INTERNAL_ID
         ? LanguageDefinedFunction.getMainFunctionName()
@@ -686,7 +719,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeBreak(store, cmd) {
+  async executeBreak (store, cmd) {
     if (this.checkContext(Context.BREAKABLE)) {
       store.mode = Modes.BREAK;
       return store;
@@ -702,7 +735,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeAssign(store, cmd) {
+  async executeAssign (store, cmd) {
     const inStore = store.applyStore(cmd.id);
     if (inStore.isConst) {
       throw ProcessorErrorFactory.invalid_const_assignment_full(
@@ -772,7 +805,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeArrayIndexAssign(store, cmd) {
+  async executeArrayIndexAssign (store, cmd) {
     const mustBeArray = store.applyStore(cmd.id);
     let used_dims = 0;
     if (mustBeArray.isConst) {
@@ -899,7 +932,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeDeclaration(store, cmd) {
+  async executeDeclaration (store, cmd) {
     if (cmd instanceof Commands.ArrayDeclaration) {
       return this.executeArrayDeclaration(store, cmd);
     } else {
@@ -943,7 +976,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeArrayDeclaration(store, cmd) {
+  async executeArrayDeclaration (store, cmd) {
     const linesSV = await this.evaluateExpression(store, cmd.lines);
     if (!Types.INTEGER.isCompatible(linesSV.type)) {
       throw ProcessorErrorFactory.array_dimension_not_int_full(cmd.sourceInfo);
@@ -1001,7 +1034,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<import('./store/value/istore_value').IStoreValue>}
    */
-  async evaluateExpression(store, exp) {
+  async evaluateExpression (store, exp) {
     this.instruction_count += 1;
     if (this.instruction_count % Config.suspend_threshold == 0) {
       //every Config.suspend_threshold instruction should briefly delay its execution in order to allow the browser to process other things
@@ -1031,6 +1064,8 @@ export class IVProgProcessor {
       return this.evaluateLiteral(store, exp);
     } else if (exp instanceof Expressions.StringLiteral) {
       return this.evaluateLiteral(store, exp);
+    } else if (exp instanceof Expressions.CharLiteral) {
+      return this.evaluateLiteral(store, exp);
     } else if (exp instanceof Expressions.ArrayLiteral) {
       throw new Error(
         "Internal Error: The system should not eval an array literal."
@@ -1041,7 +1076,7 @@ export class IVProgProcessor {
     return null;
   }
 
-  async evaluateFunctionCall(store, exp) {
+  async evaluateFunctionCall (store, exp) {
     if (exp.isMainCall) {
       throw ProcessorErrorFactory.void_in_expression_full(
         LanguageDefinedFunction.getMainFunctionName(),
@@ -1080,7 +1115,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<StoreValue[]>}
    */
-  async evaluateArrayLiteral(store, exp, type, lines, columns) {
+  async evaluateArrayLiteral (store, exp, type, lines, columns) {
     if (!exp.isVector) {
       if (columns == null) {
         throw new Error(
@@ -1114,7 +1149,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<StoreValue[]>} store object list
    */
-  async evaluateVector(store, exps, type, n_elements) {
+  async evaluateVector (store, exps, type, n_elements) {
     const values = exps.value;
     if (n_elements !== values.length) {
       throw ProcessorErrorFactory.invalid_number_elements_vector(
@@ -1157,7 +1192,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<StoreValue[][]>}
    */
-  async evaluateMatrix(store, exps, type, lines, columns) {
+  async evaluateMatrix (store, exps, type, lines, columns) {
     const values = exps.value;
     if (values.length !== lines) {
       throw ProcessorErrorFactory.invalid_number_lines_matrix(
@@ -1181,7 +1216,7 @@ export class IVProgProcessor {
    *
    * @returns {import('./store/value/istore_value').IStoreValue}
    */
-  async evaluateLiteral(_, exp) {
+  async evaluateLiteral (_, exp) {
     return new StoreValue(exp.type, exp.value);
   }
 
@@ -1192,7 +1227,7 @@ export class IVProgProcessor {
    *
    * @returns {import('./store/value/istore_value').IStoreValue}
    */
-  async evaluateVariableLiteral(store, exp) {
+  async evaluateVariableLiteral (store, exp) {
     const val = store.applyStore(exp.id);
     return val;
   }
@@ -1204,7 +1239,7 @@ export class IVProgProcessor {
    *
    * @returns {import('./store/value/istore_value').IStoreValue}
    */
-  async evaluateArrayAccess(store, exp) {
+  async evaluateArrayAccess (store, exp) {
     const mustBeArray = store.getStoreObject(exp.id);
     if (!(mustBeArray.type instanceof ArrayType)) {
       throw ProcessorErrorFactory.invalid_array_access_full(
@@ -1308,7 +1343,7 @@ export class IVProgProcessor {
    *
    * @returns {import('./store/value/istore_value').IStoreValue}
    */
-  async evaluateUnaryApp(store, unaryApp) {
+  async evaluateUnaryApp (store, unaryApp) {
     const left = await this.evaluateExpression(store, unaryApp.left);
     const resultType = resultTypeAfterUnaryOp(unaryApp.op, left.type);
     if (Types.UNDEFINED.isCompatible(resultType)) {
@@ -1340,7 +1375,7 @@ export class IVProgProcessor {
    *
    * @returns {import('./store/value/istore_value').IStoreValue}
    */
-  async evaluateInfixApp(store, infixApp) {
+  async evaluateInfixApp (store, infixApp) {
     const left = await this.evaluateExpression(store, infixApp.left);
     const right = await this.evaluateExpression(store, infixApp.right);
     let shouldImplicitCast = false;
@@ -1375,6 +1410,10 @@ export class IVProgProcessor {
         } else if (Types.STRING.isCompatible(right.type)) {
           const leftStr = convertToString(left.get(), left.type);
           return new StoreValue(resultType, leftStr + right.get());
+        } else if (Types.CHAR.isCompatible(left.type)) {
+          const strLeft = convertToString(left.get(), left.type);
+          const strRight = convertToString(right.get(), right.type);
+          return new StoreValue(resultType, strLeft + strRight);
         } else {
           return new StoreValue(resultType, left.get().plus(right.get()));
         }
@@ -1413,6 +1452,8 @@ export class IVProgProcessor {
         let rightValue = right.get();
         if (Types.STRING.isCompatible(left.type)) {
           result = leftValue.length > rightValue.length;
+        } else if (Types.CHAR.isCompatible(left.type)) {
+          result = leftValue.charCodeAt(0) > rightValue.charCodeAt(0);
         } else {
           if (shouldImplicitCast) {
             resultType = Types.BOOLEAN;
@@ -1428,6 +1469,8 @@ export class IVProgProcessor {
         let rightValue = right.get();
         if (Types.STRING.isCompatible(left.type)) {
           result = leftValue.length >= rightValue.length;
+        } else if (Types.CHAR.isCompatible(left.type)) {
+          result = leftValue.charCodeAt(0) >= rightValue.charCodeAt(0);
         } else {
           if (shouldImplicitCast) {
             resultType = Types.BOOLEAN;
@@ -1443,6 +1486,8 @@ export class IVProgProcessor {
         let rightValue = right.get();
         if (Types.STRING.isCompatible(left.type)) {
           result = leftValue.length < rightValue.length;
+        } else if (Types.CHAR.isCompatible(left.type)) {
+          result = leftValue.charCodeAt(0) < rightValue.charCodeAt(0);
         } else {
           if (shouldImplicitCast) {
             resultType = Types.BOOLEAN;
@@ -1458,6 +1503,8 @@ export class IVProgProcessor {
         let rightValue = right.get();
         if (Types.STRING.isCompatible(left.type)) {
           result = leftValue.length <= rightValue.length;
+        } else if (Types.CHAR.isCompatible(left.type)) {
+          result = leftValue.charCodeAt(0) <= rightValue.charCodeAt(0);
         } else {
           if (shouldImplicitCast) {
             resultType = Types.BOOLEAN;

+ 25 - 0
js/processor/lib/lang.js

@@ -17,6 +17,7 @@ import { StoreValue } from '../store/value/store_value';
  * cast_int
  * cast_bool
  * cast_string
+ * cast_char
  */
 
 export function createIsRealFun () {
@@ -148,6 +149,12 @@ export function createCastIntFun () {
         sto.mode = Modes.RETURN;
         return sto;
       }
+      case Types.CHAR.ord: {
+        const temp = new StoreValue(Types.INTEGER, value.charCodeAt(0));
+        sto.insertStore("$", temp);
+        sto.mode = Modes.RETURN;
+        return sto;
+      }
       case Types.STRING.ord: {
         const parser = IVProgParser.createParser(value);
         try {
@@ -217,4 +224,22 @@ export function createCastStringFun () {
     [new Commands.FormalParameter(Types.ALL, 'str', false)],
     block);
   return func;
+}
+
+export function createCastCharFun () {
+  const castCharFun = (store, _) => {
+    const valSV = store.applyStore('charCode');
+    // Force the int value to the range [0, 255]
+    const value = valSV.get().toNumber() & 0xFF;
+    const result = String.fromCharCode(value);
+    const temp = new StoreValue(Types.CHAR, result);
+    store.insertStore("$", temp);
+    store.mode = Modes.RETURN;
+    return store;
+  }
+  const block = new Commands.CommandBlock([], [new Commands.SysCall(castCharFun)]);
+  const func = new Commands.Function('$castChar', Types.CHAR,
+    [new Commands.FormalParameter(Types.INTEGER, 'charCode', false)],
+    block);
+  return func;
 }

+ 2 - 2
js/processor/lib/strings.js

@@ -87,13 +87,13 @@ export function createrCharAtFun () {
       throw ProcessorErrorFactory.invalid_string_index(idx.get().toNumber(), str.get(),
         this.function_call_stack.pop());
     }
-    const temp = new StoreValue(Types.STRING, str.get().charAt(idx.get().toNumber()));
+    const temp = new StoreValue(Types.CHAR, str.get().charAt(idx.get().toNumber()));
     sto.insertStore("$", temp);
     sto.mode = Modes.RETURN;
     return sto;
   }
   const block = new Commands.CommandBlock([],  [new Commands.SysCall(charAtFun)]);
-  const func = new Commands.Function('$charAt', Types.STRING,
+  const func = new Commands.Function('$charAt', Types.CHAR,
     [new Commands.FormalParameter(Types.STRING, 'str', false),
     new Commands.FormalParameter(Types.INTEGER, 'index', false)],
     block);

File diff suppressed because it is too large
+ 483 - 180
js/processor/semantic/semanticAnalyser.js


+ 8 - 6
js/typeSystem/array_type.ts

@@ -9,7 +9,7 @@ export class ArrayType implements IType {
     this.innerType = type;
   }
 
-  get isVector () {
+  get isVector (): boolean {
     return this.dimensions == 1;
   }
 
@@ -23,23 +23,25 @@ export class ArrayType implements IType {
     return false;
   }
 
-  stringInfo () {
+  stringInfo (): object[] {
     const list = this.innerType.stringInfo();
     list.forEach(v => {
-      v.dim = this.dimensions;
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      const tmp = v as any;
+      tmp.dim = this.dimensions;
     });
     return list;
   }
 
-  get value () {
+  get value (): undefined {
     return undefined;
   }
 
-  get ord () {
+  get ord (): undefined {
     return undefined;
   }
 
-  canAccept (another: IType, used_dims: number) {
+  canAccept (another: IType, used_dims: number): boolean {
     const free_dims = this.dimensions - used_dims;
     if(another instanceof ArrayType) {
       return free_dims == another.dimensions && this.innerType.isCompatible(another.innerType);

+ 4 - 3
js/typeSystem/itype.ts

@@ -1,10 +1,11 @@
+// eslint-disable-next-line @typescript-eslint/interface-name-prefix
 export interface IType {
 
-  value?: String;
+  value: string | undefined;
 
-  ord?: number;
+  ord: number | undefined;
 
-  stringInfo (): any[];
+  stringInfo (): object[];
 
   isCompatible (another: IType): boolean;
 

+ 5 - 5
js/typeSystem/multiType.ts

@@ -6,16 +6,16 @@ export class MultiType implements IType {
   constructor (public types: Type[]) {
   }
 
-  get value () {
+  get value (): undefined {
     return undefined;
   }
 
-  get ord () {
+  get ord (): undefined {
     return undefined;
   }
 
-  stringInfo () {
-    let list: any[] = [];
+  stringInfo (): object[] {
+    let list: object[] = [];
     for (let i = 0; i < this.types.length; i++) {
       const t = this.types[i];
       list = list.concat(t.stringInfo());
@@ -23,7 +23,7 @@ export class MultiType implements IType {
     return list;
   }
 
-  isCompatible (another: Type) {
+  isCompatible (another: Type): boolean {
     for (let i = 0; i < this.types.length; i++) {
       const t = this.types[i];
       if (another.isCompatible(t)) {

+ 6 - 0
js/typeSystem/parsers.js

@@ -20,6 +20,12 @@ export function toString (str) {
   return value;
 }
 
+export function toChar (str) {
+  let value = str.replace(/^'/, '');
+  value = value.replace(/'$/, '');
+  return value;
+}
+
 export function toReal (value) {
   return new Decimal(value);
 }

+ 10 - 4
js/typeSystem/type.ts

@@ -2,13 +2,19 @@ import { IType } from "./itype";
 
 export class Type implements IType {
 
-  constructor(public value: String, public ord: number) { }
+  public value: string;
+  public ord: number;
 
-  stringInfo () {
-    return [{type: this.value, dim: 0}];
+  constructor(value: string, ord: number) {
+    this.value = value;
+    this.ord = ord;
   }
 
-  isCompatible (another: IType) {
+  stringInfo (): object[] {
+    return [{ type: this.value, dim: 0 }];
+  }
+
+  isCompatible (another: IType): boolean {
     return this.value === another.value && this.ord === another.ord;
   }
 }

+ 10 - 8
js/typeSystem/types.ts

@@ -6,29 +6,31 @@ import { Maybe } from "../util/maybe";
 const INTEGER = new Type("integer", 0);
 const REAL = new Type("real", 1);
 const STRING = new Type("text", 2);
-const BOOLEAN =new Type("boolean", 3);
-const VOID = new Type("void", 4);
-const UNDEFINED = new Type("undefined", 5);
-const ALL = new MultiType([INTEGER, REAL, STRING, BOOLEAN]);
+const BOOLEAN = new Type("boolean", 3);
+const CHAR = new Type("char", 4);
+const VOID = new Type("void", 5);
+const UNDEFINED = new Type("undefined", 6);
+const ALL = new MultiType([INTEGER, REAL, STRING, CHAR, BOOLEAN]);
 
 interface TypeMap {
-  [key: string]: IType
+  [key: string]: IType;
 }
 
 export const Types = Object.freeze({
   INTEGER: INTEGER,
   REAL: REAL,
   STRING: STRING,
+  CHAR: CHAR,
   BOOLEAN: BOOLEAN,
   VOID: VOID,
   UNDEFINED: UNDEFINED,
   ALL: ALL
 });
 
-export function fromOrdToType (ord:number): Maybe<IType> {
+export function fromOrdToType (ord: number): Maybe<IType> {
   const typeMap = Types as TypeMap;
-  for(let t in typeMap) {
-    if(typeMap[t].ord! === ord){
+  for (const t in typeMap) {
+    if (typeMap[t].ord && typeMap[t].ord === ord){
       return Maybe.some<IType>(typeMap[t]);
     }
   }

+ 0 - 23
js/util/config.js

@@ -1,23 +0,0 @@
-class ConfigObject {
-
-  constructor () {
-    this.decimalPlaces = 8;
-    this.intConvertRoundMode = 2;
-    this.default_lang = 'pt';
-    this.enable_type_casting = true;
-    this.idle_input_interval = 5000;
-    this.suspend_threshold = 100;
-    // this.max_instruction_count = 350250; - automated evaluation limit
-    this.max_instruction_count = Number.MAX_SAFE_INTEGER;
-  }
-
-  setConfig (opts) {
-    for (const key in opts) {
-      if(Object.prototype.hasOwnProperty.call(this, key)){
-        this[key] = opts[key];
-      }
-    }
-  }
-}
-const config = new ConfigObject();
-export const Config = config;

+ 38 - 0
js/util/config.ts

@@ -0,0 +1,38 @@
+interface ConfigInterface {
+  [id: string]: unknown;
+}
+
+class ConfigObject implements ConfigInterface{
+
+  public decimalPlaces: number;
+  public intConvertRoundMode: number;
+  public default_lang: string;
+  public enable_type_casting: boolean;
+  public idle_input_interval: number;
+  public suspend_threshold: number;
+  public max_instruction_count: number;
+  [id: string]: unknown;
+
+  constructor () {
+    this.decimalPlaces = 8;
+    this.intConvertRoundMode = 2;
+    this.default_lang = 'pt';
+    this.enable_type_casting = true;
+    this.idle_input_interval = 5000;
+    this.suspend_threshold = 100;
+    // this.max_instruction_count = 350250; - automated evaluation limit
+    this.max_instruction_count = Number.MAX_SAFE_INTEGER;
+  }
+
+  setConfig (opts: object): void {
+    const otherConfig = opts as ConfigInterface;
+    for (const key in otherConfig) {
+      if(Object.prototype.hasOwnProperty.call(this, key)){
+        this[key] = otherConfig[key];
+      }
+    }
+  }
+}
+
+const config = new ConfigObject();
+export const Config = config;

+ 3 - 3
js/util/either.ts

@@ -1,5 +1,5 @@
-type Left<T> = { tag: "left", value: T };
-type Right<T> = { tag: "right", value: T };
+type Left<T> = { tag: "left"; value: T };
+type Right<T> = { tag: "right"; value: T };
 export type Either<L, R> = Left<L> | Right<R>;
 
 export function left<T> (value: T): Left<T> {
@@ -10,7 +10,7 @@ export function right<T> (value: T): Right<T> {
   return {tag: "right", value: value}
 }
 
-export function match<T, L, R> (input: Either<L, R>, left: (l: L) => T, right: (right: R) => T) {
+export function match<T, L, R> (input: Either<L, R>, left: (l: L) => T, right: (right: R) => T): T {
   switch(input.tag) {
     case "left":
       return left(input.value);

+ 1 - 1
js/util/iassignHelpers.js

@@ -95,7 +95,7 @@ export function autoEval (originalData, callback) {
     const autoAssessment = new IVProgAssessment(ast_code, getTestCases(), new TestConsole([]));
     autoAssessment.runTest().then( grade => callback(grade)).catch(err => {
       console.log(err);
-      callback(0);
+      callback(-5); // @FeedbackConvention Falha na execução
     });
   }
 }

+ 1 - 1
js/util/utils.js

@@ -156,7 +156,7 @@ 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"];
+  const typeList = ["RK_REAL","RK_VOID","RK_BOOLEAN","RK_STRING","RK_INTEGER","RK_CHARACTER"];
   const atomList = ["RK_FALSE", "RK_TRUE"];
 
   const case_default = [];

+ 196 - 112
js/visualUI/code_generator.js

@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-use-before-define */
+/* globals $*/
 import { Types } from "./types";
 import * as Models from "./ivprog_elements";
 import { LocalizedStrings } from "./../services/localizedStringsService";
@@ -52,6 +54,9 @@ function functionsCode (function_obj) {
     case Types.BOOLEAN:
       ret += LocalizedStrings.getUI("type_boolean");
       break;
+    case Types.CHAR:
+      ret += LocalizedStrings.getUI("type_char");
+      break;
     case Types.VOID:
       ret += LocalizedStrings.getUI("type_void");
       break;
@@ -66,7 +71,7 @@ function functionsCode (function_obj) {
 
   ret += function_obj.name + " ( ";
 
-  for (var j = 0; j < function_obj.parameters_list.length; j++) {
+  for (let j = 0; j < function_obj.parameters_list.length; j++) {
     ret += parametersCode(function_obj.parameters_list[j]);
     if (j + 1 < function_obj.parameters_list.length) {
       ret += ", ";
@@ -75,29 +80,29 @@ function functionsCode (function_obj) {
 
   ret += " )  {";
 
-  for (var j = 0; j < function_obj.variables_list.length; j++) {
+  for (let j = 0; j < function_obj.variables_list.length; j++) {
     ret += variablesCode(function_obj.variables_list[j]);
   }
 
-  for (var j = 0; j < function_obj.commands.length; j++) {
+  for (let j = 0; j < function_obj.commands.length; j++) {
     //try {
     ret += commandsCode(function_obj.commands[j]);
     /*} catch (err) {
 
-			has_error = true;
+                        has_error = true;
+
+                        console.error(err.message);
 
-			console.error(err.message);
+                        var todos = $('body').find('.command_container');
 
-			var todos = $('body').find('.command_container');
+                        for (var i = 0; i < todos.length; i++) {
+                                if ($(todos[i]).data('command') == function_obj.commands[j]) {
+                                        $( todos[i] ).prepend( ' <i class="ui icon red exclamation triangle error_icon"></i> ' );
+                                        break;
+                                }
+                        }
 
-			for (var i = 0; i < todos.length; i++) {
-				if ($(todos[i]).data('command') == function_obj.commands[j]) {
-					$( todos[i] ).prepend( ' <i class="ui icon red exclamation triangle error_icon"></i> ' );
-					break;
-				}
-			}
-			
-		}*/
+                }*/
   }
 
   ret += "\n\t}";
@@ -162,13 +167,15 @@ function returnsCode (command_obj, indentation) {
     try {
       ret += " " + elementExpressionCode(command_obj.variable_value_menu);
       //ret += ' ' + variableValueMenuCode(command_obj.variable_value_menu, true);
-    } catch (err) {}
+    } catch (err) {
+      continue;
+    }
   }
 
   return ret;
 }
 
-function breaksCode (command_obj, indentation) {
+function breaksCode (_command_obj, indentation) {
   let ret = "\n";
 
   for (let i = 0; i < indentation; i++) {
@@ -183,7 +190,7 @@ function breaksCode (command_obj, indentation) {
 function switchsCode (command_obj, indentation) {
   let ret = "\n";
 
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -194,13 +201,13 @@ function switchsCode (command_obj, indentation) {
   ret += " ) { ";
 
   if (command_obj.cases) {
-    for (var i = 0; i < command_obj.cases.length; i++) {
+    for (let i = 0; i < command_obj.cases.length; i++) {
       ret += switchcasesCode(command_obj.cases[i], indentation + 1);
     }
   }
 
   ret += "\n";
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
   ret += "} ";
@@ -211,7 +218,7 @@ function switchsCode (command_obj, indentation) {
 function switchcasesCode (switchcase, indentation) {
   let ret = "\n";
 
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -220,7 +227,7 @@ function switchcasesCode (switchcase, indentation) {
   ret += " :";
 
   if (switchcase.commands_block) {
-    for (var i = 0; i < switchcase.commands_block.length; i++) {
+    for (let i = 0; i < switchcase.commands_block.length; i++) {
       ret += commandsCode(switchcase.commands_block[i], indentation + 1);
     }
   }
@@ -231,7 +238,7 @@ function switchcasesCode (switchcase, indentation) {
 function repeatNtimesCode (command_obj, indentation) {
   let ret = "\n";
 
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -262,41 +269,41 @@ function repeatNtimesCode (command_obj, indentation) {
   }
 
   /*if (command_obj.var_incrementation) {
-		ret += variableValueMenuCode(command_obj.var_incrementation);
-		ret += ' <- ';
-		ret += variableValueMenuCode(command_obj.expression3.itens[0]);
-
-		switch (command_obj.expression3.itens[1]) {
-			case Models.ARITHMETIC_TYPES.plus:
-				ret += ' + ';
-				break;
-			case Models.ARITHMETIC_TYPES.minus:
-				ret += ' - ';
-				break;
-			case Models.ARITHMETIC_TYPES.multiplication:
-				ret += ' * ';
-				break;
-			case Models.ARITHMETIC_TYPES.division:
-				ret += ' / ';
-				break;
-			case Models.ARITHMETIC_TYPES.module:
-				ret += ' % ';
-				break;
-		}
-
-		ret += variableValueMenuCode(command_obj.expression3.itens[2]);		
-	}*/
+                ret += variableValueMenuCode(command_obj.var_incrementation);
+                ret += ' <- ';
+                ret += variableValueMenuCode(command_obj.expression3.itens[0]);
+
+                switch (command_obj.expression3.itens[1]) {
+                        case Models.ARITHMETIC_TYPES.plus:
+                                ret += ' + ';
+                                break;
+                        case Models.ARITHMETIC_TYPES.minus:
+                                ret += ' - ';
+                                break;
+                        case Models.ARITHMETIC_TYPES.multiplication:
+                                ret += ' * ';
+                                break;
+                        case Models.ARITHMETIC_TYPES.division:
+                                ret += ' / ';
+                                break;
+                        case Models.ARITHMETIC_TYPES.module:
+                                ret += ' % ';
+                                break;
+                }
+
+                ret += variableValueMenuCode(command_obj.expression3.itens[2]);
+        }*/
 
   ret += " { ";
 
   if (command_obj.commands_block) {
-    for (var i = 0; i < command_obj.commands_block.length; i++) {
+    for (let i = 0; i < command_obj.commands_block.length; i++) {
       ret += commandsCode(command_obj.commands_block[i], indentation + 1);
     }
   }
 
   ret += "\n";
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -307,7 +314,7 @@ function repeatNtimesCode (command_obj, indentation) {
 function iftruesCode (command_obj, indentation) {
   let ret = "\n";
 
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -325,37 +332,37 @@ function iftruesCode (command_obj, indentation) {
   }
 
   /*switch (command_obj.expression.expression.type) {
-		case Models.EXPRESSION_TYPES.exp_logic:
-			ret += logicExpressionCode(command_obj.expression.expression);
-			break;
-		case Models.EXPRESSION_TYPES.exp_arithmetic:
-			ret += arithmeticExpressionCode(command_obj.expression.expression);
-			break;
-	}*/
+                case Models.EXPRESSION_TYPES.exp_logic:
+                        ret += logicExpressionCode(command_obj.expression.expression);
+                        break;
+                case Models.EXPRESSION_TYPES.exp_arithmetic:
+                        ret += arithmeticExpressionCode(command_obj.expression.expression);
+                        break;
+        }*/
 
   ret += " { ";
 
   if (command_obj.commands_block) {
-    for (var i = 0; i < command_obj.commands_block.length; i++) {
+    for (let i = 0; i < command_obj.commands_block.length; i++) {
       ret += commandsCode(command_obj.commands_block[i], indentation + 1);
     }
   }
 
   ret += "\n";
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
   ret += "} " + LocalizedStrings.getUI("text_else") + " {";
 
   if (command_obj.commands_else) {
-    for (var i = 0; i < command_obj.commands_else.length; i++) {
+    for (let i = 0; i < command_obj.commands_else.length; i++) {
       ret += commandsCode(command_obj.commands_else[i], indentation + 1);
     }
   }
 
   ret += "\n";
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -367,20 +374,20 @@ function iftruesCode (command_obj, indentation) {
 function doWhilesCode (command_obj, indentation) {
   let ret = "\n";
 
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
   ret += LocalizedStrings.getUI("text_code_do") + " { ";
 
   if (command_obj.commands_block) {
-    for (var i = 0; i < command_obj.commands_block.length; i++) {
+    for (let i = 0; i < command_obj.commands_block.length; i++) {
       ret += commandsCode(command_obj.commands_block[i], indentation + 1);
     }
   }
 
   ret += "\n";
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -394,13 +401,13 @@ function doWhilesCode (command_obj, indentation) {
   }
 
   /*switch (command_obj.expression.expression.type) {
-		case Models.EXPRESSION_TYPES.exp_logic:
-			ret += logicExpressionCode(command_obj.expression.expression);
-			break;
-		case Models.EXPRESSION_TYPES.exp_arithmetic:
-			ret += arithmeticExpressionCode(command_obj.expression.expression);
-			break;
-	}*/
+                case Models.EXPRESSION_TYPES.exp_logic:
+                        ret += logicExpressionCode(command_obj.expression.expression);
+                        break;
+                case Models.EXPRESSION_TYPES.exp_arithmetic:
+                        ret += arithmeticExpressionCode(command_obj.expression.expression);
+                        break;
+        }*/
 
   if (command_obj.expression) {
     ret += " ( ";
@@ -414,7 +421,7 @@ function doWhilesCode (command_obj, indentation) {
 function whiletruesCode (command_obj, indentation) {
   let ret = "\n";
 
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -428,13 +435,13 @@ function whiletruesCode (command_obj, indentation) {
   }
 
   /*switch (command_obj.expression.expression.type) {
-		case Models.EXPRESSION_TYPES.exp_logic:
-			ret += logicExpressionCode(command_obj.expression.expression);
-			break;
-		case Models.EXPRESSION_TYPES.exp_arithmetic:
-			ret += arithmeticExpressionCode(command_obj.expression.expression);
-			break;
-	}*/
+                case Models.EXPRESSION_TYPES.exp_logic:
+                        ret += logicExpressionCode(command_obj.expression.expression);
+                        break;
+                case Models.EXPRESSION_TYPES.exp_arithmetic:
+                        ret += arithmeticExpressionCode(command_obj.expression.expression);
+                        break;
+        }*/
   if (command_obj.expression) {
     ret += " ( ";
     ret += elementExpressionCode(command_obj.expression);
@@ -444,13 +451,13 @@ function whiletruesCode (command_obj, indentation) {
   ret += " { ";
 
   if (command_obj.commands_block) {
-    for (var i = 0; i < command_obj.commands_block.length; i++) {
+    for (let i = 0; i < command_obj.commands_block.length; i++) {
       ret += commandsCode(command_obj.commands_block[i], indentation + 1);
     }
   }
 
   ret += "\n";
-  for (var i = 0; i < indentation; i++) {
+  for (let i = 0; i < indentation; i++) {
     ret += "\t";
   }
 
@@ -563,8 +570,8 @@ function attributionsCode (command_obj, indentation) {
   ret += variableValueMenuCode(command_obj.variable) + " <- ";
 
   /*for (var i = 0; i < command_obj.expression.length; i++) {
-		ret += elementExpressionCode(command_obj.expression[i]);
-	}*/
+                ret += elementExpressionCode(command_obj.expression[i]);
+        }*/
   ret += elementExpressionCode(command_obj.expression);
 
   return ret;
@@ -739,17 +746,18 @@ function writersCode (command_obj, indentation) {
   ret += LocalizedStrings.getUI("text_command_write") + " ( ";
 
   /*for (var i = 0; i < command_obj.content.length; i++) {
-		ret += variableValueMenuCode(command_obj.content[i]);
+                ret += variableValueMenuCode(command_obj.content[i]);
 
-		if ((i + 1) < command_obj.content.length) {
-			ret += ' + ';
-		}
-	}*/
+                if ((i + 1) < command_obj.content.length) {
+                        ret += ' + ';
+                }
+        }*/
 
   ret += elementExpressionCode(command_obj.content);
   if (command_obj.newline) {
     ret += ', "\\n"';
   }
+
   ret += " ) ";
   return ret;
 }
@@ -782,6 +790,9 @@ function parametersCode (parameter_obj) {
     case Types.BOOLEAN:
       ret += " " + LocalizedStrings.getUI("type_boolean") + " ";
       break;
+    case Types.CHAR:
+      ret += " " + LocalizedStrings.getUI("type_char") + " ";
+      break;
   }
   ret += parameter_obj.name + "";
 
@@ -816,6 +827,9 @@ function variablesCode (variable_obj) {
     case Types.BOOLEAN:
       ret += LocalizedStrings.getUI("type_boolean") + " ";
       break;
+    case Types.CHAR:
+      ret += LocalizedStrings.getUI("type_char") + " ";
+      break;
   }
   ret += temp.name + " ";
 
@@ -825,7 +839,7 @@ function variablesCode (variable_obj) {
     switch (temp.type) {
       case Types.INTEGER:
         ret += "<- {";
-        for (var j = 0; j < temp.value.length; j++) {
+        for (let j = 0; j < temp.value.length; j++) {
           ret += temp.value[j];
           if (j + 1 < temp.value.length) {
             ret += ", ";
@@ -835,7 +849,7 @@ function variablesCode (variable_obj) {
         break;
       case Types.REAL:
         ret += "<- {";
-        for (var j = 0; j < temp.value.length; j++) {
+        for (let j = 0; j < temp.value.length; j++) {
           ret += temp.value[j].toFixed(2);
           if (j + 1 < temp.value.length) {
             ret += ", ";
@@ -845,7 +859,7 @@ function variablesCode (variable_obj) {
         break;
       case Types.TEXT:
         ret += "<- {";
-        for (var j = 0; j < temp.value.length; j++) {
+        for (let j = 0; j < temp.value.length; j++) {
           ret += '"' + temp.value[j] + '"';
           if (j + 1 < temp.value.length) {
             ret += ", ";
@@ -855,7 +869,7 @@ function variablesCode (variable_obj) {
         break;
       case Types.BOOLEAN:
         ret += "<- {";
-        for (var j = 0; j < temp.value.length; j++) {
+        for (let j = 0; j < temp.value.length; j++) {
           if (temp.value[j]) {
             ret += LocalizedStrings.getUI("logic_value_true");
           } else {
@@ -867,6 +881,16 @@ function variablesCode (variable_obj) {
         }
         ret += "}";
         break;
+      case Types.CHAR:
+        ret += "<- {";
+        for (let j = 0; j < temp.value.length; j++) {
+          ret += "'" + temp.value[j] + "'";
+          if (j + 1 < temp.value.length) {
+            ret += ", ";
+          }
+        }
+        ret += "}";
+        break;
     }
   } else if (temp.dimensions == 2) {
     ret += "[" + temp.rows + "][" + temp.columns + "] ";
@@ -875,10 +899,10 @@ function variablesCode (variable_obj) {
       case Types.INTEGER:
         ret += "<- {";
 
-        for (var j = 0; j < temp.rows; j++) {
+        for (let j = 0; j < temp.rows; j++) {
           ret += "{";
 
-          for (var k = 0; k < temp.columns; k++) {
+          for (let k = 0; k < temp.columns; k++) {
             ret += temp.value[j][k];
 
             if (k + 1 < temp.columns) {
@@ -897,10 +921,10 @@ function variablesCode (variable_obj) {
       case Types.REAL:
         ret += "<- {";
 
-        for (var j = 0; j < temp.rows; j++) {
+        for (let j = 0; j < temp.rows; j++) {
           ret += "{";
 
-          for (var k = 0; k < temp.columns; k++) {
+          for (let k = 0; k < temp.columns; k++) {
             ret += temp.value[j][k].toFixed(2);
 
             if (k + 1 < temp.columns) {
@@ -919,10 +943,10 @@ function variablesCode (variable_obj) {
       case Types.TEXT:
         ret += "<- {";
 
-        for (var j = 0; j < temp.rows; j++) {
+        for (let j = 0; j < temp.rows; j++) {
           ret += "{";
 
-          for (var k = 0; k < temp.columns; k++) {
+          for (let k = 0; k < temp.columns; k++) {
             ret += '"' + temp.value[j][k] + '"';
 
             if (k + 1 < temp.columns) {
@@ -939,10 +963,10 @@ function variablesCode (variable_obj) {
         break;
       case Types.BOOLEAN:
         ret += "<- {";
-        for (var j = 0; j < temp.rows; j++) {
+        for (let j = 0; j < temp.rows; j++) {
           ret += "{";
 
-          for (var k = 0; k < temp.columns; k++) {
+          for (let k = 0; k < temp.columns; k++) {
             if (temp.value[j][k]) {
               ret += LocalizedStrings.getUI("logic_value_true");
             } else {
@@ -961,6 +985,27 @@ function variablesCode (variable_obj) {
         }
         ret += "}";
         break;
+      case Types.CHAR:
+        ret += "<- {";
+
+        for (let j = 0; j < temp.rows; j++) {
+          ret += "{";
+
+          for (let k = 0; k < temp.columns; k++) {
+            ret += "'" + temp.value[j][k] + "'";
+
+            if (k + 1 < temp.columns) {
+              ret += ", ";
+            }
+          }
+
+          ret += "}";
+          if (j + 1 < temp.rows) {
+            ret += ", ";
+          }
+        }
+        ret += "}";
+        break;
     }
   } else {
     switch (temp.type) {
@@ -981,6 +1026,9 @@ function variablesCode (variable_obj) {
           ret += LocalizedStrings.getUI("logic_value_false");
         }
         break;
+      case Types.CHAR:
+        ret += "<- '" + temp.value + "'";
+        break;
     }
   }
 
@@ -1012,6 +1060,9 @@ function globalsCode () {
         case Types.BOOLEAN:
           ret += LocalizedStrings.getUI("type_boolean");
           break;
+        case Types.CHAR:
+          ret += LocalizedStrings.getUI("type_char");
+          break;
       }
       ret += " " + temp.name + " ";
 
@@ -1021,7 +1072,7 @@ function globalsCode () {
         switch (temp.type) {
           case Types.INTEGER:
             ret += "<- {";
-            for (var j = 0; j < temp.value.length; j++) {
+            for (let j = 0; j < temp.value.length; j++) {
               ret += temp.value[j];
               if (j + 1 < temp.value.length) {
                 ret += ", ";
@@ -1031,7 +1082,7 @@ function globalsCode () {
             break;
           case Types.REAL:
             ret += "<- {";
-            for (var j = 0; j < temp.value.length; j++) {
+            for (let j = 0; j < temp.value.length; j++) {
               ret += temp.value[j].toFixed(2);
               if (j + 1 < temp.value.length) {
                 ret += ", ";
@@ -1041,7 +1092,7 @@ function globalsCode () {
             break;
           case Types.TEXT:
             ret += "<- {";
-            for (var j = 0; j < temp.value.length; j++) {
+            for (let j = 0; j < temp.value.length; j++) {
               ret += '"' + temp.value[j] + '"';
               if (j + 1 < temp.value.length) {
                 ret += ", ";
@@ -1051,7 +1102,7 @@ function globalsCode () {
             break;
           case Types.BOOLEAN:
             ret += "<- {";
-            for (var j = 0; j < temp.value.length; j++) {
+            for (let j = 0; j < temp.value.length; j++) {
               if (temp.value[j]) {
                 ret += LocalizedStrings.getUI("logic_value_true");
               } else {
@@ -1063,6 +1114,16 @@ function globalsCode () {
             }
             ret += "}";
             break;
+          case Types.CHAR:
+            ret += "<- {";
+            for (let j = 0; j < temp.value.length; j++) {
+              ret += "'" + temp.value[j] + "'";
+              if (j + 1 < temp.value.length) {
+                ret += ", ";
+              }
+            }
+            ret += "}";
+            break;
         }
       } else if (temp.dimensions == 2) {
         ret += "[" + temp.rows + "][" + temp.columns + "] ";
@@ -1071,10 +1132,10 @@ function globalsCode () {
           case Types.INTEGER:
             ret += "<- {";
 
-            for (var j = 0; j < temp.rows; j++) {
+            for (let j = 0; j < temp.rows; j++) {
               ret += "{";
 
-              for (var k = 0; k < temp.columns; k++) {
+              for (let k = 0; k < temp.columns; k++) {
                 ret += temp.value[j][k];
 
                 if (k + 1 < temp.columns) {
@@ -1093,10 +1154,10 @@ function globalsCode () {
           case Types.REAL:
             ret += "<- {";
 
-            for (var j = 0; j < temp.rows; j++) {
+            for (let j = 0; j < temp.rows; j++) {
               ret += "{";
 
-              for (var k = 0; k < temp.columns; k++) {
+              for (let k = 0; k < temp.columns; k++) {
                 ret += temp.value[j][k].toFixed(2);
 
                 if (k + 1 < temp.columns) {
@@ -1115,10 +1176,10 @@ function globalsCode () {
           case Types.TEXT:
             ret += "<- {";
 
-            for (var j = 0; j < temp.rows; j++) {
+            for (let j = 0; j < temp.rows; j++) {
               ret += "{";
 
-              for (var k = 0; k < temp.columns; k++) {
+              for (let k = 0; k < temp.columns; k++) {
                 ret += '"' + temp.value[j][k] + '"';
 
                 if (k + 1 < temp.columns) {
@@ -1135,10 +1196,10 @@ function globalsCode () {
             break;
           case Types.BOOLEAN:
             ret += "<- {";
-            for (var j = 0; j < temp.rows; j++) {
+            for (let j = 0; j < temp.rows; j++) {
               ret += "{";
 
-              for (var k = 0; k < temp.columns; k++) {
+              for (let k = 0; k < temp.columns; k++) {
                 if (temp.value[j][k]) {
                   ret += LocalizedStrings.getUI("logic_value_true");
                 } else {
@@ -1157,6 +1218,27 @@ function globalsCode () {
             }
             ret += "}";
             break;
+          case Types.CHAR:
+            ret += "<- {";
+
+            for (let j = 0; j < temp.rows; j++) {
+              ret += "{";
+
+              for (let k = 0; k < temp.columns; k++) {
+                ret += "'" + temp.value[j][k] + "'";
+
+                if (k + 1 < temp.columns) {
+                  ret += ", ";
+                }
+              }
+
+              ret += "}";
+              if (j + 1 < temp.rows) {
+                ret += ", ";
+              }
+            }
+            ret += "}";
+            break;
         }
       } else {
         switch (temp.type) {
@@ -1177,6 +1259,9 @@ function globalsCode () {
               ret += LocalizedStrings.getUI("logic_value_false");
             }
             break;
+          case Types.CHAR:
+            ret += "<- '" + temp.value + "'";
+            break;
         }
       }
     }
@@ -1184,4 +1269,3 @@ function globalsCode () {
 
   return ret;
 }
-

File diff suppressed because it is too large
+ 3 - 1
js/visualUI/functions.js


+ 34 - 1
js/visualUI/globals.js

@@ -133,7 +133,19 @@ function updateInitialValues (global_var) {
 			global_var.value = [[true, true], [true, true]];
 		}
 	}
-	registerSystemEvent(function_name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.name,
+
+	if (global_var.type == Types.CHAR) {
+		if (global_var.dimensions == 0) {
+			global_var.value = 'A';
+		}
+		if (global_var.dimensions == 1) {
+			global_var.value = ['A', 'A'];
+		}
+		if (global_var.dimensions == 2) {
+			global_var.value = [['A', 'A'], ['A', 'A']];
+		}
+	}
+	registerSystemEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.name,
 		global_var.value);
 }
 
@@ -171,6 +183,10 @@ function addGlobalColumnVector (global_var) {
 	if (global_var.type == Types.BOOLEAN) {
 		global_var.value.push(true);
 	}
+
+	if (global_var.type == Types.CHAR) {
+		global_var.value.push(LocalizedStrings.getUI('charvar_default_value'));
+	}
 }
 
 function removeColumnGlobalMatrix (global_var) {
@@ -208,6 +224,11 @@ function addColumnGlobalMatrix (global_var) {
 			global_var.value[i].push(true);
 		}
 	}
+	if (global_var.type == Types.CHAR) {
+		for (var i = 0; i < global_var.rows; i++) {
+			global_var.value[i].push(LocalizedStrings.getUI('charvar_default_value'));
+		}
+	}
 }
 
 function removeLineGlobalMatrix (global_var) {
@@ -252,6 +273,14 @@ function addLineGlobalMatrix (global_var) {
 		}
 		global_var.value.push(n_l);
 	}
+
+	if (global_var.type == Types.CHAR) {
+		var n_l = [];
+		for (i = 0; i < global_var.columns; i++) {
+			n_l.push(LocalizedStrings.getUI('charvar_default_value'));
+		}
+		global_var.value.push(n_l);
+	}
 }
 
 function alternateBooleanGlobalMatrixValue (global_var, row, index, value_container) {
@@ -734,6 +763,8 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 			} else{
 				if (global_var.type == Types.INTEGER) {
 					global_var.value = parseInt(input_field.val().trim());
+				} else if (var_obj.type == Types.CHAR) {
+					var_obj.value = input_field.val().charAt(0);
 				} else {
 					global_var.value = input_field.val().trim();
 				}
@@ -776,6 +807,8 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 				} else {
 					if (global_var.type == Types.INTEGER) {
 						global_var.value = parseInt(input_field.val().trim());
+					} else if (var_obj.type == Types.CHAR) {
+						var_obj.value = input_field.val().charAt(0);
 					} else {
 						global_var.value = input_field.val().trim();
 					}

+ 1 - 0
js/visualUI/types.js

@@ -2,6 +2,7 @@ export const Types = Object.freeze({
   INTEGER: "integer",
   REAL: "real",
   TEXT: "text",
+  CHAR: 'char',
   BOOLEAN: "boolean",
   VOID: "void"
 });

+ 32 - 0
js/visualUI/variables.js

@@ -415,6 +415,14 @@ function addLineMatrix (var_obj) {
 		}
 		var_obj.value.push(n_l);
 	}
+
+	if (var_obj.type == Types.CHAR) {
+		var n_l = [];
+		for (i = 0; i < var_obj.columns; i++) {
+			n_l.push(LocalizedStrings.getUI('charvar_default_value'));
+		}
+		var_obj.value.push(n_l);
+	}
 }
 
 function removeLineMatrix (var_obj) {
@@ -449,6 +457,11 @@ function addColumnMatrix (var_obj) {
 			var_obj.value[i].push(true);
 		}
 	}
+	if (var_obj.type == Types.CHAR) {
+		for (var i = 0; i < var_obj.rows; i++) {
+			var_obj.value[i].push(LocalizedStrings.getUI('charvar_default_value'));
+		}
+	}
 }
 
 function removeColumnMatrix (var_obj) {
@@ -478,6 +491,9 @@ function addColumnVector (var_obj) {
 	if (var_obj.type == Types.BOOLEAN) {
 		var_obj.value.push(true);
 	}
+	if (var_obj.type == Types.CHAR) {
+		var_obj.value.push(LocalizedStrings.getUI('charvar_default_value'));
+	}
 }
 
 function removeColumnVector (var_obj) {
@@ -548,6 +564,18 @@ function updateInitialValues (variable_obj, function_name) {
 			variable_obj.value = [[true, true], [true, true]];
 		}
 	}
+
+	if (variable_obj.type == Types.CHAR) {
+		if (variable_obj.dimensions == 0) {
+			variable_obj.value = 'A';
+		}
+		if (variable_obj.dimensions == 1) {
+			variable_obj.value = ['A', 'A'];
+		}
+		if (variable_obj.dimensions == 2) {
+			variable_obj.value = [['A', 'A'], ['A', 'A']];
+		}
+	}
 	registerSystemEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, variable_obj.name, variable_obj.value);
 }
 
@@ -742,6 +770,8 @@ function enableValueUpdate (var_obj, parent_node, function_name) {
 			} else{
 				if (var_obj.type == Types.INTEGER) {
 					var_obj.value = parseInt(input_field.val().trim());
+				} else if (var_obj.type == Types.CHAR) {
+					var_obj.value = input_field.val().charAt(0);
 				} else {
 					var_obj.value = input_field.val().trim();
 				}
@@ -785,6 +815,8 @@ function enableValueUpdate (var_obj, parent_node, function_name) {
 				} else{
 					if (var_obj.type == Types.INTEGER) {
 						var_obj.value = parseInt(input_field.val().trim());
+					} else if (var_obj.type == Types.CHAR) {
+						var_obj.value = input_field.val().charAt(0);
 					} else {
 						var_obj.value = input_field.val().trim();
 					}