typechecker/op-rule-manager.spice
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | // Std imports | ||
| 4 | import "std/data/vector"; | ||
| 5 | import "std/data/unordered-map"; | ||
| 6 | import "std/data/pair"; | ||
| 7 | import "std/text/stringstream"; | ||
| 8 | import "std/math/hash"; | ||
| 9 | |||
| 10 | // Own imports | ||
| 11 | import "@/source-file"; | ||
| 12 | import "@/ast/ast-nodes"; | ||
| 13 | import "@/exception/error-manager"; | ||
| 14 | import "@/exception/semantic-error"; | ||
| 15 | import "@/model/function"; | ||
| 16 | import "@/symboltablebuilder/lifecycle"; | ||
| 17 | import "@/symboltablebuilder/qual-type"; | ||
| 18 | import "@/symboltablebuilder/scope"; | ||
| 19 | import "@/symboltablebuilder/super-type"; | ||
| 20 | import "@/symboltablebuilder/symbol-table-entry"; | ||
| 21 | import "@/symboltablebuilder/type"; | ||
| 22 | import "@/symboltablebuilder/type-qualifiers"; | ||
| 23 | import "@/typechecker/expr-result"; | ||
| 24 | import "@/typechecker/function-manager"; | ||
| 25 | import "@/typechecker/type-checker"; | ||
| 26 | import "@/util/custom-hash-functions"; | ||
| 27 | |||
| 28 | // Custom error message prefixes | ||
| 29 | public const string ERROR_MSG_RETURN = "Passed wrong data type to return statement"; | ||
| 30 | public const string ERROR_FOREACH_ITEM = "Passed wrong data type to foreach item"; | ||
| 31 | public const string ERROR_FIELD_ASSIGN = "Given type of the field value does not match declaration"; | ||
| 32 | |||
| 33 | // Unary operator rule: lhs type, result type | ||
| 34 | public type UnaryOpRule struct { | ||
| 35 | public SuperType lhsType | ||
| 36 | public SuperType resultType | ||
| 37 | } | ||
| 38 | |||
| 39 | // Binary operator rule: lhs type, rhs type, result type | ||
| 40 | public type BinaryOpRule struct { | ||
| 41 | public SuperType lhsType | ||
| 42 | public SuperType rhsType | ||
| 43 | public SuperType resultType | ||
| 44 | } | ||
| 45 | |||
| 46 | public type UnaryOpRules alias Vector<UnaryOpRule>; | ||
| 47 | public type BinaryOpRules alias Vector<BinaryOpRule>; | ||
| 48 | |||
| 49 | /** | ||
| 50 | * Helper class for the TypeChecker to check whether certain operator/type combinations are valid or not and which result type | ||
| 51 | * is produced. | ||
| 52 | * | ||
| 53 | * Spice only supports globals of primitive type, so the operator rules are stored in the OpRuleManager and filled once by its | ||
| 54 | * constructor (see initRules). | ||
| 55 | * | ||
| 56 | * Error handling: for invalid operator/type combinations, a soft error is recorded and the unresolved type is returned, which | ||
| 57 | * the visit methods of the TypeChecker propagate. | ||
| 58 | */ | ||
| 59 | 15513 | public type OpRuleManager struct { | |
| 60 | 15850 | TypeChecker* typeChecker = nil<TypeChecker*> | |
| 61 | BinaryOpRules assignOpRules | ||
| 62 | BinaryOpRules plusEqualOpRules | ||
| 63 | BinaryOpRules minusEqualOpRules | ||
| 64 | BinaryOpRules mulEqualOpRules | ||
| 65 | BinaryOpRules divEqualOpRules | ||
| 66 | BinaryOpRules remEqualOpRules | ||
| 67 | BinaryOpRules shlEqualOpRules | ||
| 68 | BinaryOpRules shrEqualOpRules | ||
| 69 | BinaryOpRules andEqualOpRules | ||
| 70 | BinaryOpRules orEqualOpRules | ||
| 71 | BinaryOpRules xorEqualOpRules | ||
| 72 | BinaryOpRules logicalAndOpRules | ||
| 73 | BinaryOpRules logicalOrOpRules | ||
| 74 | BinaryOpRules bitwiseOrOpRules | ||
| 75 | BinaryOpRules bitwiseXorOpRules | ||
| 76 | BinaryOpRules bitwiseAndOpRules | ||
| 77 | BinaryOpRules equalOpRules | ||
| 78 | BinaryOpRules notEqualOpRules | ||
| 79 | BinaryOpRules lessOpRules | ||
| 80 | BinaryOpRules greaterOpRules | ||
| 81 | BinaryOpRules lessEqualOpRules | ||
| 82 | BinaryOpRules greaterEqualOpRules | ||
| 83 | BinaryOpRules shiftLeftOpRules | ||
| 84 | BinaryOpRules shiftRightOpRules | ||
| 85 | BinaryOpRules plusOpRules | ||
| 86 | BinaryOpRules minusOpRules | ||
| 87 | BinaryOpRules mulOpRules | ||
| 88 | BinaryOpRules divOpRules | ||
| 89 | BinaryOpRules remOpRules | ||
| 90 | UnaryOpRules prefixMinusOpRules | ||
| 91 | UnaryOpRules prefixPlusPlusOpRules | ||
| 92 | UnaryOpRules prefixMinusMinusOpRules | ||
| 93 | UnaryOpRules prefixNotOpRules | ||
| 94 | UnaryOpRules prefixBitwiseNotOpRules | ||
| 95 | UnaryOpRules postfixPlusPlusOpRules | ||
| 96 | UnaryOpRules postfixMinusMinusOpRules | ||
| 97 | BinaryOpRules castOpRules | ||
| 98 | } | ||
| 99 | |||
| 100 | // Only default-initializes the field of the TypeChecker, whose ctor replaces it with a manager created by the ctor below. It does | ||
| 101 | // not fill the rule tables, because those would be leaked by that replacement. | ||
| 102 | 15850 | public p OpRuleManager.ctor() {} | |
| 103 | |||
| 104 | 7925 | public p OpRuleManager.ctor(TypeChecker* typeChecker) { | |
| 105 | 7925 | this.typeChecker = typeChecker; | |
| 106 | 7925 | this.initRules(); | |
| 107 | 7925 | } | |
| 108 | |||
| 109 | // Fill the operator rule tables | ||
| 110 | 7925 | p OpRuleManager.initRules() { | |
| 111 | // Assign op rules | ||
| 112 | 7925 | this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double = double -> double | |
| 113 | 7925 | this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int = int -> int | |
| 114 | 7925 | this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short = short -> short | |
| 115 | 7925 | this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long = long -> long | |
| 116 | 7925 | this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte = byte -> byte | |
| 117 | 7925 | this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_CHAR}); // char = char -> char | |
| 118 | 7925 | this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_STRING, SuperType::TY_STRING, SuperType::TY_STRING}); // string = string -> string | |
| 119 | 7925 | this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool = bool -> bool | |
| 120 | |||
| 121 | // Plus equal op rules | ||
| 122 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double += double -> double | |
| 123 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int += int -> int | |
| 124 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int += short -> int | |
| 125 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int += long -> int | |
| 126 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short += int -> short | |
| 127 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short += short -> short | |
| 128 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short += long -> short | |
| 129 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long += int -> long | |
| 130 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long += short -> long | |
| 131 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long += long -> long | |
| 132 | 7925 | this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_CHAR}); // char += int -> char | |
| 133 | |||
| 134 | // Minus equal op rules | ||
| 135 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double -= double -> double | |
| 136 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int -= int -> int | |
| 137 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int -= short -> int | |
| 138 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int -= long -> int | |
| 139 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short -= int -> short | |
| 140 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short -= short -> short | |
| 141 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short -= long -> short | |
| 142 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long -= int -> long | |
| 143 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long -= short -> long | |
| 144 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long -= long -> long | |
| 145 | 7925 | this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_CHAR}); // char -= int -> char | |
| 146 | |||
| 147 | // Mul equal op rules | ||
| 148 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double *= double -> double | |
| 149 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int *= int -> int | |
| 150 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int *= short -> int | |
| 151 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int *= long -> int | |
| 152 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short *= int -> short | |
| 153 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short *= short -> short | |
| 154 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short *= long -> short | |
| 155 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long *= int -> long | |
| 156 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long *= short -> long | |
| 157 | 7925 | this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long *= long -> long | |
| 158 | |||
| 159 | // Div equal op rules | ||
| 160 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double /= double -> double | |
| 161 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int /= int -> int | |
| 162 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int /= short -> int | |
| 163 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int /= long -> int | |
| 164 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short /= int -> short | |
| 165 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short /= short -> short | |
| 166 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short /= long -> short | |
| 167 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long /= int -> long | |
| 168 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long /= short -> long | |
| 169 | 7925 | this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long /= long -> long | |
| 170 | |||
| 171 | // Rem equal op rules | ||
| 172 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double %= double -> double | |
| 173 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int %= int -> int | |
| 174 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int %= short -> int | |
| 175 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int %= long -> int | |
| 176 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short %= int -> short | |
| 177 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short %= short -> short | |
| 178 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short %= long -> short | |
| 179 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long %= int -> long | |
| 180 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long %= short -> long | |
| 181 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long %= long -> long | |
| 182 | 7925 | this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte %= byte -> byte | |
| 183 | |||
| 184 | // Shl equal op rules | ||
| 185 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int <<= int -> int | |
| 186 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int <<= short -> int | |
| 187 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int <<= long -> int | |
| 188 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short <<= int -> short | |
| 189 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short <<= short -> short | |
| 190 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short <<= long -> short | |
| 191 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long <<= int -> long | |
| 192 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long <<= short -> long | |
| 193 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long <<= long -> long | |
| 194 | 7925 | this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte <<= byte -> byte | |
| 195 | |||
| 196 | // Shr equal op rules | ||
| 197 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int >>= int -> int | |
| 198 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int >>= short -> int | |
| 199 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int >>= long -> int | |
| 200 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short >>= int -> short | |
| 201 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short >>= short -> short | |
| 202 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short >>= long -> short | |
| 203 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long >>= int -> long | |
| 204 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long >>= short -> long | |
| 205 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long >>= long -> long | |
| 206 | 7925 | this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte >>= byte -> byte | |
| 207 | |||
| 208 | // And equal op rules | ||
| 209 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int &= int -> int | |
| 210 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int &= short -> int | |
| 211 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int &= long -> int | |
| 212 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short &= int -> short | |
| 213 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short &= short -> short | |
| 214 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short &= long -> short | |
| 215 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long &= int -> long | |
| 216 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long &= short -> long | |
| 217 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long &= long -> long | |
| 218 | 7925 | this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte &= byte -> byte | |
| 219 | |||
| 220 | // Or equal op rules | ||
| 221 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int |= int -> int | |
| 222 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int |= short -> int | |
| 223 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int |= long -> int | |
| 224 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short |= int -> short | |
| 225 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short |= short -> short | |
| 226 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short |= long -> short | |
| 227 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long |= int -> long | |
| 228 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long |= short -> long | |
| 229 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long |= long -> long | |
| 230 | 7925 | this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte |= byte -> byte | |
| 231 | |||
| 232 | // Xor equal op rules | ||
| 233 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int ^= int -> int | |
| 234 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int ^= short -> int | |
| 235 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int ^= long -> int | |
| 236 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short ^= int -> short | |
| 237 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short ^= short -> short | |
| 238 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short ^= long -> short | |
| 239 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long ^= int -> long | |
| 240 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long ^= short -> long | |
| 241 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long ^= long -> long | |
| 242 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte ^= byte -> byte | |
| 243 | 7925 | this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_CHAR}); // char ^= char -> char | |
| 244 | |||
| 245 | // Logical and op rules | ||
| 246 | 7925 | this.logicalAndOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool && bool -> bool | |
| 247 | |||
| 248 | // Logical or op rules | ||
| 249 | 7925 | this.logicalOrOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool || bool -> bool | |
| 250 | |||
| 251 | // Bitwise or op rules | ||
| 252 | 7925 | this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int | int -> int | |
| 253 | 7925 | this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short | short -> short | |
| 254 | 7925 | this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long | long -> long | |
| 255 | 7925 | this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte | byte -> byte | |
| 256 | 7925 | this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool | bool -> bool | |
| 257 | |||
| 258 | // Bitwise xor op rules | ||
| 259 | 7925 | this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int ^ int -> int | |
| 260 | 7925 | this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short ^ short -> short | |
| 261 | 7925 | this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long ^ long -> long | |
| 262 | 7925 | this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte ^ byte -> byte | |
| 263 | 7925 | this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool ^ bool -> bool | |
| 264 | |||
| 265 | // Bitwise and op rules | ||
| 266 | 7925 | this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int & int -> int | |
| 267 | 7925 | this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short & short -> short | |
| 268 | 7925 | this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long & long -> long | |
| 269 | 7925 | this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte & byte -> byte | |
| 270 | 7925 | this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool & bool -> bool | |
| 271 | |||
| 272 | // Equal op rules | ||
| 273 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double == double -> bool | |
| 274 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double == int -> bool | |
| 275 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double == short -> bool | |
| 276 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double == long -> bool | |
| 277 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int == double -> bool | |
| 278 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int == int -> bool | |
| 279 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int == short -> bool | |
| 280 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int == long -> bool | |
| 281 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_CHAR, SuperType::TY_BOOL}); // int == char -> bool | |
| 282 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short == double -> bool | |
| 283 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short == int -> bool | |
| 284 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short == short -> bool | |
| 285 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short == long -> bool | |
| 286 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_CHAR, SuperType::TY_BOOL}); // short == char -> bool | |
| 287 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long == double -> bool | |
| 288 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long == int -> bool | |
| 289 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long == short -> bool | |
| 290 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long == long -> bool | |
| 291 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_CHAR, SuperType::TY_BOOL}); // long == char -> bool | |
| 292 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte == byte -> bool | |
| 293 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_BOOL}); // char == int -> bool | |
| 294 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_SHORT, SuperType::TY_BOOL}); // char == short -> bool | |
| 295 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_LONG, SuperType::TY_BOOL}); // char == long -> bool | |
| 296 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char == char -> bool | |
| 297 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_STRING, SuperType::TY_STRING, SuperType::TY_BOOL}); // string == string -> bool | |
| 298 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool == bool -> bool | |
| 299 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_FUNCTION, SuperType::TY_FUNCTION, SuperType::TY_BOOL}); // function == function -> bool | |
| 300 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_PROCEDURE, SuperType::TY_PROCEDURE, SuperType::TY_BOOL}); // procedure == procedure -> bool | |
| 301 | 7925 | this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* == any* -> bool | |
| 302 | |||
| 303 | // Not equal op rules | ||
| 304 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double != double -> bool | |
| 305 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double != int -> bool | |
| 306 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double != short -> bool | |
| 307 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double != long -> bool | |
| 308 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int != double -> bool | |
| 309 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int != int -> bool | |
| 310 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int != short -> bool | |
| 311 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int != long -> bool | |
| 312 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_CHAR, SuperType::TY_BOOL}); // int != char -> bool | |
| 313 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short != double -> bool | |
| 314 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short != int -> bool | |
| 315 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short != short -> bool | |
| 316 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short != long -> bool | |
| 317 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_CHAR, SuperType::TY_BOOL}); // short != char -> bool | |
| 318 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long != double -> bool | |
| 319 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long != int -> bool | |
| 320 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long != short -> bool | |
| 321 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long != long -> bool | |
| 322 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_CHAR, SuperType::TY_BOOL}); // long != char -> bool | |
| 323 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte != byte -> bool | |
| 324 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_BOOL}); // char != int -> bool | |
| 325 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_SHORT, SuperType::TY_BOOL}); // char != short -> bool | |
| 326 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_LONG, SuperType::TY_BOOL}); // char != long -> bool | |
| 327 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char != char -> bool | |
| 328 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_STRING, SuperType::TY_STRING, SuperType::TY_BOOL}); // string != string -> bool | |
| 329 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool != bool -> bool | |
| 330 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_FUNCTION, SuperType::TY_FUNCTION, SuperType::TY_BOOL}); // function != function -> bool | |
| 331 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_PROCEDURE, SuperType::TY_PROCEDURE, SuperType::TY_BOOL}); // procedure != procedure -> bool | |
| 332 | 7925 | this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* != any* -> bool | |
| 333 | |||
| 334 | // Less op rules | ||
| 335 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double < double -> bool | |
| 336 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double < int -> bool | |
| 337 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double < short -> bool | |
| 338 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double < long -> bool | |
| 339 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int < double -> bool | |
| 340 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int < int -> bool | |
| 341 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int < short -> bool | |
| 342 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int < long -> bool | |
| 343 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short < double -> bool | |
| 344 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short < int -> bool | |
| 345 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short < short -> bool | |
| 346 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short < long -> bool | |
| 347 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long < double -> bool | |
| 348 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long < int -> bool | |
| 349 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long < short -> bool | |
| 350 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long < long -> bool | |
| 351 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte < byte -> bool | |
| 352 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char < char -> bool | |
| 353 | 7925 | this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* < any* -> bool | |
| 354 | |||
| 355 | // Greater op rules | ||
| 356 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double > double -> bool | |
| 357 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double > int -> bool | |
| 358 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double > short -> bool | |
| 359 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double > long -> bool | |
| 360 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int > double -> bool | |
| 361 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int > int -> bool | |
| 362 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int > short -> bool | |
| 363 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int > long -> bool | |
| 364 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short > double -> bool | |
| 365 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short > int -> bool | |
| 366 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short > short -> bool | |
| 367 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short > long -> bool | |
| 368 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long > double -> bool | |
| 369 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long > int -> bool | |
| 370 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long > short -> bool | |
| 371 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long > long -> bool | |
| 372 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte > byte -> bool | |
| 373 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char > char -> bool | |
| 374 | 7925 | this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* > any* -> bool | |
| 375 | |||
| 376 | // Less equal op rules | ||
| 377 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double <= double -> bool | |
| 378 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double <= int -> bool | |
| 379 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double <= short -> bool | |
| 380 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double <= long -> bool | |
| 381 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int <= double -> bool | |
| 382 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int <= int -> bool | |
| 383 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int <= short -> bool | |
| 384 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int <= long -> bool | |
| 385 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short <= double -> bool | |
| 386 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short <= int -> bool | |
| 387 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short <= short -> bool | |
| 388 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short <= long -> bool | |
| 389 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long <= double -> bool | |
| 390 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long <= int -> bool | |
| 391 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long <= short -> bool | |
| 392 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long <= long -> bool | |
| 393 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte <= byte -> bool | |
| 394 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char <= char -> bool | |
| 395 | 7925 | this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* <= any* -> bool | |
| 396 | |||
| 397 | // Greater equal op rules | ||
| 398 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double >= double -> bool | |
| 399 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double >= int -> bool | |
| 400 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double >= short -> bool | |
| 401 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double >= long -> bool | |
| 402 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int >= double -> bool | |
| 403 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int >= int -> bool | |
| 404 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int >= short -> bool | |
| 405 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int >= long -> bool | |
| 406 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short >= double -> bool | |
| 407 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short >= int -> bool | |
| 408 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short >= short -> bool | |
| 409 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short >= long -> bool | |
| 410 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long >= double -> bool | |
| 411 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long >= int -> bool | |
| 412 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long >= short -> bool | |
| 413 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long >= long -> bool | |
| 414 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte >= byte -> bool | |
| 415 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char >= char -> bool | |
| 416 | 7925 | this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* >= any* -> bool | |
| 417 | |||
| 418 | // Shift left op rules | ||
| 419 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int << int -> int | |
| 420 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int << short -> int | |
| 421 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int << long -> int | |
| 422 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short << int -> short | |
| 423 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short << short -> short | |
| 424 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short << long -> short | |
| 425 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long << int -> long | |
| 426 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long << short -> long | |
| 427 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long << long -> long | |
| 428 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_INT, SuperType::TY_BYTE}); // byte << int -> byte | |
| 429 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_SHORT, SuperType::TY_BYTE}); // byte << short -> byte | |
| 430 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_LONG, SuperType::TY_BYTE}); // byte << long -> byte | |
| 431 | 7925 | this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte << byte -> byte | |
| 432 | |||
| 433 | // Shift right op rules | ||
| 434 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int >> int -> int | |
| 435 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int >> short -> int | |
| 436 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int >> long -> int | |
| 437 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short >> int -> short | |
| 438 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short >> short -> short | |
| 439 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short >> long -> short | |
| 440 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long >> int -> long | |
| 441 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long >> short -> long | |
| 442 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long >> long -> long | |
| 443 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_INT, SuperType::TY_BYTE}); // byte >> int -> byte | |
| 444 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_SHORT, SuperType::TY_BYTE}); // byte >> short -> byte | |
| 445 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_LONG, SuperType::TY_BYTE}); // byte >> long -> byte | |
| 446 | 7925 | this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte >> byte -> byte | |
| 447 | |||
| 448 | // Plus op rules | ||
| 449 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double + double -> double | |
| 450 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // double + int -> double | |
| 451 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // double + short -> double | |
| 452 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // double + long -> double | |
| 453 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // int + double -> double | |
| 454 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int + int -> int | |
| 455 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int + short -> int | |
| 456 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int + long -> long | |
| 457 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // short + double -> double | |
| 458 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short + int -> int | |
| 459 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short + short -> short | |
| 460 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short + long -> long | |
| 461 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // long + double -> double | |
| 462 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long + int -> long | |
| 463 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long + short -> long | |
| 464 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long + long -> long | |
| 465 | 7925 | this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte + byte -> byte | |
| 466 | |||
| 467 | // Minus op rules | ||
| 468 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double - double -> double | |
| 469 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // double - int -> double | |
| 470 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // double - short -> double | |
| 471 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // double - long -> double | |
| 472 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // int - double -> double | |
| 473 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int - int -> int | |
| 474 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int - short -> int | |
| 475 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int - long -> long | |
| 476 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // short - double -> double | |
| 477 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short - int -> int | |
| 478 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short - short -> short | |
| 479 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short - long -> long | |
| 480 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // long - double -> double | |
| 481 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long - int -> long | |
| 482 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long - short -> long | |
| 483 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long - long -> long | |
| 484 | 7925 | this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte - byte -> byte | |
| 485 | |||
| 486 | // Mul op rules | ||
| 487 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double * double -> double | |
| 488 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // double * int -> double | |
| 489 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // double * short -> double | |
| 490 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // double * long -> double | |
| 491 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // int * double -> double | |
| 492 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int * int -> int | |
| 493 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int * short -> int | |
| 494 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int * long -> long | |
| 495 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // short * double -> double | |
| 496 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short * int -> int | |
| 497 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short * short -> short | |
| 498 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short * long -> long | |
| 499 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // long * double -> double | |
| 500 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long * int -> long | |
| 501 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long * short -> long | |
| 502 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long * long -> long | |
| 503 | 7925 | this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte * byte -> byte | |
| 504 | |||
| 505 | // Div op rules | ||
| 506 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double / double -> double | |
| 507 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // double / int -> double | |
| 508 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // double / short -> double | |
| 509 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // double / long -> double | |
| 510 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // int / double -> double | |
| 511 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int / int -> int | |
| 512 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int / short -> int | |
| 513 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int / long -> long | |
| 514 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // short / double -> double | |
| 515 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short / int -> int | |
| 516 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short / short -> short | |
| 517 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short / long -> long | |
| 518 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // long / double -> double | |
| 519 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long / int -> long | |
| 520 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long / short -> long | |
| 521 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long / long -> long | |
| 522 | 7925 | this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte / byte -> byte | |
| 523 | |||
| 524 | // Rem op rules | ||
| 525 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double % double -> double | |
| 526 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int % int -> int | |
| 527 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int % short -> int | |
| 528 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int % long -> long | |
| 529 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short % int -> int | |
| 530 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short % short -> short | |
| 531 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short % long -> long | |
| 532 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long % int -> long | |
| 533 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long % short -> long | |
| 534 | 7925 | this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long % long -> long | |
| 535 | |||
| 536 | // Prefix Minus op rules | ||
| 537 | 7925 | this.prefixMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // -double -> double | |
| 538 | 7925 | this.prefixMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // -int -> int | |
| 539 | 7925 | this.prefixMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // -short -> short | |
| 540 | 7925 | this.prefixMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // -long -> long | |
| 541 | |||
| 542 | // Prefix Plus-Plus op rules | ||
| 543 | 7925 | this.prefixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // int++ -> int | |
| 544 | 7925 | this.prefixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // short++ -> short | |
| 545 | 7925 | this.prefixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // long++ -> long | |
| 546 | |||
| 547 | // Prefix Minus-Minus op rules | ||
| 548 | 7925 | this.prefixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // in-- -> int | |
| 549 | 7925 | this.prefixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // short-- -> short | |
| 550 | 7925 | this.prefixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // long-- -> long | |
| 551 | |||
| 552 | // Prefix not op rules | ||
| 553 | 7925 | this.prefixNotOpRules.pushBack(UnaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL}); // !bool -> bool | |
| 554 | |||
| 555 | // Prefix bitwise not op rules | ||
| 556 | 7925 | this.prefixBitwiseNotOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // ~int -> int | |
| 557 | 7925 | this.prefixBitwiseNotOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // ~short -> short | |
| 558 | 7925 | this.prefixBitwiseNotOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // ~long -> long | |
| 559 | 7925 | this.prefixBitwiseNotOpRules.pushBack(UnaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE}); // ~byte -> byte | |
| 560 | |||
| 561 | // Postfix Plus-Plus op rules | ||
| 562 | 7925 | this.postfixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // int++ -> int | |
| 563 | 7925 | this.postfixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // short++ -> short | |
| 564 | 7925 | this.postfixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // long++ -> long | |
| 565 | |||
| 566 | // Postfix Minus-Minus op rules | ||
| 567 | 7925 | this.postfixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // int++ -> int | |
| 568 | 7925 | this.postfixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // short++ -> short | |
| 569 | 7925 | this.postfixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // long++ -> long | |
| 570 | |||
| 571 | // Cast op rules | ||
| 572 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // cast<double>(double) -> double | |
| 573 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // cast<double>(int) -> double | |
| 574 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // cast<double>(short) -> double | |
| 575 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // cast<double>(long) -> double | |
| 576 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_INT}); // cast<int>(double) -> int | |
| 577 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // cast<int>(int) -> int | |
| 578 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // cast<int>(short) -> int | |
| 579 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // cast<int>(long) -> int | |
| 580 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_BYTE, SuperType::TY_INT}); // cast<int>(byte) -> int | |
| 581 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_CHAR, SuperType::TY_INT}); // cast<int>(char) -> int | |
| 582 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_BOOL, SuperType::TY_INT}); // cast<int>(bool) -> int | |
| 583 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_SHORT}); // cast<short>(double) -> short | |
| 584 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // cast<short>(int) -> short | |
| 585 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // cast<short>(short) -> short | |
| 586 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // cast<short>(long) -> short | |
| 587 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_BOOL, SuperType::TY_SHORT}); // cast<short>(bool) -> short | |
| 588 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_LONG}); // cast<long>(double) -> long | |
| 589 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // cast<long>(int) -> long | |
| 590 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // cast<long>(short) -> long | |
| 591 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // cast<long>(long) -> long | |
| 592 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_BOOL, SuperType::TY_LONG}); // cast<long>(bool) -> long | |
| 593 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_INT, SuperType::TY_BYTE}); // cast<byte>(int) -> byte | |
| 594 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // cast<byte>(byte) -> byte | |
| 595 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_CHAR, SuperType::TY_BYTE}); // cast<byte>(char) -> byte | |
| 596 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BOOL, SuperType::TY_BYTE}); // cast<byte>(bool) -> byte | |
| 597 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_CHAR}); // cast<char>(int) -> char | |
| 598 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_SHORT, SuperType::TY_CHAR}); // cast<char>(short) -> char | |
| 599 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_LONG, SuperType::TY_CHAR}); // cast<char>(long) -> char | |
| 600 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_BYTE, SuperType::TY_CHAR}); // cast<char>(byte) -> char | |
| 601 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_CHAR}); // cast<char>(char) -> char | |
| 602 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_STRING, SuperType::TY_STRING, SuperType::TY_STRING}); // cast<string>(string) -> string | |
| 603 | 7925 | this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // cast<bool>(bool) -> bool | |
| 604 | 7925 | } | |
| 605 | |||
| 606 | // Build an expression result without symbol table entry | ||
| 607 | 169469 | f<ExprResult> toExprResult(const QualType& qualType) { | |
| 608 | 169469 | return ExprResult{qualType, nil<SymbolTableEntry*>}; | |
| 609 | } | ||
| 610 | |||
| 611 | // Operand list for the overload lookup of a binary operator | ||
| 612 | 73129 | f<Vector<ExprResult>> binaryOperands(const ExprResult& lhs, const ExprResult& rhs) { | |
| 613 | 73129 | Vector<ExprResult> operands; | |
| 614 | 73129 | operands.pushBack(lhs); | |
| 615 | 73129 | operands.pushBack(rhs); | |
| 616 | 73129 | return operands; | |
| 617 | } | ||
| 618 | |||
| 619 | // Operand list for the overload lookup of a unary operator | ||
| 620 | 9338 | f<Vector<ExprResult>> unaryOperand(const ExprResult& lhs) { | |
| 621 | 9338 | Vector<ExprResult> operands; | |
| 622 | 9338 | operands.pushBack(lhs); | |
| 623 | 9338 | return operands; | |
| 624 | } | ||
| 625 | |||
| 626 | // Result of an assignment: the result type and the called copy ctor | ||
| 627 | 110673 | f<Pair<QualType, Function*>> assignResult(const QualType& qualType, Function* copyCtor = nil<Function*>) { | |
| 628 | 110673 | return Pair<QualType, Function*>(qualType, copyCtor); | |
| 629 | } | ||
| 630 | |||
| 631 | 106554 | public f<Pair<QualType, Function*>> OpRuleManager.getAssignResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, bool isDecl = false, bool isReturn = false, string errMsgPrefix = "") { | |
| 632 | // Retrieve types | ||
| 633 | 106554 | const QualType lhsType = lhs.ty; | |
| 634 | 106554 | const QualType rhsType = rhs.ty; | |
| 635 | |||
| 636 | // Check if lhs is a temporary | ||
| 637 | 106554 | if lhs.isTemporary() { | |
| 638 | 1 | throwSemanticError(node, SemanticErrorType::OPERATOR_WRONG_DATA_TYPE, String("Cannot assign to a temporary value")); | |
| 639 | 2 | return assignResult(QualType(SuperType::TY_UNRESOLVED)); | |
| 640 | 1 | } | |
| 641 | |||
| 642 | // Skip type compatibility check if the lhs is of type dyn -> perform type inference | ||
| 643 | 106553 | if lhsType.is(SuperType::TY_DYN) { | |
| 644 | 283 | return assignResult(rhsType); | |
| 645 | } | ||
| 646 | |||
| 647 | // Check if we try to assign a constant value | ||
| 648 | 106270 | this.ensureNoConstAssign(node, lhsType, isDecl, isReturn); | |
| 649 | |||
| 650 | // Allow pointers and references of the same type straight away | ||
| 651 | 106270 | const dyn ptrOrRefTypes = [SuperType::TY_PTR, SuperType::TY_REF]; | |
| 652 | 106270 | if lhsType.isOneOf(ptrOrRefTypes, len(ptrOrRefTypes)) && lhsType.matches(rhsType, false, false, true) { | |
| 653 | // If we perform a heap x* = heap x* assignment, we need set the right hand side to MOVED | ||
| 654 | 13976 | const QualType rhsUnwrappedType = rhsType.removeReferenceWrapper(); | |
| 655 | 13976 | if rhs.entry != nil<SymbolTableEntry*> && lhsType.isPtr() && lhsType.isHeap() && rhsUnwrappedType.isPtr() && rhsType.isHeap() { | |
| 656 | 1859 | rhs.entry.updateState(LifecycleState::MOVED); | |
| 657 | 1859 | } | |
| 658 | 13976 | return assignResult(rhsType); | |
| 659 | } | ||
| 660 | // Allow ref type to type of the same contained type straight away | ||
| 661 | 92294 | if rhsType.isRef() { | |
| 662 | // If this is const ref, remove both: the reference and the constness | ||
| 663 | 2178 | const QualType rhsContainedType = rhsType.getContained(); | |
| 664 | 2178 | const QualType rhsNonRef = rhsContainedType.toNonConst(); | |
| 665 | 2178 | if lhsType.matches(rhsNonRef, false, false, true) { | |
| 666 | 2172 | if rhsNonRef.is(SuperType::TY_STRUCT) { | |
| 667 | 1020 | return this.performStructAssign(node, lhs, rhs, rhsNonRef, isDecl, isReturn); | |
| 668 | } | ||
| 669 | 1152 | return assignResult(lhsType); | |
| 670 | } | ||
| 671 | 6 | } | |
| 672 | // Allow arrays, unions, interfaces, functions, procedures of the same type straight away | ||
| 673 | 90122 | const dyn directlyAssignableTypes = [SuperType::TY_ARRAY, SuperType::TY_UNION, SuperType::TY_INTERFACE, SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE]; | |
| 674 | 90122 | if lhsType.isOneOf(directlyAssignableTypes, len(directlyAssignableTypes)) && lhsType.matches(rhsType, false, true, true) { | |
| 675 | 522 | return assignResult(rhsType); | |
| 676 | } | ||
| 677 | // Allow struct of the same type straight away | ||
| 678 | 89600 | if lhsType.is(SuperType::TY_STRUCT) && lhsType.matches(rhsType, false, true, true) { | |
| 679 | 10972 | return this.performStructAssign(node, lhs, rhs, rhsType, isDecl, isReturn); | |
| 680 | } | ||
| 681 | // Allow assignment through an already-bound reference to a struct. Unlike binding a reference (declaration/return, | ||
| 682 | // which pass isDecl/isReturn and fall through to the common rules below), an assign-through must run the struct's | ||
| 683 | // copy-assignment operator / copy ctor on the referenced value instead of rebinding or shallow-copying it. Otherwise | ||
| 684 | // the referent would alias the rhs' owned members (heap buffers) and double-free once one of them is destructed. | ||
| 685 | 78628 | if !isDecl && !isReturn && lhsType.isRef() { | |
| 686 | 482 | const QualType lhsContainedType = lhsType.getContained(); | |
| 687 | 482 | const QualType rhsUnwrappedType = rhsType.removeReferenceWrapper(); | |
| 688 | 482 | if lhsContainedType.is(SuperType::TY_STRUCT) && lhs.entry != nil<SymbolTableEntry*> && lhs.entry.isInitialized() && lhsContainedType.matches(rhsUnwrappedType, false, true, true) { | |
| 689 | 51 | return this.performStructAssign(node, lhs, rhs, lhsContainedType, isDecl, isReturn); | |
| 690 | } | ||
| 691 | 431 | } | |
| 692 | |||
| 693 | // Check common type combinations | ||
| 694 | 78577 | const QualType resultType = this.getAssignResultTypeCommon(node, lhs, rhs, isDecl, isReturn); | |
| 695 | 78577 | if !resultType.is(SuperType::TY_INVALID) { | |
| 696 | 3694 | return assignResult(resultType); | |
| 697 | } | ||
| 698 | |||
| 699 | // An assignment through an already-bound reference assigns the referenced value, so it follows the rules for assigning to | ||
| 700 | // the referenced type. E.g. the value of a const source can be copied into a non-const referent. | ||
| 701 | 74883 | if !isDecl && !isReturn && lhsType.isRef() { | |
| 702 | 6 | const ExprResult referencedLhs = ExprResult{lhsType.getContained(), lhs.entry}; | |
| 703 | 6 | const Pair<QualType, Function*> referencedResult = this.getAssignResultType(node, referencedLhs, rhs, false, false, errMsgPrefix); | |
| 704 | 6 | const QualType referencedResultType = referencedResult.getFirst(); | |
| 705 | 6 | if referencedResultType.is(SuperType::TY_UNRESOLVED) { | |
| 706 | 1 | return referencedResult; | |
| 707 | } | ||
| 708 | 5 | return assignResult(lhsType, referencedResult.getSecond()); | |
| 709 | } | ||
| 710 | |||
| 711 | // Check primitive type combinations | ||
| 712 | 74877 | const QualType binOpType = this.validateBinaryOperation(node, this.assignOpRules, "=", lhsType, rhsType, true, errMsgPrefix); | |
| 713 | 74877 | return assignResult(binOpType); | |
| 714 | } | ||
| 715 | |||
| 716 | 4120 | public f<Pair<QualType, Function*>> OpRuleManager.getFieldAssignResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, bool imm, bool isDecl = false) { | |
| 717 | // Retrieve types | ||
| 718 | 4120 | const QualType lhsType = lhs.ty; | |
| 719 | 4120 | const QualType rhsType = rhs.ty; | |
| 720 | 4120 | assert !lhsType.is(SuperType::TY_DYN); | |
| 721 | |||
| 722 | // Check if we try to assign a constant value | ||
| 723 | 4120 | this.ensureNoConstAssign(node, lhsType, isDecl, false); | |
| 724 | |||
| 725 | // Allow pointers and arrays of the same type straight away | ||
| 726 | 4120 | const dyn ptrOrArrayTypes = [SuperType::TY_PTR, SuperType::TY_ARRAY]; | |
| 727 | 4120 | if lhsType.isOneOf(ptrOrArrayTypes, len(ptrOrArrayTypes)) && lhsType == rhsType { | |
| 728 | // If we perform a heap x* = heap x* assignment, we need set the right hand side to MOVED | ||
| 729 | 746 | const QualType rhsUnwrappedType = rhsType.removeReferenceWrapper(); | |
| 730 | 746 | if rhs.entry != nil<SymbolTableEntry*> && lhsType.isPtr() && lhsType.isHeap() && rhsUnwrappedType.isPtr() && rhsType.isHeap() { | |
| 731 | ✗ | rhs.entry.updateState(LifecycleState::MOVED); | |
| 732 | ✗ | } | |
| 733 | 746 | return assignResult(rhsType); | |
| 734 | } | ||
| 735 | // Allow struct of the same type straight away | ||
| 736 | 3374 | if lhsType.is(SuperType::TY_STRUCT) && lhsType.matches(rhsType, false, true, true) { | |
| 737 | 75 | return this.performStructAssign(node, lhs, rhs, rhsType, isDecl, false); | |
| 738 | } | ||
| 739 | // Allow union of the same type straight away (always trivially copyable, so no copy-ctor machinery is needed) | ||
| 740 | 3299 | if lhsType.is(SuperType::TY_UNION) && lhsType.matches(rhsType, false, true, true) { | |
| 741 | ✗ | return assignResult(rhsType); | |
| 742 | } | ||
| 743 | // Allow ref type to type of the same contained type straight away | ||
| 744 | 3299 | if rhsType.isRef() { | |
| 745 | 19 | const QualType rhsContainedType = rhsType.getContained(); | |
| 746 | 19 | if lhsType.matches(rhsContainedType, false, false, true) { | |
| 747 | // Initializing a field constructs a new value, so we copy via the copy ctor instead of calling an overloaded | ||
| 748 | // assign operator. The rhs may have no entry (e.g. a function call returning a reference), so go by type | ||
| 749 | 6 | Function* copyCtor = nil<Function*>; | |
| 750 | 6 | const QualType rhsContainedNonConstType = rhsContainedType.toNonConst(); | |
| 751 | 6 | if rhsContainedNonConstType.is(SuperType::TY_STRUCT) && !rhs.isTemporary() { | |
| 752 | 1 | copyCtor = this.typeChecker.implicitlyCallStructCopyCtor(rhsContainedNonConstType, node); | |
| 753 | 1 | } | |
| 754 | 6 | return assignResult(lhsType, copyCtor); | |
| 755 | } | ||
| 756 | 13 | } | |
| 757 | // Allow ref type to type of the same contained type straight away | ||
| 758 | 3293 | if rhsType.isRef() { | |
| 759 | // If this is const ref, remove both: the reference and the constness | ||
| 760 | 13 | const QualType rhsContainedType = rhsType.getContained(); | |
| 761 | 13 | const QualType rhsNonRef = rhsContainedType.toNonConst(); | |
| 762 | 13 | if lhsType.matches(rhsNonRef, false, false, true) { | |
| 763 | 13 | return this.performStructAssign(node, lhs, rhs, rhsNonRef, isDecl, false); | |
| 764 | } | ||
| 765 | ✗ | } | |
| 766 | // Allow immediate value to const ref of the same contained type straight away | ||
| 767 | 3280 | if lhsType.isConstRef() && imm { | |
| 768 | 2 | return assignResult(rhsType); | |
| 769 | } | ||
| 770 | |||
| 771 | // Check common type combinations | ||
| 772 | 3278 | const QualType resultType = this.getAssignResultTypeCommon(node, lhs, rhs, isDecl, false); | |
| 773 | 3278 | if !resultType.is(SuperType::TY_INVALID) { | |
| 774 | 9 | return assignResult(resultType); | |
| 775 | } | ||
| 776 | |||
| 777 | // Check primitive type combinations | ||
| 778 | 3269 | const QualType binOpType = this.validateBinaryOperation(node, this.assignOpRules, "=", lhsType, rhsType, true, ERROR_FIELD_ASSIGN); | |
| 779 | 3269 | return assignResult(binOpType); | |
| 780 | } | ||
| 781 | |||
| 782 | 81855 | f<QualType> OpRuleManager.getAssignResultTypeCommon(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, bool isDecl, bool isReturn) { | |
| 783 | // Retrieve types | ||
| 784 | 81855 | const QualType lhsType = lhs.ty; | |
| 785 | 81855 | const QualType rhsType = rhs.ty; | |
| 786 | |||
| 787 | // Allow type to ref type of the same contained type straight away | ||
| 788 | 81855 | if lhsType.isRef() { | |
| 789 | 2978 | const QualType lhsContainedType = lhsType.getContained(); | |
| 790 | 2978 | if lhsContainedType.matches(rhsType, false, false, true) { | |
| 791 | 2961 | const bool isDeclOrReturn = isDecl || isReturn; | |
| 792 | 2961 | if isDeclOrReturn && !lhsType.canBind(rhsType, rhs.isTemporary()) { | |
| 793 | 2 | throwSemanticError(node, SemanticErrorType::TEMP_TO_NON_CONST_REF, String("Temporary values can only be bound to const reference variables/fields")); | |
| 794 | 4 | return QualType(SuperType::TY_UNRESOLVED); | |
| 795 | 2 | } | |
| 796 | 2959 | if isReturn && rhs.isTemporary() { | |
| 797 | 1 | throwSemanticError(node, SemanticErrorType::RETURN_OF_TEMPORARY_VALUE, String("Cannot return reference to temporary value")); | |
| 798 | 2 | return QualType(SuperType::TY_UNRESOLVED); | |
| 799 | 1 | } | |
| 800 | 2958 | return lhsType; | |
| 801 | } | ||
| 802 | 17 | } | |
| 803 | // Allow char* = string | ||
| 804 | 78894 | if lhsType.isPtrTo(SuperType::TY_CHAR) && rhsType.is(SuperType::TY_STRING) && lhsType.qualifiers == rhsType.qualifiers { | |
| 805 | 1 | return lhsType; | |
| 806 | } | ||
| 807 | // Allow array to pointer | ||
| 808 | 78893 | if lhsType.isPtr() && rhsType.isArray() { | |
| 809 | 12 | const QualType lhsContainedType = lhsType.getContained(); | |
| 810 | 12 | const QualType rhsContainedType = rhsType.getContained(); | |
| 811 | 12 | if lhsContainedType.matches(rhsContainedType, false, false, true) { | |
| 812 | 12 | return lhsType; | |
| 813 | } | ||
| 814 | ✗ | } | |
| 815 | // Allow interface* = struct* or interface& = struct that implements this interface | ||
| 816 | 78881 | const bool sameChainDepth = hasSameTypeChainDepth(lhsType.getType(), rhsType.getType()); | |
| 817 | 78881 | const bool typesCompatible = (lhsType.isPtr() && rhsType.isPtr() && sameChainDepth) || lhsType.isRef(); | |
| 818 | 78881 | if typesCompatible && lhsType.isBase(SuperType::TY_INTERFACE) && rhsType.isBase(SuperType::TY_STRUCT) { | |
| 819 | 25 | QualType lhsTypeCopy = lhsType; | |
| 820 | 25 | QualType rhsTypeCopy = rhsType; | |
| 821 | 25 | unwrapBothWithRefWrappers(lhsTypeCopy, rhsTypeCopy); | |
| 822 | 25 | if lhsTypeCopy.matchesInterfaceImplementedByStruct(rhsTypeCopy) { | |
| 823 | 25 | return lhsType; | |
| 824 | } | ||
| 825 | ✗ | } | |
| 826 | // Allow type* = heap type* straight away. This is used for initializing non-owning pointers to heap allocations | ||
| 827 | 78856 | if lhsType.isPtr() && rhsType.isHeap() && lhsType.matches(rhsType, false, true, true) { | |
| 828 | 704 | TypeQualifiers rhsQualifiers = rhsType.qualifiers; | |
| 829 | 704 | rhsQualifiers.isHeap = false; | |
| 830 | 704 | if lhsType.qualifiers == rhsQualifiers { | |
| 831 | 704 | return lhsType; | |
| 832 | } | ||
| 833 | ✗ | } | |
| 834 | |||
| 835 | // Nothing matched | ||
| 836 | 78152 | return QualType(SuperType::TY_INVALID); | |
| 837 | } | ||
| 838 | |||
| 839 | 12131 | f<Pair<QualType, Function*>> OpRuleManager.performStructAssign(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, const QualType& rhsType, bool isDecl, bool isReturn) { | |
| 840 | 12131 | const bool rhsIsRef = rhs.ty.isRef(); | |
| 841 | |||
| 842 | // Check is there is an overloaded operator function available | ||
| 843 | 12131 | if !isDecl && !isReturn && lhs.entry.isInitialized() { | |
| 844 | 1658 | const ExprResult overloadResult = this.isOperatorOverloadingFctAvailable(node, OP_FCT_ASSIGN, binaryOperands(lhs, rhs), 0l); | |
| 845 | 1658 | if !overloadResult.ty.is(SuperType::TY_INVALID) { | |
| 846 | 1374 | return assignResult(overloadResult.ty); | |
| 847 | } | ||
| 848 | 1658 | } | |
| 849 | |||
| 850 | // If temp stealing is possible, delete any rhs anonymous entry | ||
| 851 | 11444 | if !rhsIsRef && rhs.isTemporary() { | |
| 852 | 9960 | if rhs.entry != nil<SymbolTableEntry*> && rhs.entry.anonymous { | |
| 853 | 5585 | this.typeChecker.currentScope.symbolTable.deleteAnonymous(rhs.entry.name); | |
| 854 | 5585 | } | |
| 855 | 9960 | return assignResult(rhsType); | |
| 856 | } | ||
| 857 | |||
| 858 | // If RVO is possible, cancel here | ||
| 859 | 1484 | if isReturn && this.typeChecker.isReturnValueOptimizable(rhs) { | |
| 860 | 200 | return assignResult(rhsType); | |
| 861 | } | ||
| 862 | |||
| 863 | // => We have to copy | ||
| 864 | // If struct, try to call copy ctor | ||
| 865 | 1284 | if rhsType.is(SuperType::TY_STRUCT) { | |
| 866 | 1280 | return assignResult(rhsType, this.typeChecker.implicitlyCallStructCopyCtor(rhsType, node)); | |
| 867 | } | ||
| 868 | |||
| 869 | // Perform shallow copy | ||
| 870 | 4 | return assignResult(rhsType); | |
| 871 | } | ||
| 872 | |||
| 873 | // Result of the compound assignment operators +=, -=, *= and /=, which support operator overloading | ||
| 874 | 2360 | f<ExprResult> OpRuleManager.getArithmeticEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, string fctName, const BinaryOpRules& opRules, string name, bool allowPtrArithmetic) { | |
| 875 | // Check is there is an overloaded operator function available | ||
| 876 | 2360 | const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, binaryOperands(lhs, rhs), 0l); | |
| 877 | 2360 | if !resultType.ty.is(SuperType::TY_INVALID) { | |
| 878 | 1752 | return resultType; | |
| 879 | } | ||
| 880 | |||
| 881 | // Check if we try to assign a constant value | ||
| 882 | 1484 | this.ensureNoConstAssign(node, lhs.ty, false, false); | |
| 883 | |||
| 884 | // Remove reference wrappers | ||
| 885 | 1484 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 886 | 1484 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 887 | |||
| 888 | // Check if this is an unsafe operation | ||
| 889 | 1484 | const dyn integerTypes = [SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_SHORT]; | |
| 890 | 1484 | if allowPtrArithmetic && lhsType.isPtr() && rhsType.isOneOf(integerTypes, len(integerTypes)) { | |
| 891 | 15 | this.ensureUnsafeAllowed(node, name, lhsType, rhsType); | |
| 892 | 30 | return lhs; | |
| 893 | } | ||
| 894 | |||
| 895 | 1469 | const QualType binOpType = this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, ""); | |
| 896 | 2938 | return toExprResult(applyIntegerSignedness(binOpType, lhsType, rhsType, false)); | |
| 897 | 2360 | } | |
| 898 | |||
| 899 | 1998 | public f<ExprResult> OpRuleManager.getPlusEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 900 | 1998 | return this.getArithmeticEqualResultType(node, lhs, rhs, OP_FCT_PLUS_EQUAL, this.plusEqualOpRules, "+=", true); | |
| 901 | } | ||
| 902 | |||
| 903 | 94 | public f<ExprResult> OpRuleManager.getMinusEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 904 | 94 | return this.getArithmeticEqualResultType(node, lhs, rhs, OP_FCT_MINUS_EQUAL, this.minusEqualOpRules, "-=", true); | |
| 905 | } | ||
| 906 | |||
| 907 | 160 | public f<ExprResult> OpRuleManager.getMulEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 908 | 160 | return this.getArithmeticEqualResultType(node, lhs, rhs, OP_FCT_MUL_EQUAL, this.mulEqualOpRules, "*=", false); | |
| 909 | } | ||
| 910 | |||
| 911 | 108 | public f<ExprResult> OpRuleManager.getDivEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 912 | 108 | return this.getArithmeticEqualResultType(node, lhs, rhs, OP_FCT_DIV_EQUAL, this.divEqualOpRules, "/=", false); | |
| 913 | } | ||
| 914 | |||
| 915 | // Result of the compound assignment operators without operator overloading support (%=, <<=, >>=, &=, |=, ^=) | ||
| 916 | 407 | f<QualType> OpRuleManager.getSimpleEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, const BinaryOpRules& opRules, string name) { | |
| 917 | // Check if we try to assign a constant value | ||
| 918 | 407 | this.ensureNoConstAssign(node, lhs.ty, false, false); | |
| 919 | |||
| 920 | // Remove reference wrappers | ||
| 921 | 407 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 922 | 407 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 923 | |||
| 924 | 407 | const QualType binOpType = this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, ""); | |
| 925 | 407 | return applyIntegerSignedness(binOpType, lhsType, rhsType, false); | |
| 926 | } | ||
| 927 | |||
| 928 | 62 | public f<QualType> OpRuleManager.getRemEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 929 | 62 | return this.getSimpleEqualResultType(node, lhs, rhs, this.remEqualOpRules, "%="); | |
| 930 | } | ||
| 931 | |||
| 932 | 13 | public f<QualType> OpRuleManager.getSHLEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 933 | 13 | return this.getSimpleEqualResultType(node, lhs, rhs, this.shlEqualOpRules, "<<="); | |
| 934 | } | ||
| 935 | |||
| 936 | 20 | public f<QualType> OpRuleManager.getSHREqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 937 | 20 | return this.getSimpleEqualResultType(node, lhs, rhs, this.shrEqualOpRules, ">>="); | |
| 938 | } | ||
| 939 | |||
| 940 | 30 | public f<QualType> OpRuleManager.getAndEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 941 | 30 | return this.getSimpleEqualResultType(node, lhs, rhs, this.andEqualOpRules, "&="); | |
| 942 | } | ||
| 943 | |||
| 944 | 32 | public f<QualType> OpRuleManager.getOrEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 945 | 32 | return this.getSimpleEqualResultType(node, lhs, rhs, this.orEqualOpRules, "|="); | |
| 946 | } | ||
| 947 | |||
| 948 | 250 | public f<QualType> OpRuleManager.getXorEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 949 | 250 | return this.getSimpleEqualResultType(node, lhs, rhs, this.xorEqualOpRules, "^="); | |
| 950 | } | ||
| 951 | |||
| 952 | // Result of a binary operator without operator overloading support and without special cases | ||
| 953 | 20337 | f<QualType> OpRuleManager.getSimpleBinaryResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, const BinaryOpRules& opRules, string name) { | |
| 954 | // Remove reference wrappers | ||
| 955 | 20337 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 956 | 20337 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 957 | |||
| 958 | 20337 | const QualType binOpType = this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, ""); | |
| 959 | 20337 | return applyIntegerSignedness(binOpType, lhsType, rhsType, true); | |
| 960 | } | ||
| 961 | |||
| 962 | 4421 | public f<QualType> OpRuleManager.getLogicalOrResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 963 | 4421 | return this.getSimpleBinaryResultType(node, lhs, rhs, this.logicalOrOpRules, "||"); | |
| 964 | } | ||
| 965 | |||
| 966 | 2257 | public f<QualType> OpRuleManager.getLogicalAndResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 967 | 2257 | return this.getSimpleBinaryResultType(node, lhs, rhs, this.logicalAndOpRules, "&&"); | |
| 968 | } | ||
| 969 | |||
| 970 | // Result of a binary operator with operator overloading support and without special cases | ||
| 971 | 4672 | f<ExprResult> OpRuleManager.getOverloadableBinaryResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx, string fctName, const BinaryOpRules& opRules, string name, bool considerRhsSignedness = true) { | |
| 972 | // Check if there is an overloaded operator function available | ||
| 973 | 4672 | const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, binaryOperands(lhs, rhs), opIdx); | |
| 974 | 4672 | if !resultType.ty.is(SuperType::TY_INVALID) { | |
| 975 | 1188 | return resultType; | |
| 976 | } | ||
| 977 | |||
| 978 | // Remove reference wrappers | ||
| 979 | 4078 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 980 | 4078 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 981 | |||
| 982 | 4078 | const QualType binOpType = this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, ""); | |
| 983 | 8156 | return toExprResult(applyIntegerSignedness(binOpType, lhsType, rhsType, considerRhsSignedness)); | |
| 984 | 4672 | } | |
| 985 | |||
| 986 | 446 | public f<ExprResult> OpRuleManager.getBitwiseOrResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 987 | 446 | return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_BITWISE_OR, this.bitwiseOrOpRules, "|"); | |
| 988 | } | ||
| 989 | |||
| 990 | 91 | public f<ExprResult> OpRuleManager.getBitwiseXorResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 991 | 91 | return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_BITWISE_XOR, this.bitwiseXorOpRules, "^"); | |
| 992 | } | ||
| 993 | |||
| 994 | 314 | public f<ExprResult> OpRuleManager.getBitwiseAndResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 995 | 314 | return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_BITWISE_AND, this.bitwiseAndOpRules, "&"); | |
| 996 | } | ||
| 997 | |||
| 998 | // Result of == and != | ||
| 999 | 28633 | f<ExprResult> OpRuleManager.getEqualityResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, string fctName, const BinaryOpRules& opRules, string name) { | |
| 1000 | // Check is there is an overloaded operator function available | ||
| 1001 | 28633 | const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, binaryOperands(lhs, rhs), 0l); | |
| 1002 | 28633 | if !resultType.ty.is(SuperType::TY_INVALID) { | |
| 1003 | 3546 | return resultType; | |
| 1004 | } | ||
| 1005 | |||
| 1006 | // Remove reference wrappers | ||
| 1007 | 26860 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1008 | 26860 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 1009 | |||
| 1010 | // Allow 'pointer == unsigned long' straight away | ||
| 1011 | 26860 | if lhsType.isPtr() && rhsType.is(SuperType::TY_LONG) && rhsType.isUnsigned() { | |
| 1012 | 4 | return toExprResult(QualType(SuperType::TY_BOOL)); | |
| 1013 | } | ||
| 1014 | |||
| 1015 | // Allow 'string == char*' and vice versa straight away | ||
| 1016 | 26858 | if (lhsType.is(SuperType::TY_STRING) && rhsType.isPtrTo(SuperType::TY_CHAR)) || (lhsType.isPtrTo(SuperType::TY_CHAR) && rhsType.is(SuperType::TY_STRING)) { | |
| 1017 | 4 | return toExprResult(QualType(SuperType::TY_BOOL)); | |
| 1018 | } | ||
| 1019 | |||
| 1020 | // Check primitive type combinations | ||
| 1021 | 53712 | return toExprResult(this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, "")); | |
| 1022 | 28633 | } | |
| 1023 | |||
| 1024 | 23659 | public f<ExprResult> OpRuleManager.getEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 1025 | 23659 | return this.getEqualityResultType(node, lhs, rhs, OP_FCT_EQUAL, this.equalOpRules, "=="); | |
| 1026 | } | ||
| 1027 | |||
| 1028 | 4974 | public f<ExprResult> OpRuleManager.getNotEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 1029 | 4974 | return this.getEqualityResultType(node, lhs, rhs, OP_FCT_NOT_EQUAL, this.notEqualOpRules, "!="); | |
| 1030 | } | ||
| 1031 | |||
| 1032 | // Result of <, > and <= | ||
| 1033 | 13467 | f<ExprResult> OpRuleManager.getRelationalResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, string fctName, const BinaryOpRules& opRules, string name) { | |
| 1034 | // Check if there is an overloaded operator function available | ||
| 1035 | 13467 | const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, binaryOperands(lhs, rhs), 0l); | |
| 1036 | 13467 | if !resultType.ty.is(SuperType::TY_INVALID) { | |
| 1037 | 36 | return resultType; | |
| 1038 | } | ||
| 1039 | 26898 | return toExprResult(this.getSimpleBinaryResultType(node, lhs, rhs, opRules, name)); | |
| 1040 | 13467 | } | |
| 1041 | |||
| 1042 | 7303 | public f<ExprResult> OpRuleManager.getLessResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 1043 | 7303 | return this.getRelationalResultType(node, lhs, rhs, OP_FCT_LESS, this.lessOpRules, "<"); | |
| 1044 | } | ||
| 1045 | |||
| 1046 | 3862 | public f<ExprResult> OpRuleManager.getGreaterResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 1047 | 3862 | return this.getRelationalResultType(node, lhs, rhs, OP_FCT_GREATER, this.greaterOpRules, ">"); | |
| 1048 | } | ||
| 1049 | |||
| 1050 | 2302 | public f<ExprResult> OpRuleManager.getLessEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 1051 | 2302 | return this.getRelationalResultType(node, lhs, rhs, OP_FCT_LESS_EQUAL, this.lessEqualOpRules, "<="); | |
| 1052 | } | ||
| 1053 | |||
| 1054 | 4346 | public f<ExprResult> OpRuleManager.getGreaterEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 1055 | // Check if there is an overloaded operator function available | ||
| 1056 | 4346 | const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, OP_FCT_GREATER_EQUAL, binaryOperands(lhs, rhs), 0l); | |
| 1057 | 4346 | if !resultType.ty.is(SuperType::TY_INVALID) { | |
| 1058 | 12 | return resultType; | |
| 1059 | } | ||
| 1060 | |||
| 1061 | // Remove reference wrappers | ||
| 1062 | 4340 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1063 | 4340 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 1064 | |||
| 1065 | // Allow 'pointer == pointer' straight away | ||
| 1066 | 4340 | if lhsType.isPtr() && rhsType.isPtr() { | |
| 1067 | 8 | return toExprResult(QualType(SuperType::TY_BOOL)); | |
| 1068 | } | ||
| 1069 | |||
| 1070 | 8672 | return toExprResult(this.validateBinaryOperation(node, this.greaterEqualOpRules, ">=", lhsType, rhsType, false, "")); | |
| 1071 | 4346 | } | |
| 1072 | |||
| 1073 | 666 | public f<ExprResult> OpRuleManager.getShiftLeftResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 1074 | 666 | return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_SHL, this.shiftLeftOpRules, "<<", false); | |
| 1075 | } | ||
| 1076 | |||
| 1077 | 324 | public f<ExprResult> OpRuleManager.getShiftRightResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 1078 | 324 | return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_SHR, this.shiftRightOpRules, ">>", false); | |
| 1079 | } | ||
| 1080 | |||
| 1081 | 10918 | public f<ExprResult> OpRuleManager.getPlusResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 1082 | // Check is there is an overloaded operator function available | ||
| 1083 | 10918 | const ExprResult overloadResult = this.isOperatorOverloadingFctAvailable(node, OP_FCT_PLUS, binaryOperands(lhs, rhs), opIdx); | |
| 1084 | 10918 | if !overloadResult.ty.is(SuperType::TY_INVALID) { | |
| 1085 | 230 | return overloadResult; | |
| 1086 | } | ||
| 1087 | |||
| 1088 | // Remove reference wrappers | ||
| 1089 | 10803 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1090 | 10803 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 1091 | |||
| 1092 | // Allow any* + <int/long/short> | ||
| 1093 | 10803 | const dyn integerTypes = [SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_SHORT]; | |
| 1094 | 10803 | if lhsType.isPtr() && rhsType.isOneOf(integerTypes, len(integerTypes)) { | |
| 1095 | 2683 | this.ensureUnsafeAllowed(node, "+", lhsType, rhsType); | |
| 1096 | 5366 | return toExprResult(lhsType); | |
| 1097 | } | ||
| 1098 | // Allow <int/long/short> + any* | ||
| 1099 | 8120 | if lhsType.isOneOf(integerTypes, len(integerTypes)) && rhsType.isPtr() { | |
| 1100 | ✗ | this.ensureUnsafeAllowed(node, "+", lhsType, rhsType); | |
| 1101 | ✗ | return toExprResult(rhsType); | |
| 1102 | } | ||
| 1103 | |||
| 1104 | 8120 | const QualType binOpType = this.validateBinaryOperation(node, this.plusOpRules, "+", lhsType, rhsType, false, ""); | |
| 1105 | 16240 | return toExprResult(applyIntegerSignedness(binOpType, lhsType, rhsType, true)); | |
| 1106 | 10918 | } | |
| 1107 | |||
| 1108 | 7075 | public f<ExprResult> OpRuleManager.getMinusResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 1109 | // Check is there is an overloaded operator function available | ||
| 1110 | 7075 | const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, OP_FCT_MINUS, binaryOperands(lhs, rhs), opIdx); | |
| 1111 | 7075 | if !resultType.ty.is(SuperType::TY_INVALID) { | |
| 1112 | 4 | return resultType; | |
| 1113 | } | ||
| 1114 | |||
| 1115 | // Remove reference wrappers | ||
| 1116 | 7073 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1117 | 7073 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 1118 | |||
| 1119 | // Allow any* - <int/long/short> | ||
| 1120 | 7073 | const dyn integerTypes = [SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_SHORT]; | |
| 1121 | 7073 | if lhsType.isPtr() && rhsType.isOneOf(integerTypes, len(integerTypes)) { | |
| 1122 | 267 | this.ensureUnsafeAllowed(node, "-", lhsType, rhsType); | |
| 1123 | 534 | return lhs; | |
| 1124 | } | ||
| 1125 | |||
| 1126 | 6806 | const QualType binOpType = this.validateBinaryOperation(node, this.minusOpRules, "-", lhsType, rhsType, false, ""); | |
| 1127 | 13612 | return toExprResult(applyIntegerSignedness(binOpType, lhsType, rhsType, true)); | |
| 1128 | 7075 | } | |
| 1129 | |||
| 1130 | 2482 | public f<ExprResult> OpRuleManager.getMulResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 1131 | 2482 | return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_MUL, this.mulOpRules, "*"); | |
| 1132 | } | ||
| 1133 | |||
| 1134 | 349 | public f<ExprResult> OpRuleManager.getDivResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) { | |
| 1135 | 349 | return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_DIV, this.divOpRules, "/"); | |
| 1136 | } | ||
| 1137 | |||
| 1138 | 210 | public f<ExprResult> OpRuleManager.getRemResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) { | |
| 1139 | 210 | return toExprResult(this.getSimpleBinaryResultType(node, lhs, rhs, this.remOpRules, "%")); | |
| 1140 | } | ||
| 1141 | |||
| 1142 | 948 | public f<QualType> OpRuleManager.getPrefixMinusResultType(const ASTNode* node, const ExprResult& lhs) { | |
| 1143 | // Remove reference wrappers | ||
| 1144 | 948 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1145 | |||
| 1146 | 948 | return this.validateUnaryOperation(node, this.prefixMinusOpRules, "-", lhsType); | |
| 1147 | } | ||
| 1148 | |||
| 1149 | // Result of the prefix operators ++ and -- | ||
| 1150 | 70 | f<QualType> OpRuleManager.getPrefixIncDecResultType(const ASTNode* node, const ExprResult& lhs, const UnaryOpRules& opRules, string name) { | |
| 1151 | // Check if we try to assign a constant value | ||
| 1152 | 70 | this.ensureNoConstAssign(node, lhs.ty, false, false); | |
| 1153 | |||
| 1154 | // Remove reference wrappers | ||
| 1155 | 70 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1156 | |||
| 1157 | // Check if this is an unsafe operation | ||
| 1158 | 70 | if lhsType.isPtr() { | |
| 1159 | ✗ | this.ensureUnsafeAllowed(node, name, lhsType); | |
| 1160 | ✗ | return lhsType; | |
| 1161 | } | ||
| 1162 | |||
| 1163 | 70 | return this.validateUnaryOperation(node, opRules, name, lhsType); | |
| 1164 | } | ||
| 1165 | |||
| 1166 | 25 | public f<QualType> OpRuleManager.getPrefixPlusPlusResultType(const ASTNode* node, const ExprResult& lhs) { | |
| 1167 | 25 | return this.getPrefixIncDecResultType(node, lhs, this.prefixPlusPlusOpRules, "++"); | |
| 1168 | } | ||
| 1169 | |||
| 1170 | 45 | public f<QualType> OpRuleManager.getPrefixMinusMinusResultType(const ASTNode* node, const ExprResult& lhs) { | |
| 1171 | 45 | return this.getPrefixIncDecResultType(node, lhs, this.prefixMinusMinusOpRules, "--"); | |
| 1172 | } | ||
| 1173 | |||
| 1174 | 4072 | public f<QualType> OpRuleManager.getPrefixNotResultType(const ASTNode* node, const ExprResult& lhs) { | |
| 1175 | // Remove reference wrappers | ||
| 1176 | 4072 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1177 | |||
| 1178 | 4072 | return this.validateUnaryOperation(node, this.prefixNotOpRules, "!", lhsType); | |
| 1179 | } | ||
| 1180 | |||
| 1181 | 33 | public f<ExprResult> OpRuleManager.getPrefixBitwiseNotResultType(ASTNode* node, const ExprResult& lhs) { | |
| 1182 | // Check if there is an overloaded operator function available | ||
| 1183 | 33 | const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, OP_FCT_BITWISE_NOT, unaryOperand(lhs), 0l); | |
| 1184 | 33 | if !resultType.ty.is(SuperType::TY_INVALID) { | |
| 1185 | 4 | return resultType; | |
| 1186 | } | ||
| 1187 | |||
| 1188 | // Remove reference wrappers | ||
| 1189 | 31 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1190 | |||
| 1191 | 62 | return toExprResult(this.validateUnaryOperation(node, this.prefixBitwiseNotOpRules, "~", lhsType)); | |
| 1192 | 33 | } | |
| 1193 | |||
| 1194 | 999 | public f<QualType> OpRuleManager.getPrefixMulResultType(const ASTNode* node, const ExprResult& lhs) { | |
| 1195 | // Remove reference wrappers | ||
| 1196 | 999 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1197 | |||
| 1198 | 999 | if !lhsType.isPtr() { | |
| 1199 | 1 | throwSemanticError(node, SemanticErrorType::OPERATOR_WRONG_DATA_TYPE, "Cannot apply de-referencing operator on type " + lhsType.getName(true)); | |
| 1200 | 2 | return QualType(SuperType::TY_UNRESOLVED); | |
| 1201 | 1 | } | |
| 1202 | 998 | return lhsType.getContained(); | |
| 1203 | } | ||
| 1204 | |||
| 1205 | 1577 | public f<QualType> OpRuleManager.getPrefixBitwiseAndResultType(const ASTNode* node, const ExprResult& lhs) { | |
| 1206 | // Remove reference wrappers | ||
| 1207 | 1577 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1208 | |||
| 1209 | 1577 | return lhsType.toPtr(node); | |
| 1210 | } | ||
| 1211 | |||
| 1212 | // Result of the postfix operators ++ and -- | ||
| 1213 | 9305 | f<ExprResult> OpRuleManager.getPostfixIncDecResultType(ASTNode* node, const ExprResult& lhs, string fctName, const UnaryOpRules& opRules, string name) { | |
| 1214 | // Check is there is an overloaded operator function available | ||
| 1215 | 9305 | const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, unaryOperand(lhs), 0l); | |
| 1216 | 9305 | if !resultType.ty.is(SuperType::TY_INVALID) { | |
| 1217 | 46 | return resultType; | |
| 1218 | } | ||
| 1219 | |||
| 1220 | // Check if we try to assign a constant value | ||
| 1221 | 9282 | this.ensureNoConstAssign(node, lhs.ty, false, false); | |
| 1222 | |||
| 1223 | // Remove reference wrappers | ||
| 1224 | 9282 | const QualType lhsType = lhs.ty.removeReferenceWrapper(); | |
| 1225 | |||
| 1226 | // Check if this is an unsafe operation | ||
| 1227 | 9282 | if lhsType.isPtr() { | |
| 1228 | 32 | this.ensureUnsafeAllowed(node, name, lhsType); | |
| 1229 | 64 | return lhs; | |
| 1230 | } | ||
| 1231 | |||
| 1232 | 18500 | return toExprResult(this.validateUnaryOperation(node, opRules, name, lhsType)); | |
| 1233 | 9305 | } | |
| 1234 | |||
| 1235 | 8526 | public f<ExprResult> OpRuleManager.getPostfixPlusPlusResultType(ASTNode* node, const ExprResult& lhs) { | |
| 1236 | 8526 | return this.getPostfixIncDecResultType(node, lhs, OP_FCT_POSTFIX_PLUS_PLUS, this.postfixPlusPlusOpRules, "++"); | |
| 1237 | } | ||
| 1238 | |||
| 1239 | 779 | public f<ExprResult> OpRuleManager.getPostfixMinusMinusResultType(ASTNode* node, const ExprResult& lhs) { | |
| 1240 | 779 | return this.getPostfixIncDecResultType(node, lhs, OP_FCT_POSTFIX_MINUS_MINUS, this.postfixMinusMinusOpRules, "--"); | |
| 1241 | } | ||
| 1242 | |||
| 1243 | 12175 | public f<QualType> OpRuleManager.getCastResultType(const ASTNode* node, const QualType& origLhsType, const ExprResult& rhs) { | |
| 1244 | // Remove reference wrappers | ||
| 1245 | 12175 | const QualType lhsType = origLhsType.removeReferenceWrapper(); | |
| 1246 | 12175 | const QualType rhsType = rhs.ty.removeReferenceWrapper(); | |
| 1247 | |||
| 1248 | // Only allow to cast the 'heap' qualifier away, if we are in unsafe mode | ||
| 1249 | 12175 | if lhsType.qualifiers.isHeap != rhsType.qualifiers.isHeap { | |
| 1250 | 721 | this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType); | |
| 1251 | 721 | } | |
| 1252 | |||
| 1253 | // Allow identity casts | ||
| 1254 | 12175 | if lhsType.matches(rhsType, false, true, true) { | |
| 1255 | 1352 | return lhsType; | |
| 1256 | } | ||
| 1257 | // Allow casts string -> char* and string -> char[] | ||
| 1258 | 10823 | const dyn ptrOrArrayTypes = [SuperType::TY_PTR, SuperType::TY_ARRAY]; | |
| 1259 | 10823 | if lhsType.isOneOf(ptrOrArrayTypes, len(ptrOrArrayTypes)) && rhsType.is(SuperType::TY_STRING) { | |
| 1260 | 4245 | const QualType lhsContainedType = lhsType.getContained(); | |
| 1261 | 4245 | if lhsContainedType.is(SuperType::TY_CHAR) { | |
| 1262 | 4244 | return lhsType; | |
| 1263 | } | ||
| 1264 | 1 | } | |
| 1265 | // Allow casts char* -> string and char[] -> string | ||
| 1266 | 6579 | if lhsType.is(SuperType::TY_STRING) && rhsType.isOneOf(ptrOrArrayTypes, len(ptrOrArrayTypes)) { | |
| 1267 | 298 | const QualType rhsContainedType = rhsType.getContained(); | |
| 1268 | 298 | if rhsContainedType.is(SuperType::TY_CHAR) { | |
| 1269 | 267 | return lhsType; | |
| 1270 | } | ||
| 1271 | 31 | } | |
| 1272 | // Allow safe upcasts baseStruct* <- derivedStruct* and interface* <- struct* without requiring an unsafe | ||
| 1273 | // block. These are the only struct-pointer casts where the target subobject is guaranteed to be present; | ||
| 1274 | // the IR generator advances the pointer to that subobject (past any vtable prefix). The reverse direction | ||
| 1275 | // (down/sibling casts) is not covered here and still falls through to the unsafe any* -> any* rule below. | ||
| 1276 | 6312 | if lhsType.isPtr() && rhsType.isPtr() { | |
| 1277 | 2147 | const QualType lhsContained = lhsType.getContained(); | |
| 1278 | 2147 | const QualType rhsContained = rhsType.getContained(); | |
| 1279 | 2147 | if lhsContained.matchesInterfaceImplementedByStruct(rhsContained) || lhsContained.matchesComposedBaseOfStruct(rhsContained) { | |
| 1280 | 6 | return lhsType; | |
| 1281 | } | ||
| 1282 | 2141 | } | |
| 1283 | // Allow casts any* -> any* | ||
| 1284 | 6306 | const dyn ptrOrStringTypes = [SuperType::TY_PTR, SuperType::TY_STRING]; | |
| 1285 | 6306 | if lhsType.isOneOf(ptrOrStringTypes, len(ptrOrStringTypes)) && rhsType.isOneOf(ptrOrStringTypes, len(ptrOrStringTypes)) { | |
| 1286 | 2173 | this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType); | |
| 1287 | 2173 | return lhsType; | |
| 1288 | } | ||
| 1289 | // Allow casts any* -> long and long -> any*. Only 'long' is accepted on the integer side: it is the only Spice | ||
| 1290 | // integer type that is guaranteed to be 64 bit wide on every target (see docs/docs/language/primitive-types.md), | ||
| 1291 | // so it is the only one that can round-trip a pointer without silently truncating it on a 64-bit target. The | ||
| 1292 | // qualifiers of the cast destination are preserved, so 'unsigned long' works just as well as the signed variant. | ||
| 1293 | 4133 | if lhsType.is(SuperType::TY_LONG) && rhsType.isOneOf(ptrOrStringTypes, len(ptrOrStringTypes)) { | |
| 1294 | 12 | this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType); | |
| 1295 | 12 | return lhsType; | |
| 1296 | } | ||
| 1297 | 4121 | if lhsType.isOneOf(ptrOrStringTypes, len(ptrOrStringTypes)) && rhsType.is(SuperType::TY_LONG) { | |
| 1298 | 10 | this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType); | |
| 1299 | 10 | return lhsType; | |
| 1300 | } | ||
| 1301 | // Allow casts p()/f<>() -> byte* | ||
| 1302 | 4111 | const dyn functionTypes = [SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE]; | |
| 1303 | 4111 | if lhsType.isPtrTo(SuperType::TY_BYTE) && rhsType.isOneOf(functionTypes, len(functionTypes)) { | |
| 1304 | 42 | this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType); | |
| 1305 | 42 | return lhsType; | |
| 1306 | } | ||
| 1307 | // Check primitive type combinations | ||
| 1308 | 4069 | return this.validateBinaryOperation(node, this.castOpRules, "(cast)", lhsType, rhsType, true, ""); | |
| 1309 | } | ||
| 1310 | |||
| 1311 | /** | ||
| 1312 | * Check if there is an operator overloading function available for the given operator and operand types. The operands are | ||
| 1313 | * passed as a list of one or two elements. | ||
| 1314 | * | ||
| 1315 | * @param node AST node of the operator | ||
| 1316 | * @param fctName Name of the operator function | ||
| 1317 | * @param op Operands | ||
| 1318 | * @param opIdx Index of the operator within the node | ||
| 1319 | * @return Result of the operator function call or the invalid type if no operator function is available | ||
| 1320 | */ | ||
| 1321 | 95644 | public f<ExprResult> OpRuleManager.isOperatorOverloadingFctAvailable(ASTNode* node, string fctName, const Vector<ExprResult>& op, unsigned long opIdx) { | |
| 1322 | 95644 | assert op.getSize() == 1l || op.getSize() == 2l; // Only unary and binary operators are overloadable | |
| 1323 | 95644 | const String fctNameStr = String(fctName); | |
| 1324 | |||
| 1325 | // Most operators are applied to operands without an overloaded operator function (e.g. int == int). Searching all | ||
| 1326 | // source files for one is expensive, so skip the search if it found nothing for the same operator and operand types in | ||
| 1327 | // this source file before and no function was inserted since then. | ||
| 1328 | 95644 | Hash cacheKey = 0ul; | |
| 1329 | 95644 | hashCombine64(cacheKey, hashPointer(this.typeChecker.sourceFile)); | |
| 1330 | 95644 | hashCombine64(cacheKey, hash(fctNameStr)); | |
| 1331 | 277594 | foreach const ExprResult& operand : op { | |
| 1332 | 181950 | hashCombine64(cacheKey, hashQualType(operand.ty)); | |
| 1333 | 181950 | hashCombine64(cacheKey, hash(operand.isTemporary())); | |
| 1334 | 181950 | } | |
| 1335 | 95644 | const unsigned long registryVersion = getFunctionRegistryVersion(); | |
| 1336 | 95644 | UnorderedMap<Hash, unsigned long>& unavailableOpFctCache = this.typeChecker.resourceManager.unavailableOpFctCache; | |
| 1337 | 95644 | if unavailableOpFctCache.contains(cacheKey) && unavailableOpFctCache.get(cacheKey) == registryVersion { | |
| 1338 | 117526 | return toExprResult(QualType(SuperType::TY_INVALID)); | |
| 1339 | } | ||
| 1340 | |||
| 1341 | 36881 | Scope* calleeParentScope = nil<Scope*>; | |
| 1342 | 36881 | Function* callee = nil<Function*>; | |
| 1343 | 36881 | const QualType thisType = QualType(SuperType::TY_DYN); | |
| 1344 | 36881 | ArgList args; | |
| 1345 | // The first match wins, so iterate the source files in creation order. The order of the source file map depends on the | ||
| 1346 | // hash function, which would make the choice between operator functions of different source files arbitrary | ||
| 1347 | 432383 | foreach SourceFile* sourceFile : this.typeChecker.resourceManager.sourceFilesInCreationOrder { | |
| 1348 | // Check if there is a registered operator function | ||
| 1349 | 400555 | if sourceFile.getNameRegistryEntry(fctNameStr) == nil<const NameRegistryEntry*> { | |
| 1350 | 256585 | continue; | |
| 1351 | } | ||
| 1352 | |||
| 1353 | // Match callees in the global scope of this source file | ||
| 1354 | 143970 | calleeParentScope = sourceFile.globalScope; | |
| 1355 | 143970 | args.clear(); | |
| 1356 | 429278 | for unsigned long i = 0l; i < op.getSize(); i++ { | |
| 1357 | 285308 | const ExprResult& operand = op[i]; | |
| 1358 | 285308 | const QualType argType = this.typeChecker.mapLocalTypeToImportedScopeType(calleeParentScope, operand.ty); | |
| 1359 | 285308 | args.pushBack(Pair<QualType, bool>(argType, operand.isTemporary())); | |
| 1360 | 285308 | } | |
| 1361 | 143970 | const QualTypeList noTemplateTypeHints; | |
| 1362 | 143970 | callee = matchFunction(calleeParentScope, fctNameStr, thisType, args, noTemplateTypeHints, false, node); | |
| 1363 | 143970 | if callee != nil<Function*> { | |
| 1364 | 5053 | break; | |
| 1365 | } | ||
| 1366 | 143970 | } | |
| 1367 | |||
| 1368 | // Return invalid type if the callee was not found | ||
| 1369 | 36881 | if callee == nil<Function*> { | |
| 1370 | 31828 | unavailableOpFctCache.upsert(cacheKey, registryVersion); | |
| 1371 | 63656 | return toExprResult(QualType(SuperType::TY_INVALID)); | |
| 1372 | } | ||
| 1373 | 5053 | assert calleeParentScope != nil<Scope*>; | |
| 1374 | |||
| 1375 | // Save the pointer to the operator function in the AST node | ||
| 1376 | 5053 | Vector<const Function*>& opFctPointers = this.typeChecker.getOpFctPointers(node); | |
| 1377 | 5321 | while opFctPointers.getSize() <= cast<long>(opIdx) { | |
| 1378 | 268 | opFctPointers.pushBack(nil<const Function*>); | |
| 1379 | 268 | } | |
| 1380 | 5053 | const Function*& opFctPointer = opFctPointers.get(opIdx); | |
| 1381 | 5053 | opFctPointer = callee; | |
| 1382 | |||
| 1383 | // Check if we need to request a re-visit, because the function body was not type-checked yet | ||
| 1384 | 5053 | requestRevisitIfRequired(callee); | |
| 1385 | |||
| 1386 | // By-value params of non-trivially copyable types get copies of the operands, which require their copy ctors | ||
| 1387 | 5053 | this.typeChecker.matchCopyCtorsForOwnedParams(callee, node); | |
| 1388 | |||
| 1389 | // Check if the called function has sufficient visibility | ||
| 1390 | 5053 | const bool isImported = calleeParentScope.isImportedBy(this.typeChecker.rootScope); | |
| 1391 | 5053 | const SymbolTableEntry* calleeEntry = callee.entry; | |
| 1392 | 5053 | const QualType calleeEntryType = calleeEntry.getQualType(); | |
| 1393 | 5053 | if isImported && !calleeEntryType.isPublic() { | |
| 1394 | 1 | throwSemanticError(node, SemanticErrorType::INSUFFICIENT_VISIBILITY, "Overloaded operator '" + callee.getSignature() + "' has insufficient visibility"); | |
| 1395 | 2 | return toExprResult(QualType(SuperType::TY_UNRESOLVED)); | |
| 1396 | 1 | } | |
| 1397 | |||
| 1398 | // Procedures always have the return type 'bool' | ||
| 1399 | 5052 | if callee.isProcedure() { | |
| 1400 | 3162 | return toExprResult(QualType(SuperType::TY_BOOL)); | |
| 1401 | } | ||
| 1402 | 3471 | const QualType& returnType = callee.returnType; | |
| 1403 | |||
| 1404 | // Add anonymous symbol to keep track of dtor call, if non-trivially destructible | ||
| 1405 | 3471 | SymbolTableEntry* anonymousSymbol = nil<SymbolTableEntry*>; | |
| 1406 | 3471 | if returnType.is(SuperType::TY_STRUCT) && !returnType.isTriviallyDestructible(node) { | |
| 1407 | 149 | anonymousSymbol = this.typeChecker.currentScope.symbolTable.insertAnonymous(returnType, node, opIdx); | |
| 1408 | 149 | } | |
| 1409 | |||
| 1410 | 3471 | const QualType localReturnType = this.typeChecker.mapImportedScopeTypeToLocalType(calleeParentScope, returnType); | |
| 1411 | 6942 | return ExprResult{localReturnType, anonymousSymbol}; | |
| 1412 | 95644 | } | |
| 1413 | |||
| 1414 | /** | ||
| 1415 | * Apply the signedness of the operands to an integer result type. The op rule tables only contain the super types, so the | ||
| 1416 | * result type would always be signed otherwise. Like in C, the result is unsigned if an operand that has the same type as | ||
| 1417 | * the result is unsigned: e.g. 'unsigned int + unsigned long' and 'int + unsigned long' are unsigned, but | ||
| 1418 | * 'unsigned int + long' is signed, because a long can hold all values of an unsigned int. | ||
| 1419 | * | ||
| 1420 | * @param resultType Result type of the operation | ||
| 1421 | * @param lhs Left side of the operation | ||
| 1422 | * @param rhs Right side of the operation | ||
| 1423 | * @param considerRhs Whether the right side is considered (not for unary, shift and compound assign operations) | ||
| 1424 | * @return Result type with the correct signedness | ||
| 1425 | */ | ||
| 1426 | 55586 | f<QualType> applyIntegerSignedness(const QualType& origResultType, const QualType& lhs, const QualType& rhs, bool considerRhs) { | |
| 1427 | 55586 | const dyn integerTypes = [SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_LONG]; | |
| 1428 | 55586 | if !origResultType.isOneOf(integerTypes, len(integerTypes)) { | |
| 1429 | 25572 | return origResultType; | |
| 1430 | } | ||
| 1431 | 30014 | QualType resultType = origResultType; | |
| 1432 | 30014 | const SuperType resultSuperType = resultType.getSuperType(); | |
| 1433 | 30014 | const bool isLhsUnsigned = lhs.getSuperType() == resultSuperType && lhs.isUnsigned(); | |
| 1434 | 30014 | const bool isRhsUnsigned = considerRhs && rhs.getSuperType() == resultSuperType && rhs.isUnsigned(); | |
| 1435 | 30014 | if isLhsUnsigned || isRhsUnsigned { | |
| 1436 | 26008 | resultType.makeUnsigned(); | |
| 1437 | 26008 | } | |
| 1438 | 30014 | return resultType; | |
| 1439 | } | ||
| 1440 | |||
| 1441 | 14371 | f<QualType> OpRuleManager.validateUnaryOperation(const ASTNode* node, const UnaryOpRules& opRules, string name, const QualType& lhs) { | |
| 1442 | 31495 | for unsigned long i = 0l; i < opRules.getSize(); i++ { | |
| 1443 | 31493 | const UnaryOpRule& rule = opRules[i]; | |
| 1444 | 31493 | if rule.lhsType == lhs.getSuperType() { | |
| 1445 | 14369 | return applyIntegerSignedness(QualType(rule.resultType), lhs, lhs, false); | |
| 1446 | } | ||
| 1447 | 17124 | } | |
| 1448 | 2 | throwSemanticError(node, SemanticErrorType::OPERATOR_WRONG_DATA_TYPE, getUnaryErrorMessage(name, lhs)); | |
| 1449 | 4 | return QualType(SuperType::TY_UNRESOLVED); | |
| 1450 | 2 | } | |
| 1451 | |||
| 1452 | 154624 | f<QualType> OpRuleManager.validateBinaryOperation(const ASTNode* node, const BinaryOpRules& opRules, string name, const QualType& lhs, const QualType& rhs, bool preserveQualifiersFromLhs, string customMessagePrefix) { | |
| 1453 | 1533240 | for unsigned long i = 0l; i < opRules.getSize(); i++ { | |
| 1454 | 1533206 | const BinaryOpRule& rule = opRules[i]; | |
| 1455 | 1533206 | if rule.lhsType == lhs.getSuperType() && rule.rhsType == rhs.getSuperType() { | |
| 1456 | 154590 | QualType resultType = QualType(rule.resultType); | |
| 1457 | 154590 | if preserveQualifiersFromLhs { | |
| 1458 | 82198 | resultType.setQualifiers(lhs.qualifiers); | |
| 1459 | 82198 | } | |
| 1460 | 154590 | return resultType; | |
| 1461 | } | ||
| 1462 | 1378616 | } | |
| 1463 | 34 | throwSemanticError(node, SemanticErrorType::OPERATOR_WRONG_DATA_TYPE, getBinaryErrorMessage(name, lhs, rhs, customMessagePrefix)); | |
| 1464 | 68 | return QualType(SuperType::TY_UNRESOLVED); | |
| 1465 | 34 | } | |
| 1466 | |||
| 1467 | // Message of the semantic error for an invalid unary operator/type combination | ||
| 1468 | 2 | f<String> getUnaryErrorMessage(string name, const QualType& lhs) { | |
| 1469 | 4 | return "Cannot apply '" + String(name) + "' operator on type " + lhs.getName(true); | |
| 1470 | 2 | } | |
| 1471 | |||
| 1472 | // Message of the semantic error for an invalid binary operator/type combination | ||
| 1473 | 34 | f<String> getBinaryErrorMessage(string name, const QualType& lhs, const QualType& rhs, string messagePrefix) { | |
| 1474 | 34 | StringStream errorMsg; | |
| 1475 | 34 | const String messagePrefixStr = String(messagePrefix); | |
| 1476 | 34 | if !messagePrefixStr.isEmpty() { | |
| 1477 | 4 | errorMsg << messagePrefix << ". Expected " << lhs.getName(true) << " but got " << rhs.getName(true); | |
| 1478 | 4 | } else { | |
| 1479 | 30 | errorMsg << "Cannot apply '" << name << "' operator on types " << lhs.getName(true) << " and " << rhs.getName(true); | |
| 1480 | 30 | } | |
| 1481 | 68 | return errorMsg.str(); | |
| 1482 | 34 | } | |
| 1483 | |||
| 1484 | 32 | p OpRuleManager.ensureUnsafeAllowed(const ASTNode* node, string name, const QualType& lhs) { | |
| 1485 | 32 | if this.typeChecker.currentScope.doesAllowUnsafeOperations() { | |
| 1486 | 32 | return; | |
| 1487 | } | ||
| 1488 | // Print error message | ||
| 1489 | ✗ | const String lhsName = lhs.getName(true); | |
| 1490 | ✗ | const String errorMsg = "Cannot apply '" + String(name) + "' operator on type " + lhsName + " as this is an unsafe operation. Please use unsafe blocks if you know what you are doing."; | |
| 1491 | ✗ | this.softError(node, SemanticErrorType::UNSAFE_OPERATION_IN_SAFE_CONTEXT, errorMsg); | |
| 1492 | ✗ | } | |
| 1493 | |||
| 1494 | 5923 | p OpRuleManager.ensureUnsafeAllowed(const ASTNode* node, string name, const QualType& lhs, const QualType& rhs) { | |
| 1495 | 5923 | if this.typeChecker.currentScope.doesAllowUnsafeOperations() { | |
| 1496 | 5920 | return; | |
| 1497 | } | ||
| 1498 | // Print error message | ||
| 1499 | 3 | const String lhsName = lhs.getName(true); | |
| 1500 | 3 | const String rhsName = rhs.getName(true); | |
| 1501 | 3 | const String errorMsg = "Cannot apply '" + String(name) + "' operator on types " + lhsName + " and " + rhsName + " as this is an unsafe operation. Please use unsafe blocks if you know what you are doing."; | |
| 1502 | 3 | this.softError(node, SemanticErrorType::UNSAFE_OPERATION_IN_SAFE_CONTEXT, errorMsg); | |
| 1503 | 3 | } | |
| 1504 | |||
| 1505 | 121633 | p OpRuleManager.ensureNoConstAssign(const ASTNode* node, const QualType& lhs, bool isDecl, bool isReturn) { | |
| 1506 | // Check if we try to assign a constant value | ||
| 1507 | 121633 | const QualType lhsUnwrappedType = lhs.removeReferenceWrapper(); | |
| 1508 | 121633 | if lhsUnwrappedType.isConst() && !isDecl && !isReturn { | |
| 1509 | 20 | const String errorMessage = "Trying to assign value to an immutable variable of type " + lhs.getName(true); | |
| 1510 | 20 | this.softError(node, SemanticErrorType::REASSIGN_CONST_VARIABLE, errorMessage); | |
| 1511 | 20 | } | |
| 1512 | 121633 | } | |
| 1513 | |||
| 1514 | // Add a soft error to the error list | ||
| 1515 | 23 | p OpRuleManager.softError(const ASTNode* node, SemanticErrorType errorType, const String& message) { | |
| 1516 | 23 | ErrorManager& errorManager = this.typeChecker.resourceManager.getErrorManager(); | |
| 1517 | 23 | errorManager.addSoftError(node, errorType, message); | |
| 1518 | 23 | } | |
| 1519 |