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