shithub: femtolisp

Download patch

ref: 929ec92a653b36aea0aaf454084eb49f049b7462
parent: 51f645a916842c2ea52d52c70a6e554eb32f631f
author: JeffBezanson <jeff.bezanson@gmail.com>
date: Sun Aug 9 14:04:03 EDT 2009

adding support for eof-object
renaming exported symbol NIL to FL_NIL
making default vector fill #f
some misc. cleanup


--- a/femtolisp/aliases.scm
+++ b/femtolisp/aliases.scm
@@ -39,6 +39,7 @@
 (define (exact? x) (integer? x))
 (define (inexact? x) (not (exact? x)))
 (define quotient div0)
+(define remainder mod0)
 (define (inexact x) x)
 (define (exact x)
   (if (exact? x) x
@@ -90,6 +91,7 @@
 (define close-output-port io.close)
 (define (read-char (s *input-stream*)) (io.getc s))
 (define (write-char c (s *output-stream*)) (io.putc s c))
+(define (port-eof? p) (io.eof? p))
 (define (open-input-string str)
   (let ((b (buffer)))
     (io.write b str)
--- a/femtolisp/builtins.c
+++ b/femtolisp/builtins.c
@@ -29,8 +29,8 @@
 static value_t fl_nconc(value_t *args, u_int32_t nargs)
 {
     if (nargs == 0)
-        return NIL;
-    value_t lst, first=NIL;
+        return FL_NIL;
+    value_t lst, first=FL_NIL;
     value_t *pcdr = &first;
     cons_t *c;
     uint32_t i=0;
@@ -44,7 +44,7 @@
                 c = (cons_t*)ptr(c->cdr);
             pcdr = &c->cdr;
         }
-        else if (lst != NIL) {
+        else if (lst != FL_NIL) {
             type_error("nconc", "cons", lst);
         }
     }
@@ -100,7 +100,7 @@
         if (cv_class(cv)->eltype != NULL)
             return size_wrap(cvalue_arraylen(a));
     }
-    else if (a == NIL) {
+    else if (a == FL_NIL) {
         return fixnum(0);
     }
     else if (iscons(a)) {
@@ -120,7 +120,7 @@
     if (nargs > 0)
         exit(tofixnum(args[0], "exit"));
     exit(0);
-    return NIL;
+    return FL_NIL;
 }
 
 static value_t fl_symbol(value_t *args, u_int32_t nargs)
@@ -173,7 +173,7 @@
 {
     (void)args;
     argcount("environment", nargs, 0);
-    value_t lst = NIL;
+    value_t lst = FL_NIL;
     fl_gc_handle(&lst);
     global_env_list(symtab, &lst);
     fl_free_gc_handles(1);
@@ -286,9 +286,9 @@
     if (nargs == 2)
         f = args[1];
     else
-        f = NIL;
-    v = alloc_vector((unsigned)i, f==NIL);
-    if (f != NIL) {
+        f = FL_F;
+    v = alloc_vector((unsigned)i, f==FL_F);
+    if (f != FL_F) {
         int k;
         for(k=0; k < i; k++)
             vector_elt(v,k) = f;
--- a/femtolisp/color.lsp
+++ b/femtolisp/color.lsp
@@ -84,6 +84,6 @@
   (let ((result ()))
     (dotimes (x 25)
       (dotimes (y 25)
-        (if (and (/= x y) (can-attack x y))
+        (if (and (not (= x y)) (can-attack x y))
             (set! result (cons (cons x y) result)) ())))
     result))
--- a/femtolisp/cvalues.c
+++ b/femtolisp/cvalues.c
@@ -638,6 +638,8 @@
             return booleansym;
         if (args[0] == NIL)
             return nullsym;
+        if (args[0] == FL_EOF)
+            return symbol("eof-object");
         if (isbuiltin(args[0]))
             return builtinsym;
         return FUNCTION;
--- a/femtolisp/flisp.boot
+++ b/femtolisp/flisp.boot
@@ -1,1 +1,1 @@
-(*banner* ";  _\n; |_ _ _ |_ _ |  . _ _\n; | (-||||_(_)|__|_)|_)\n;-------------------|----------------------------------------------------------\n\n" *syntax-environment* #table(with-bindings #fn(">000s1c0qe1c2|32e1e3|32e1c4|3243;" [#fn("B000r3e0c1L1e2c3g2|33L1e4e2c5|}3331c6e0c7L1e4\x7f3132e0c7L1e4e2c8|g2333132L3L144;" [nconc let map #.list copy-list #fn("8000r2c0|}L3;" [set!]) unwind-protect begin #fn("8000r2c0|}L3;" [set!])]) map #.car cadr #fn("6000r1e040;" [gensym])])  letrec #fn("?000s1e0e0c1L1e2c3|32L1e2c4|32e5}3134L1e2c6|3242;" [nconc lambda map #.car #fn("9000r1e0c1L1e2|3142;" [nconc set! copy-list]) copy-list #fn("6000r1^;" [])])  backquote #fn("7000r1e0|41;" [bq-process])  assert #fn("<000r1c0|]c1c2c3|L2L2L2L4;" [if raise quote assert-failed])  label #fn(":000r2c0|L1c1|}L3L3^L2;" [lambda set!])  do #fn("A000s2c0qe130}Me2c3|32e2e4|32e2c5|3245;" [#fn("B000r5c0|c1g2c2}e3c4L1e5\x7fN3132e3c4L1e5i0231e3|L1g432L133L4L3L2L1e3|L1g332L3;" [letrec lambda if nconc begin copy-list]) gensym map #.car cadr #fn("7000r1e0|31F680e1|41;|M;" [cddr caddr])])  when #fn("<000s1c0|c1}K^L4;" [if begin])  dotimes #fn(";000s1c0q|M|\x8442;" [#fn("=000r2c0`c1}aL3e2c3L1|L1L1e4\x7f3133L4;" [for - nconc lambda copy-list])])  unwind-protect #fn("8000r2c0qe130e13042;" [#fn("@000r2c0}c1_\x7fL3L2L1c2c3~c1|L1c4}L1c5|L2L3L3L3}L1L3L3;" [let lambda prog1 trycatch begin raise]) gensym])  define-macro #fn("?000s1c0c1|ML2e2c3L1|NL1e4}3133L3;" [set-syntax! quote nconc lambda copy-list])  receive #fn("@000s2c0c1_}L3e2c1L1|L1e3g23133L3;" [call-with-values lambda nconc copy-list])  unless #fn("=000s1c0|^c1}KL4;" [if begin])  let #fn(":000s1c0q^41;" [#fn("<000r1~C6D0~m02\x7fMo002\x7fNo01530^2c0qe1c2L1e3c4~32L1e5\x7f3133e3c6~3242;" [#fn("8000r2~6;0c0~|L3530|}K;" [label]) nconc lambda map #fn("6000r1|F650|M;|;" []) copy-list #fn("6000r1|F650|\x84;^;" [])])])  cond #fn("9000s0c0q^41;" [#fn("7000r1c0qm02|~41;" [#fn("7000r1|?640^;c0q|M41;" [#fn(";000r1|Mc0<17702|M]<6@0|N\x8550|M;c1|NK;|N\x85@0c2|Mi10~N31L3;c3|Mc1|NKi10~N31L4;" [else begin or if])] cond-clauses->if)])])  throw #fn(":000r2c0c1c2c3L2|}L4L2;" [raise list quote thrown-value])  time #fn("7000r1c0qe13041;" [#fn(">000r1c0|c1L1L2L1c2~c3c4c5c1L1|L3c6L4L3L3;" [let time.now prog1 princ "Elapsed time: " - " seconds\n"]) gensym])  let* #fn("A000s1|?6E0e0c1L1_L1e2}3133L1;e0c1L1e3|31L1L1e2|NF6H0e0c4L1|NL1e2}3133L1530}3133e5|31L2;" [nconc lambda copy-list caar let* cadar])  case #fn(":000s1c0q^41;" [#fn("7000r1c0m02c1qe23041;" [#fn(";000r2}c0\x8250c0;}\x8540^;}C6=0c1|e2}31L3;}?6=0c3|e2}31L3;}N\x85>0c3|e2}M31L3;e4c5}326=0c6|c7}L2L3;c8|c7}L2L3;" [else eq? quote-value eqv? every #.symbol? memq quote memv] vals->cond) #fn("<000r1c0|i10L2L1e1c2L1e3c4qi113232L3;" [let nconc cond map #fn("8000r1i10~|M32|NK;" [])]) gensym])])  with-output-to #fn("=000s1e0c1L1c2|L2L1L1e3}3143;" [nconc with-bindings *output-stream* copy-list])  catch #fn("7000r2c0qe13041;" [#fn("@000r1c0\x7fc1|L1c2c3c4|L2c5c6|L2c7c8L2L3c5c9|L2~L3L4c:|L2c;|L2L4L3L3;" [trycatch lambda if and pair? eq car quote thrown-value cadr caddr raise]) gensym])) *whitespace* "\t\n\v\f\r \u0085  ᠎           \u2028\u2029   " /= #fn("7000r2|}W@;" [] /=) 1+ #fn("7000r1|aw;" [] 1+) 1- #fn("7000r1|ax;" [] 1-) 1arg-lambda? #fn("8000r1|F16T02|Mc0<16J02|NF16B02|\x84F16:02e1|\x84a42;" [lambda length=] 1arg-lambda?) <= #fn("7000r2|}X17602|}W;" [] <=) > #fn("7000r2}|X;" [] >) >= #fn("7000r2}|X17602|}W;" [] >=) Instructions #table(not 16  vargc 67  load1 49  = 39  setc.l 64  sub2 72  brne.l 83  largc 74  brnn 85  loadc.l 58  loadi8 50  < 40  nop 0  set-cdr! 32  loada 55  bound? 21  / 37  neg 73  brn.l 88  lvargc 75  brt 7  trycatch 68  null? 17  load0 48  jmp.l 8  loadv 51  seta 61  keyargs 91  * 36  function? 26  builtin? 23  aref 43  optargs 89  vector? 24  loadt 45  brf 6  symbol? 19  cdr 30  for 69  loadc00 78  pop 2  pair? 22  cadr 84  closure 65  loadf 46  compare 41  loadv.l 52  setg.l 60  brn 87  eqv? 13  aset! 44  eq? 12  atom? 15  boolean? 18  brt.l 10  tapply 70  dummy_nil 94  loada0 76  brbound 90  list 28  dup 1  apply 33  loadc 57  l
\ No newline at end of file
+(*banner* ";  _\n; |_ _ _ |_ _ |  . _ _\n; | (-||||_(_)|__|_)|_)\n;-------------------|----------------------------------------------------------\n\n" *interactive* #f *syntax-environment* #table(with-bindings #fn(">000s1c0qe1c2|32e1e3|32e1c4|3243;" [#fn("B000r3e0c1L1e2c3g2|33L1e4e2c5|}3331c6e0c7L1e4\x7f3132e0c7L1e4e2c8|g2333132L3L144;" [nconc let map #.list copy-list #fn("8000r2c0|}L3;" [set!]) unwind-protect begin #fn("8000r2c0|}L3;" [set!])]) map #.car cadr #fn("6000r1e040;" [gensym])])  letrec #fn("?000s1e0e0c1L1e2c3|32L1e2c4|32e5}3134L1e2c6|3242;" [nconc lambda map #.car #fn("9000r1e0c1L1e2|3142;" [nconc set! copy-list]) copy-list #fn("6000r1^;" [])])  backquote #fn("7000r1e0|41;" [bq-process])  assert #fn("<000r1c0|]c1c2c3|L2L2L2L4;" [if raise quote assert-failed])  label #fn(":000r2c0|L1c1|}L3L3^L2;" [lambda set!])  do #fn("A000s2c0qe130}Me2c3|32e2e4|32e2c5|3245;" [#fn("B000r5c0|c1g2c2}e3c4L1e5\x7fN3132e3c4L1e5i0231e3|L1g432L133L4L3L2L1e3|L1g332L3;" [letrec lambda if nconc begin copy-list]) gensym map #.car cadr #fn("7000r1e0|31F680e1|41;|M;" [cddr caddr])])  when #fn("<000s1c0|c1}K^L4;" [if begin])  dotimes #fn(";000s1c0q|M|\x8442;" [#fn("=000r2c0`c1}aL3e2c3L1|L1L1e4\x7f3133L4;" [for - nconc lambda copy-list])])  unwind-protect #fn("8000r2c0qe130e13042;" [#fn("@000r2c0}c1_\x7fL3L2L1c2c3~c1|L1c4}L1c5|L2L3L3L3}L1L3L3;" [let lambda prog1 trycatch begin raise]) gensym])  define-macro #fn("?000s1c0c1|ML2e2c3L1|NL1e4}3133L3;" [set-syntax! quote nconc lambda copy-list])  receive #fn("@000s2c0c1_}L3e2c1L1|L1e3g23133L3;" [call-with-values lambda nconc copy-list])  unless #fn("=000s1c0|^c1}KL4;" [if begin])  let #fn(":000s1c0q^41;" [#fn("<000r1~C6D0~m02\x7fMo002\x7fNo01530^2c0qe1c2L1e3c4~32L1e5\x7f3133e3c6~3242;" [#fn("8000r2~6;0c0~|L3530|}K;" [label]) nconc lambda map #fn("6000r1|F650|M;|;" []) copy-list #fn("6000r1|F650|\x84;^;" [])])])  cond #fn("9000s0c0q^41;" [#fn("7000r1c0qm02|~41;" [#fn("7000r1|?640^;c0q|M41;" [#fn(";000r1|Mc0<17702|M]<6@0|N\x8550|M;c1|NK;|N\x85@0c2|Mi10~N31L3;c3|Mc1|NKi10~N31L4;" [else begin or if])] cond-clauses->if)])])  throw #fn(":000r2c0c1c2c3L2|}L4L2;" [raise list quote thrown-value])  time #fn("7000r1c0qe13041;" [#fn(">000r1c0|c1L1L2L1c2~c3c4c5c1L1|L3c6L4L3L3;" [let time.now prog1 princ "Elapsed time: " - " seconds\n"]) gensym])  let* #fn("A000s1|?6E0e0c1L1_L1e2}3133L1;e0c1L1e3|31L1L1e2|NF6H0e0c4L1|NL1e2}3133L1530}3133e5|31L2;" [nconc lambda copy-list caar let* cadar])  case #fn(":000s1c0q^41;" [#fn("7000r1c0m02c1qe23041;" [#fn(";000r2}c0\x8250c0;}\x8540^;}C6=0c1|e2}31L3;}?6=0c3|e2}31L3;}N\x85>0c3|e2}M31L3;e4c5}326=0c6|c7}L2L3;c8|c7}L2L3;" [else eq? quote-value eqv? every #.symbol? memq quote memv] vals->cond) #fn("<000r1c0|i10L2L1e1c2L1e3c4qi113232L3;" [let nconc cond map #fn("8000r1i10~|M32|NK;" [])]) gensym])])  with-output-to #fn("=000s1e0c1L1c2|L2L1L1e3}3143;" [nconc with-bindings *output-stream* copy-list])  catch #fn("7000r2c0qe13041;" [#fn("@000r1c0\x7fc1|L1c2c3c4|L2c5c6|L2c7c8L2L3c5c9|L2~L3L4c:|L2c;|L2L4L3L3;" [trycatch lambda if and pair? eq car quote thrown-value cadr caddr raise]) gensym])) *whitespace* "\t\n\v\f\r \u0085  ᠎           \u2028\u2029   " 1+ #fn("7000r1|aw;" [] 1+) 1- #fn("7000r1|ax;" [] 1-) 1arg-lambda? #fn("8000r1|F16T02|Mc0<16J02|NF16B02|\x84F16:02e1|\x84a42;" [lambda length=] 1arg-lambda?) <= #fn("7000r2|}X17602|}W;" [] <=) > #fn("7000r2}|X;" [] >) >= #fn("7000r2}|X17602|}W;" [] >=) Instructions #table(not 16  vargc 67  load1 49  = 39  setc.l 64  sub2 72  brne.l 83  largc 74  brnn 85  loadc.l 58  loadi8 50  < 40  nop 0  set-cdr! 32  loada 55  bound? 21  / 37  neg 73  brn.l 88  lvargc 75  brt 7  trycatch 68  null? 17  load0 48  jmp.l 8  loadv 51  seta 61  keyargs 91  * 36  function? 26  builtin? 23  aref 43  optargs 89  vector? 24  loadt 45  brf 6  symbol? 19  cdr 30  for 69  loadc00 78  pop 2  pair? 22  cadr 84  closure 65  loadf 46  compare 41  loadv.l 52  setg.l 60  brn 87  eqv? 13  aset! 44  eq? 12  atom? 15  boolean? 18  brt.l 10  tapply 70  dummy_nil 94  loada0 76  brbound 90  list 28  dup 1  apply 33  loadc 57  loadc01 79  
\ No newline at end of file
--- a/femtolisp/flisp.c
+++ b/femtolisp/flisp.c
@@ -89,13 +89,12 @@
 static value_t *GCHandleStack[N_GC_HANDLES];
 static uint32_t N_GCHND = 0;
 
-value_t NIL, FL_T, FL_F;
+value_t FL_NIL, FL_T, FL_F, FL_EOF, QUOTE;
 value_t IOError, ParseError, TypeError, ArgError, UnboundError, MemoryError;
 value_t DivideError, BoundsError, Error, KeyError, EnumerationError;
 value_t printwidthsym, printreadablysym, printprettysym;
 
-value_t QUOTE;
-static value_t LAMBDA, IF, TRYCATCH;
+static value_t NIL, LAMBDA, IF, TRYCATCH;
 static value_t BACKQUOTE, COMMA, COMMAAT, COMMADOT, FUNCTION;
 
 static value_t pairsym, symbolsym, fixnumsym, vectorsym, builtinsym, vu8sym;
@@ -378,7 +377,7 @@
     if (init) {
         unsigned int i;
         for(i=0; i < n; i++)
-            vector_elt(v, i) = NIL;
+            vector_elt(v, i) = FL_F;
     }
     return v;
 }
@@ -1242,7 +1241,8 @@
             NEXT_OP;
         OP(OP_FUNCTIONP)
             v = Stack[SP-1];
-            Stack[SP-1] = ((tag(v)==TAG_FUNCTION &&v!=FL_F&&v!=FL_T&&v!=NIL) ||
+            Stack[SP-1] = ((tag(v)==TAG_FUNCTION &&
+                            (uintval(v)<=OP_ASET || v>(N_BUILTINS<<3))) ||
                            iscbuiltin(v)) ? FL_T : FL_F;
             NEXT_OP;
         OP(OP_VECTORP)
@@ -2100,9 +2100,10 @@
     N_STACK = 262144;
     Stack = malloc(N_STACK*sizeof(value_t));
 
-    NIL = builtin(OP_THE_EMPTY_LIST);
+    FL_NIL = NIL = builtin(OP_THE_EMPTY_LIST);
     FL_T = builtin(OP_BOOL_CONST_T);
     FL_F = builtin(OP_BOOL_CONST_F);
+    FL_EOF = builtin(OP_EOF_OBJECT);
     LAMBDA = symbol("lambda");        FUNCTION = symbol("function");
     QUOTE = symbol("quote");          TRYCATCH = symbol("trycatch");
     BACKQUOTE = symbol("backquote");  COMMA = symbol("*comma*");
--- a/femtolisp/flisp.h
+++ b/femtolisp/flisp.h
@@ -56,7 +56,7 @@
 #define issymbol(x)  (tag(x) == TAG_SYM)
 #define isfixnum(x)  (((x)&3) == TAG_NUM)
 #define bothfixnums(x,y) ((((x)|(y))&3) == TAG_NUM)
-#define isbuiltin(x) ((tag(x) == TAG_FUNCTION) && (x) < (OP_BOOL_CONST_T<<3))
+#define isbuiltin(x) ((tag(x) == TAG_FUNCTION) && uintval(x) <= OP_ASET)
 #define isvector(x) (tag(x) == TAG_VECTOR)
 #define iscvalue(x) (tag(x) == TAG_CVALUE)
 #define iscprim(x)  (tag(x) == TAG_CPRIM)
@@ -113,7 +113,7 @@
 
 #define N_BUILTINS ((int)N_OPCODES)
 
-extern value_t NIL, FL_T, FL_F;
+extern value_t FL_NIL, FL_T, FL_F, FL_EOF;
 
 /* read, eval, print main entry points */
 value_t read_sexpr(value_t f);
--- a/femtolisp/iostream.c
+++ b/femtolisp/iostream.c
@@ -49,6 +49,19 @@
     return isiostream(args[0]) ? FL_T : FL_F;
 }
 
+value_t fl_eof_object(value_t *args, uint32_t nargs)
+{
+    (void)args;
+    argcount("eof-object", nargs, 0);
+    return FL_EOF;
+}
+
+value_t fl_eof_objectp(value_t *args, uint32_t nargs)
+{
+    argcount("eof-object?", nargs, 1);
+    return (FL_EOF == args[0]) ? FL_T : FL_F;
+}
+
 static ios_t *toiostream(value_t v, char *fname)
 {
     if (!isiostream(v))
@@ -101,8 +114,11 @@
     else {
         arg = args[0];
     }
-    (void)toiostream(arg, "read");
-    return read_sexpr(arg);
+    ios_t *s = toiostream(arg, "read");
+    value_t v = read_sexpr(arg);
+    if (ios_eof(s))
+        return FL_EOF;
+    return v;
 }
 
 value_t fl_iogetc(value_t *args, u_int32_t nargs)
@@ -111,7 +127,8 @@
     ios_t *s = toiostream(args[0], "io.getc");
     uint32_t wc;
     if (ios_getutf8(s, &wc) == IOS_EOF)
-        lerror(IOError, "io.getc: end of file reached");
+        //lerror(IOError, "io.getc: end of file reached");
+        return FL_EOF;
     return mk_wchar(wc);
 }
 
@@ -215,7 +232,8 @@
     else data = cp_data((cprim_t*)ptr(cv));
     size_t got = ios_read(value2c(ios_t*,args[0]), data, n);
     if (got < n)
-        lerror(IOError, "io.read: end of input reached");
+        //lerror(IOError, "io.read: end of input reached");
+        return FL_EOF;
     return cv;
 }
 
@@ -306,7 +324,7 @@
     }
     ((char*)cv->data)[n] = '\0';
     if (n == 0 && ios_eof(src))
-        return FL_F;
+        return FL_EOF;
     return str;
 }
 
@@ -345,7 +363,7 @@
     else {
         char *b = ios_takebuf(st, &n); n--;
         b[n] = '\0';
-        str = cvalue_from_ref(stringtype, b, n, NIL);
+        str = cvalue_from_ref(stringtype, b, n, FL_NIL);
         cv_autorelease((cvalue_t*)ptr(str));
     }
     return str;
@@ -362,6 +380,8 @@
 
 static builtinspec_t iostreamfunc_info[] = {
     { "iostream?", fl_iostreamp },
+    { "eof-object", fl_eof_object },
+    { "eof-object?", fl_eof_objectp },
     { "dump", fl_dump },
     { "file", fl_file },
     { "buffer", fl_buffer },
@@ -399,9 +419,9 @@
     assign_global_builtins(iostreamfunc_info);
 
     setc(symbol("*stdout*"), cvalue_from_ref(iostreamtype, ios_stdout,
-                                             sizeof(ios_t), NIL));
+                                             sizeof(ios_t), FL_NIL));
     setc(symbol("*stderr*"), cvalue_from_ref(iostreamtype, ios_stderr,
-                                             sizeof(ios_t), NIL));
+                                             sizeof(ios_t), FL_NIL));
     setc(symbol("*stdin*" ), cvalue_from_ref(iostreamtype, ios_stdin,
-                                             sizeof(ios_t), NIL));
+                                             sizeof(ios_t), FL_NIL));
 }
--- a/femtolisp/opcodes.h
+++ b/femtolisp/opcodes.h
@@ -29,7 +29,7 @@
     OP_BRNE, OP_BRNEL, OP_CADR, OP_BRNN, OP_BRNNL, OP_BRN, OP_BRNL,
     OP_OPTARGS, OP_BRBOUND, OP_KEYARGS,
 
-    OP_BOOL_CONST_T, OP_BOOL_CONST_F, OP_THE_EMPTY_LIST,
+    OP_BOOL_CONST_T, OP_BOOL_CONST_F, OP_THE_EMPTY_LIST, OP_EOF_OBJECT,
 
     N_OPCODES
 };
--- a/femtolisp/print.c
+++ b/femtolisp/print.c
@@ -386,8 +386,11 @@
         else if (v == FL_F) {
             outsn("#f", f, 2);
         }
-        else if (v == NIL) {
+        else if (v == FL_NIL) {
             outsn("()", f, 2);
+        }
+        else if (v == FL_EOF) {
+            outsn("#<eof>", f, 6);
         }
         else if (isbuiltin(v)) {
             if (!print_princ)
--- a/femtolisp/string.c
+++ b/femtolisp/string.c
@@ -151,7 +151,7 @@
     size_t len = cv_len((cvalue_t*)ptr(args[0]));
     size_t dlen = cv_len((cvalue_t*)ptr(args[1]));
     size_t ssz, tokend=0, tokstart=0, i=0;
-    value_t first=NIL, c=NIL, last;
+    value_t first=FL_NIL, c=FL_NIL, last;
     size_t junk;
     fl_gc_handle(&first);
     fl_gc_handle(&last);
@@ -164,7 +164,7 @@
             tokend = i;
         ssz = tokend - tokstart;
         last = c;  // save previous cons cell
-        c = fl_cons(cvalue_string(ssz), NIL);
+        c = fl_cons(cvalue_string(ssz), FL_NIL);
 
         // we've done allocation; reload movable pointers
         s = cv_data((cvalue_t*)ptr(args[0]));
@@ -173,7 +173,7 @@
         if (ssz) memcpy(cv_data((cvalue_t*)ptr(car_(c))), &s[tokstart], ssz);
 
         // link new cell
-        if (last == NIL)
+        if (last == FL_NIL)
             first = c;   // first time, save first cons
         else
             ((cons_t*)ptr(last))->cdr = c;
--- a/femtolisp/system.lsp
+++ b/femtolisp/system.lsp
@@ -97,7 +97,6 @@
 	((eqv?       (caar lst) item) (car lst))
 	(#t          (assv item (cdr lst)))))
 
-(define (/= a b) (not (= a b)))
 (define (>  a b) (< b a))
 (define (<= a b) (or (< a b) (= a b)))
 (define (>= a b) (or (< b a) (= a b)))
@@ -116,8 +115,6 @@
 				  -1))
 			 0)))
 (define (mod x y) (- x (* (div x y) y)))
-(define quotient div0)
-(define remainder mod0)
 (define (random n)
   (if (integer? n)
       (mod (rand) n)
@@ -547,7 +544,10 @@
 (define (io.readall s)
   (let ((b (buffer)))
     (io.copy b s)
-    (io.tostring! b)))
+    (let ((str (io.tostring! b)))
+      (if (and (equal? str "") (io.eof? s))
+	  (eof-object)
+	  str))))
 
 (define-macro (with-output-to stream . body)
   `(with-bindings ((*output-stream* ,stream))
@@ -777,7 +777,7 @@
       (if p
 	  (symbol (string.join (map string (reverse! p)) "/"))
 	  'lambda)))
-  (let ((st (reverse! (list-tail st 5)))
+  (let ((st (reverse! (list-tail st (if *interactive* 5 4))))
 	(e (filter closure? (map (lambda (s) (and (bound? s)
 						  (top-level-value s)))
 				 (environment))))
@@ -883,8 +883,10 @@
   (__init_globals)
   (if (pair? (cdr argv))
       (begin (set! *argv* (cdr argv))
+	     (set! *interactive* #f)
 	     (__script (cadr argv)))
       (begin (set! *argv* argv)
+	     (set! *interactive* #t)
 	     (princ *banner*)
 	     (repl)))
   (exit 0))
--- a/femtolisp/table.c
+++ b/femtolisp/table.c
@@ -99,7 +99,7 @@
     htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(nt));
     htable_new(h, cnt/2);
     uint32_t i;
-    value_t k=NIL, arg=NIL;
+    value_t k=FL_NIL, arg=FL_NIL;
     FOR_ARGS(i,0,arg,args) {
         if (i&1)
             equalhash_put(h, (void*)k, (void*)arg);
--- a/femtolisp/unittest.lsp
+++ b/femtolisp/unittest.lsp
@@ -152,6 +152,9 @@
 (assert (equal? ((lambda ((x 0) . r) (list x r)) 1 2 3) '(1 (2 3))))
 
 ; keyword arguments
+(assert (keyword? kw:))
+(assert (not (keyword? 'kw)))
+(assert (not (keyword? ':)))
 (assert (equal? ((lambda (x (a 2) (b: a) . r) (list x a b r)) 1 0 8 4 5)
 		'(1 0 0 (8 4 5))))
 (assert (equal? ((lambda (x (a 2) (b: a) . r) (list x a b r)) 0 b: 3 1)
@@ -177,6 +180,16 @@
 (assert (not (eq? (gensym) (gensym))))
 (assert (not (equal? (string (gensym)) (string (gensym)))))
 (let ((gs (gensym))) (assert (eq? gs gs)))
+
+; eof object
+(assert (eof-object? (eof-object)))
+(assert (not (eof-object? 1)))
+(assert (not (eof-object? 'a)))
+(assert (not (eof-object? '())))
+(assert (not (eof-object? #f)))
+(assert (not (null? (eof-object))))
+(assert (not (builtin? (eof-object))))
+(assert (not (function? (eof-object))))
 
 ; ok, a couple end-to-end tests as well
 (define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))