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 */ 8#include "Forth.h" 9#include "SkString.h" 10 11class Reporter { 12public: 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 20typedef 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 29static 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 35static 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 43static 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 51static 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 60static 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 70static 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 81static 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 92static 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 105static 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 116static 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 131static 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 142////////////////////////////////////////////////////////////////////////////// 143 144static 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 156static 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 164static 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 176static 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 194static 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 206static 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 215static 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 223static 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 234static 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 245static 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 257static 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 271static 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 288static 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 305static 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 320static 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 334static 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 }, 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 }, 366}; 367 368/////////////////////////////////////////////////////////////////////////////// 369 370void 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 376void Reporter::reportFailure(const char msg[]) { 377 SkDebugf("%s\n"); 378 fFailureCount += 1; 379} 380 381void Forth_test_stdwords(bool verbose); 382void Forth_test_stdwords(bool verbose) { 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 { 395 if (verbose) { 396 SkDebugf("--- testing %s %p\n", gRecs[i].fName, word); 397 } 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