Browse Source

Merge branch 'char-type' of LInE/iVProg into master

GitAdmin 3 years ago
parent
commit
787c1b6b95

+ 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,4 +137,6 @@ 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}",
+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;
 }

+ 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()
   }
 }
 

+ 49 - 35
js/processor/ivprogProcessor.js

@@ -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);
@@ -152,7 +152,7 @@ export class IVProgProcessor {
     return finalSto;
   }
 
-  async associateParameters(
+  async associateParameters (
     formal_params,
     effective_params,
     caller_store,
@@ -256,7 +256,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) {
@@ -272,7 +272,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
@@ -333,7 +333,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);
   }
@@ -345,7 +345,7 @@ export class IVProgProcessor {
    *
    * @returns {Promise<Store>}
    */
-  async executeFunctionCall(store, cmd) {
+  async executeFunctionCall (store, cmd) {
     let func = null;
     if (cmd.isMainCall) {
       func = this.findMainFunction();
@@ -377,7 +377,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;
@@ -424,7 +424,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;
@@ -492,7 +492,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) {
@@ -519,7 +519,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)) {
@@ -549,7 +549,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(
@@ -577,7 +577,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()
@@ -621,7 +621,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;
@@ -637,7 +637,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(
@@ -707,7 +707,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) {
@@ -834,7 +834,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 {
@@ -878,7 +878,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);
@@ -936,7 +936,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
@@ -966,6 +966,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."
@@ -1015,7 +1017,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(
@@ -1049,7 +1051,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(
@@ -1092,7 +1094,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(
@@ -1116,7 +1118,7 @@ export class IVProgProcessor {
    *
    * @returns {import('./store/value/istore_value').IStoreValue}
    */
-  async evaluateLiteral(_, exp) {
+  async evaluateLiteral (_, exp) {
     return new StoreValue(exp.type, exp.value);
   }
 
@@ -1127,7 +1129,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;
   }
@@ -1139,7 +1141,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(
@@ -1243,7 +1245,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)) {
@@ -1275,7 +1277,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;
@@ -1310,6 +1312,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()));
         }
@@ -1348,6 +1354,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;
@@ -1363,6 +1371,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;
@@ -1378,6 +1388,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;
@@ -1393,6 +1405,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);

+ 3 - 1
js/processor/semantic/semanticAnalyser.js

@@ -2,7 +2,7 @@ import { ProcessorErrorFactory } from './../error/processorErrorFactory';
 import { LanguageDefinedFunction } from './../definedFunctions';
 import { LanguageService } from './../../services/languageService';
 import { ArrayDeclaration, While, For, Switch, Assign, Break, IfThenElse, Return, ArrayIndexAssign } from '../../ast/commands';
-import { InfixApp, UnaryApp, FunctionCall, IntLiteral, RealLiteral, StringLiteral, BoolLiteral, VariableLiteral, ArrayAccess } from '../../ast/expressions';
+import { InfixApp, UnaryApp, FunctionCall, IntLiteral, RealLiteral, StringLiteral, BoolLiteral, VariableLiteral, ArrayAccess, CharLiteral } from '../../ast/expressions';
 import { Literal } from '../../ast/expressions/literal';
 import { resultTypeAfterInfixOp, resultTypeAfterUnaryOp } from '../compatibilityTable';
 import { Types } from '../../typeSystem/types';
@@ -242,6 +242,8 @@ export class SemanticAnalyser {
       return literal.type;
     } else if (literal instanceof BoolLiteral) {
       return literal.type;
+    } else if (literal instanceof CharLiteral) {
+      return literal.type;
     } else if (literal instanceof VariableLiteral) {
       const typeInfo = this.findSymbol(literal.id, this.symbolMap);
       if(typeInfo === null) {

+ 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/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 = [];

+ 79 - 0
js/visualUI/code_generator.js

@@ -52,6 +52,8 @@ function functionsCode (function_obj) {
 		case Types.BOOLEAN:
 			ret += LocalizedStrings.getUI('type_boolean');
 			break;
+		case Types.CHAR:
+			ret += LocalizedStrings.getUI('type_char');
 		case Types.VOID:
 			ret += LocalizedStrings.getUI('type_void');
 			break;
@@ -771,6 +773,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 + '';
 
@@ -805,6 +810,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 + ' ';
 
@@ -856,6 +864,16 @@ function variablesCode (variable_obj) {
 				}
 				ret += '}';
 				break;
+			case Types.CHAR:
+				ret += '<- {';
+				for (var 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) {
@@ -952,6 +970,27 @@ function variablesCode (variable_obj) {
 				}
 				ret += '}';
 				break;
+			case Types.CHAR:
+				ret += '<- {';
+
+				for (var j = 0; j < temp.rows; j++) {
+					ret += '{';
+
+					for (var 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 {
 
@@ -973,6 +1012,9 @@ function variablesCode (variable_obj) {
 					ret += LocalizedStrings.getUI('logic_value_false');
 				}
 				break;
+			case Types.CHAR:
+				ret += '<- \'' + temp.value + '\'';
+				break;
 		}
 
 	}
@@ -1006,6 +1048,9 @@ function globalsCode () {
 				case Types.BOOLEAN:
 					ret += LocalizedStrings.getUI('type_boolean');
 					break;
+				case Types.CHAR:
+					ret += LocalizedStrings.getUI('type_char');
+					break;
 			}
 			ret += ' ' + temp.name + ' ';
 
@@ -1057,6 +1102,16 @@ function globalsCode () {
 						}
 						ret += '}';
 						break;
+					case Types.CHAR:
+						ret += '<- {';
+						for (var 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) {
@@ -1153,6 +1208,27 @@ function globalsCode () {
 						}
 						ret += '}';
 						break;
+					case Types.CHAR:
+						ret += '<- {';
+
+						for (var j = 0; j < temp.rows; j++) {
+							ret += '{';
+
+							for (var 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 {
 
@@ -1174,6 +1250,9 @@ function globalsCode () {
 							ret += LocalizedStrings.getUI('logic_value_false');;
 						}
 						break;
+					case Types.CHAR:
+						ret += '<- \'' + temp.value + '\'';
+						break;
 				}
 
 			}

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();
 					}