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

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: 
                    175:     : EMPTY-FSTACK ( ... -- ... )
                    176:         FDEPTH START-FDEPTH @ < IF
                    177:             FDEPTH START-FDEPTH @ SWAP DO 0E LOOP
                    178:         THEN
                    179:         FDEPTH START-FDEPTH @ > IF
                    180:             FDEPTH START-FDEPTH @ DO FDROP LOOP
                    181:         THEN ;
                    182: 
                    183:     : F{ ( -- )
                    184:         FDEPTH START-FDEPTH ! 0 FCURSOR ! ;
                    185: 
                    186:     : F-> ( ... -- ... )
                    187:         FDEPTH DUP ACTUAL-FDEPTH !
                    188:         START-FDEPTH @ > IF
1.8       anton     189:             FDEPTH START-FDEPTH @ - 0 DO ACTUAL-FRESULTS I FLOATS + F! LOOP
1.1       anton     190:         THEN ;
                    191: 
                    192:     : F} ( ... -- ... )
                    193:         FDEPTH ACTUAL-FDEPTH @ = IF
                    194:             FDEPTH START-FDEPTH @ > IF
1.10      anton     195:                 FDEPTH START-FDEPTH @ - 0 DO
1.1       anton     196:                     ACTUAL-FRESULTS I FLOATS + F@ FCONF= INVERT IF
                    197:                         S" INCORRECT FP RESULT: " ERROR LEAVE
                    198:                     THEN
                    199:                 LOOP
                    200:             THEN
                    201:         ELSE
                    202:             S" WRONG NUMBER OF FP RESULTS: " ERROR
                    203:         THEN ;
                    204: 
                    205:     : F...}T ( -- )
1.6       anton     206:         FCURSOR @ START-FDEPTH @ + ACTUAL-FDEPTH @ <> IF
1.11      anton     207:             S" NUMBER OF FLOAT RESULTS BEFORE '->' DOES NOT MATCH ...}T SPECIFICATION: " ERROR
1.8       anton     208:         ELSE FDEPTH START-FDEPTH @ = 0= IF
                    209:             S" NUMBER OF FLOAT RESULTS BEFORE AND AFTER '->' DOES NOT MATCH: " ERROR
                    210:         THEN THEN ;
                    211: 
1.1       anton     212:     
                    213:     : FTESTER ( R -- )
1.6       anton     214:         FDEPTH 0= ACTUAL-FDEPTH @ FCURSOR @ START-FDEPTH @ + 1+ < OR IF
1.8       anton     215:             S" NUMBER OF FLOAT RESULTS AFTER '->' BELOW ...}T SPECIFICATION: " ERROR 
                    216:         ELSE ACTUAL-FRESULTS FCURSOR @ FLOATS + F@ FCONF= 0= IF
1.9       anton     217:             S" INCORRECT FP RESULT: " ERROR
                    218:         THEN THEN
1.1       anton     219:         1 FCURSOR +! ;
                    220:         
                    221: [ELSE]
                    222:     : EMPTY-FSTACK ;
                    223:     : F{ ;
                    224:     : F-> ;
                    225:     : F} ;
                    226:     : F...}T ;
                    227: 
1.12      anton     228:     HAS-FLOATING [IF]
1.3       anton     229:     DECIMAL
1.1       anton     230:     : COMPUTE-CELLS-PER-FP ( -- U )
1.3       anton     231:         DEPTH 0E DEPTH 1- >R FDROP R> SWAP - ;
                    232:     HEX
1.1       anton     233: 
                    234:     COMPUTE-CELLS-PER-FP CONSTANT CELLS-PER-FP
1.12      anton     235: 
1.1       anton     236:     : FTESTER ( R -- )
1.6       anton     237:         DEPTH CELLS-PER-FP < ACTUAL-DEPTH @ XCURSOR @ START-DEPTH @ + CELLS-PER-FP + < OR IF
                    238:             S" NUMBER OF RESULTS AFTER '->' BELOW ...}T SPECIFICATION: " ERROR EXIT
1.9       anton     239:         ELSE ACTUAL-RESULTS XCURSOR @ CELLS + F@ FCONF= 0= IF
1.1       anton     240:             S" INCORRECT FP RESULT: " ERROR
1.9       anton     241:         THEN THEN
1.1       anton     242:         CELLS-PER-FP XCURSOR +! ;
1.12      anton     243:     [THEN]
                    244: [THEN]    
1.1       anton     245: 
1.14    ! anton     246: : EMPTY-STACK  \ ( ... -- ) empty stack; handles underflowed stack too.
1.1       anton     247:     DEPTH START-DEPTH @ < IF
                    248:         DEPTH START-DEPTH @ SWAP DO 0 LOOP
                    249:     THEN
                    250:     DEPTH START-DEPTH @ > IF
                    251:         DEPTH START-DEPTH @ DO DROP LOOP
                    252:     THEN
                    253:     EMPTY-FSTACK ;
                    254: 
1.14    ! anton     255: : ERROR1       \ ( C-ADDR U -- ) display an error message 
        !           256:                \ followed by the line that had the error.
        !           257:    TYPE SOURCE TYPE CR                 \ display line corresponding to error
        !           258:    EMPTY-STACK                         \ throw away everything else
1.1       anton     259: ;
                    260: 
                    261: ' ERROR1 ERROR-XT !
                    262: 
1.14    ! anton     263: : T{           \ ( -- ) syntactic sugar.
1.3       anton     264:    DEPTH START-DEPTH ! 0 XCURSOR ! F{ ;
1.1       anton     265: 
1.14    ! anton     266: : ->           \ ( ... -- ) record depth and contents of stack.
        !           267:    DEPTH DUP ACTUAL-DEPTH !            \ record depth
        !           268:    START-DEPTH @ > IF          \ if there is something on the stack
        !           269:        DEPTH START-DEPTH @ - 0 DO ACTUAL-RESULTS I CELLS + ! LOOP \ save them
1.1       anton     270:    THEN
                    271:    F-> ;
                    272: 
                    273: : }T           \ ( ... -- ) COMPARE STACK (EXPECTED) CONTENTS WITH SAVED
                    274:                \ (ACTUAL) CONTENTS.
1.14    ! anton     275:    DEPTH ACTUAL-DEPTH @ = IF           \ if depths match
        !           276:       DEPTH START-DEPTH @ > IF         \ if there is something on the stack
        !           277:          DEPTH START-DEPTH @ - 0 DO    \ for each stack item
        !           278:            ACTUAL-RESULTS I CELLS + @  \ compare actual with expected
1.1       anton     279:            <> IF S" INCORRECT RESULT: " ERROR LEAVE THEN
                    280:         LOOP
                    281:       THEN
1.14    ! anton     282:    ELSE                                        \ depth mismatch
1.1       anton     283:       S" WRONG NUMBER OF RESULTS: " ERROR
                    284:    THEN
                    285:    F} ;
                    286: 
                    287: : ...}T ( -- )
1.6       anton     288:     XCURSOR @ START-DEPTH @ + ACTUAL-DEPTH @ <> IF
1.7       anton     289:         S" NUMBER OF CELL RESULTS BEFORE '->' DOES NOT MATCH ...}T SPECIFICATION: " ERROR
1.8       anton     290:     ELSE DEPTH START-DEPTH @ = 0= IF
                    291:         S" NUMBER OF CELL RESULTS BEFORE AND AFTER '->' DOES NOT MATCH: " ERROR
                    292:     THEN THEN
1.1       anton     293:     F...}T ;
                    294: 
                    295: : XTESTER ( X -- )
1.6       anton     296:     DEPTH 0= ACTUAL-DEPTH @ XCURSOR @ START-DEPTH @ + 1+ < OR IF
                    297:         S" NUMBER OF CELL RESULTS AFTER '->' BELOW ...}T SPECIFICATION: " ERROR EXIT
1.8       anton     298:     ELSE ACTUAL-RESULTS XCURSOR @ CELLS + @ <> IF
1.9       anton     299:         S" INCORRECT CELL RESULT: " ERROR
                    300:     THEN THEN
1.1       anton     301:     1 XCURSOR +! ;
                    302: 
                    303: : X}T XTESTER ...}T ;
1.12      anton     304: : XX}T XTESTER XTESTER ...}T ;
                    305: : XXX}T XTESTER XTESTER XTESTER ...}T ;
                    306: : XXXX}T XTESTER XTESTER XTESTER XTESTER ...}T ;
                    307: 
                    308: HAS-FLOATING [IF]
1.1       anton     309: : R}T FTESTER ...}T ;
                    310: : XR}T FTESTER XTESTER ...}T ;
                    311: : RX}T XTESTER FTESTER ...}T ;
                    312: : RR}T FTESTER FTESTER ...}T ;
                    313: : XXR}T FTESTER XTESTER XTESTER ...}T ;
                    314: : XRX}T XTESTER FTESTER XTESTER ...}T ;
                    315: : XRR}T FTESTER FTESTER XTESTER ...}T ;
                    316: : RXX}T XTESTER XTESTER FTESTER ...}T ;
                    317: : RXR}T FTESTER XTESTER FTESTER ...}T ;
                    318: : RRX}T XTESTER FTESTER FTESTER ...}T ;
                    319: : RRR}T FTESTER FTESTER FTESTER ...}T ;
                    320: : XXXR}T FTESTER XTESTER XTESTER XTESTER ...}T ;
                    321: : XXRX}T XTESTER FTESTER XTESTER XTESTER ...}T ;
                    322: : XXRR}T FTESTER FTESTER XTESTER XTESTER ...}T ;
                    323: : XRXX}T XTESTER XTESTER FTESTER XTESTER ...}T ;
                    324: : XRXR}T FTESTER XTESTER FTESTER XTESTER ...}T ;
                    325: : XRRX}T XTESTER FTESTER FTESTER XTESTER ...}T ;
                    326: : XRRR}T FTESTER FTESTER FTESTER XTESTER ...}T ;
                    327: : RXXX}T XTESTER XTESTER XTESTER FTESTER ...}T ;
                    328: : RXXR}T FTESTER XTESTER XTESTER FTESTER ...}T ;
                    329: : RXRX}T XTESTER FTESTER XTESTER FTESTER ...}T ;
                    330: : RXRR}T FTESTER FTESTER XTESTER FTESTER ...}T ;
                    331: : RRXX}T XTESTER XTESTER FTESTER FTESTER ...}T ;
                    332: : RRXR}T FTESTER XTESTER FTESTER FTESTER ...}T ;
                    333: : RRRX}T XTESTER FTESTER FTESTER FTESTER ...}T ;
                    334: : RRRR}T FTESTER FTESTER FTESTER FTESTER ...}T ;
1.12      anton     335: [THEN]
1.1       anton     336: 
1.14    ! anton     337: \ Set the following flag to TRUE for more verbose output; this may
        !           338: \ allow you to tell which test caused your system to hang.
        !           339: VARIABLE VERBOSE
        !           340:    FALSE VERBOSE !
        !           341: 
1.1       anton     342: : TESTING      \ ( -- ) TALKING COMMENT.
                    343:    SOURCE VERBOSE @
                    344:    IF DUP >R TYPE CR R> >IN !
                    345:    ELSE >IN ! DROP
                    346:    THEN ;
1.4       anton     347: 
1.6       anton     348: BASE !
1.14    ! anton     349: \ end of ttester.fs

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