Browse Source

Implement char type, AST representation and processor function

Lucas de Souza 4 years ago
parent
commit
db93c20693

+ 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++;

+ 37 - 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;

+ 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) {

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

+ 9 - 7
js/typeSystem/types.ts

@@ -6,10 +6,11 @@ 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
@@ -19,16 +20,17 @@ 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]);
     }
   }