Annotation of gforth/test/ttester.fs, revision 1.15

1.14      anton       1: \ This file contains the code for ttester, a utility for testing Forth words,
                      2: \ as developed by several authors (see below), together with some explanations
                      3: \ of its use.
                      4: 
                      5: \ ttester is based on the original tester suite by Hayes:
1.7       anton       6: \ From: John Hayes S1I
                      7: \ Subject: tester.fr
                      8: \ Date: Mon, 27 Nov 95 13:10:09 PST  
1.1       anton       9: \ (C) 1995 JOHNS HOPKINS UNIVERSITY / APPLIED PHYSICS LABORATORY
                     10: \ MAY BE DISTRIBUTED FREELY AS LONG AS THIS COPYRIGHT NOTICE REMAINS.
                     11: \ VERSION 1.1
1.14      anton      12: \ All the subsequent changes have been placed in the public domain.
                     13: \ The primary changes from the original are the replacement of "{" by "T{"
                     14: \ and "}" by "}T" (to avoid conflicts with the uses of { for locals and }
                     15: \ for FSL arrays), modifications so that the stack is allowed to be non-empty
                     16: \ before T{, and extensions for the handling of floating point tests.
                     17: \ Code for testing equality of floating point values comes
1.7       anton      18: \ from ftester.fs written by David N. Williams, based on the idea of
1.14      anton      19: \ approximate equality in Dirk Zoller's float.4th.
                     20: \ Further revisions were provided by Anton Ertl, including the ability
                     21: \ to handle either integrated or separate floating point stacks.
                     22: \ Revision history and possibly newer versions can be found at
1.13      anton      23: \ http://www.complang.tuwien.ac.at/cvsweb/cgi-bin/cvsweb/gforth/test/ttester.fs
1.14      anton      24: \ Explanatory material and minor reformatting (no code changes) by
                     25: \ C. G. Montgomery March 2009, with helpful comments from David Williams
                     26: \ and Krishna Myneni.
                     27: 
                     28: \ Usage:
                     29: 
                     30: \ The basic usage takes the form  T{ <code> -> <expected stack> }T .
                     31: \ This executes  <code>  and compares the resulting stack contents with
                     32: \ the  <expected stack>  values, and reports any discrepancy between the
                     33: \ two sets of values.
                     34: \ For example:
                     35: \ T{ 1 2 3 swap -> 1 3 2 }T  ok
                     36: \ T{ 1 2 3 swap -> 1 2 2 }T INCORRECT RESULT: T{ 1 2 3 swap -> 1 2 2 }T ok
                     37: \ T{ 1 2 3 swap -> 1 2 }T WRONG NUMBER OF RESULTS: T{ 1 2 3 swap -> 1 2 }T ok
                     38: 
                     39: \ Floating point testing can involve further complications.  The code
                     40: \ attempts to determine whether floating-point support is present, and
                     41: \ if so, whether there is a separate floating-point stack, and behave
                     42: \ accordingly.  The CONSTANTs HAS-FLOATING and HAS-FLOATING-STACK
                     43: \ contain the results of its efforts, so the behavior of the code can
                     44: \ be modified by the user if necessary.
                     45: 
                     46: \ Then there are the perennial issues of floating point value
                     47: \ comparisons.  Exact equality is specified by SET-EXACT (the
                     48: \ default).  If approximate equality tests are desired, execute
                     49: \ SET-NEAR .  Then the FVARIABLEs REL-NEAR (default 1E-12) and
                     50: \ ABS-NEAR (default 0E) contain the values to be used in comparisons
                     51: \ by the (internal) word FNEARLY= .
                     52: 
                     53: \ When there is not a separate floating point stack and you want to
                     54: \ use approximate equality for FP values, it is necessary to identify
                     55: \ which stack items are floating point quantities.  This can be done
                     56: \ by replacing the closing }T with a version that specifies this, such
                     57: \ as RRXR}T which identifies the stack picture ( r r x r ).  The code
                     58: \ provides such words for all combinations of R and X with up to four
                     59: \ stack items.  They can be used with either an integrated or separate
                     60: \ floating point stacks. Adding more if you need them is
                     61: \ straightforward; see the examples in the source.  Here is an example
                     62: \ which also illustrates controlling the precision of comparisons:
                     63: 
                     64: \   SET-NEAR
                     65: \   1E-6 REL-NEAR F!
                     66: \   T{ S" 3.14159E" >FLOAT -> -1E FACOS TRUE RX}T
                     67: 
                     68: \ The word ERROR is now vectored, so that its action can be changed by
                     69: \ the user (for example, to add a counter for the number of errors).
                     70: \ The default action ERROR1 can be used as a factor in the display of
                     71: \ error reports.
1.13      anton      72: 
1.14      anton      73: \ Loading ttester.fs does not change BASE.  Remember that floating point input
                     74: \ is ambiguous if the base is not decimal.
1.7       anton      75: 
1.14      anton      76: \ The file defines some 70 words in all, but in most cases only the
                     77: \ ones mentioned above will be needed for successful testing.
1.1       anton      78: 
1.4       anton      79: BASE @
1.1       anton      80: HEX
                     81: 
1.14      anton      82: VARIABLE ACTUAL-DEPTH                  \ stack record
1.1       anton      83: CREATE ACTUAL-RESULTS 20 CELLS ALLOT
                     84: VARIABLE START-DEPTH
1.14      anton      85: VARIABLE XCURSOR      \ for ...}T
1.1       anton      86: VARIABLE ERROR-XT
                     87: 
1.14      anton      88: : ERROR ERROR-XT @ EXECUTE ;   \ for vectoring of error reporting
1.1       anton      89: 
1.14      anton      90: : "FLOATING" S" FLOATING" ;    \ only compiled S" in CORE
1.1       anton      91: : "FLOATING-STACK" S" FLOATING-STACK" ;
                     92: "FLOATING" ENVIRONMENT? [IF]
                     93:     [IF]
                     94:         TRUE
                     95:     [ELSE]
                     96:         FALSE
                     97:     [THEN]
                     98: [ELSE]
                     99:     FALSE
                    100: [THEN] CONSTANT HAS-FLOATING
                    101: "FLOATING-STACK" ENVIRONMENT? [IF]
                    102:     [IF]
                    103:         TRUE
                    104:     [ELSE]
                    105:         FALSE
                    106:     [THEN]
1.14      anton     107: [ELSE]            \ We don't know whether the FP stack is separate.
                    108:     HAS-FLOATING  \ If we have FLOATING, we assume it is.
1.1       anton     109: [THEN] CONSTANT HAS-FLOATING-STACK
                    110: 
                    111: HAS-FLOATING [IF]
1.14      anton     112:     \ Set the following to the relative and absolute tolerances you
                    113:     \ want for approximate float equality, to be used with F~ in
                    114:     \ FNEARLY=.  Keep the signs, because F~ needs them.
1.5       anton     115:     FVARIABLE REL-NEAR DECIMAL 1E-12 HEX REL-NEAR F!
1.1       anton     116:     FVARIABLE ABS-NEAR    DECIMAL 0E HEX ABS-NEAR F!
                    117: 
1.14      anton     118:     \ When EXACT? is TRUE, }F uses FEXACTLY=, otherwise FNEARLY=.
1.1       anton     119:     
                    120:     TRUE VALUE EXACT?
                    121:     : SET-EXACT  ( -- )   TRUE TO EXACT? ;
                    122:     : SET-NEAR   ( -- )  FALSE TO EXACT? ;
                    123: 
                    124:     DECIMAL
                    125:     : FEXACTLY=  ( F: X Y -- S: FLAG )
                    126:         (
1.14      anton     127:         Leave TRUE if the two floats are identical.
1.1       anton     128:         )
                    129:         0E F~ ;
                    130:     HEX
                    131:     
                    132:     : FABS=  ( F: X Y -- S: FLAG )
                    133:         (
1.14      anton     134:         Leave TRUE if the two floats are equal within the tolerance
                    135:         stored in ABS-NEAR.
1.1       anton     136:         )
                    137:         ABS-NEAR F@ F~ ;
                    138:     
                    139:     : FREL=  ( F: X Y -- S: FLAG )
                    140:         (
1.14      anton     141:         Leave TRUE if the two floats are relatively equal based on the
                    142:         tolerance stored in ABS-NEAR.
1.1       anton     143:         )
                    144:         REL-NEAR F@ FNEGATE F~ ;
                    145: 
                    146:     : F2DUP  FOVER FOVER ;
                    147:     : F2DROP FDROP FDROP ;
                    148:     
                    149:     : FNEARLY=  ( F: X Y -- S: FLAG )
                    150:         (
1.14      anton     151:         Leave TRUE if the two floats are nearly equal.  This is a 
                    152:         refinement of Dirk Zoller's FEQ to also allow X = Y, including
                    153:         both zero, or to allow approximately equality when X and Y are too
                    154:         small to satisfy the relative approximation mode in the F~ 
                    155:         specification.
1.1       anton     156:         )
                    157:         F2DUP FEXACTLY= IF F2DROP TRUE EXIT THEN
                    158:         F2DUP FREL=     IF F2DROP TRUE EXIT THEN
                    159:         FABS= ;
                    160: 
                    161:     : FCONF= ( R1 R2 -- F )
                    162:         EXACT? IF
                    163:             FEXACTLY=
                    164:         ELSE
                    165:             FNEARLY=
                    166:         THEN ;
                    167: [THEN]
                    168: 
                    169: HAS-FLOATING-STACK [IF]
                    170:     VARIABLE ACTUAL-FDEPTH
                    171:     CREATE ACTUAL-FRESULTS 20 FLOATS ALLOT
                    172:     VARIABLE START-FDEPTH
                    173:     VARIABLE FCURSOR
                    174: 
1.15    ! anton     175:     DECIMAL
1.1       anton     176:     : EMPTY-FSTACK ( ... -- ... )
                    177:         FDEPTH START-FDEPTH @ < IF
                    178:             FDEPTH START-FDEPTH @ SWAP DO 0E LOOP
                    179:         THEN
                    180:         FDEPTH START-FDEPTH @ > IF
                    181:             FDEPTH START-FDEPTH @ DO FDROP LOOP
                    182:         THEN ;
1.15    ! anton     183:     HEX
        !           184:     
1.1       anton     185:     : F{ ( -- )
                    186:         FDEPTH START-FDEPTH ! 0 FCURSOR ! ;
                    187: 
                    188:     : F-> ( ... -- ... )
                    189:         FDEPTH DUP ACTUAL-FDEPTH !
                    190:         START-FDEPTH @ > IF
1.8       anton     191:             FDEPTH START-FDEPTH @ - 0 DO ACTUAL-FRESULTS I FLOATS + F! LOOP
1.1       anton     192:         THEN ;
                    193: 
                    194:     : F} ( ... -- ... )
                    195:         FDEPTH ACTUAL-FDEPTH @ = IF
                    196:             FDEPTH START-FDEPTH @ > IF
1.10      anton     197:                 FDEPTH START-FDEPTH @ - 0 DO
1.1       anton     198:                     ACTUAL-FRESULTS I FLOATS + F@ FCONF= INVERT IF
                    199:                         S" INCORRECT FP RESULT: " ERROR LEAVE
                    200:                     THEN
                    201:                 LOOP
                    202:             THEN
                    203:         ELSE
                    204:             S" WRONG NUMBER OF FP RESULTS: " ERROR
                    205:         THEN ;
                    206: 
                    207:     : F...}T ( -- )
1.6       anton     208:         FCURSOR @ START-FDEPTH @ + ACTUAL-FDEPTH @ <> IF
1.11      anton     209:             S" NUMBER OF FLOAT RESULTS BEFORE '->' DOES NOT MATCH ...}T SPECIFICATION: " ERROR
1.8       anton     210:         ELSE FDEPTH START-FDEPTH @ = 0= IF
                    211:             S" NUMBER OF FLOAT RESULTS BEFORE AND AFTER '->' DOES NOT MATCH: " ERROR
                    212:         THEN THEN ;
                    213: 
1.1       anton     214:     
                    215:     : FTESTER ( R -- )
1.6       anton     216:         FDEPTH 0= ACTUAL-FDEPTH @ FCURSOR @ START-FDEPTH @ + 1+ < OR IF
1.8       anton     217:             S" NUMBER OF FLOAT RESULTS AFTER '->' BELOW ...}T SPECIFICATION: " ERROR 
                    218:         ELSE ACTUAL-FRESULTS FCURSOR @ FLOATS + F@ FCONF= 0= IF
1.9       anton     219:             S" INCORRECT FP RESULT: " ERROR
                    220:         THEN THEN
1.1       anton     221:         1 FCURSOR +! ;
                    222:         
                    223: [ELSE]
                    224:     : EMPTY-FSTACK ;
                    225:     : F{ ;
                    226:     : F-> ;
                    227:     : F} ;
                    228:     : F...}T ;
                    229: 
1.12      anton     230:     HAS-FLOATING [IF]
1.3       anton     231:     DECIMAL
1.1       anton     232:     : COMPUTE-CELLS-PER-FP ( -- U )
1.3       anton     233:         DEPTH 0E DEPTH 1- >R FDROP R> SWAP - ;
                    234:     HEX
1.1       anton     235: 
                    236:     COMPUTE-CELLS-PER-FP CONSTANT CELLS-PER-FP
1.12      anton     237: 
1.1       anton     238:     : FTESTER ( R -- )
1.6       anton     239:         DEPTH CELLS-PER-FP < ACTUAL-DEPTH @ XCURSOR @ START-DEPTH @ + CELLS-PER-FP + < OR IF
                    240:             S" NUMBER OF RESULTS AFTER '->' BELOW ...}T SPECIFICATION: " ERROR EXIT
1.9       anton     241:         ELSE ACTUAL-RESULTS XCURSOR @ CELLS + F@ FCONF= 0= IF
1.1       anton     242:             S" INCORRECT FP RESULT: " ERROR
1.9       anton     243:         THEN THEN
1.1       anton     244:         CELLS-PER-FP XCURSOR +! ;
1.12      anton     245:     [THEN]
                    246: [THEN]    
1.1       anton     247: 
1.14      anton     248: : EMPTY-STACK  \ ( ... -- ) empty stack; handles underflowed stack too.
1.1       anton     249:     DEPTH START-DEPTH @ < IF
                    250:         DEPTH START-DEPTH @ SWAP DO 0 LOOP
                    251:     THEN
                    252:     DEPTH START-DEPTH @ > IF
                    253:         DEPTH START-DEPTH @ DO DROP LOOP
                    254:     THEN
                    255:     EMPTY-FSTACK ;
                    256: 
1.14      anton     257: : ERROR1       \ ( C-ADDR U -- ) display an error message 
                    258:                \ followed by the line that had the error.
                    259:    TYPE SOURCE TYPE CR                 \ display line corresponding to error
                    260:    EMPTY-STACK                         \ throw away everything else
1.1       anton     261: ;
                    262: 
                    263: ' ERROR1 ERROR-XT !
                    264: 
1.14      anton     265: : T{           \ ( -- ) syntactic sugar.
1.3       anton     266:    DEPTH START-DEPTH ! 0 XCURSOR ! F{ ;
1.1       anton     267: 
1.14      anton     268: : ->           \ ( ... -- ) record depth and contents of stack.
                    269:    DEPTH DUP ACTUAL-DEPTH !            \ record depth
                    270:    START-DEPTH @ > IF          \ if there is something on the stack
                    271:        DEPTH START-DEPTH @ - 0 DO ACTUAL-RESULTS I CELLS + ! LOOP \ save them
1.1       anton     272:    THEN
                    273:    F-> ;
                    274: 
                    275: : }T           \ ( ... -- ) COMPARE STACK (EXPECTED) CONTENTS WITH SAVED
                    276:                \ (ACTUAL) CONTENTS.
1.14      anton     277:    DEPTH ACTUAL-DEPTH @ = IF           \ if depths match
                    278:       DEPTH START-DEPTH @ > IF         \ if there is something on the stack
                    279:          DEPTH START-DEPTH @ - 0 DO    \ for each stack item
                    280:            ACTUAL-RESULTS I CELLS + @  \ compare actual with expected
1.1       anton     281:            <> IF S" INCORRECT RESULT: " ERROR LEAVE THEN
                    282:         LOOP
                    283:       THEN
1.14      anton     284:    ELSE                                        \ depth mismatch
1.1       anton     285:       S" WRONG NUMBER OF RESULTS: " ERROR
                    286:    THEN
                    287:    F} ;
                    288: 
                    289: : ...}T ( -- )
1.6       anton     290:     XCURSOR @ START-DEPTH @ + ACTUAL-DEPTH @ <> IF
1.7       anton     291:         S" NUMBER OF CELL RESULTS BEFORE '->' DOES NOT MATCH ...}T SPECIFICATION: " ERROR
1.8       anton     292:     ELSE DEPTH START-DEPTH @ = 0= IF
                    293:         S" NUMBER OF CELL RESULTS BEFORE AND AFTER '->' DOES NOT MATCH: " ERROR
                    294:     THEN THEN
1.1       anton     295:     F...}T ;
                    296: 
                    297: : XTESTER ( X -- )
1.6       anton     298:     DEPTH 0= ACTUAL-DEPTH @ XCURSOR @ START-DEPTH @ + 1+ < OR IF
                    299:         S" NUMBER OF CELL RESULTS AFTER '->' BELOW ...}T SPECIFICATION: " ERROR EXIT
1.8       anton     300:     ELSE ACTUAL-RESULTS XCURSOR @ CELLS + @ <> IF
1.9       anton     301:         S" INCORRECT CELL RESULT: " ERROR
                    302:     THEN THEN
1.1       anton     303:     1 XCURSOR +! ;
                    304: 
                    305: : X}T XTESTER ...}T ;
1.12      anton     306: : XX}T XTESTER XTESTER ...}T ;
                    307: : XXX}T XTESTER XTESTER XTESTER ...}T ;
                    308: : XXXX}T XTESTER XTESTER XTESTER XTESTER ...}T ;
                    309: 
                    310: HAS-FLOATING [IF]
1.1       anton     311: : R}T FTESTER ...}T ;
                    312: : XR}T FTESTER XTESTER ...}T ;
                    313: : RX}T XTESTER FTESTER ...}T ;
                    314: : RR}T FTESTER FTESTER ...}T ;
                    315: : XXR}T FTESTER XTESTER XTESTER ...}T ;
                    316: : XRX}T XTESTER FTESTER XTESTER ...}T ;
                    317: : XRR}T FTESTER FTESTER XTESTER ...}T ;
                    318: : RXX}T XTESTER XTESTER FTESTER ...}T ;
                    319: : RXR}T FTESTER XTESTER FTESTER ...}T ;
                    320: : RRX}T XTESTER FTESTER FTESTER ...}T ;
                    321: : RRR}T FTESTER FTESTER FTESTER ...}T ;
                    322: : XXXR}T FTESTER XTESTER XTESTER XTESTER ...}T ;
                    323: : XXRX}T XTESTER FTESTER XTESTER XTESTER ...}T ;
                    324: : XXRR}T FTESTER FTESTER XTESTER XTESTER ...}T ;
                    325: : XRXX}T XTESTER XTESTER FTESTER XTESTER ...}T ;
                    326: : XRXR}T FTESTER XTESTER FTESTER XTESTER ...}T ;
                    327: : XRRX}T XTESTER FTESTER FTESTER XTESTER ...}T ;
                    328: : XRRR}T FTESTER FTESTER FTESTER XTESTER ...}T ;
                    329: : RXXX}T XTESTER XTESTER XTESTER FTESTER ...}T ;
                    330: : RXXR}T FTESTER XTESTER XTESTER FTESTER ...}T ;
                    331: : RXRX}T XTESTER FTESTER XTESTER FTESTER ...}T ;
                    332: : RXRR}T FTESTER FTESTER XTESTER FTESTER ...}T ;
                    333: : RRXX}T XTESTER XTESTER FTESTER FTESTER ...}T ;
                    334: : RRXR}T FTESTER XTESTER FTESTER FTESTER ...}T ;
                    335: : RRRX}T XTESTER FTESTER FTESTER FTESTER ...}T ;
                    336: : RRRR}T FTESTER FTESTER FTESTER FTESTER ...}T ;
1.12      anton     337: [THEN]
1.1       anton     338: 
1.14      anton     339: \ Set the following flag to TRUE for more verbose output; this may
                    340: \ allow you to tell which test caused your system to hang.
                    341: VARIABLE VERBOSE
                    342:    FALSE VERBOSE !
                    343: 
1.1       anton     344: : TESTING      \ ( -- ) TALKING COMMENT.
                    345:    SOURCE VERBOSE @
                    346:    IF DUP >R TYPE CR R> >IN !
                    347:    ELSE >IN ! DROP
                    348:    THEN ;
1.4       anton     349: 
1.6       anton     350: BASE !
1.14      anton     351: \ end of ttester.fs

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>