tisp

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

test.c (28587B)


      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 'numerator)",                    "3"            },
    139 	{ "(get 83 'denominator)",                 "1"            },
    140 	{ "(get 3/2 'denominator)",                "2"            },
    141 	{ "(get 10/15 'denominator)",              "3"            },
    142 	{ "(get 9/2 'numerator)",                  "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)",                            "Nil"  },
    166 	{ "(= 'bar 'bar)",                               "True" },
    167 	{ "(= \"foo\" \"foo\" \"foo\" \"foo\" \"foo\")", "True" },
    168 	{ "(= \"foo\" \"bar\" \"foo\" \"foo\" \"foo\")", "Nil"  },
    169 	{ "(= \"foo\" 3)",                               "Nil"  },
    170 	{ "(= \"foo\" \"foo\" 4 \"foo\" \"foo\")",       "Nil"  },
    171 	{ "(= \"foo\" \"FOO\")",                         "Nil"  },
    172 	{ "(= True True)",                               "True" },
    173 	{ "(= car car)",                                 "True" },
    174 	{ "(= car cdr)",                                 "Nil"  },
    175 	{ "(= quote quote quote)",                       "True" },
    176 	{ "(= '(1 2 3) (list 1 2 3))",                   "True" },
    177 	{ "(= '(a b c) '(a b c))",                       "True" },
    178 	{ "(= '(a b c) '(a b d))",                       "Nil"  },
    179 	{ "(= '(1 2 3) '(1 2))",                         "Nil"  },
    180 	{ "(= '(1 2 3) '(1))",                           "Nil"  },
    181 	{ "(= '((1 2) 3 4) '((1 2) 3 4))",               "True" },
    182 	{ "(= '((1 b) 3 4) '((1 2) 3 4))",               "Nil"  },
    183 	{ "(= (Func (it) it) @it)",                      "True" },
    184 	{ "(= @it (Func (x) x))",                        "Nil"  },
    185 	{ "(/=)",                                        "Nil"  },
    186 	{ "(/= 'a)",                                     "Nil"  },
    187 	{ "(/= '(1 . 2) (list* 1 2))",                   "Nil"  },
    188 	{ "(/= 1 2)",                                    "True" },
    189 	{ "(/= 1 1 2 1 1 1)",                            "True" },
    190 	{ "(/= \"foo\" \"bar\")",                        "True" },
    191 	{ "(/= 'greg 'greg 'greg 'greg)",                "Nil"  },
    192 
    193 	{ "def",                         NULL      },
    194 	{ "(def foo 4)",                 "Void"    },
    195 	{ "foo",                         "4"       },
    196 	{ "(def bar foo)",               "Void"    },
    197 	{ "bar",                         "4"       },
    198 	{ "(set! foo 5)",                "5"       },
    199 	{ "foo",                         "5"       },
    200 	{ "(set! foo (+ foo bar))",      "9"       },
    201 	{ "foo",                         "9"       },
    202 	{ "(def add +)",                 "Void"    },
    203 	{ "(add foo bar)",               "13"      },
    204 	{ "(def (one x) (add x 1))",     "Void"    },
    205 	{ "(one foo)",                   "10"      },
    206 	{ "(def (more x)"
    207 	  "        (def term 3)"
    208 	  "        (+ x term))",         "Void"    },
    209 	{ "(more 8)",                    "11"      },
    210 	{ "(def (add2 x)"
    211 	  "        (+ x 1) (+ x 2))",    "Void"    },
    212 	{ "(add2 2)",                    "4"       },
    213 	{ "(set! add2 2)",               "2"       },
    214 	{ "add2",                        "2"       },
    215 	{ "(set! add2 \"2\")",           "2"       },
    216 	{ "add2",                        "2"       },
    217 	{ "defined?",                    NULL      },
    218 	{ "(defined? invalid-var)",      "Nil"     },
    219 	{ "(defined? defined?)",         "True"    },
    220 	{ "(defined? car)",              "True"    },
    221 	{ "(defined? when)",             "True"    },
    222 	{ "(defined? apply)",            "True"    },
    223 
    224 	{ "Func",                       NULL },
    225 	{ "((Func (x) x) 3)",           "3"  },
    226 	{ "((Func (x) x) (+ 1 2))",     "3"  },
    227 	{ "((Func (x) (+ x 1)) 8)",     "9"  },
    228 	{ "((Func (a b) (+ a b)) 2 2)", "4"  },
    229 	{ "((Func () 5))",              "5"  },
    230 
    231 	{ "control",                                              NULL      },
    232 	{ "(if True 1 2)",                                        "1"       },
    233 	{ "(if () 1 2)",                                          "2"       },
    234 	{ "(if (integer? 3) True ())",                            "True"    },
    235 	{ "(if (ratio? car) (cons 1 2) (car '(1 2)))",            "1"       },
    236 	{ "(when True 'foo)",                                     "foo"     },
    237 	{ "(when () 'b  ar)",                                     "Void"    },
    238 	{ "(when (= 1 1) 4)",                                     "4"       },
    239 	{ "(unless True 'foo)",                                   "Void"    },
    240 	{ "(unless () 'bar)",                                     "bar"     },
    241 	{ "(unless 3 4)",                                         "Void"    },
    242 	{ "(unless (< 5 4) 7)",                                   "7"       },
    243 	{ "(switch 5 (3 'yes) (5 'no))",                          "no"      },
    244 	{ "(switch (+ 1 2) ((mod 8 5) 'yes) (err 'no))",          "yes"     },
    245 	{ "(switch 2 (3 'yes) (5 'no))",                          "Void"    },
    246 	{ "(switch \"foo\" (e \"bar\") (\"foo\" 'zar) ('baz 3))", "zar"     },
    247 
    248 	/* TODO other syms as well */
    249 	{ "logic",              NULL   },
    250 	{ "(not ())",           "True" },
    251 	{ "(not True)",         "Nil"  },
    252 	{ "(and () ())",        "Nil"  },
    253 	{ "(and True ())",      "Nil"  },
    254 	{ "(and () True)",      "Nil"  },
    255 	{ "(and True True)",    "True" },
    256 	{ "(nand () ())",       "True" },
    257 	{ "(nand True ())",     "True" },
    258 	{ "(nand () True)",     "True" },
    259 	{ "(nand True True)",   "Nil"  },
    260 	{ "(or () ())",         "Nil"  },
    261 	{ "(or True ())",       "True" },
    262 	{ "(or () True)",       "True" },
    263 	{ "(or True True)",     "True" },
    264 	{ "(nor () ())",        "True" },
    265 	{ "(nor True ())",      "Nil"  },
    266 	{ "(nor () True)",      "Nil"  },
    267 	{ "(nor True True)",    "Nil"  },
    268 
    269 	{ "list",                     NULL                 },
    270 	{ "(list 1 2 3)",             "(1 2 3)"            },
    271 	{ "(list (* 2 2) (+ 2 3))",   "(4 5)"              },
    272 	{ "(list 'a 'b 'c 'd 'e 'f)", "(a b c d e f)"      },
    273 	{ "(list \"foo\")",           "(foo)"              },
    274 	{ "(list)",                   "Nil"                },
    275 	{ "(list 1/2 2/8 . 1/8)",     "(1/2 1/4 . 1/8)"    },
    276 	{ "(list* .5 .25 .125)",      "(0.5 0.25 . 0.125)" },
    277 	{ "(list* 1 2 3 4 5 6)",      "(1 2 3 4 5 . 6)"    },
    278 	{ "(list* (sqr 3) (cube 4))", "(9 . 64)"           },
    279 	{ "(list* 5/4)",              "5/4"                },
    280 
    281 	{ "list get",                               NULL            },
    282 	{ "(last '(1 2 3))",                        "3"             },
    283 	{ "(last (list 4 5))",                      "5"             },
    284 	{ "(last '(a b c d e f))",                  "f"             },
    285 	{ "(last (cons 1 (cons 2 ())))",            "2"             },
    286 	{ "(length '(1 2 3))",                      "3"             },
    287 	{ "(length (list .3 -3/2 12 5))",           "4"             },
    288 	{ "(length '(a b))",                        "2"             },
    289 	{ "(length (list list))",                   "1"             },
    290 	{ "(length ())",                            "0"             },
    291 	{ "(length Nil)",                           "0"             },
    292 	{ "(nth '(1 2 3) 1)",                       "2"             },
    293 	{ "(nth (list 3 5/2 .332 -2) 2)",           "0.332"         },
    294 	{ "(nth '(a b c) 0)",                       "a"             },
    295 	{ "(nth (list 'foo 'bar 'zar 'baz) 3)",     "baz"           },
    296 	{ "(head '(1.2 1.3 1.4 1.5) 2)",            "(1.2 1.3)"     },
    297 	{ "(head '(1 1e1 1e2 1e3) 3)",              "(1 10 100)"    },
    298 	{ "(head '(1 2 3) 1)",                      "(1)"           },
    299 	{ "(head '(1 2) 0)",                        "Nil"           },
    300 	{ "(tail '(randy bobandy lahey bubs) 3)",   "(bubs)"        },
    301 	{ "(tail (list 1/2 1/3 1/4) 0)",            "(1/2 1/3 1/4)" },
    302 	{ "(tail '(2 4 9 16 25 36) 2)",             "(9 16 25 36)"  },
    303 	{ "(count 3 '(1 2 3 4))",                   "1"             },
    304 	{ "(count 1/2 (list 1/2 1/3 2/4 8 9.0))",   "2"             },
    305 	{ "(count 'a '(b c a a f h a b c a))",      "4"             },
    306 	{ "(count 3.2 Nil)",                        "0"             },
    307 	{ "(count \"Bobandy\" '(1/2 1/4 \"Jim\"))", "0"             },
    308 
    309 	{ "list proc",                                              NULL                    },
    310 	{ "(apply list '(1 2 3))",                                  "(1 2 3)"               },
    311 	{ "(apply + '(2 90))",                                      "92"                    },
    312 	{ "(apply list '(a b c d e))",                              "(a b c d e)"           },
    313 	{ "(map car '((1 a) (2 b) (3 c)))",                         "(1 2 3)"               },
    314 	{ "(map cdr '((1 a) (2 b) (3 c)))",                         "((a) (b) (c))"         },
    315 	{ "(map (Func (x) (car (cdr x))) '((1 a) (2 b) (3 c)))",    "(a b c)"               },
    316 	{ "(map cadr '((1/2 .5) (\"conky\" .25) ('bubbles .125)))", "(0.5 0.25 0.125)"      },
    317 	{ "(map inc (list 2 4 8 (^ 2 4)))",                         "(3 5 9 17)"            },
    318 	{ "(convert 1 2 '(1 2 3 1 1 4 5 6 7 1))",                   "(2 2 3 2 2 4 5 6 7 2)" },
    319 	{ "(convert 'hey 'hello '(hi sup hey hey hello hola))",
    320 		"(hi sup hello hello hello hola)"                                           },
    321 	{ "((compose - sqrt) 9)",                                   "-3"                    },
    322 	{ "((compose / sqrt sqr) 18)",                              "1/18"                  },
    323 	{ "((compose - sqrt cube) 4)",                              "-8"                    },
    324 	{ "((compose -) 5/3)",                                      "-5/3"                  },
    325 	{ "((compose - +) 5 6)",                                    "-11"                   },
    326 	{ "((compose sqrt Int *) 4.5 2)",                           "3"                     },
    327 	/* { "(foldr + 0 '(1 2 4 5))",                              "12"                    }, */
    328 	/* { "(foldr list 0 '(1 2 3 4))",                           "((((0 1) 2) 3) 4)"     }, */
    329 
    330 	{ "list filter",                                         NULL                  },
    331 	{ "(filter positive? '(1 2 -4 5 -9 10))",                "(1 2 5 10)"          },
    332 	{ "(filter odd? '(8 6 17 9 82 34 27))",                  "(17 9 27)"           },
    333 	{ "(filter integer? (list 1/2 3.e-2 9/3 3.2 0.0 8 17))", "(3 8 17)"            },
    334 	{ "(keep '+ '(+ * - - + + - / sqrt))",                   "(+ + +)"             },
    335 	{ "(keep 5 (list (+ 1 2) (- 10 5) 3/2 5 (/ 15 5))))",    "(5 5)"               },
    336 	{ "(keep 3.2 '(3. 3 3.02 3.12 3.20 3.7))",               "(3.2)"               },
    337 	{ "(keep 'a '('a b c d e))",                             "Nil"                 },
    338 	{ "(remove 1/2 (list 3/4 4/8 6/7 19/17 6/8 1/2))",       "(3/4 6/7 19/17 3/4)" },
    339 	{ "(remove 2 '(1 3 4 5))",                               "(1 3 4 5)"           },
    340 	{ "(remove \"greg\" '(greg 'greg \"wirt\" beatrice))",
    341 		"(greg (quote greg) wirt beatrice)"                                    },
    342 
    343 	{ "list mod",                                 NULL              },
    344 	{ "(reverse '(1 2 3 4 5))",                   "(5 4 3 2 1)"     },
    345 	{ "(reverse (list -20 5/2 .398))",            "(0.398 5/2 -20)" },
    346 	{ "(reverse '(a b))",                         "(b a)"           },
    347 	{ "(reverse (list \"foo\" \"bar\" \"baz\"))", "(baz bar foo)"   },
    348 	{ "(reverse (cons 1/2 Nil))",                 "(1/2)"           },
    349 	{ "(reverse ())",                             "Nil"             },
    350 	{ "(append '(1 2 3) '(4 5 6))",               "(1 2 3 4 5 6)"   },
    351 	{ "(append (list (+ 1 2) 4) '(a b c))",       "(3 4 a b c)"     },
    352 
    353 	{ "assoc",                                                      NULL          },
    354 	{ "(zip '(1 2 3 4) '(a b c d))",
    355 		"((1 . a) (2 . b) (3 . c) (4 . d))"                                   },
    356 	{ "(zip (list 'ricky 'lahey) (list \"julian\" \"randy\"))",
    357 		"((ricky . julian) (lahey . randy))"                                  },
    358 	{ "(assoc 'baz '((foo . 3) (bar . 8) (baz . 14)))",             "(baz . 14)"  },
    359 	{ "(assoc 'a '((a b) (3 2.1) (3.2 4/3) (3.2 3.2)))",            "(a b)"       },
    360 	{ "(assoc 3 '((1 b)))",                                         "Nil"         },
    361 	{ "(assoc 4/3 (list (list 1 pi) (list 4/3 1/2 3) (list 2 3)))", "(4/3 1/2 3)" },
    362 
    363 	{ "list member",                                    NULL                 },
    364 	{ "(memp even? (list 1 3 19 4 7 8 2))",             "(4 7 8 2)"          },
    365 	{ "(memp negative? (list 1/3 pi 3.2e-9 0 4 -7 2))", "(-7 2)"             },
    366 	{ "(memp (Func (x) (> x 8)) '(1/3 1/2 5/3 8 9))",   "(9)"                },
    367 	{ "(memp (Func (x) (= x \"fry\")) "
    368 		"'(\"fry\" \"nibbler\" \"prof\"))",         "(fry nibbler prof)" },
    369 	{ "(member 'foo '(foo bar baz))",                   "(foo bar baz)"      },
    370 	{ "(member 'bar '(foo bar baz))",                   "(bar baz)"          },
    371 	{ "(member 4 '(12 38 4 8))",                        "(4 8)"              },
    372 	{ "(member 3.2 '(4/3 2 8 2 3.14 3.2))",             "(3.2)"              },
    373 	{ "(member \"quux\" (list 4.2 3 'quux))",           "Nil"                },
    374 	{ "(member 'qux '(foo bar baz))",                   "Nil"                },
    375 	{ "(everyp? even? '(2 4 10 18))",                   "True"               },
    376 	{ "(everyp? odd? '(1 2 3 9 10))",                   "Nil"                },
    377 	{ "(everyp? integer? '(1. 2/3 3.14 4/5))",          "Nil"                },
    378 	{ "(every? 'foo '(foo bar baz))",                   "Nil"                },
    379 	{ "(every? \"a\" '(a 'a \"a\"))",                   "Nil"                },
    380 	{ "(every? 3 (list 3 (+ 1 2) (- 5 2)))",            "True"               },
    381 
    382 	{ "quasiquote",               NULL              },
    383 	{ "`7.2",                     "7.2"             },
    384 	{ "`cory",                    "cory"            },
    385 	{ "`,foo",                    "9"               },
    386 	{ "`(1 2 3)",                 "(1 2 3)"         },
    387 	{ "`(\"sunnyvale\")",         "(sunnyvale)"     },
    388 	{ "`(1/2 . 2/1)",             "(1/2 . 2)"       },
    389 	{ "`(cory trevor)",           "(cory trevor)"   },
    390 	{ "`(foo bar quax)",          "(foo bar quax)"  },
    391 	{ "`(,foo ,bar)",             "(9 4)"           },
    392 	{ "`(,foo . ,bar)",           "(9 . 4)"         },
    393 	{ "`(,foo . ,bar)",           "(9 . 4)"         },
    394 	{ "`(foo bar ,foo fry)",      "(foo bar 9 fry)" },
    395 	{ "`(1 ,(+ 1 2) 5 ,(- 9 2))", "(1 3 5 7)"       },
    396 	{ "`(1 ,@(list 4 9))",        "(1 4 9)"         },
    397 	{ "`(3 ,@foo)",               "(3 . 9)"         },
    398 	{ "`(a b c ,@foo)",           "(a b c . 9)"     },
    399 	{ "`(0 ,@(list 1 2) 3 4)",    "(0 1 2 3 4)"     },
    400 
    401 	{ "stack",                                   NULL                 },
    402 	{ "(peek '(1 2 3 4 5 6))",                   "1"                  },
    403 	{ "(peek (list 'a 'b 'c))",                  "a"                  },
    404 	{ "(pop (list 1/2 1/4))",                    "(1/4)"              },
    405 	{ "(pop '(\"foo\" \"bar\" \"baz\"))",        "(bar baz)"          },
    406 	{ "(push '(6 3 5/3 .38) .5)",                "(0.5 6 3 5/3 0.38)" },
    407 	{ "(push (list \"ni\" 'shrubbery) (* 3 2))", "(6 ni shrubbery)"   },
    408 	{ "(swap '(1 2 3 5 7 11))",                  "(2 1 3 5 7 11)"     },
    409 	{ "(swap (list 1/2 1/4 1/9 1/16))",          "(1/4 1/2 1/9 1/16)" },
    410 
    411 	{ "stack!",                  NULL               },
    412 	{ "(def s '(1 2 3 4 5))",    "Void"             },
    413 	{ "(peek s)",                "1"                },
    414 	{ "(pop! s)",                "1"                },
    415 	{ "s",                       "(2 3 4 5)"        },
    416 	{ "(pop! s)",                "2"                },
    417 	{ "s",                       "(3 4 5)"          },
    418 	{ "(push! s 3/2)",           "(3/2 3 4 5)"      },
    419 	{ "s",                       "(3/2 3 4 5)"      },
    420 	{ "(push! s (- (/ 2)))",     "(-1/2 3/2 3 4 5)" },
    421 	{ "s",                       "(-1/2 3/2 3 4 5)" },
    422 	{ "(swap! s)",               "(3/2 -1/2 3 4 5)" },
    423 	{ "s",                       "(3/2 -1/2 3 4 5)" },
    424 	{ "(swap! s)",               "(-1/2 3/2 3 4 5)" },
    425 	{ "s",                       "(-1/2 3/2 3 4 5)" },
    426 
    427 	{ "numbers",            NULL   },
    428 	{ "(Dec 1/2)",          "0.5"  },
    429 	{ "(Dec 3/-2)",         "-1.5" },
    430 	{ "(Dec 1)",            "1.0"  },
    431 	{ "(Dec 3.14)",         "3.14" },
    432 	{ "(Int 1/2)",          "0"    },
    433 	{ "(Int 3/-2)",         "-1"   },
    434 	{ "(Int 1)",            "1"    },
    435 	{ "(Int 3.14)",         "3"    },
    436 
    437 	{ "round",               NULL    },
    438 	{ "(round 7/3)",         "2"     },
    439 	{ "(round -3/4)",        "-1"    },
    440 	{ "(round 6.3)",         "6.0"   },
    441 	{ "(round -8.1)",        "-8.0"  },
    442 	{ "(round 3)",           "3"     },
    443 	{ "(round -81)",         "-81"   },
    444 	{ "(round 0)",           "0"     },
    445 	{ "(floor 5/3)",         "1"     },
    446 	{ "(floor -9/4)",        "-3"    },
    447 	{ "(floor 6.3)",         "6.0"   },
    448 	{ "(floor -8.1)",        "-9.0"  },
    449 	{ "(floor 3)",           "3"     },
    450 	{ "(floor -81)",         "-81"   },
    451 	{ "(floor 0)",           "0"     },
    452 	{ "(ceil 1/2)",          "1"     },
    453 	{ "(ceil -8/5)",         "-1"    },
    454 	{ "(ceil pi)",           "4.0"   },
    455 	{ "(ceil (- .2))",       "-0.0"  },
    456 	{ "(ceil 128)",          "128"   },
    457 	{ "(ceil -2)",           "-2"    },
    458 	{ "(ceil 0)",            "0"     },
    459 	{ "(truncate (/ 17 2))", "8"     },
    460 	{ "(truncate -12/5)",    "-2"    },
    461 	{ "(truncate (exp 2.))", "7.0"   },
    462 	{ "(truncate 124.1380)", "124.0" },
    463 	{ "(truncate 8)",        "8"     },
    464 	{ "(truncate -5)",       "-5"    },
    465 	{ "(truncate 0)",        "0"     },
    466 
    467 	{ "arithmetic",    NULL               },
    468 	{ "(+ 1 1)",       "2"                },
    469 	{ "(+ 1 (+ 1 2))", "4"                },
    470 	{ "(+ 1029 283)",  "1312"             },
    471 	{ "(+ 204  8.3)",  "212.3"            },
    472 	{ "(+ 33   3/4)",  "135/4"            },
    473 	{ "(+ 1/3 5)",     "16/3"             },
    474 	{ "(+ 7/4 pi)",    "4.89159265358979" },
    475 	{ "(+ 2/5 3/2)",   "19/10"            },
    476 	{ "(+ 2.1 2)",     "4.1"              },
    477 	{ "(+ 8.6 5.3)",   "13.9"             },
    478 	{ "(+ 3.7 1/8)",   "3.825"            },
    479 	{ "(- 3)",         "-3"                },
    480 	{ "(- +3)",        "-3"                },
    481 	{ "(- -289)",      "289"               },
    482 	{ "(- 7/8)",       "-7/8"              },
    483 	{ "(- -6.412E2)",  "641.2"             },
    484 	{ "(- 5 4)",       "1"                 },
    485 	{ "(- 53 88)",     "-35"               },
    486 	{ "(- 204  8.3)",  "195.7"             },
    487 	{ "(- 33   3/4)",  "129/4"             },
    488 	{ "(- 1/3 5)",     "-14/3"             },
    489 	{ "(- 7/4 pi)",    "-1.39159265358979" },
    490 	{ "(- 2/5 3/2)",   "-11/10"            },
    491 	{ "(- 2.1 2)",     "0.1"               },
    492 	{ "(- 8.6 5.3)",   "3.3"               },
    493 	{ "(- 3.7 1/8)",   "3.575"             },
    494 	{ "(* 3 2)",          "6"                 },
    495 	{ "(* -2 8.89)",      "-17.78"            },
    496 	{ "(* 6 3/4)",        "9/2"               },
    497 	{ "(* 1.004 8)",      "8.032"             },
    498 	{ "(* 1.34e3 .0012)", "1.608"             },
    499 	{ "(* e -5/2)",       "-6.79570457114761" },
    500 	{ "(* 1/3 6)",        "2"                 },
    501 	{ "(* 5/2 14.221)",   "35.5525"           },
    502 	{ "(* 6/8 8/7)",      "6/7"               },
    503 	{ "(/ 1 2)",            "1/2"                },
    504 	{ "(/ 8 4)",            "2"                  },
    505 	{ "(/ 6 2.1)",          "2.85714285714286"   },
    506 	{ "(/ 4 4/3)",          "3"                  },
    507 	{ "(/ 5)",              "1/5"                },
    508 	{ "(/ 4473)",           "1/4473"             },
    509 	{ "(/ 10.42 5)",        "2.084"              },
    510 	{ "(/ 1.34e-2 4.3332)", "0.0030924028431644" },
    511 	{ "(/ 1.04 -15/4)",     "-0.277333333333333" },
    512 	{ "(/ 4/3 7)",          "4/21"               },
    513 	{ "(/ 5/4 3.2)",        "0.390625"           },
    514 	{ "(/ 1/3 5/4)",        "4/15"               },
    515 	{ "(mod 10 3)",   "1"  },
    516 	{ "(mod -11 3)",  "-2" },
    517 	{ "(mod 10 -3)",  "1"  },
    518 	{ "(mod -10 -3)", "-1" },
    519 	{ "(mod 10 5)",   "0"  },
    520 	{ "(mod 7 2)",    "1"  },
    521 	{ "(mod 8 5)",    "3"  },
    522 
    523 	{ "compare",      NULL   },
    524 	{ "(< 2 3)",      "True" },
    525 	{ "(< 3 3)",      "Nil"  },
    526 	{ "(< 4 3)",      "Nil"  },
    527 	{ "(<= -2 +4)",   "True" },
    528 	{ "(<= -2 -2)",   "True" },
    529 	{ "(<= 4 -2)",    "Nil"  },
    530 	{ "(> 89 34)",    "True" },
    531 	{ "(> 48 48)",    "Nil"  },
    532 	{ "(> 98 183)",   "Nil"  },
    533 	{ "(>= +4 -282)", "True" },
    534 	{ "(>= 39 39)",   "True" },
    535 	{ "(>= -32 -30)", "Nil"  },
    536 
    537 	{ "abs",        NULL  },
    538 	{ "(abs 4)",    "4"   },
    539 	{ "(abs -3/5)", "3/5" },
    540 	{ "(abs 0.0)",  "0.0" },
    541 
    542 	{ "sgn",         NULL   },
    543 	{ "(sgn 239)",   "1"    },
    544 	{ "(sgn -3)",    "-1"   },
    545 	{ "(sgn 5/4)",   "1"    },
    546 	{ "(sgn -1/7)",  "-1"   },
    547 	{ "(sgn 3.17)",  "1.0"  },
    548 	{ "(sgn -.457)", "-1.0" },
    549 	{ "(sgn 0)",     "0"    },
    550 	{ "(sgn 0.0)",   "0.0"  },
    551 
    552 	{ "max/min",          NULL    },
    553 	{ "(max 9346 13297)", "13297" },
    554 	{ "(max -3 8)",       "8"     },
    555 	{ "(max 3/2 1/2)",    "3/2"   },
    556 	{ "(max 0 -.5)",      "0"     },
    557 	{ "(min 4 48)",       "4"     },
    558 	{ "(min -80 -148)",   "-148"  },
    559 	{ "(min 7/2 -3)",     "-3"    },
    560 	{ "(min 1/2 1/3)",    "1/3"   },
    561 	{ "(min .05 .06)",    "0.05"  },
    562 
    563 	{ NULL,          NULL },
    564 };
    565 
    566 int
    567 tisp_test(Tsp st, const char *input, const char *expect, int output)
    568 {
    569 	Val v;
    570 	FILE *f;
    571 	size_t nread;
    572 	char buf[BUFSIZ] = {0};
    573 
    574 	if (!(st->file = strdup(input)))
    575 		return 0;
    576 	st->filec = 0;
    577 	if (!(v = tisp_read(st)))
    578 		return 0;
    579 	if (!(v = tisp_eval(st, st->global, v))) {
    580 		if (output)
    581 			putchar('\n');
    582 		return 0;
    583 	}
    584 
    585 	f = fopen("test.out", "w");
    586 	tisp_print(f, v);
    587 	fclose(f);
    588 
    589 	f = fopen("test.out", "r");
    590 	while ((nread = fread(buf, 1, sizeof(buf), f)) > 0) ;
    591 	fclose(f);
    592 	remove("test.out");
    593 
    594 	if (output)
    595 		printf("%s\n", buf);
    596 	return strcmp(buf, expect) == 0;
    597 }
    598 
    599 int
    600 main(void)
    601 {
    602 	int correct = 0, total = 0, seccorrect = 0, sectotal = 0, last = 1;
    603 	int errors[LEN(tests)] = {0};
    604 	Tsp st = tisp_env_init(1024);
    605 	tib_env_math(st);
    606 	tib_env_string(st);
    607 	tisp_env_lib(st, tibs);
    608 
    609 	for (int i = 0; ; i++) {
    610 		if (!tests[i][1]) {
    611 			if (i != 0) {
    612 				printf("%d/%d\n", seccorrect, sectotal);
    613 				for (int j = last; j < i; j++)
    614 					if (!tests[j][1]) {
    615 						printf("%-10s\n", tests[j][0]);
    616 					} else if (errors[j]) {
    617 						printf("  input: %s\n"
    618 						       "    expect: %s\n"
    619 						       "    output: ", tests[j][0], tests[j][1]);
    620 						tisp_test(st, tests[j][0], tests[j][1], 1);
    621 					}
    622 				last = i + 1;
    623 			}
    624 			if (!tests[i][0])
    625 				break;
    626 			printf("%-10s ", tests[i][0]);
    627 			seccorrect = 0;
    628 			sectotal = 0;
    629 		} else {
    630 			if (tisp_test(st, tests[i][0], tests[i][1], 0)) {
    631 				correct++;
    632 				seccorrect++;
    633 			} else {
    634 				errors[i] = 1;
    635 			}
    636 			total++;
    637 			sectotal++;
    638 		}
    639 	}
    640 	printf("%-10s %d/%d\n", "total", correct, total);
    641 
    642 	return correct != total;
    643 }