|
@@ -0,0 +1,246 @@
|
|
|
+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 (): IType[][] {
|
|
|
+ const table: IType[][] = [[], [], [], [], []]
|
|
|
+
|
|
|
+ table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
|
|
|
+ table[Types.INTEGER.ord][Types.REAL.ord] = Types.REAL;
|
|
|
+ table[Types.INTEGER.ord][Types.STRING.ord] = Types.STRING;
|
|
|
+
|
|
|
+ table[Types.REAL.ord][Types.INTEGER.ord] = Types.REAL;
|
|
|
+ table[Types.REAL.ord][Types.REAL.ord] = Types.REAL;
|
|
|
+ table[Types.REAL.ord][Types.STRING.ord] = Types.STRING;
|
|
|
+
|
|
|
+ table[Types.STRING.ord][Types.INTEGER.ord] = Types.STRING;
|
|
|
+ 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 (): IType[][] {
|
|
|
+ const table: IType[][] = [[],[]];
|
|
|
+
|
|
|
+ table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
|
|
|
+ table[Types.INTEGER.ord][Types.REAL.ord] = Types.REAL;
|
|
|
+
|
|
|
+ table[Types.REAL.ord][Types.INTEGER.ord] = Types.REAL;
|
|
|
+ table[Types.REAL.ord][Types.REAL.ord] = Types.REAL;
|
|
|
+
|
|
|
+ return table;
|
|
|
+}
|
|
|
+
|
|
|
+function buildInfixEqualityInequalityTable (): IType[][] {
|
|
|
+ const table: IType[][] = [[], [], [], [], []];
|
|
|
+
|
|
|
+ table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ table[Types.REAL.ord][Types.REAL.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ table[Types.BOOLEAN.ord][Types.BOOLEAN.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ table[Types.STRING.ord][Types.STRING.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ table[Types.CHAR.ord][Types.CHAR.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ return table;
|
|
|
+}
|
|
|
+
|
|
|
+function buildInfixRelationalTable (): IType[][] {
|
|
|
+ const table: IType[][] = [[], [], [], [], []];
|
|
|
+
|
|
|
+ table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ table[Types.REAL.ord][Types.REAL.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ table[Types.STRING.ord][Types.STRING.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ table[Types.CHAR.ord][Types.CHAR.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ return table;
|
|
|
+}
|
|
|
+
|
|
|
+function buildInfixAndOrTable (): IType[][] {
|
|
|
+ const table: IType[][] = [[],[],[],[]];
|
|
|
+
|
|
|
+ table[Types.BOOLEAN.ord][Types.BOOLEAN.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ return table;
|
|
|
+}
|
|
|
+
|
|
|
+function buildInfixModTable (): IType[][] {
|
|
|
+ const table: IType[][] = [[]];
|
|
|
+
|
|
|
+ table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
|
|
|
+
|
|
|
+ return table;
|
|
|
+}
|
|
|
+
|
|
|
+function buildUnarySumSubList (): IType[] {
|
|
|
+ const list: IType[] = [];
|
|
|
+
|
|
|
+ list[Types.INTEGER.ord] = Types.INTEGER;
|
|
|
+
|
|
|
+ list[Types.REAL.ord] = Types.REAL;
|
|
|
+
|
|
|
+ return list;
|
|
|
+}
|
|
|
+
|
|
|
+function buildUnaryNegList (): IType[] {
|
|
|
+ const list: IType[] = [];
|
|
|
+
|
|
|
+ list[Types.BOOLEAN.ord] = Types.BOOLEAN;
|
|
|
+
|
|
|
+ return list;
|
|
|
+}
|
|
|
+
|
|
|
+function buildInfixCompatibilityTable (): WeakMap<Operator, IType[][]> {
|
|
|
+ const compatibilityMap = new WeakMap();
|
|
|
+ compatibilityMap.set(Operators.ADD, buildInfixAddTable());
|
|
|
+ compatibilityMap.set(Operators.SUB, buildInfixMultiDivSubTable());
|
|
|
+ compatibilityMap.set(Operators.MULT, buildInfixMultiDivSubTable());
|
|
|
+ compatibilityMap.set(Operators.DIV, buildInfixMultiDivSubTable());
|
|
|
+ compatibilityMap.set(Operators.EQ, buildInfixEqualityInequalityTable());
|
|
|
+ compatibilityMap.set(Operators.NEQ, buildInfixEqualityInequalityTable());
|
|
|
+ compatibilityMap.set(Operators.GE, buildInfixRelationalTable());
|
|
|
+ compatibilityMap.set(Operators.GT, buildInfixRelationalTable());
|
|
|
+ compatibilityMap.set(Operators.LE, buildInfixRelationalTable());
|
|
|
+ compatibilityMap.set(Operators.LT, buildInfixRelationalTable());
|
|
|
+ compatibilityMap.set(Operators.OR, buildInfixAndOrTable());
|
|
|
+ compatibilityMap.set(Operators.AND, buildInfixAndOrTable());
|
|
|
+ compatibilityMap.set(Operators.MOD, buildInfixModTable());
|
|
|
+ return compatibilityMap;
|
|
|
+}
|
|
|
+
|
|
|
+function buildUnaryCompatibilityTable (): WeakMap<Operator, IType[]> {
|
|
|
+ const compatibilityMap = new WeakMap();
|
|
|
+ compatibilityMap.set(Operators.ADD, buildUnarySumSubList());
|
|
|
+ compatibilityMap.set(Operators.SUB, buildUnarySumSubList());
|
|
|
+ compatibilityMap.set(Operators.NOT, buildUnaryNegList());
|
|
|
+ return compatibilityMap;
|
|
|
+}
|
|
|
+
|
|
|
+const infixMap = buildInfixCompatibilityTable();
|
|
|
+const unaryMap = buildUnaryCompatibilityTable();
|
|
|
+
|
|
|
+export function resultTypeAfterInfixOp (
|
|
|
+ operator: Operator,
|
|
|
+ leftExpressionType: IType,
|
|
|
+ rightExpressionType: IType
|
|
|
+): IType {
|
|
|
+ try {
|
|
|
+ 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) {
|
|
|
+ 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)) {
|
|
|
+ return new MultiType([Types.INTEGER, Types.REAL]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Types.UNDEFINED;
|
|
|
+ } else {
|
|
|
+ return new MultiType(newMulti as Type[])
|
|
|
+ }
|
|
|
+ } 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)) {
|
|
|
+ return rightExpressionType;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Types.UNDEFINED;
|
|
|
+ }
|
|
|
+ } 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)) {
|
|
|
+ return leftExpressionType;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Types.UNDEFINED;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const resultTable = infixMap.get(operator) || [];
|
|
|
+
|
|
|
+ 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) {
|
|
|
+ return Types.INTEGER;
|
|
|
+ } else if (operator.ord >= 5 && operator.ord <= 10){
|
|
|
+ return Types.BOOLEAN;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Types.UNDEFINED
|
|
|
+ }
|
|
|
+ return resultType;
|
|
|
+ } catch (e) {
|
|
|
+ if (e instanceof TypeError) {
|
|
|
+ return Types.UNDEFINED;
|
|
|
+ } else {
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export function resultTypeAfterUnaryOp (operator: Operator, leftExpressionType: IType): IType {
|
|
|
+ try {
|
|
|
+ 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 resultTable = unaryMap.get(operator) || [];
|
|
|
+
|
|
|
+ const resultType = resultTable[leftExpressionType.ord!];
|
|
|
+ if (resultType == null) {
|
|
|
+ return Types.UNDEFINED;
|
|
|
+ }
|
|
|
+ return resultType;
|
|
|
+ } catch (e) {
|
|
|
+ if (e instanceof TypeError) {
|
|
|
+ return Types.UNDEFINED;
|
|
|
+ } else {
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|