123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- 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) || [];
- // 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) {
- 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) || [];
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- 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;
- }
- }
- }
|