compatibilityTable.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import { Types } from '../typeSystem/types';
  2. import { IType } from '../typeSystem/itype';
  3. import { Type } from '../typeSystem/type';
  4. import { Operators, Operator } from '../ast/operators';
  5. import { MultiType } from '../typeSystem/multiType';
  6. import { Config } from '../util/config';
  7. function buildInfixAddTable (): IType[][] {
  8. const table: IType[][] = [[], [], [], [], []]
  9. table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
  10. table[Types.INTEGER.ord][Types.REAL.ord] = Types.REAL;
  11. table[Types.INTEGER.ord][Types.STRING.ord] = Types.STRING;
  12. table[Types.REAL.ord][Types.INTEGER.ord] = Types.REAL;
  13. table[Types.REAL.ord][Types.REAL.ord] = Types.REAL;
  14. table[Types.REAL.ord][Types.STRING.ord] = Types.STRING;
  15. table[Types.STRING.ord][Types.INTEGER.ord] = Types.STRING;
  16. table[Types.STRING.ord][Types.REAL.ord] = Types.STRING;
  17. table[Types.STRING.ord][Types.STRING.ord] = Types.STRING;
  18. table[Types.STRING.ord][Types.BOOLEAN.ord] = Types.STRING;
  19. table[Types.STRING.ord][Types.CHAR.ord] = Types.STRING;
  20. table[Types.CHAR.ord][Types.CHAR.ord] = Types.STRING;
  21. table[Types.CHAR.ord][Types.STRING.ord] = Types.STRING;
  22. return table;
  23. }
  24. function buildInfixMultiDivSubTable (): IType[][] {
  25. const table: IType[][] = [[], []];
  26. table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
  27. table[Types.INTEGER.ord][Types.REAL.ord] = Types.REAL;
  28. table[Types.REAL.ord][Types.INTEGER.ord] = Types.REAL;
  29. table[Types.REAL.ord][Types.REAL.ord] = Types.REAL;
  30. return table;
  31. }
  32. function buildInfixEqualityInequalityTable (): IType[][] {
  33. const table: IType[][] = [[], [], [], [], []];
  34. table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.BOOLEAN;
  35. table[Types.REAL.ord][Types.REAL.ord] = Types.BOOLEAN;
  36. table[Types.BOOLEAN.ord][Types.BOOLEAN.ord] = Types.BOOLEAN;
  37. table[Types.STRING.ord][Types.STRING.ord] = Types.BOOLEAN;
  38. table[Types.CHAR.ord][Types.CHAR.ord] = Types.BOOLEAN;
  39. return table;
  40. }
  41. function buildInfixRelationalTable (): IType[][] {
  42. const table: IType[][] = [[], [], [], [], []];
  43. table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.BOOLEAN;
  44. table[Types.REAL.ord][Types.REAL.ord] = Types.BOOLEAN;
  45. table[Types.STRING.ord][Types.STRING.ord] = Types.BOOLEAN;
  46. table[Types.CHAR.ord][Types.CHAR.ord] = Types.BOOLEAN;
  47. return table;
  48. }
  49. function buildInfixAndOrTable (): IType[][] {
  50. const table: IType[][] = [[], [], [], []];
  51. table[Types.BOOLEAN.ord][Types.BOOLEAN.ord] = Types.BOOLEAN;
  52. return table;
  53. }
  54. function buildInfixModTable (): IType[][] {
  55. const table: IType[][] = [[]];
  56. table[Types.INTEGER.ord][Types.INTEGER.ord] = Types.INTEGER;
  57. return table;
  58. }
  59. function buildUnarySumSubList (): IType[] {
  60. const list: IType[] = [];
  61. list[Types.INTEGER.ord] = Types.INTEGER;
  62. list[Types.REAL.ord] = Types.REAL;
  63. return list;
  64. }
  65. function buildUnaryNegList (): IType[] {
  66. const list: IType[] = [];
  67. list[Types.BOOLEAN.ord] = Types.BOOLEAN;
  68. return list;
  69. }
  70. function buildInfixCompatibilityTable (): WeakMap<Operator, IType[][]> {
  71. const compatibilityMap = new WeakMap();
  72. compatibilityMap.set(Operators.ADD, buildInfixAddTable());
  73. compatibilityMap.set(Operators.SUB, buildInfixMultiDivSubTable());
  74. compatibilityMap.set(Operators.MULT, buildInfixMultiDivSubTable());
  75. compatibilityMap.set(Operators.DIV, buildInfixMultiDivSubTable());
  76. compatibilityMap.set(Operators.EQ, buildInfixEqualityInequalityTable());
  77. compatibilityMap.set(Operators.NEQ, buildInfixEqualityInequalityTable());
  78. compatibilityMap.set(Operators.GE, buildInfixRelationalTable());
  79. compatibilityMap.set(Operators.GT, buildInfixRelationalTable());
  80. compatibilityMap.set(Operators.LE, buildInfixRelationalTable());
  81. compatibilityMap.set(Operators.LT, buildInfixRelationalTable());
  82. compatibilityMap.set(Operators.OR, buildInfixAndOrTable());
  83. compatibilityMap.set(Operators.AND, buildInfixAndOrTable());
  84. compatibilityMap.set(Operators.MOD, buildInfixModTable());
  85. return compatibilityMap;
  86. }
  87. function buildUnaryCompatibilityTable (): WeakMap<Operator, IType[]> {
  88. const compatibilityMap = new WeakMap();
  89. compatibilityMap.set(Operators.ADD, buildUnarySumSubList());
  90. compatibilityMap.set(Operators.SUB, buildUnarySumSubList());
  91. compatibilityMap.set(Operators.NOT, buildUnaryNegList());
  92. return compatibilityMap;
  93. }
  94. const infixMap = buildInfixCompatibilityTable();
  95. const unaryMap = buildUnaryCompatibilityTable();
  96. export function resultTypeAfterInfixOp (
  97. operator: Operator,
  98. leftExpressionType: IType,
  99. rightExpressionType: IType
  100. ): IType {
  101. try {
  102. if (leftExpressionType instanceof MultiType && rightExpressionType instanceof MultiType) {
  103. let newMulti = [];
  104. for (let i = 0; i < leftExpressionType.types.length; ++i) {
  105. const typeA = leftExpressionType.types[i];
  106. for (let j = 0; j < rightExpressionType.types.length; ++i) {
  107. const typeB = rightExpressionType.types[j];
  108. newMulti.push(resultTypeAfterInfixOp(operator, typeA, typeB));
  109. }
  110. }
  111. newMulti = newMulti.filter(x => !x.isCompatible(Types.UNDEFINED));
  112. if (newMulti.length <= 0) {
  113. if (Config.enable_type_casting) {
  114. if (leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
  115. if (rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
  116. return new MultiType([Types.INTEGER, Types.REAL]);
  117. }
  118. }
  119. }
  120. return Types.UNDEFINED;
  121. } else {
  122. return new MultiType(newMulti as Type[])
  123. }
  124. } else if (leftExpressionType instanceof MultiType) {
  125. if (leftExpressionType.isCompatible(rightExpressionType as Type)) {
  126. return resultTypeAfterInfixOp(operator, rightExpressionType, rightExpressionType);
  127. } else {
  128. if (Config.enable_type_casting) {
  129. if (leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
  130. if (rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
  131. return rightExpressionType;
  132. }
  133. }
  134. }
  135. return Types.UNDEFINED;
  136. }
  137. } else if (rightExpressionType instanceof MultiType) {
  138. if (rightExpressionType.isCompatible(leftExpressionType as Type)) {
  139. return resultTypeAfterInfixOp(operator, leftExpressionType, leftExpressionType);
  140. } else {
  141. if (Config.enable_type_casting) {
  142. if (leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
  143. if (rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
  144. return leftExpressionType;
  145. }
  146. }
  147. }
  148. return Types.UNDEFINED;
  149. }
  150. }
  151. const resultTable = infixMap.get(operator) || [];
  152. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  153. const resultType = resultTable[leftExpressionType.ord!][rightExpressionType.ord!];
  154. if (resultType === null || resultType === undefined) {
  155. if (Config.enable_type_casting) {
  156. if (leftExpressionType.isCompatible(Types.INTEGER) || leftExpressionType.isCompatible(Types.REAL)) {
  157. if (rightExpressionType.isCompatible(Types.INTEGER) || rightExpressionType.isCompatible(Types.REAL)) {
  158. if (operator === Operators.MOD) {
  159. return Types.INTEGER;
  160. } else if (operator.ord >= 5 && operator.ord <= 10) {
  161. return Types.BOOLEAN;
  162. }
  163. }
  164. }
  165. }
  166. return Types.UNDEFINED
  167. }
  168. return resultType;
  169. } catch (e) {
  170. if (e instanceof TypeError) {
  171. return Types.UNDEFINED;
  172. } else {
  173. throw e;
  174. }
  175. }
  176. }
  177. export function resultTypeAfterUnaryOp (operator: Operator, leftExpressionType: IType): IType {
  178. try {
  179. if (leftExpressionType instanceof MultiType) {
  180. let newMulti = [];
  181. for (let i = 0; i < leftExpressionType.types.length; ++i) {
  182. const type = leftExpressionType.types[i];
  183. newMulti.push(resultTypeAfterUnaryOp(operator, type));
  184. }
  185. newMulti = newMulti.filter(x => !x.isCompatible(Types.UNDEFINED));
  186. if (newMulti.length <= 0) {
  187. return Types.UNDEFINED;
  188. }
  189. return new MultiType(newMulti as Type[]);
  190. }
  191. const resultTable = unaryMap.get(operator) || [];
  192. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  193. const resultType = resultTable[leftExpressionType.ord!];
  194. if (resultType == null) {
  195. return Types.UNDEFINED;
  196. }
  197. return resultType;
  198. } catch (e) {
  199. if (e instanceof TypeError) {
  200. return Types.UNDEFINED;
  201. } else {
  202. throw e;
  203. }
  204. }
  205. }