epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | |
| 2 | /* |
| 3 | * Copyright 2011 Google Inc. |
| 4 | * |
| 5 | * Use of this source code is governed by a BSD-style license that can be |
| 6 | * found in the LICENSE file. |
| 7 | */ |
reed@android.com | e50025a | 2009-09-01 21:00:44 +0000 | [diff] [blame] | 8 | #include "Forth.h" |
| 9 | #include "SkString.h" |
| 10 | |
| 11 | class Reporter { |
| 12 | public: |
| 13 | int fFailureCount; |
| 14 | |
| 15 | Reporter() : fFailureCount(0) {} |
| 16 | void reportFailure(const char expression[], const char file[], int line); |
| 17 | void reportFailure(const char msg[]); |
| 18 | }; |
| 19 | |
| 20 | typedef void (*ForthWordTestProc)(ForthWord*, ForthEngine*, Reporter*); |
| 21 | |
| 22 | #define FORTH_ASSERT(reporter, expression) \ |
| 23 | do { \ |
| 24 | if (!(expression)) { \ |
| 25 | reporter->reportFailure(#expression, __FILE__, __LINE__); \ |
| 26 | } \ |
| 27 | } while (0) |
| 28 | |
| 29 | static void drop_test0(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 30 | fe->push(-17); |
| 31 | word->exec(fe); |
| 32 | FORTH_ASSERT(reporter, 0 == fe->depth()); |
| 33 | } |
| 34 | |
| 35 | static void drop_test1(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 36 | fe->push(-17); |
| 37 | fe->push(93); |
| 38 | word->exec(fe); |
| 39 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 40 | FORTH_ASSERT(reporter, -17 == fe->peek(0)); |
| 41 | } |
| 42 | |
| 43 | static void dup_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 44 | fe->push(-17); |
| 45 | word->exec(fe); |
| 46 | FORTH_ASSERT(reporter, 2 == fe->depth()); |
| 47 | FORTH_ASSERT(reporter, -17 == fe->peek(0)); |
| 48 | FORTH_ASSERT(reporter, -17 == fe->peek(1)); |
| 49 | } |
| 50 | |
| 51 | static void swap_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 52 | fe->push(-17); |
| 53 | fe->push(42); |
| 54 | word->exec(fe); |
| 55 | FORTH_ASSERT(reporter, 2 == fe->depth()); |
| 56 | FORTH_ASSERT(reporter, -17 == fe->peek(0)); |
| 57 | FORTH_ASSERT(reporter, 42 == fe->peek(1)); |
| 58 | } |
| 59 | |
| 60 | static void over_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 61 | fe->push(1); |
| 62 | fe->push(2); |
| 63 | word->exec(fe); |
| 64 | FORTH_ASSERT(reporter, 3 == fe->depth()); |
| 65 | FORTH_ASSERT(reporter, 1 == fe->peek(0)); |
| 66 | FORTH_ASSERT(reporter, 2 == fe->peek(1)); |
| 67 | FORTH_ASSERT(reporter, 1 == fe->peek(2)); |
| 68 | } |
| 69 | |
| 70 | static void rot_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 71 | fe->push(1); |
| 72 | fe->push(2); |
| 73 | fe->push(3); |
| 74 | word->exec(fe); |
| 75 | FORTH_ASSERT(reporter, 3 == fe->depth()); |
| 76 | FORTH_ASSERT(reporter, 2 == fe->peek(2)); |
| 77 | FORTH_ASSERT(reporter, 3 == fe->peek(1)); |
| 78 | FORTH_ASSERT(reporter, 1 == fe->peek(0)); |
| 79 | } |
| 80 | |
| 81 | static void rrot_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 82 | fe->push(1); |
| 83 | fe->push(2); |
| 84 | fe->push(3); |
| 85 | word->exec(fe); |
| 86 | FORTH_ASSERT(reporter, 3 == fe->depth()); |
| 87 | FORTH_ASSERT(reporter, 2 == fe->peek(0)); |
| 88 | FORTH_ASSERT(reporter, 1 == fe->peek(1)); |
| 89 | FORTH_ASSERT(reporter, 3 == fe->peek(2)); |
| 90 | } |
| 91 | |
| 92 | static void swap2_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 93 | fe->push(1); |
| 94 | fe->push(2); |
| 95 | fe->push(3); |
| 96 | fe->push(4); |
| 97 | word->exec(fe); |
| 98 | FORTH_ASSERT(reporter, 4 == fe->depth()); |
| 99 | FORTH_ASSERT(reporter, 2 == fe->peek(0)); |
| 100 | FORTH_ASSERT(reporter, 1 == fe->peek(1)); |
| 101 | FORTH_ASSERT(reporter, 4 == fe->peek(2)); |
| 102 | FORTH_ASSERT(reporter, 3 == fe->peek(3)); |
| 103 | } |
| 104 | |
| 105 | static void dup2_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 106 | fe->push(1); |
| 107 | fe->push(2); |
| 108 | word->exec(fe); |
| 109 | FORTH_ASSERT(reporter, 4 == fe->depth()); |
| 110 | FORTH_ASSERT(reporter, 1 == fe->peek(3)); |
| 111 | FORTH_ASSERT(reporter, 2 == fe->peek(2)); |
| 112 | FORTH_ASSERT(reporter, 1 == fe->peek(1)); |
| 113 | FORTH_ASSERT(reporter, 2 == fe->peek(0)); |
| 114 | } |
| 115 | |
| 116 | static void over2_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 117 | fe->push(1); |
| 118 | fe->push(2); |
| 119 | fe->push(3); |
| 120 | fe->push(4); |
| 121 | word->exec(fe); |
| 122 | FORTH_ASSERT(reporter, 6 == fe->depth()); |
| 123 | FORTH_ASSERT(reporter, 1 == fe->peek(5)); |
| 124 | FORTH_ASSERT(reporter, 2 == fe->peek(4)); |
| 125 | FORTH_ASSERT(reporter, 3 == fe->peek(3)); |
| 126 | FORTH_ASSERT(reporter, 4 == fe->peek(2)); |
| 127 | FORTH_ASSERT(reporter, 1 == fe->peek(1)); |
| 128 | FORTH_ASSERT(reporter, 2 == fe->peek(0)); |
| 129 | } |
| 130 | |
| 131 | static void drop2_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 132 | fe->push(1); |
| 133 | fe->push(2); |
| 134 | fe->push(3); |
| 135 | fe->push(4); |
| 136 | word->exec(fe); |
| 137 | FORTH_ASSERT(reporter, 2 == fe->depth()); |
| 138 | FORTH_ASSERT(reporter, 1 == fe->peek(1)); |
| 139 | FORTH_ASSERT(reporter, 2 == fe->peek(0)); |
| 140 | } |
| 141 | |
reed@android.com | de2e7fb | 2009-09-02 02:07:32 +0000 | [diff] [blame] | 142 | ////////////////////////////////////////////////////////////////////////////// |
| 143 | |
| 144 | static void iadd_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 145 | fe->push(35); |
| 146 | fe->push(99); |
| 147 | word->exec(fe); |
| 148 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 149 | FORTH_ASSERT(reporter, 134 == fe->top()); |
| 150 | fe->push(-135); |
| 151 | word->exec(fe); |
| 152 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 153 | FORTH_ASSERT(reporter, -1 == fe->top()); |
| 154 | } |
| 155 | |
| 156 | static void isub_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 157 | fe->push(35); |
| 158 | fe->push(99); |
| 159 | word->exec(fe); |
| 160 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 161 | FORTH_ASSERT(reporter, 35-99 == fe->top()); |
| 162 | } |
| 163 | |
| 164 | static void imul_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 165 | fe->push(15); |
| 166 | fe->push(-20); |
| 167 | word->exec(fe); |
| 168 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 169 | FORTH_ASSERT(reporter, -300 == fe->top()); |
| 170 | fe->push(0); |
| 171 | word->exec(fe); |
| 172 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 173 | FORTH_ASSERT(reporter, 0 == fe->top()); |
| 174 | } |
| 175 | |
| 176 | static void idiv_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 177 | fe->push(100); |
| 178 | fe->push(25); |
| 179 | word->exec(fe); |
| 180 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 181 | FORTH_ASSERT(reporter, 4 == fe->top()); |
| 182 | fe->setTop(10); |
| 183 | fe->push(-3); |
| 184 | word->exec(fe); |
| 185 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 186 | FORTH_ASSERT(reporter, -3 == fe->top()); |
| 187 | fe->setTop(-1); |
| 188 | fe->push(-1); |
| 189 | word->exec(fe); |
| 190 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 191 | FORTH_ASSERT(reporter, 1 == fe->top()); |
| 192 | } |
| 193 | |
| 194 | static void imod_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 195 | fe->push(10); |
| 196 | fe->push(3); |
| 197 | word->exec(fe); |
| 198 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 199 | FORTH_ASSERT(reporter, 1 == fe->top()); |
| 200 | fe->push(5); |
| 201 | word->exec(fe); |
| 202 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 203 | FORTH_ASSERT(reporter, 1 == fe->top()); |
| 204 | } |
| 205 | |
| 206 | static void idivmod_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 207 | fe->push(10); |
| 208 | fe->push(3); |
| 209 | word->exec(fe); |
| 210 | FORTH_ASSERT(reporter, 2 == fe->depth()); |
| 211 | FORTH_ASSERT(reporter, 1 == fe->peek(1)); |
| 212 | FORTH_ASSERT(reporter, 3 == fe->peek(0)); |
| 213 | } |
| 214 | |
| 215 | static void idot_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 216 | fe->push(1); |
| 217 | fe->push(2); |
| 218 | word->exec(fe); |
| 219 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 220 | FORTH_ASSERT(reporter, 1 == fe->top()); |
| 221 | } |
| 222 | |
| 223 | static void iabs_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 224 | fe->push(10); |
| 225 | word->exec(fe); |
| 226 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 227 | FORTH_ASSERT(reporter, 10 == fe->top()); |
| 228 | fe->setTop(-10); |
| 229 | word->exec(fe); |
| 230 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 231 | FORTH_ASSERT(reporter, 10 == fe->top()); |
| 232 | } |
| 233 | |
| 234 | static void inegate_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 235 | fe->push(10); |
| 236 | word->exec(fe); |
| 237 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 238 | FORTH_ASSERT(reporter, -10 == fe->top()); |
| 239 | fe->setTop(-10); |
| 240 | word->exec(fe); |
| 241 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 242 | FORTH_ASSERT(reporter, 10 == fe->top()); |
| 243 | } |
| 244 | |
| 245 | static void imin_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 246 | fe->push(10); |
| 247 | fe->push(3); |
| 248 | word->exec(fe); |
| 249 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 250 | FORTH_ASSERT(reporter, 3 == fe->top()); |
| 251 | fe->push(-10); |
| 252 | word->exec(fe); |
| 253 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 254 | FORTH_ASSERT(reporter, -10 == fe->top()); |
| 255 | } |
| 256 | |
| 257 | static void imax_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 258 | fe->push(10); |
| 259 | fe->push(3); |
| 260 | word->exec(fe); |
| 261 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 262 | FORTH_ASSERT(reporter, 10 == fe->top()); |
| 263 | fe->push(-10); |
| 264 | word->exec(fe); |
| 265 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 266 | FORTH_ASSERT(reporter, 10 == fe->top()); |
| 267 | } |
| 268 | |
| 269 | /////////////////////////////////////////////////////////////////////////////// |
| 270 | |
| 271 | static void logical_and_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 272 | const static int data[] = { |
| 273 | 0, 0, 0, |
| 274 | 2, 0, 0, |
| 275 | 0, -1, 0, |
| 276 | 1, 5, -1 |
| 277 | }; |
| 278 | for (size_t i = 0; i < SK_ARRAY_COUNT(data)/3; i++) { |
| 279 | fe->push(data[i*3 + 0]); |
| 280 | fe->push(data[i*3 + 1]); |
| 281 | word->exec(fe); |
| 282 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 283 | FORTH_ASSERT(reporter, data[i*3 + 2] == fe->top()); |
| 284 | fe->pop(); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | static void logical_or_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 289 | const static int data[] = { |
| 290 | 0, 0, 0, |
| 291 | 2, 0, -1, |
| 292 | 0, -1, -1, |
| 293 | 1, 5, -1 |
| 294 | }; |
| 295 | for (size_t i = 0; i < SK_ARRAY_COUNT(data)/3; i++) { |
| 296 | fe->push(data[i*3 + 0]); |
| 297 | fe->push(data[i*3 + 1]); |
| 298 | word->exec(fe); |
| 299 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 300 | FORTH_ASSERT(reporter, data[i*3 + 2] == fe->top()); |
| 301 | fe->pop(); |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | static void logical_not_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 306 | const static int data[] = { |
| 307 | 0, -1, |
| 308 | 5, 0, |
| 309 | -1, 0 |
| 310 | }; |
| 311 | for (size_t i = 0; i < SK_ARRAY_COUNT(data)/2; i++) { |
| 312 | fe->push(data[i*2 + 0]); |
| 313 | word->exec(fe); |
| 314 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 315 | FORTH_ASSERT(reporter, data[i*2 + 1] == fe->top()); |
| 316 | fe->pop(); |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | static void if_dup_test(ForthWord* word, ForthEngine* fe, Reporter* reporter) { |
| 321 | fe->push(10); |
| 322 | word->exec(fe); |
| 323 | FORTH_ASSERT(reporter, 2 == fe->depth()); |
| 324 | FORTH_ASSERT(reporter, 10 == fe->peek(1)); |
| 325 | FORTH_ASSERT(reporter, 10 == fe->peek(0)); |
| 326 | fe->pop(); |
| 327 | fe->pop(); |
| 328 | fe->push(0); |
| 329 | word->exec(fe); |
| 330 | FORTH_ASSERT(reporter, 1 == fe->depth()); |
| 331 | FORTH_ASSERT(reporter, 0 == fe->top()); |
| 332 | } |
| 333 | |
reed@android.com | e50025a | 2009-09-01 21:00:44 +0000 | [diff] [blame] | 334 | static const struct { |
| 335 | const char* fName; |
| 336 | ForthWordTestProc fProc; |
| 337 | } gRecs[] = { |
| 338 | { "DROP", drop_test0 }, { "DROP", drop_test1 }, |
| 339 | { "DUP", dup_test }, |
| 340 | { "SWAP", swap_test }, |
| 341 | { "OVER", over_test }, |
| 342 | { "ROT", rot_test }, |
| 343 | { "-ROT", rrot_test }, |
| 344 | { "2SWAP", swap2_test }, |
| 345 | { "2DUP", dup2_test }, |
| 346 | { "2OVER", over2_test }, |
| 347 | { "2DROP", drop2_test }, |
reed@android.com | de2e7fb | 2009-09-02 02:07:32 +0000 | [diff] [blame] | 348 | |
| 349 | { "+", iadd_test }, |
| 350 | { "-", isub_test }, |
| 351 | { "*", imul_test }, |
| 352 | { "/", idiv_test }, |
| 353 | { "MOD", imod_test }, |
| 354 | { "/MOD", idivmod_test }, |
| 355 | |
| 356 | // { ".", idot_test }, |
| 357 | { "ABS", iabs_test }, |
| 358 | { "NEGATE", inegate_test }, |
| 359 | { "MIN", imin_test }, |
| 360 | { "MAX", imax_test }, |
| 361 | |
| 362 | { "AND", logical_and_test }, |
| 363 | { "OR", logical_or_test }, |
| 364 | { "0=", logical_not_test }, |
| 365 | { "?DUP", if_dup_test }, |
reed@android.com | e50025a | 2009-09-01 21:00:44 +0000 | [diff] [blame] | 366 | }; |
| 367 | |
| 368 | /////////////////////////////////////////////////////////////////////////////// |
| 369 | |
| 370 | void Reporter::reportFailure(const char expression[], const char file[], |
| 371 | int line) { |
| 372 | SkDebugf("failed %s:%d: %s\n", file, line, expression); |
| 373 | fFailureCount += 1; |
| 374 | } |
| 375 | |
| 376 | void Reporter::reportFailure(const char msg[]) { |
| 377 | SkDebugf("%s\n"); |
| 378 | fFailureCount += 1; |
| 379 | } |
| 380 | |
reed@android.com | de2e7fb | 2009-09-02 02:07:32 +0000 | [diff] [blame] | 381 | void Forth_test_stdwords(bool verbose); |
| 382 | void Forth_test_stdwords(bool verbose) { |
reed@android.com | e50025a | 2009-09-01 21:00:44 +0000 | [diff] [blame] | 383 | ForthEnv env; |
| 384 | Reporter reporter; |
| 385 | |
| 386 | for (size_t i = 0; i < SK_ARRAY_COUNT(gRecs); i++) { |
| 387 | ForthEngine engine(NULL); |
| 388 | |
| 389 | ForthWord* word = env.findWord(gRecs[i].fName); |
| 390 | if (NULL == word) { |
| 391 | SkString str; |
| 392 | str.printf("--- can't find stdword %d", gRecs[i].fName); |
| 393 | reporter.reportFailure(str.c_str()); |
| 394 | } else { |
reed@android.com | de2e7fb | 2009-09-02 02:07:32 +0000 | [diff] [blame] | 395 | if (verbose) { |
| 396 | SkDebugf("--- testing %s %p\n", gRecs[i].fName, word); |
| 397 | } |
reed@android.com | e50025a | 2009-09-01 21:00:44 +0000 | [diff] [blame] | 398 | gRecs[i].fProc(word, &engine, &reporter); |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | if (0 == reporter.fFailureCount) { |
| 403 | SkDebugf("--- success!\n"); |
| 404 | } else { |
| 405 | SkDebugf("--- %d failures\n", reporter.fFailureCount); |
| 406 | } |
| 407 | } |
| 408 | |