github.com/hattya/go.sh@v0.0.0-20240328132134-f53276d95cc6/interp/arith_test.go (about) 1 // 2 // go.sh/interp :: arith_test.go 3 // 4 // Copyright (c) 2021-2024 Akinori Hattori <hattya@gmail.com> 5 // 6 // SPDX-License-Identifier: MIT 7 // 8 9 package interp_test 10 11 import ( 12 "testing" 13 14 "github.com/hattya/go.sh/interp" 15 ) 16 17 var evalTests = []struct { 18 expr string 19 n int 20 }{ 21 {" - 1 ", -1}, 22 {" 0 ", 0}, 23 {" + 1 ", 1}, 24 // dec 25 {"9", 9}, 26 {"+9", 9}, 27 {"-9", -9}, 28 {"~0", -1}, 29 {"!0", 1}, 30 {"!9", 0}, 31 {"!+9", 0}, 32 {"!-9", 0}, 33 {"(9)", 9}, 34 {"((9))", 9}, 35 {"+(-(+9))", -9}, 36 {"-(+(-9))", 9}, 37 // oct 38 {"07", 7}, 39 {"+07", 7}, 40 {"-07", -7}, 41 // hex 42 {"0xf", 15}, 43 {"0Xf", 15}, 44 {"+0xf", 15}, 45 {"+0Xf", 15}, 46 {"-0xf", -15}, 47 {"-0Xf", -15}, 48 // ident 49 {"_", 0}, 50 {"E", 0}, 51 {"D", 4}, 52 {"O", 3}, 53 {"X", 7}, 54 {"+X", 7}, 55 {"-X", -7}, 56 {"~X", -8}, 57 {"!X", 0}, 58 {"((X))", 7}, 59 {"+(-(+X))", -7}, 60 {"-(+(-X))", 7}, 61 // inc 62 {"X++", 7}, 63 {"+X++", 7}, 64 {"-X++", -7}, 65 {"++X", 8}, 66 {"+(++X)", 8}, 67 {"-(++X)", -8}, 68 // dec 69 {"X--", 7}, 70 {"+X--", 7}, 71 {"-X--", -7}, 72 {"--X", 6}, 73 {"+(--X)", 6}, 74 {"-(--X)", -6}, 75 // mul 76 {" 0 * 0 * 0 ", 0}, 77 {" 2 * 4 * 8 ", 64}, 78 {"+2 * 4 * 8 ", 64}, 79 {" 2 * -4 * 8 ", -64}, 80 {" 2 * 4 * +8 ", 64}, 81 {"-2 * +4 * -8 ", 64}, 82 {"-2 * (4 * 8)", -64}, 83 // div 84 {" 64 / 8 / 4 ", 2}, 85 {"+64 / 8 / 4 ", 2}, 86 {" 64 / -8 / 4 ", -2}, 87 {" 64 / 8 / +4 ", 2}, 88 {"-64 / +8 / -4 ", 2}, 89 {"-64 / (8 / 4)", -32}, 90 // mod 91 {" 140 % 71 % 37 ", 32}, 92 {"+140 % 71 % 37 ", 32}, 93 {" 140 % -71 % 37 ", 32}, 94 {" 140 % 71 % +37 ", 32}, 95 {"-140 % +71 % -37 ", -32}, 96 {"-140 % (71 % 37)", -4}, 97 // add 98 {" 0 + 0 + 0 ", 0}, 99 {" 8 + 4 + 2 ", 14}, 100 {" 8 * 4 + 2 ", 34}, 101 {" 8 * (4 + 2)", 48}, 102 {" 8 + 4 / 2 ", 10}, 103 {"(8 + 4) / 2 ", 6}, 104 {" 8 % 4 + 2 ", 2}, 105 {" 8 % (4 + 2)", 2}, 106 // sub 107 {" 0 - 0 - 0", 0}, 108 {" 8 - 4 - 2 ", 2}, 109 {" 8 * 4 - 2 ", 30}, 110 {" 8 * (4 - 2)", 16}, 111 {" 8 - 4 / 2 ", 6}, 112 {"(8 - 4) / 2 ", 2}, 113 {" 8 % 4 - 2 ", -2}, 114 {" 8 % (4 - 2)", 0}, 115 // lsh 116 {" 4 << 2 << 1 ", 32}, 117 {" 4 + 2 << 1 ", 12}, 118 {" 4 + (2 << 1)", 8}, 119 {" 4 << 2 - 1 ", 8}, 120 {"(4 << 2) - 1 ", 15}, 121 // rsh 122 {" 8 >> 2 >> 1 ", 1}, 123 {" 8 + 2 >> 1 ", 5}, 124 {" 8 + (2 >> 1)", 9}, 125 {" 8 >> 2 - 1 ", 4}, 126 {"(8 >> 2) - 1 ", 1}, 127 // lt 128 {" 1 < 2 ", 1}, 129 {" 2 < 2 ", 0}, 130 {" 2 < 1 ", 0}, 131 {" 1 << 2 < 4 ", 0}, 132 {" 1 << (2 < 4)", 2}, 133 {" 1 < 4 >> 1 ", 1}, 134 {"(1 < 4) >> 1 ", 0}, 135 // le 136 {" 1 <= 2 ", 1}, 137 {" 2 <= 2 ", 1}, 138 {" 2 <= 1 ", 0}, 139 {" 1 << 2 <= 4 ", 1}, 140 {" 1 << (2 <= 4)", 2}, 141 {" 1 <= 4 >> 1 ", 1}, 142 {"(1 <= 4) >> 1 ", 0}, 143 // gt 144 {" 1 > 2 ", 0}, 145 {" 2 > 2 ", 0}, 146 {" 2 > 1 ", 1}, 147 {" 4 << 2 > 2 ", 1}, 148 {" 4 << (2 > 2)", 4}, 149 {" 4 > 2 >> 1 ", 1}, 150 {"(4 > 2) >> 1 ", 0}, 151 // ge 152 {" 1 >= 2 ", 0}, 153 {" 2 >= 2 ", 1}, 154 {" 2 >= 1 ", 1}, 155 {" 4 << 2 >= 2 ", 1}, 156 {" 4 << (2 >= 2)", 8}, 157 {" 4 >= 2 >> 1 ", 1}, 158 {"(4 >= 2) >> 1 ", 0}, 159 // eq 160 {" 1 == 1 ", 1}, 161 {" 1 == 0 ", 0}, 162 {" 1 < 1 == 0 ", 1}, 163 {" 1 < (1 == 0)", 0}, 164 {" 0 == 1 <= 1 ", 0}, 165 {"(0 == 1) <= 1 ", 1}, 166 {" 0 > 1 == 0 ", 1}, 167 {" 0 > (1 == 0)", 0}, 168 {" 0 == 1 >= 0 ", 0}, 169 {"(0 == 1) >= 0 ", 1}, 170 // ne 171 {" 1 != 1 ", 0}, 172 {" 1 != 2 ", 1}, 173 {" 1 < 0 != 1 ", 1}, 174 {" 1 < (0 != 1)", 0}, 175 {" 1 != 0 <= 1 ", 0}, 176 {"(1 != 0) <= 1 ", 1}, 177 {" 0 > 1 != 1 ", 1}, 178 {" 0 > (1 != 1)", 0}, 179 {" 1 != 1 >= 0 ", 0}, 180 {"(1 != 1) >= 0 ", 1}, 181 // and 182 {" 0 & 0 ", 0}, 183 {" 0 & 1 ", 0}, 184 {" 1 & 0 ", 0}, 185 {" 1 & 1 ", 1}, 186 {" 0 == 1 & 0 ", 0}, 187 {" 0 == (1 & 0)", 1}, 188 {" 0 & 1 != 1 ", 0}, 189 {"(0 & 1) != 1 ", 1}, 190 // xor 191 {" 0 ^ 0 ", 0}, 192 {" 0 ^ 1 ", 1}, 193 {" 1 ^ 0 ", 1}, 194 {" 1 ^ 1 ", 0}, 195 {" 0 & 0 ^ 1 ", 1}, 196 {" 0 & (0 ^ 1)", 0}, 197 {" 1 ^ 0 & 0 ", 1}, 198 {"(1 ^ 0) & 0 ", 0}, 199 // or 200 {" 0 | 0 ", 0}, 201 {" 0 | 1 ", 1}, 202 {" 1 | 0 ", 1}, 203 {" 1 | 1 ", 1}, 204 {" 1 ^ 0 | 1 ", 1}, 205 {" 1 ^ (0 | 1)", 0}, 206 {" 1 | 0 ^ 1 ", 1}, 207 {"(1 | 0) ^ 1 ", 0}, 208 // logical and 209 {" 0 && 0 && 0 ", 0}, 210 {" 0 && 0 && 1 ", 0}, 211 {" 0 && 1 && 0 ", 0}, 212 {" 1 && 0 && 0 ", 0}, 213 {" 1 && 1 && 1 ", 1}, 214 {" 1 | 1 && 0 ", 0}, 215 {" 1 | (1 && 0)", 1}, 216 {" 0 && 1 | 1 ", 0}, 217 {"(0 && 1) | 1 ", 1}, 218 // logical or 219 {" 0 || 0 || 0 ", 0}, 220 {" 0 || 0 || 1 ", 1}, 221 {" 0 || 1 || 0 ", 1}, 222 {" 1 || 0 || 0 ", 1}, 223 {" 1 || 1 || 1 ", 1}, 224 {" 0 && 0 || 1 ", 1}, 225 {" 0 && (0 || 1)", 0}, 226 {" 1 || 0 && 0 ", 1}, 227 {"(1 || 0) && 0 ", 0}, 228 // conditional 229 {"-1 == -1 ? -1 : 0 == 0 ? 0 : 1", -1}, 230 {" 0 == -1 ? -1 : 0 == 0 ? 0 : 1", 0}, 231 {" 1 == -1 ? -1 : 1 == 0 ? 0 : 1", 1}, 232 // assignment 233 {"X = 2", 2}, 234 {"X *= 2", 14}, 235 {"X /= 2", 3}, 236 {"X %= 2", 1}, 237 {"X += 2", 9}, 238 {"X -= 2", 5}, 239 {"X <<= 2", 28}, 240 {"X >>= 2", 1}, 241 {"X &= 2", 2}, 242 {"X ^= 2", 5}, 243 {"X |= 2", 7}, 244 } 245 246 func TestEval(t *testing.T) { 247 env := interp.NewExecEnv(name) 248 env.Unset("_") 249 for _, tt := range evalTests { 250 env.Set("E", "") 251 env.Set("D", "4") 252 env.Set("O", "03") 253 env.Set("X", "0x7") 254 switch g, err := env.Eval(tt.expr); { 255 case err != nil: 256 t.Error("unexpected error:", err) 257 case g != tt.n: 258 t.Errorf("expected %v, got %v", tt.n, g) 259 } 260 } 261 } 262 263 var evalErrorTests = []struct { 264 expr string 265 err string 266 }{ 267 // empty 268 {"", "unexpected EOF"}, 269 // number 270 {"09", `invalid number "09"`}, 271 {"0xz", `invalid number "0xz"`}, 272 {"0 1 2", "unexpected NUMBER"}, 273 // ident 274 {"A", `invalid number "alpha"`}, 275 {"Z", `invalid number "0z777"`}, 276 {"M N", "unexpected IDENT"}, 277 // parenthesis 278 {"(", "unexpected EOF"}, 279 {")", "unexpected ')'"}, 280 // op 281 {"$", "unexpected '$'"}, 282 {"++_--", "'++' requires lvalue"}, 283 {"+++_", "'++' requires lvalue"}, 284 {"++0--", "'++' requires lvalue"}, 285 {"0++", "'++' requires lvalue"}, 286 {"++0", "'++' requires lvalue"}, 287 {"+++0", "'++' requires lvalue"}, 288 {"--_++", "'--' requires lvalue"}, 289 {"---_", "'--' requires lvalue"}, 290 {"--0++", "'--' requires lvalue"}, 291 {"0--", "'--' requires lvalue"}, 292 {"--0", "'--' requires lvalue"}, 293 {"---0", "'--' requires lvalue"}, 294 {"<<", "unexpected '<<'"}, 295 {">>", "unexpected '>>'"}, 296 {"<", "unexpected '<'"}, 297 {">", "unexpected '>'"}, 298 {"<=", "unexpected '<='"}, 299 {">=", "unexpected '>='"}, 300 {"==", "unexpected '=='"}, 301 {"!=", "unexpected '!='"}, 302 {"&&", "unexpected '&&'"}, 303 {"||", "unexpected '||'"}, 304 {"=", "unexpected '='"}, 305 {"*=", "unexpected '*='"}, 306 {"/=", "unexpected '/='"}, 307 {"%=", "unexpected '%='"}, 308 {"+=", "unexpected '+='"}, 309 {"-=", "unexpected '-='"}, 310 {"<<=", "unexpected '<<='"}, 311 {">>=", "unexpected '>>='"}, 312 {"&=", "unexpected '&='"}, 313 {"^=", "unexpected '^='"}, 314 {"|=", "unexpected '|='"}, 315 {"0 = 1", "'=' requires lvalue"}, 316 {"0 *= 1", "'*=' requires lvalue"}, 317 {"0 /= 1", "'/=' requires lvalue"}, 318 {"0 %= 1", "'%=' requires lvalue"}, 319 {"0 += 1", "'+=' requires lvalue"}, 320 {"0 -= 1", "'-=' requires lvalue"}, 321 {"0 <<= 1", "'<<=' requires lvalue"}, 322 {"0 >>= 1", "'>>=' requires lvalue"}, 323 {"0 &= 1", "'&=' requires lvalue"}, 324 {"0 ^= 1", "'^=' requires lvalue"}, 325 {"0 |= 1", "'|=' requires lvalue"}, 326 // divide by zero 327 {"0 / 0", "integer divide by zero"}, 328 {"0 % 0", "integer divide by zero"}, 329 {"M /= 0", "integer divide by zero"}, 330 {"M %= 0", "integer divide by zero"}, 331 // negative shift 332 {"1 << -1", "negative shift amount"}, 333 {"1 >> -1", "negative shift amount"}, 334 {"N <<= -1", "negative shift amount"}, 335 {"N >>= -1", "negative shift amount"}, 336 } 337 338 func TestEvalError(t *testing.T) { 339 env := interp.NewExecEnv(name) 340 env.Set("A", "alpha") 341 env.Set("M", "0") 342 env.Set("N", "1") 343 env.Set("Z", "0z777") 344 env.Unset("_") 345 for _, tt := range evalErrorTests { 346 switch _, err := env.Eval(tt.expr); { 347 case err == nil: 348 t.Error("expected error") 349 case err.Error() != tt.err: 350 t.Error("unexpected error:", err) 351 } 352 } 353 }