shithub: femtolisp

Download patch

ref: 0c0471e85605e670aab34592cd69cf3f922afd1b
parent: 79e12b2dcbe71f78a6c93656a2e440ca09595913
author: JeffBezanson <jeff.bezanson@gmail.com>
date: Wed Feb 18 22:31:40 EST 2009

moving implementation of startup, repl, load, and top-level
exception handler into system.lsp

adding several iostream functions

adding support for internal define


--- a/femtolisp/ast/rpasses.lsp
+++ b/femtolisp/ast/rpasses.lsp
@@ -20,8 +20,9 @@
 ; transformations
 
 (let ((ctr 0))
-  (define (r-gensym) (prog1 (intern (string "%r:" ctr))
-			    (set! ctr (+ ctr 1)))))
+  (set! r-gensym (lambda ()
+		   (prog1 (intern (string "%r:" ctr))
+			  (set! ctr (+ ctr 1))))))
 
 (define (dollarsign-transform e)
   (pattern-expand
--- a/femtolisp/builtins.c
+++ b/femtolisp/builtins.c
@@ -35,12 +35,6 @@
     return NIL;
 }
 
-value_t fl_load(value_t *args, u_int32_t nargs)
-{
-    argcount("load", nargs, 1);
-    return load_file(tostring(args[0], "load"));
-}
-
 value_t fl_exit(value_t *args, u_int32_t nargs)
 {
     if (nargs > 0)
@@ -375,7 +369,6 @@
     { "environment", fl_global_env },
     { "constant?", fl_constantp },
 
-    { "load", fl_load },
     { "exit", fl_exit },
     { "intern", fl_intern },
     { "fixnum", fl_fixnum },
--- a/femtolisp/flisp.c
+++ b/femtolisp/flisp.c
@@ -111,7 +111,6 @@
 
 static exception_context_t *ctx = NULL;
 static value_t lasterror;
-static char lerrorbuf[512];
 
 #define FL_TRY \
   exception_context_t _ctx; int l__tr, l__ca; \
@@ -122,14 +121,11 @@
 
 #define FL_CATCH \
   else \
-      for (l__ca=1; l__ca; l__ca=0, lerrorbuf[0]='\0', lasterror=NIL)
+      for (l__ca=1; l__ca; l__ca=0, lasterror=NIL)
 
 void raise(value_t e)
 {
-    if (e != lasterror) {
-        lasterror = e;
-        lerrorbuf[0] = '\0';  // overwriting exception; clear error buf
-    }
+    lasterror = e;
     // unwind read state
     while (readstate != ctx->rdst) {
         free_readstate(readstate);
@@ -142,15 +138,21 @@
     longjmp(thisctx->buf, 1);
 }
 
+static value_t make_error_msg(char *format, va_list args)
+{
+    char msgbuf[512];
+    vsnprintf(msgbuf, sizeof(msgbuf), format, args);
+    return string_from_cstr(msgbuf);
+}
+
 void lerror(value_t e, char *format, ...)
 {
     va_list args;
     va_start(args, format);
-    vsnprintf(lerrorbuf, sizeof(lerrorbuf), format, args);
+    value_t msg = make_error_msg(format, args);
     va_end(args);
 
-    lasterror = e;
-    raise(e);
+    raise(list2(e, msg));
 }
 
 void type_error(char *fname, char *expected, value_t got)
@@ -1470,7 +1472,6 @@
     set(printprettysym=symbol("*print-pretty*"), FL_T);
     set(printwidthsym=symbol("*print-width*"), fixnum(SCR_WIDTH));
     lasterror = NIL;
-    lerrorbuf[0] = '\0';
     special_apply_form = fl_cons(builtin(F_SPECIAL_APPLY), NIL);
     i = 0;
     while (isspecial(builtin(i))) {
@@ -1483,13 +1484,13 @@
     }
 
 #ifdef LINUX
-    set(symbol("os.name"), symbol("linux"));
+    set(symbol("*os-name*"), symbol("linux"));
 #elif defined(WIN32) || defined(WIN64)
-    set(symbol("os.name"), symbol("win32"));
+    set(symbol("*os-name*"), symbol("win32"));
 #elif defined(MACOSX)
-    set(symbol("os.name"), symbol("macos"));
+    set(symbol("*os-name*"), symbol("macos"));
 #else
-    set(symbol("os.name"), symbol("unknown"));
+    set(symbol("*os-name*"), symbol("unknown"));
 #endif
 
     cvalues_init();
@@ -1521,81 +1522,15 @@
     return v;
 }
 
-static void print_toplevel_exception()
-{
-    if (iscons(lasterror) && car_(lasterror) == TypeError &&
-        llength(lasterror) == 4) {
-        ios_printf(ios_stderr, "type-error: ");
-        print(ios_stderr, car_(cdr_(lasterror)), 1);
-        ios_printf(ios_stderr, ": expected ");
-        print(ios_stderr, car_(cdr_(cdr_(lasterror))), 1);
-        ios_printf(ios_stderr, ", got ");
-        print(ios_stderr, car_(cdr_(cdr_(cdr_(lasterror)))), 0);
-    }
-    else if (iscons(lasterror) && car_(lasterror) == UnboundError &&
-             iscons(cdr_(lasterror))) {
-        ios_printf(ios_stderr, "unbound-error: eval: variable %s has no value",
-                   (symbol_name(car_(cdr_(lasterror)))));
-    }
-    else if (iscons(lasterror) && car_(lasterror) == Error) {
-        value_t v = cdr_(lasterror);
-        ios_printf(ios_stderr, "error: ");
-        while (iscons(v)) {
-            print(ios_stderr, car_(v), 1);
-            v = cdr_(v);
-        }
-    }
-    else {
-        if (lasterror != NIL) {
-            if (!lerrorbuf[0])
-                ios_printf(ios_stderr, "*** Unhandled exception: ");
-            print(ios_stderr, lasterror, 0);
-            if (lerrorbuf[0])
-                ios_printf(ios_stderr, ": ");
-        }
-    }
-
-    if (lerrorbuf[0])
-        ios_printf(ios_stderr, "%s", lerrorbuf);
-}
-
-value_t load_file(char *fname)
-{
-    value_t volatile e, v=NIL;
-    ios_t fi;
-    ios_t * volatile f;
-    fname = strdup(fname);
-    f = &fi; f = ios_file(f, fname, 1, 0, 0, 0);
-    if (f == NULL) lerror(IOError, "file \"%s\" not found", fname);
-    FL_TRY {
-        while (1) {
-            e = read_sexpr(f);
-            //print(ios_stdout,e,0); ios_putc('\n', ios_stdout);
-            if (ios_eof(f)) break;
-            v = toplevel_eval(e);
-        }
-    }
-    FL_CATCH {
-        ios_close(f);
-        size_t msglen = strlen(lerrorbuf);
-        snprintf(&lerrorbuf[msglen], sizeof(lerrorbuf)-msglen,
-                 "\nin file \"%s\"", fname);
-        lerrorbuf[sizeof(lerrorbuf)-1] = '\0';
-        free(fname);
-        raise(lasterror);
-    }
-    free(fname);
-    ios_close(f);
-    return v;
-}
-
 static value_t argv_list(int argc, char *argv[])
 {
     int i;
     PUSH(NIL);
-    if (argc > 1) { argc--; argv++; }
-    for(i=argc-1; i >= 0; i--)
-        Stack[SP-1] = fl_cons(cvalue_static_cstring(argv[i]), Stack[SP-1]);
+    for(i=argc-1; i >= 0; i--) {
+        PUSH(cvalue_static_cstring(argv[i]));
+        Stack[SP-2] = fl_cons(Stack[SP-1], Stack[SP-2]);
+        (void)POP();
+    }
     return POP();
 }
 
@@ -1603,23 +1538,21 @@
 
 int main(int argc, char *argv[])
 {
-    value_t v;
+    value_t e, v;
     char fname_buf[1024];
 
     locale_is_utf8 = u8_is_locale_utf8(setlocale(LC_ALL, ""));
 
     lisp_init();
-    set(symbol("argv"), argv_list(argc, argv));
+
     FL_TRY {
         // install toplevel exception handler
     }
     FL_CATCH {
-        print_toplevel_exception();
-        lerrorbuf[0] = '\0';
-        lasterror = NIL;
-        ios_puts("\n\n", ios_stderr);
-        if (argc > 1) return 1;
-        else goto repl;
+        ios_printf(ios_stderr, "fatal error during bootstrap:\n");
+        print(ios_stderr, lasterror, 0);
+        ios_putc('\n', ios_stderr);
+        exit(1);
     }
     fname_buf[0] = '\0';
     if (EXEDIR != NULL) {
@@ -1627,27 +1560,19 @@
         strcat(fname_buf, PATHSEPSTRING);
     }
     strcat(fname_buf, "system.lsp");
-    load_file(fname_buf);
-    if (argc > 1) { load_file(argv[1]); return 0; }
-    printf(";  _                   \n");
-    printf("; |_ _ _ |_ _ |  . _ _\n");
-    printf("; | (-||||_(_)|__|_)|_)\n");
-    printf(";-------------------|----------------------------------------------------------\n\n");
- repl:
+
+    ios_t fi;
+    ios_t *f = &fi; f = ios_file(f, fname_buf, 1, 0, 0, 0);
+    if (f == NULL) lerror(IOError, "file \"%s\" not found", fname_buf);
     while (1) {
-        ios_puts("> ", ios_stdout); ios_flush(ios_stdout);
-        FL_TRY {
-            v = read_sexpr(ios_stdin);
-        }
-        FL_CATCH {
-            ios_purge(ios_stdin);
-            raise(lasterror);
-        }
-        if (ios_eof(ios_stdin)) break;
-        print(ios_stdout, v=toplevel_eval(v), 0);
-        set(symbol("that"), v);
-        ios_puts("\n\n", ios_stdout);
+        e = read_sexpr(f);
+        if (ios_eof(f)) break;
+        v = toplevel_eval(e);
     }
-    ios_putc('\n', ios_stdout);
+    ios_close(f);
+
+    PUSH(symbol_value(symbol("__start")));
+    PUSH(argv_list(argc, argv));
+    (void)toplevel_eval(special_apply_form);
     return 0;
 }
--- a/femtolisp/iostream.c
+++ b/femtolisp/iostream.c
@@ -86,11 +86,51 @@
     else
         s = toiostream(symbol_value(instrsym), "read");
     value_t v = read_sexpr(s);
-    if (ios_eof(s))
-        lerror(IOError, "read: end of file reached");
     return v;
 }
 
+value_t fl_iogetc(value_t *args, u_int32_t nargs)
+{
+    argcount("io.getc", nargs, 1);
+    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");
+    return mk_wchar(wc);
+}
+
+value_t fl_ioflush(value_t *args, u_int32_t nargs)
+{
+    argcount("io.flush", nargs, 1);
+    ios_t *s = toiostream(args[0], "io.flush");
+    if (ios_flush(s) != 0)
+        return FL_F;
+    return FL_T;
+}
+
+value_t fl_ioclose(value_t *args, u_int32_t nargs)
+{
+    argcount("io.close", nargs, 1);
+    ios_t *s = toiostream(args[0], "io.close");
+    ios_close(s);
+    return FL_T;
+}
+
+value_t fl_iopurge(value_t *args, u_int32_t nargs)
+{
+    argcount("io.discardbuffer", nargs, 1);
+    ios_t *s = toiostream(args[0], "io.discardbuffer");
+    ios_purge(s);
+    return FL_T;
+}
+
+value_t fl_ioeof(value_t *args, u_int32_t nargs)
+{
+    argcount("io.eof?", nargs, 1);
+    ios_t *s = toiostream(args[0], "io.eof?");
+    return (ios_eof(s) ? FL_T : FL_F);
+}
+
 static void do_ioprint(value_t *args, u_int32_t nargs, int princ, char *fname)
 {
     if (nargs < 2)
@@ -99,7 +139,6 @@
     unsigned i;
     for (i=1; i < nargs; i++) {
         print(s, args[i], princ);
-        if (!princ) ios_putc('\n', s);
     }
 }
 value_t fl_ioprint(value_t *args, u_int32_t nargs)
@@ -119,6 +158,11 @@
     { "read", fl_read },
     { "io.print", fl_ioprint },
     { "io.princ", fl_ioprinc },
+    { "io.flush", fl_ioflush },
+    { "io.close", fl_ioclose },
+    { "io.eof?" , fl_ioeof },
+    { "io.getc" , fl_iogetc },
+    { "io.discardbuffer", fl_iopurge },
     { NULL, NULL }
 };
 
--- a/femtolisp/system.lsp
+++ b/femtolisp/system.lsp
@@ -101,6 +101,43 @@
 	((eqv        (caar lst) item) (car lst))
 	(#t          (assv item (cdr lst)))))
 
+(define (delete-duplicates lst)
+  (if (atom? lst)
+      lst
+      (let ((elt  (car lst))
+	    (tail (cdr lst)))
+	(if (member elt tail)
+	    (delete-duplicates tail)
+	    (cons elt
+		  (delete-duplicates tail))))))
+
+(define (get-defined-vars- expr)
+  (cond ((atom? expr) ())
+	((and (eq? (car expr) 'define)
+	      (pair? (cdr expr)))
+	 (or (and (symbol? (cadr expr))
+		  (list (cadr expr)))
+	     (and (pair? (cadr expr))
+		  (symbol? (caadr expr))
+		  (list (caadr expr)))
+	     ()))
+	((eq? (car expr) 'begin)
+	 (apply append (map get-defined-vars- (cdr expr))))
+	(else ())))
+(define (get-defined-vars expr)
+  (delete-duplicates (get-defined-vars- expr)))
+
+; redefine f-body to support internal defines
+(define f-body- f-body)
+(define (f-body e)
+  ((lambda (B)
+     ((lambda (V)
+	(if (null? V)
+	    B
+	    (cons (list 'lambda V B) (map (lambda (x) #f) V))))
+      (get-defined-vars B)))
+   (f-body- e)))
+
 (define (macrocall? e) (and (symbol? (car e))
 			    (symbol-syntax (car e))))
 
@@ -173,6 +210,7 @@
 (define (abs x)   (if (< x 0) (- x) x))
 (define (identity x) x)
 (define K prog1)  ; K combinator ;)
+(define begin0 prog1)
 
 (define (caar x) (car (car x)))
 (define (cdar x) (cdr (car x)))
@@ -290,18 +328,19 @@
 
 (define-macro (let* binds . body)
   (cons (list 'lambda (map car binds)
-              (cons 'begin
-                    (nconc (map (lambda (b) (cons 'set! b)) binds)
-                           body)))
+              (f-body
+	       (nconc (map (lambda (b) (cons 'set! b)) binds)
+		      body)))
         (map (lambda (x) #f) binds)))
+(set-syntax! 'letrec (symbol-syntax 'let*))
 
 (define-macro (labels binds . body)
   (cons (list 'lambda (map car binds)
-              (cons 'begin
-                    (nconc (map (lambda (b)
-                                  (list 'set! (car b) (cons 'lambda (cdr b))))
-                                binds)
-                           body)))
+              (f-body
+	       (nconc (map (lambda (b)
+			     (list 'set! (car b) (cons 'lambda (cdr b))))
+			   binds)
+		      body)))
         (map (lambda (x) #f) binds)))
 
 (define-macro (when   c . body) (list 'if c (f-body body) #f))
@@ -545,3 +584,97 @@
   (string.encode #array(wchar 9 10 11 12 13 32 133 160 5760 6158 8192
 			      8193 8194 8195 8196 8197 8198 8199 8200
 			      8201 8202 8232 8233 8239 8287 12288)))
+
+(define (load filename)
+  (let ((F (file filename :read)))
+    (trycatch
+     (prog1
+      (let next (E v)
+	(if (not (io.eof? F))
+	    (next (read F)
+		  (eval E))
+	    v))
+      (io.close F))
+     (lambda (e)
+       (begin
+	 (io.close F)
+	 (raise `(load-error ,filename ,e)))))))
+
+(define *banner*
+";  _
+; |_ _ _ |_ _ |  . _ _
+; | (-||||_(_)|__|_)|_)
+;-------------------|----------------------------------------------------------
+
+")
+
+(define (repl)
+  (define (prompt)
+    (princ "> ") (io.flush *output-stream*)
+    (let ((v (trycatch (read)
+		       (lambda (e) (begin (io.discardbuffer *input-stream*)
+					  (raise e))))))
+      (and (not (io.eof? *input-stream*))
+	   (let ((V (eval v)))
+	     (print V)
+	     (set! that V)
+	     #t))))
+  (define (reploop)
+    (when (trycatch (and (prompt) (princ "\n"))
+		    print-exception)
+	  (begin (princ "\n")
+		 (reploop))))
+  (reploop)
+  (princ "\n"))
+
+(define (print-exception e)
+  (cond ((and (pair? e)
+	      (eq? (car e) 'type-error)
+	      (= (length e) 4))
+	 (io.princ *stderr* "type-error: ")
+	 (io.print *stderr* (cadr e))
+	 (io.princ *stderr* ": expected ")
+	 (io.print *stderr* (caddr e))
+	 (io.princ *stderr* ", got ")
+	 (io.print *stderr* (cadddr e)))
+
+	((and (pair? e)
+	      (eq? (car e) 'unbound-error)
+	      (pair? (cdr e)))
+	 (io.princ *stderr*
+		   "unbound-error: eval: variable " (cadr e)
+		   " has no value"))
+
+	((and (pair? e)
+	      (eq? (car e) 'error))
+	 (io.princ *stderr* "error: ")
+	 (apply io.princ (cons *stderr* (cdr e))))
+
+	((and (pair? e)
+	      (eq? (car e) 'load-error))
+	 (print-exception (caddr e))
+	 (io.princ *stderr* "in file " (cadr e)))
+
+	((and (list? e)
+	      (= (length e) 2))
+	 (io.princ *stderr* (car e) ": " (cadr e)))
+
+	(else (io.princ *stderr* "*** Unhandled exception: ")
+	      (io.print *stderr* e)))
+
+  (io.princ *stderr* "\n")
+  #t)
+
+(define (__script fname)
+  (trycatch (load fname)
+	    (lambda (e) (begin (print-exception e)
+			       (exit 1)))))
+
+(define (__start . argv)
+  (if (pair? (cdr argv))
+      (begin (set! *argv* (cdr argv))
+	     (__script (cadr argv)))
+      (begin (set! *argv* argv)
+	     (princ *banner*)
+	     (repl)))
+  (exit 0))
--- a/femtolisp/todo
+++ b/femtolisp/todo
@@ -833,22 +833,23 @@
 *read             - (read[ stream]) ; get next sexpr from stream
 *print
 *princ
+*file
  iostream         - (stream[ cvalue-as-bytestream])
  memstream
-*file
- io.eof
+ fifo
+ socket
+*io.eof
+*io.flush
+*io.close
+*io.discardbuffer
  io.write     - (io.write s cvalue)
  io.read      - (io.read s ctype [len])
- io.flush
- io.close
- io.pos       - (io.pos s [set-pos])
- io.seek      - (io.seek s offset)
  io.getc      - get utf8 character(s)
  io.readline
  io.copy      - (io.copy to from [nbytes])
  io.copyuntil - (io.copy to from byte)
- fifo
- socket
+ io.pos       - (io.pos s [set-pos])
+ io.seek      - (io.seek s offset)
  io.seekend   - move to end of stream
  io.trunc
  io.tostring! - destructively convert stringstream to string
--- a/llt/ios.c
+++ b/llt/ios.c
@@ -516,6 +516,8 @@
     s->fd = -1;
     if (s->buf!=NULL && s->ownbuf && s->buf!=&s->local[0])
         free(s->buf);
+    s->buf = NULL;
+    s->size = s->maxsize = s->bpos = 0;
 }
 
 static void _buf_init(ios_t *s, bufmode_t bm)