tisp

tiny lisp
git clone git://edryd.org/tisp
Log | Files | Refs | LICENSE

test.c (26173B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <assert.h>
      3 #include <stdio.h>
      4 #include <stdarg.h>
      5 #include <string.h>
      6 #include <unistd.h>
      7 
      8 #include "tisp.h"
      9 #include "tibs.tsp.h"
     10 
     11 tsp_include_tib(math);
     12 tsp_include_tib(string);
     13 
     14 #define LEN(X) (sizeof(X) / sizeof((X)[0]))
     15 
     16 char *tests[][2] = {
     17 
     18 	{ "self",        NULL          },
     19 	{ "1",           "1"           },
     20 	{ "2",           "2"           },
     21 	{ "0",           "0"           },
     22 	{ "30",          "30"          },
     23 	{ "12",          "12"          },
     24 	{ "-4",          "-4"          },
     25 	{ "-083",        "-83"         },
     26 	{ "-0",          "0"           },
     27 	{ "+4",          "4"           },
     28 	{ "+123",        "123"         },
     29 	{ "12.0",        "12.0"        },
     30 	{ "08",          "8"           },
     31 	{ "+12.34",      "12.34"       },
     32 	{ ".34",         "0.34"        },
     33 	{ "2.",          "2.0"         },
     34 	{ "1e0",         "1"           },
     35 	{ "1E+0",        "1"           },
     36 	{ "1e-0",        "1"           },
     37 	{ "1E4",         "10000"       },
     38 	{ ".1e-4",       "1e-05"       },
     39 	{ "-5.0e006",    "-5000000.0"  },
     40 	{ "-5.E+16",     "-5e+16"      },
     41 	{ "-.05",        "-0.05"       },
     42 	{ "-.0",         "-0.0"        },
     43 	{ "-1.e6",       "-1000000.0"  },
     44 	{ "3/4",         "3/4"         },
     45 	{ "4/3",         "4/3"         },
     46 	{ "+1/2",        "1/2"         },
     47 	{ "2/1",         "2"           },
     48 	{ "8/+1",        "8"           },
     49 	{ "8/4",         "2"           },
     50 	{ "4/8",         "1/2"         },
     51 	{ "02384/7238",  "1192/3619"   },
     52 	{ "-1/2",        "-1/2"        },
     53 	{ "1/-2",        "-1/2"        },
     54 	{ "-6/3",        "-2"          },
     55 	{ "-6/-3",       "2"           },
     56 	{ "\"foo\"",     "foo"         },
     57 	{ "\"foo bar\"", "foo bar"     },
     58 	{ "True",        "True"        },
     59 	{ "()",          "Nil"         },
     60 	{ "Nil",         "Nil"         },
     61 
     62 	{ "comments",                  NULL      },
     63 	{ "; commment",                "#<void>" },
     64 	{ "; (+ 1 1)",                 "#<void>" },
     65 	{ "(+ 1 ; more comments\n1)",  "2"       },
     66 
     67 	{ "whitespace",                      NULL      },
     68 	{ "\t \n  \n\n\t\n \t\n",            "#<void>" },
     69 	{ "\t  \t(+   \t\t5 \n \n5  \n\t)",  "10"      },
     70 
     71 	{ "quote",                   NULL        },
     72 	{ "(quote 1)",               "1"         },
     73 	{ "(quote 9234)",            "9234"      },
     74 	{ "(quote \"foo\")",         "foo"       },
     75 	{ "(quote bar)",             "bar"       },
     76 	{ "(quote (1 2 3 4))",       "(1 2 3 4)" },
     77 	{ "(quote (quote 1))",       "(quote 1)" },
     78 	{ "(quote (+ 2 2))",         "(+ 2 2)"   },
     79 	{ "'12",                     "12"        },
     80 	{ "'foo",                    "foo"       },
     81 	{ "'(1 2 3 4)",              "(1 2 3 4)" },
     82 
     83 	{ "cons",                         NULL              },
     84 	{ "(cons 1 2)",                   "(1 . 2)"         },
     85 	{ "(cons 1 (cons 2 3))",          "(1 2 . 3)"       },
     86 	{ "(cons 1 (cons 2 (cons 3 4)))", "(1 2 3 . 4)"     },
     87 	{ "(cons \"foo\" \"bar\")",       "(foo . bar)"     },
     88 	{ "(cons (+ 1 2) 3)",             "(3 . 3)"         },
     89 	{ "(cons (cons 1 2) (cons 3 4))", "((1 . 2) 3 . 4)" },
     90 
     91 	{ "cxr",                                       NULL      },
     92 	{ "(car (cons 1 2))",                          "1"       },
     93 	{ "(cdr (cons 1 2))",                          "2"       },
     94 	{ "(car (quote (1 2 3 4)))",                   "1"       },
     95 	{ "(car (cdr (quote (1 2 3 4))))",             "2"       },
     96 	{ "(car (cdr (cdr (quote (1 2 3 4)))))",       "3"       },
     97 	{ "(car (cdr (cdr (cdr (quote (1 2 3 4))))))", "4"       },
     98 	{ "(cdr (quote (1 2 3 4)))",                   "(2 3 4)" },
     99 	{ "(cdr (cdr (quote (1 2 3 4))))",             "(3 4)"   },
    100 	{ "(car (cons 1 (cons 2 3)))",                 "1"       },
    101 	{ "(cdr (cons 1 (cons 2 3)))",                 "(2 . 3)" },
    102 	{ "(cdr (cdr (cons 1 (cons 2 3))))",           "3"       },
    103 
    104 	{ "void",   NULL      },
    105 	{ "(Void)", "#<void>" },
    106 
    107 	{ "do",                                       NULL      },
    108 	{ "(do (+ 1 2) (+ 2 2))",                     "4"       },
    109 	{ "(do (+ -4 8) (- 1 2) (* 80 0) (+ 39 -3))", "36"      },
    110 	{ "(do (mod 80 2) (/ 4 2) (Void))",           "#<void>" },
    111 
    112 	{ "eval",                                   NULL        },
    113 	{ "(eval ''hey)",                           "hey"       },
    114 	{ "(eval \"sup\")",                         "sup"       },
    115 	{ "(eval (+ 1 2))",                         "3"         },
    116 	{ "(eval '(- 4 3))",                        "1"         },
    117 	{ "(eval ''(mod 9 3))",                     "(mod 9 3)" },
    118 	{ "(do (def bar '(/ 25 5)) (eval bar))",    "5"         },
    119 
    120 	{ "cond",                                          NULL      },
    121 	{ "(cond)",                                        "#<void>" },
    122 	{ "(cond (True 1))",                               "1"       },
    123 	{ "(cond ((= 1 1) 1) ((= 1 2) 2) (True 3))",       "1"       },
    124 	{ "(cond ((= 1 2) 1) ((= 1 2) 2) (else (+ 1 2)))", "3"       },
    125 	{ "(cond ((= 1 2) 1) ((= 1 1) 2) (else 3))",       "2"       },
    126 	{ "(cond ((= 1 2) 1) ((= 1 3) 2))",                "#<void>" },
    127 	{ "(cond ((= 1 2) 1) (\"foo\" 2) (else 3))",       "2"       },
    128 	{ "(cond (() (+ 1 2)))",                           "#<void>" },
    129 
    130 	{ "get",                                   NULL           },
    131 	{ "(get \"hello\" 'len)",                  "5"            },
    132 	{ "(get 'drinky-poo 'len)",                "10"           },
    133 	{ "(get (cons 1 2) 'car)",                 "1"            },
    134 	{ "(get (cons 'jamie 'mr-t) 'cdr)",        "mr-t"         },
    135 	{ "(get '(dirty-burger freedom-35) 'cdr)", "(freedom-35)" },
    136 	{ "(get '(1 2 3 4) 'cdr)",                 "(2 3 4)"      },
    137 	{ "(get '(2 4 6) 'car)",                   "2"            },
    138 	{ "(get 3 'num)",                          "3"            },
    139 	{ "(get 83 'den)",                         "1"            },
    140 	{ "(get 3/2 'den)",                        "2"            },
    141 	{ "(get 10/15 'den)",                      "3"            },
    142 	{ "(get 9/2 'num)",                        "9"            },
    143 
    144 	{ "eq",                                          NULL   },
    145 	{ "(=)",                                         "True" },
    146 	{ "(= 1)",                                       "True" },
    147 	{ "(= \"foo\")",                                 "True" },
    148 	{ "(= 1 1)",                                     "True" },
    149 	{ "(= 1 1 1 1 1 1)",                             "True" },
    150 	{ "(= 1 2)",                                     "Nil"  },
    151 	{ "(= 1 1 2 1 1 1)",                             "Nil"  },
    152 	{ "(= 1 1 1 1 1 2)",                             "Nil"  },
    153 	{ "(= 2 1 1 1 1 1)",                             "Nil"  },
    154 	{ "(= 4/5 4/5)",                                 "True" },
    155 	{ "(= 2/1 2)",                                   "True" },
    156 	{ "(= 2/4 1/2)",                                 "True" },
    157 	{ "(= 2/4 1/2 4/8 3/6)",                         "True" },
    158 	{ "(= 1/2 4/5)",                                 "Nil"  },
    159 	{ "(= 5/4 4/5)",                                 "Nil"  },
    160 	{ "(= 3 3/2)",                                   "Nil"  },
    161 	{ "(= 3 3/2 3 3 3)",                             "Nil"  },
    162 	{ "(= (+ 1 1) (+ 2 0))",                         "True" },
    163 	{ "(= \"foo\" \"foo\")",                         "True" },
    164 	{ "(= \"foo\" \"bar\")",                         "Nil"  },
    165 	{ "(= \"foo\" \"foo\" \"foo\" \"foo\" \"foo\")", "True" },
    166 	{ "(= \"foo\" \"bar\" \"foo\" \"foo\" \"foo\")", "Nil"  },
    167 	{ "(= \"foo\" 3)",                               "Nil"  },
    168 	{ "(= \"foo\" \"foo\" 4 \"foo\" \"foo\")",       "Nil"  },
    169 	{ "(= \"foo\" \"FOO\")",                         "Nil"  },
    170 	{ "(= True True)",                               "True" },
    171 	{ "(= car car)",                                 "True" },
    172 	{ "(= car cdr)",                                 "Nil"  },
    173 	{ "(= quote quote quote)",                       "True" },
    174 	{ "(= '(1 2 3) '(1 2 3))",                       "True" },
    175 	{ "(= '(a b c) '(a b c))",                       "True" },
    176 	{ "(= '(a b c) '(a b d))",                       "Nil"  },
    177 	{ "(= '(1 2 3) '(1 2))",                         "Nil"  },
    178 	{ "(= '(1 2 3) '(1))",                           "Nil"  },
    179 	{ "(= '((1 2) 3 4) '((1 2) 3 4))",               "True" },
    180 	{ "(= '((1 b) 3 4) '((1 2) 3 4))",               "Nil"  },
    181 
    182 	{ "def",                         NULL      },
    183 	{ "(def foo 4)",                 "#<void>" },
    184 	{ "foo",                         "4"       },
    185 	{ "(def bar foo)",               "#<void>" },
    186 	{ "bar",                         "4"       },
    187 	{ "(set! foo 5)",                "5"       },
    188 	{ "foo",                         "5"       },
    189 	{ "(set! foo (+ foo bar))",      "9"       },
    190 	{ "foo",                         "9"       },
    191 	{ "(def add +)",                 "#<void>" },
    192 	{ "(add foo bar)",               "13"      },
    193 	{ "(def (one x) (add x 1))",     "#<void>" },
    194 	{ "(one foo)",                   "10"      },
    195 	{ "(def (more x)"
    196 	  "        (def term 3)"
    197 	  "        (+ x term))",         "#<void>" },
    198 	{ "(more 8)",                    "11"      },
    199 	{ "(def (add2 x)"
    200 	  "        (+ x 1) (+ x 2))",    "#<void>" },
    201 	{ "(add2 2)",                    "4"       },
    202 	{ "(set! add2 2)",               "2"       },
    203 	{ "add2",                        "2"       },
    204 	{ "(set! add2 \"2\")",           "2"       },
    205 	{ "add2",                        "2"       },
    206 
    207 	{ "lambda",                       NULL },
    208 	{ "((lambda (x) x) 3)",           "3"  },
    209 	{ "((lambda (x) x) (+ 1 2))",     "3"  },
    210 	{ "((lambda (x) (+ x 1)) 8)",     "9"  },
    211 	{ "((lambda (a b) (+ a b)) 2 2)", "4"  },
    212 	{ "((lambda () 5))",              "5"  },
    213 
    214 	{ "control",                                              NULL      },
    215 	{ "(if True 1 2)",                                        "1"       },
    216 	{ "(if () 1 2)",                                          "2"       },
    217 	{ "(if (integer? 3) True ())",                            "True"    },
    218 	{ "(if (ratio? car) (cons 1 2) (car '(1 2)))",            "1"       },
    219 	{ "(when True 'foo)",                                     "foo"     },
    220 	{ "(when () 'b  ar)",                                     "#<void>" },
    221 	{ "(when (= 1 1) 4)",                                     "4"       },
    222 	{ "(unless True 'foo)",                                   "#<void>" },
    223 	{ "(unless () 'bar)",                                     "bar"     },
    224 	{ "(unless 3 4)",                                         "#<void>" },
    225 	{ "(unless (< 5 4) 7)",                                   "7"       },
    226 	{ "(switch 5 (3 'yes) (5 'no))",                          "no"      },
    227 	{ "(switch (+ 1 2) ((mod 8 5) 'yes) (err 'no))",          "yes"     },
    228 	{ "(switch 2 (3 'yes) (5 'no))",                          "#<void>" },
    229 	{ "(switch \"foo\" (e \"bar\") (\"foo\" 'zar) ('baz 3))", "zar"     },
    230 
    231 	{ "logic",              NULL   },
    232 	{ "(not ())",           "True" },
    233 	{ "(not True)",         "Nil"  },
    234 	{ "(and () ())",        "Nil"  },
    235 	{ "(and True ())",      "Nil"  },
    236 	{ "(and () True)",      "Nil"  },
    237 	{ "(and True True)",    "True" },
    238 	{ "(nand () ())",       "True" },
    239 	{ "(nand True ())",     "True" },
    240 	{ "(nand () True)",     "True" },
    241 	{ "(nand True True)",   "Nil"  },
    242 	{ "(or () ())",         "Nil"  },
    243 	{ "(or True ())",       "True" },
    244 	{ "(or () True)",       "True" },
    245 	{ "(or True True)",     "True" },
    246 	{ "(nor () ())",        "True" },
    247 	{ "(nor True ())",      "Nil"  },
    248 	{ "(nor () True)",      "Nil"  },
    249 	{ "(nor True True)",    "Nil"  },
    250 
    251 	{ "list",                     NULL                 },
    252 	{ "(list 1 2 3)",             "(1 2 3)"            },
    253 	{ "(list (* 2 2) (+ 2 3))",   "(4 5)"              },
    254 	{ "(list 'a 'b 'c 'd 'e 'f)", "(a b c d e f)"      },
    255 	{ "(list \"foo\")",           "(foo)"              },
    256 	{ "(list)",                   "Nil"                },
    257 	{ "(list 1/2 2/8 . 1/8)",     "(1/2 1/4 . 1/8)"    },
    258 	{ "(list* .5 .25 .125)",      "(0.5 0.25 . 0.125)" },
    259 	{ "(list* 1 2 3 4 5 6)",      "(1 2 3 4 5 . 6)"    },
    260 	{ "(list* (sqr 3) (cube 4))", "(9 . 64)"           },
    261 	{ "(list* 5/4)",              "5/4"                },
    262 
    263 	{ "list get",                               NULL            },
    264 	{ "(last '(1 2 3))",                        "3"             },
    265 	{ "(last (list 4 5))",                      "5"             },
    266 	{ "(last '(a b c d e f))",                  "f"             },
    267 	{ "(last (cons 1 (cons 2 ())))",            "2"             },
    268 	{ "(length '(1 2 3))",                      "3"             },
    269 	{ "(length (list .3 -3/2 12 5))",           "4"             },
    270 	{ "(length '(a b))",                        "2"             },
    271 	{ "(length (list list))",                   "1"             },
    272 	{ "(length ())",                            "0"             },
    273 	{ "(length Nil)",                           "0"             },
    274 	{ "(nth '(1 2 3) 1)",                       "2"             },
    275 	{ "(nth (list 3 5/2 .332 -2) 2)",           "0.332"         },
    276 	{ "(nth '(a b c) 0)",                       "a"             },
    277 	{ "(nth (list 'foo 'bar 'zar 'baz) 3)",     "baz"           },
    278 	{ "(head '(1.2 1.3 1.4 1.5) 2)",            "(1.2 1.3)"     },
    279 	{ "(head '(1 1e1 1e2 1e3) 3)",              "(1 10 100)"    },
    280 	{ "(head '(1 2 3) 1)",                      "(1)"           },
    281 	{ "(head '(1 2) 0)",                        "Nil"           },
    282 	{ "(tail '(randy bobandy lahey bubs) 3)",   "(bubs)"        },
    283 	{ "(tail (list 1/2 1/3 1/4) 0)",            "(1/2 1/3 1/4)" },
    284 	{ "(tail '(2 4 9 16 25 36) 2)",             "(9 16 25 36)"  },
    285 	{ "(count 3 '(1 2 3 4))",                   "1"             },
    286 	{ "(count 1/2 (list 1/2 1/3 2/4 8 9.0))",   "2"             },
    287 	{ "(count 'a '(b c a a f h a b c a))",      "4"             },
    288 	{ "(count 3.2 Nil)",                        "0"             },
    289 	{ "(count \"Bobandy\" '(1/2 1/4 \"Jim\"))", "0"             },
    290 
    291 	{ "list proc",                                              NULL                },
    292 	{ "(apply list '(1 2 3))",                                  "(1 2 3)"           },
    293 	{ "(apply + '(2 90))",                                      "92"                },
    294 	{ "(apply list '(a b c d e))",                              "(a b c d e)"       },
    295 	{ "(map car '((1 a) (2 b) (3 c)))",                         "(1 2 3)"           },
    296 	{ "(map cdr '((1 a) (2 b) (3 c)))",                         "((a) (b) (c))"     },
    297 	{ "(map (lambda (x) (car (cdr x))) '((1 a) (2 b) (3 c)))",  "(a b c)"           },
    298 	{ "(map cadr '((1/2 .5) (\"conky\" .25) ('bubbles .125)))", "(0.5 0.25 0.125)"  },
    299 	{ "(map inc (list 2 4 8 (^ 2 4)))",                         "(3 5 9 17)"        },
    300 	{ "(filter positive? '(1 2 -4 5 -9 10))",                   "(1 2 5 10)"        },
    301 	{ "(filter odd? '(8 6 17 9 82 34 27))",                     "(17 9 27)"         },
    302 	{ "(filter integer? '(1/2 3.e-2 9/3 3.2 0.0 8 17))",        "(3 8 17)"          },
    303 	{ "((compose - sqrt) 9)",                                   "-3"                },
    304 	{ "((compose / sqrt sqr) 18)",                              "1/18"              },
    305 	{ "((compose - sqrt cube) 4)",                              "-8"                },
    306 	{ "((compose -) 5/3)",                                      "-5/3"              },
    307 	{ "((compose - +) 5 6)",                                    "-11"               },
    308 	{ "((compose sqrt Int *) 4.5 2)",                           "3"                 },
    309 	/* { "(foldr + 0 '(1 2 4 5))",                              "12"                }, */
    310 	/* { "(foldr list 0 '(1 2 3 4))",                           "((((0 1) 2) 3) 4)" }, */
    311 
    312 	{ "list mod",                                 NULL              },
    313 	{ "(reverse '(1 2 3 4 5))",                   "(5 4 3 2 1)"     },
    314 	{ "(reverse (list -20 5/2 .398))",            "(0.398 5/2 -20)" },
    315 	{ "(reverse '(a b))",                         "(b a)"           },
    316 	{ "(reverse (list \"foo\" \"bar\" \"baz\"))", "(baz bar foo)"   },
    317 	{ "(reverse (cons 1/2 Nil))",                 "(1/2)"           },
    318 	{ "(reverse ())",                             "Nil"             },
    319 	{ "(append '(1 2 3) '(4 5 6))",               "(1 2 3 4 5 6)"   },
    320 	{ "(append (list (+ 1 2) 4) '(a b c))",       "(3 4 a b c)"     },
    321 
    322 	{ "assoc",                                                      NULL          },
    323 	{ "(zip '(1 2 3 4) '(a b c d))",
    324 		"((1 . a) (2 . b) (3 . c) (4 . d))"                                   },
    325 	{ "(zip (list 'ricky 'lahey) (list \"julian\" \"randy\"))",
    326 		"((ricky . julian) (lahey . randy))"                                  },
    327 	{ "(assoc 'baz '((foo . 3) (bar . 8) (baz . 14)))",             "(baz . 14)"  },
    328 	{ "(assoc 'a '((a b) (3 2.1) (3.2 4/3) (3.2 3.2)))",            "(a b)"       },
    329 	{ "(assoc 3 '((1 b)))",                                         "Nil"         },
    330 	{ "(assoc 4/3 (list (list 1 pi) (list 4/3 1/2 3) (list 2 3)))", "(4/3 1/2 3)" },
    331 
    332 	{ "member",                                         NULL                  },
    333 	{ "(memp even? (list 1 3 19 4 7 8 2))",             "(4 7 8 2)"           },
    334 	{ "(memp negative? (list 1/3 pi 3.2e-9 0 4 -7 2))", "(-7 2)"              },
    335 	{ "(memp (lambda (x) (> x 8)) '(1/3 1/2 5/3 8 9))", "(9)"                 },
    336 	{ "(memp (lambda (x) (= x \"fry\")) "
    337 		"'(\"fry\" \"nibbler\" \"prof\"))",         "(fry nibbler prof)"  },
    338 	{ "(member 'foo '(foo bar baz))",                   "(foo bar baz)"       },
    339 	{ "(member 'bar '(foo bar baz))",                   "(bar baz)"           },
    340 	{ "(member 4 '(12 38 4 8))",                        "(4 8)"               },
    341 	{ "(member 3.2 '(4/3 2 8 2 3.14 3.2))",             "(3.2)"               },
    342 	{ "(member \"quux\" (list 4.2 3 'quux))",           "Nil"                 },
    343 	{ "(member 'qux '(foo bar baz))",                   "Nil"                 },
    344 
    345 	{ "quasiquote",          NULL              },
    346 	{ "`7.2",                "7.2"             },
    347 	{ "`cory",               "cory"            },
    348 	{ "`,foo",               "9"               },
    349 	{ "`(1 2 3)",            "(1 2 3)"         },
    350 	{ "`(\"sunnyvale\")",    "(sunnyvale)"     },
    351 	{ "`(1/2 . 2/1)",        "(1/2 . 2)"       },
    352 	{ "`(cory trevor)",      "(cory trevor)"   },
    353 	{ "`(foo bar quax)",     "(foo bar quax)"  },
    354 	{ "`(,foo ,bar)",        "(9 4)"           },
    355 	{ "`(,foo . ,bar)",      "(9 . 4)"         },
    356 	{ "`(,foo . ,bar)",      "(9 . 4)"         },
    357 	{ "`(foo bar ,foo fry)", "(foo bar 9 fry)" },
    358 
    359 	{ "stack",                                   NULL                 },
    360 	{ "(peek '(1 2 3 4 5 6))",                   "1"                  },
    361 	{ "(peek (list 'a 'b 'c))",                  "a"                  },
    362 	{ "(pop (list 1/2 1/4))",                    "(1/4)"              },
    363 	{ "(pop '(\"foo\" \"bar\" \"baz\"))",        "(bar baz)"          },
    364 	{ "(push '(6 3 5/3 .38) .5)",                "(0.5 6 3 5/3 0.38)" },
    365 	{ "(push (list \"ni\" 'shrubbery) (* 3 2))", "(6 ni shrubbery)"   },
    366 	{ "(swap '(1 2 3 5 7 11))",                  "(2 1 3 5 7 11)"     },
    367 	{ "(swap (list 1/2 1/4 1/9 1/16))",          "(1/4 1/2 1/9 1/16)" },
    368 
    369 	{ "stack!",                  NULL               },
    370 	{ "(def s '(1 2 3 4 5))",    "#<void>"          },
    371 	{ "(peek s)",                "1"                },
    372 	{ "(pop! s)",                "1"                },
    373 	{ "s",                       "(2 3 4 5)"        },
    374 	{ "(pop! s)",                "2"                },
    375 	{ "s",                       "(3 4 5)"          },
    376 	{ "(push! s 3/2)",           "(3/2 3 4 5)"      },
    377 	{ "s",                       "(3/2 3 4 5)"      },
    378 	{ "(push! s (- (/ 2)))",     "(-1/2 3/2 3 4 5)" },
    379 	{ "s",                       "(-1/2 3/2 3 4 5)" },
    380 	{ "(swap! s)",               "(3/2 -1/2 3 4 5)" },
    381 	{ "s",                       "(3/2 -1/2 3 4 5)" },
    382 	{ "(swap! s)",               "(-1/2 3/2 3 4 5)" },
    383 	{ "s",                       "(-1/2 3/2 3 4 5)" },
    384 
    385 	{ "numbers",            NULL   },
    386 	{ "(Dec 1/2)",          "0.5"  },
    387 	{ "(Dec 3/-2)",         "-1.5" },
    388 	{ "(Dec 1)",            "1.0"  },
    389 	{ "(Dec 3.14)",         "3.14" },
    390 	{ "(Int 1/2)",          "0"    },
    391 	{ "(Int 3/-2)",         "-1"   },
    392 	{ "(Int 1)",            "1"    },
    393 	{ "(Int 3.14)",         "3"    },
    394 	{ "(numerator 3/2)",    "3"    },
    395 	{ "(numerator 1/2)",    "1"    },
    396 	{ "(numerator -4/2)",   "-2"   },
    397 	{ "(numerator 24)",     "24"   },
    398 	{ "(denominator 1/4)",  "4"    },
    399 	{ "(denominator 4/3)",  "3"    },
    400 	{ "(denominator 4/2)",  "1"    },
    401 	{ "(denominator 14/8)", "4"    },
    402 	{ "(denominator -4)",   "1"    },
    403 
    404 
    405 	{ "round",               NULL    },
    406 	{ "(round 7/3)",         "2"     },
    407 	{ "(round -3/4)",        "-1"    },
    408 	{ "(round 6.3)",         "6.0"   },
    409 	{ "(round -8.1)",        "-8.0"  },
    410 	{ "(round 3)",           "3"     },
    411 	{ "(round -81)",         "-81"   },
    412 	{ "(round 0)",           "0"     },
    413 	{ "(floor 5/3)",         "1"     },
    414 	{ "(floor -9/4)",        "-3"    },
    415 	{ "(floor 6.3)",         "6.0"   },
    416 	{ "(floor -8.1)",        "-9.0"  },
    417 	{ "(floor 3)",           "3"     },
    418 	{ "(floor -81)",         "-81"   },
    419 	{ "(floor 0)",           "0"     },
    420 	{ "(ceil 1/2)",          "1"     },
    421 	{ "(ceil -8/5)",         "-1"    },
    422 	{ "(ceil pi)",           "4.0"   },
    423 	{ "(ceil (- .2))",       "-0.0"  },
    424 	{ "(ceil 128)",          "128"   },
    425 	{ "(ceil -2)",           "-2"    },
    426 	{ "(ceil 0)",            "0"     },
    427 	{ "(truncate (/ 17 2))", "8"     },
    428 	{ "(truncate -12/5)",    "-2"    },
    429 	{ "(truncate (exp 2.))", "7.0"   },
    430 	{ "(truncate 124.1380)", "124.0" },
    431 	{ "(truncate 8)",        "8"     },
    432 	{ "(truncate -5)",       "-5"    },
    433 	{ "(truncate 0)",        "0"     },
    434 
    435 	{ "arithmetic",    NULL               },
    436 	{ "(+ 1 1)",       "2"                },
    437 	{ "(+ 1 (+ 1 2))", "4"                },
    438 	{ "(+ 1029 283)",  "1312"             },
    439 	{ "(+ 204  8.3)",  "212.3"            },
    440 	{ "(+ 33   3/4)",  "135/4"            },
    441 	{ "(+ 1/3 5)",     "16/3"             },
    442 	{ "(+ 7/4 pi)",    "4.89159265358979" },
    443 	{ "(+ 2/5 3/2)",   "19/10"            },
    444 	{ "(+ 2.1 2)",     "4.1"              },
    445 	{ "(+ 8.6 5.3)",   "13.9"             },
    446 	{ "(+ 3.7 1/8)",   "3.825"            },
    447 	{ "(- 3)",         "-3"                },
    448 	{ "(- +3)",        "-3"                },
    449 	{ "(- -289)",      "289"               },
    450 	{ "(- 7/8)",       "-7/8"              },
    451 	{ "(- -6.412E2)",  "641.2"             },
    452 	{ "(- 5 4)",       "1"                 },
    453 	{ "(- 53 88)",     "-35"               },
    454 	{ "(- 204  8.3)",  "195.7"             },
    455 	{ "(- 33   3/4)",  "129/4"             },
    456 	{ "(- 1/3 5)",     "-14/3"             },
    457 	{ "(- 7/4 pi)",    "-1.39159265358979" },
    458 	{ "(- 2/5 3/2)",   "-11/10"            },
    459 	{ "(- 2.1 2)",     "0.1"               },
    460 	{ "(- 8.6 5.3)",   "3.3"               },
    461 	{ "(- 3.7 1/8)",   "3.575"             },
    462 	{ "(* 3 2)",          "6"                 },
    463 	{ "(* -2 8.89)",      "-17.78"            },
    464 	{ "(* 6 3/4)",        "9/2"               },
    465 	{ "(* 1.004 8)",      "8.032"             },
    466 	{ "(* 1.34e3 .0012)", "1.608"             },
    467 	{ "(* e -5/2)",       "-6.79570457114761" },
    468 	{ "(* 1/3 6)",        "2"                 },
    469 	{ "(* 5/2 14.221)",   "35.5525"           },
    470 	{ "(* 6/8 8/7)",      "6/7"               },
    471 	{ "(/ 1 2)",            "1/2"                },
    472 	{ "(/ 8 4)",            "2"                  },
    473 	{ "(/ 6 2.1)",          "2.85714285714286"   },
    474 	{ "(/ 4 4/3)",          "3"                  },
    475 	{ "(/ 5)",              "1/5"                },
    476 	{ "(/ 4473)",           "1/4473"             },
    477 	{ "(/ 10.42 5)",        "2.084"              },
    478 	{ "(/ 1.34e-2 4.3332)", "0.0030924028431644" },
    479 	{ "(/ 1.04 -15/4)",     "-0.277333333333333" },
    480 	{ "(/ 4/3 7)",          "4/21"               },
    481 	{ "(/ 5/4 3.2)",        "0.390625"           },
    482 	{ "(/ 1/3 5/4)",        "4/15"               },
    483 	{ "(mod 10 3)",   "1"  },
    484 	{ "(mod -11 3)",  "-2" },
    485 	{ "(mod 10 -3)",  "1"  },
    486 	{ "(mod -10 -3)", "-1" },
    487 	{ "(mod 10 5)",   "0"  },
    488 	{ "(mod 7 2)",    "1"  },
    489 	{ "(mod 8 5)",    "3"  },
    490 
    491 	{ "compare",      NULL   },
    492 	{ "(< 2 3)",      "True" },
    493 	{ "(< 3 3)",      "Nil"  },
    494 	{ "(< 4 3)",      "Nil"  },
    495 	{ "(<= -2 +4)",   "True" },
    496 	{ "(<= -2 -2)",   "True" },
    497 	{ "(<= 4 -2)",    "Nil"  },
    498 	{ "(> 89 34)",    "True" },
    499 	{ "(> 48 48)",    "Nil"  },
    500 	{ "(> 98 183)",   "Nil"  },
    501 	{ "(>= +4 -282)", "True" },
    502 	{ "(>= 39 39)",   "True" },
    503 	{ "(>= -32 -30)", "Nil"  },
    504 
    505 	{ "abs",        NULL  },
    506 	{ "(abs 4)",    "4"   },
    507 	{ "(abs -3/5)", "3/5" },
    508 	{ "(abs 0.0)",  "0.0" },
    509 
    510 	{ "sgn",         NULL   },
    511 	{ "(sgn 239)",   "1"    },
    512 	{ "(sgn -3)",    "-1"   },
    513 	{ "(sgn 5/4)",   "1"    },
    514 	{ "(sgn -1/7)",  "-1"   },
    515 	{ "(sgn 3.17)",  "1.0"  },
    516 	{ "(sgn -.457)", "-1.0" },
    517 	{ "(sgn 0)",     "0"    },
    518 	{ "(sgn 0.0)",   "0.0"  },
    519 
    520 	{ "max/min",          NULL    },
    521 	{ "(max 9346 13297)", "13297" },
    522 	{ "(max -3 8)",       "8"     },
    523 	{ "(max 3/2 1/2)",    "3/2"   },
    524 	{ "(max 0 -.5)",      "0"     },
    525 	{ "(min 4 48)",       "4"     },
    526 	{ "(min -80 -148)",   "-148"  },
    527 	{ "(min 7/2 -3)",     "-3"    },
    528 	{ "(min 1/2 1/3)",    "1/3"   },
    529 	{ "(min .05 .06)",    "0.05"  },
    530 
    531 	{ NULL,          NULL },
    532 };
    533 
    534 int
    535 tisp_test(Tsp st, const char *input, const char *expect, int output)
    536 {
    537 	Val v;
    538 	FILE *f;
    539 	size_t nread;
    540 	char buf[BUFSIZ] = {0};
    541 
    542 	if (!(st->file = strdup(input)))
    543 		return 0;
    544 	st->filec = 0;
    545 	if (!(v = tisp_read(st)))
    546 		return 0;
    547 	if (!(v = tisp_eval(st, st->global, v))) {
    548 		if (output)
    549 			putchar('\n');
    550 		return 0;
    551 	}
    552 
    553 	f = fopen("test.out", "w");
    554 	tisp_print(f, v);
    555 	fclose(f);
    556 
    557 	f = fopen("test.out", "r");
    558 	while ((nread = fread(buf, 1, sizeof(buf), f)) > 0) ;
    559 	fclose(f);
    560 	remove("test.out");
    561 
    562 	if (output)
    563 		printf("%s\n", buf);
    564 	return strcmp(buf, expect) == 0;
    565 }
    566 
    567 int
    568 main(void)
    569 {
    570 	int correct = 0, total = 0, seccorrect = 0, sectotal = 0, last = 1;
    571 	int errors[LEN(tests)] = {0};
    572 	Tsp st = tisp_env_init(1024);
    573 	tib_env_math(st);
    574 	tib_env_string(st);
    575 	tisp_env_lib(st, tibs);
    576 
    577 	for (int i = 0; ; i++) {
    578 		if (!tests[i][1]) {
    579 			if (i != 0) {
    580 				printf("%d/%d\n", seccorrect, sectotal);
    581 				for (int j = last; j < i; j++)
    582 					if (!tests[j][1]) {
    583 						printf("%-10s\n", tests[j][0]);
    584 					} else if (errors[j]) {
    585 						printf("  input: %s\n"
    586 						       "    expect: %s\n"
    587 						       "    output: ", tests[j][0], tests[j][1]);
    588 						tisp_test(st, tests[j][0], tests[j][1], 1);
    589 					}
    590 				last = i + 1;
    591 			}
    592 			if (!tests[i][0])
    593 				break;
    594 			printf("%-10s ", tests[i][0]);
    595 			seccorrect = 0;
    596 			sectotal = 0;
    597 		} else {
    598 			if (tisp_test(st, tests[i][0], tests[i][1], 0)) {
    599 				correct++;
    600 				seccorrect++;
    601 			} else {
    602 				errors[i] = 1;
    603 			}
    604 			total++;
    605 			sectotal++;
    606 		}
    607 	}
    608 	printf("%-10s %d/%d\n", "total", correct, total);
    609 
    610 	return correct != total;
    611 }