shithub: femtolisp

Download patch

ref: 4cd78cb562334a8106b94d690b31b53f43f81018
parent: 9e07001ae0fc0f4ea1049b27d17b68405b71d9a1
author: JeffBezanson <[email protected]>
date: Thu Dec 23 01:49:37 EST 2010

getting rid of label
adding optional, faster built-in map
checking in soon-to-be code for quasiquote
a couple library bug fixes


--- /dev/null
+++ b/femtolisp/bq.scm
@@ -1,0 +1,122 @@
+(define (bq-process2 x d)
+  (define (splice-form? x)
+    (or (and (pair? x) (or (eq? (car x) 'unquote-splicing)
+			   (eq? (car x) 'unquote-nsplicing)
+			   (and (eq? (car x) 'unquote)
+				(length> x 2))))
+	(eq? x 'unquote)))
+  ;; bracket without splicing
+  (define (bq-bracket1 x)
+    (if (and (pair? x) (eq? (car x) 'unquote))
+	(if (= d 0)
+	    (cadr x)
+	    (list cons ''unquote
+		  (bq-process2 (cdr x) (- d 1))))
+	(bq-process2 x d)))
+  (define (bq-bracket x)
+    (cond ((atom? x)  (list list (bq-process2 x d)))
+	  ((eq? (car x) 'unquote)
+	   (if (= d 0)
+	       (cons list (cdr x))
+	       (list list (list cons ''unquote
+				(bq-process2 (cdr x) (- d 1))))))
+	  ((eq? (car x) 'unquote-splicing)
+	   (if (= d 0)
+	       (list 'copy-list (cadr x))
+	       (list list (list list ''unquote-splicing
+				(bq-process2 (cadr x) (- d 1))))))
+	  ((eq? (car x) 'unquote-nsplicing)
+	   (if (= d 0)
+	       (cadr x)
+	       (list list (list list ''unquote-nsplicing
+				(bq-process2 (cadr x) (- d 1))))))
+	  (else  (list list (bq-process2 x d)))))
+  (cond ((symbol? x)  (list 'quote x))
+	((vector? x)
+	 (let ((body (bq-process2 (vector->list x) d)))
+	   (if (eq? (car body) list)
+	       (cons vector (cdr body))
+	       (list apply vector body))))
+        ((atom? x)  x)
+        ((eq? (car x) 'quasiquote)
+	 (list list ''quasiquote (bq-process2 (cadr x) (+ d 1))))
+        ((eq? (car x) 'unquote)
+	 (if (and (= d 0) (length= x 2))
+	     (cadr x)
+	     (list cons ''unquote (bq-process2 (cdr x) (- d 1)))))
+	((or (> d 0) (not (any splice-form? x)))
+         (let ((lc    (lastcdr x))
+               (forms (map bq-bracket1 x)))
+           (if (null? lc)
+               (cons list forms)
+	       (if (null? (cdr forms))
+		   (list cons (car forms) (bq-process2 lc d))
+		   (nconc (cons list* forms) (list (bq-process2 lc d)))))))
+	(else
+	 (let loop ((p x) (q ()))
+	   (cond ((null? p) ;; proper list
+		  (cons 'nconc (reverse! q)))
+		 ((pair? p)
+		  (cond ((eq? (car p) 'unquote)
+			 ;; (... . ,x)
+			 (cons 'nconc
+			       (nreconc q
+					(if (= d 0)
+					    (cdr p)
+					    (list (list list ''unquote)
+						  (bq-process2 (cdr p)
+							       (- d 1)))))))
+			(else
+			 (loop (cdr p) (cons (bq-bracket (car p)) q)))))
+		 (else
+		  ;; (... . x)
+		  (cons 'nconc (reverse! (cons (bq-process2 p d) q)))))))))
+
+#|
+tests
+
+> ``(,a ,,a ,b ,@b ,,@b)
+`(,a ,1 ,b ,@b (unquote 2 3))
+> `(,a ,1 ,b ,@b (unquote 2 3))
+(1 1 (2 3) 2 3 2 3)
+
+(define a 1)
+
+(bq-process2 '`(,a (unquote unquote a)) 0)
+
+(define b '(unquote a))
+(define unquote 88)
+(bq-process2 '``(,a ,,,@b) 0)
+; etc. => (1 88 1)
+
+(define b '(a a))
+(bq-process2 '``(,a ,,,@b) 0)
+; etc. => (1 1 1)
+|#
+
+;; minimal version with no optimizations, vectors, or dotted lists
+(define (bq-process0 x d)
+  (define (bq-bracket x)
+    (cond ((and (pair? x) (eq? (car x) 'unquote))
+	   (if (= d 0)
+	       (cons list (cdr x))
+	       (list list (list cons ''unquote
+				(bq-process0 (cdr x) (- d 1))))))
+	  ((and (pair? x) (eq? (car x) 'unquote-splicing))
+	   (if (= d 0)
+	       (list 'copy-list (cadr x))
+	       (list list (list list ''unquote-splicing
+				(bq-process0 (cadr x) (- d 1))))))
+	  (else  (list list (bq-process0 x d)))))
+  (cond ((symbol? x)  (list 'quote x))
+        ((atom? x)    x)
+        ((eq? (car x) 'quasiquote)
+	 (list list ''quasiquote (bq-process0 (cadr x) (+ d 1))))
+        ((eq? (car x) 'unquote)
+	 (if (and (= d 0) (length= x 2))
+	     (cadr x)
+	     (list cons ''unquote (bq-process0 (cdr x) (- d 1)))))
+	(else
+	 (cons 'nconc (map bq-bracket x)))))
+
+#t
--- a/femtolisp/compiler.lsp
+++ b/femtolisp/compiler.lsp
@@ -557,7 +557,7 @@
 	(mark-label g nxt)
 	(emit-optional-arg-inits g env (cdr opta) vars (+ i 1)))))
 
-(define (free-vars e)
+#;(define (free-vars e)
   (cond ((symbol? e) (list e))
 	((or (atom? e) (eq? (car e) 'quote)) ())
 	((eq? (car e) 'lambda)
--- a/femtolisp/flisp.boot
+++ b/femtolisp/flisp.boot
@@ -37,17 +37,17 @@
   let map #.list copy-list #fn("8000r2c0|}L3;" [set!]) unwind-protect begin #fn("8000r2c0|}L3;" [set!])])
   map #.car cadr #fn("6000r1e040;" [gensym])])  letrec #fn(">000s1e0c1L1e2c3|32L1e2c4|32e5}3134e2c6|32K;" [nconc
   lambda map #.car #fn("8000r1c0e1|31K;" [set! copy-list]) copy-list #fn("6000r1e040;" [void])])  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("A000r5c0|c1g2c2}c3e4\x7fN31Ke5c3L1e4i0231|g4KL133L4L3L2L1|g3KL3;" [letrec
+  raise quote assert-failed])  do #fn("A000s2c0qe130}Me2c3|32e2e4|32e2c5|3245;" [#fn("A000r5c0|c1g2c2}c3e4\x7fN31Ke5c3L1e4i0231|g4KL133L4L3L2L1|g3KL3;" [letrec
   lambda if begin copy-list nconc]) gensym map #.car cadr #fn("7000r1e0|31F680e1|41;|M;" [cddr
   caddr])])  quasiquote #fn("7000r1e0|41;" [bq-process])  when #fn("<000s1c0|c1}K^L4;" [if
   begin])  with-input-from #fn("=000s1e0c1L1c2|L2L1L1e3}3143;" [nconc
 								with-bindings
 								*input-stream*
-								copy-list])  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!
+								copy-list])  unwind-protect #fn("8000r2c0qe130e13042;" [#fn("@000r2c0}c1_\x7fL3L2L1c2c3~c1|L1c4}L1c5|L2L3L3L3}L1L3L3;" [let
+  lambda prog1 trycatch begin raise]) gensym])  dotimes #fn(";000s1c0q|M|\x8442;" [#fn("=000r2c0`c1}aL3e2c3L1|L1L1e4\x7f3133L4;" [for
+  - nconc lambda copy-list])])  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])
+  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~|L2L1~L3530|}K;" [letrec])
   nconc lambda map #fn("6000r1|F650|M;|;" []) copy-list #fn("6000r1|F650|\x84;e040;" [void])])])  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;|\x84c3\x82W0e4e5|31316A0c6qe7e5|313141;c8qe93041;c:|Mc1|NKi10~N31L4;" [else
   begin or => 1arg-lambda? caddr #fn("=000r1c0|~ML2L1c1|c2e3e4~3131Ki20i10N31L4L3;" [let
   if begin cddr caddr]) caadr #fn("<000r1c0|~ML2L1c1|e2~31|L2i20i10N31L4L3;" [let
@@ -151,7 +151,7 @@
   keyargs emit-optional-arg-inits > 255 largc lvargc vargc argc compile-in ret
   values function encode-byte-code bcode:code const-to-idx-vec]) filter
   keyword-arg?]) length]) length]) make-code-emitter lastcdr lambda-vars filter
-  #.pair? lambda])] #0=[#:g711 ()])
+  #.pair? lambda])] #0=[#:g700 ()])
 	  compile-for #fn(":000r5e0g4316X0e1|}^g2342e1|}^g3342e1|}^g4342e2|c342;e4c541;" [1arg-lambda?
   compile-in emit for error "for: third form must be a 1-argument lambda"] compile-for)
 	  compile-if #fn("<000r4c0qe1|31e1|31g3\x84e2g331e3g331F6;0e4g331560e53045;" [#fn(";000r5g2]\x82>0e0~\x7fi02g344;g2^\x82>0e0~\x7fi02g444;e0~\x7f^g2342e1~c2|332e0~\x7fi02g3342i026<0e1~c3325:0e1~c4}332e5~|322e0~\x7fi02g4342e5~}42;" [compile-in
@@ -224,9 +224,9 @@
 	  every #fn("8000r2}?17D02|}M3116:02e0|}N42;" [every] every) expand
 	  #fn("A000r1c0q]]]]]]]]]]]4;;" [#fn("8000r;c0m02c1qm12c2L1m22c3qm32c4qm42c5qm52c6qm62c7qm72c8qm82c9m92c:qm:2g:~_42;" [#fn("8000r2|E17902e0|}32@;" [assq] top?)
   #fn("9000r1|?640|;|c0>640|;|MF16;02e1|31c2<6D0e3\x7fe4|3131\x7f|N3142;|M\x7f|N31K;" [((begin))
-  caar begin append cdar] splice-begin) *expanded* #fn("9000r2|?640|;c0q~c1}32690\x7f|31530|41;" [#fn("9000r1c0qi10c1\x7f3241;" [#fn("8000r1c0q|6:0e1~31530_41;" [#fn(":000r1c0qe1e2c3|32i213241;" [#fn("8000r1i107=0e0c1qi2042;c2qc3q^31i203141;" [map
+  caar begin append cdar] splice-begin) *expanded* #fn("9000r2|?640|;c0q~c1}32690\x7f|31530|41;" [#fn("9000r1c0qi10c1\x7f3241;" [#fn("8000r1c0q|6:0e1~31530_41;" [#fn(":000r1c0qe1e2c3|32i213241;" [#fn("8000r1i107=0e0c1qi2042;c2qc3q]31i203141;" [map
   #fn("8000r1i5:|~42;" []) #fn("7000r1c0q|41;" [#fn("9000r1]|F6]02i62e0|31<7A0|i6:|Mi1032O590|e1|31O2|Nm05\x02/2~;" [caar
-  cdar])]) #fn("6000r1c0qm0;" [#fn("9000r1|?640|;|MF16;02c0e1|31<6;0|M~|N31K;c2qi6:|Mi103241;" [define
+  cdar])]) #fn("6000r1c0qm02|;" [#fn("9000r1|?640|;|MF16;02c0e1|31<6;0|M~|N31K;c2qi6:|Mi103241;" [define
   caar #fn(":000r1e0e1c2e3|3132i2032o202i72|Ki10~N31K;" [nconc map #.list
 							 get-defined-vars])])])])
   nconc map #.list]) get-defined-vars]) define]) begin] expand-body)
@@ -242,7 +242,7 @@
   #fn("6000r2|;" [] local-expansion-env) #fn("7000r2|?640|;c0q|M41;" [#fn("9000r1c0qe1|\x7f3241;" [#fn("7000r1c0qc1q41;" [#fn(":000r1~16602~NF6M0i3:~\x84i20NQ2i39e0~31i213242;~17A02i10C@17702i10E660|40;c1qe2i203141;" [caddr
   #fn("8000r1|6B0i4:|i30NQ2i3142;i20c0\x8260i30;i20c1\x82>0i46i30i3142;i20c2\x82>0i47i30i3142;i20c3\x82>0i48i30i3142;~40;" [quote
   lambda define let-syntax]) macrocall?])
-  #fn("7000r0c0q^31i2041;" [#fn("6000r1c0qm0;" [#fn("9000r1|?640|;|M?670|M5<0i4:|Mi3132~|N31K;" [])])])])
+  #fn("7000r0c0q]31i2041;" [#fn("6000r1c0qm02|;" [#fn("9000r1|?640|;|M?670|M5<0i4:|Mi3132~|N31K;" [])])])])
   assq])] expand-in)])] expand)
 	  expand-define #fn("=000r1c0|\x84e1|31F6:0e1|315L0|\x84C6;0e230L15=0e3c4e5|313242;" [#fn("<000r2|C6:0c0|}ML3;c0|Me1c2L1|NL1e3}31|M34L3;" [set!
   nconc lambda copy-list]) cddr void error "compile error: invalid syntax "
@@ -252,9 +252,6 @@
 	  foldl #fn(":000r3g2\x8540};e0||g2M}32g2N43;" [foldl] foldl) foldr
 	  #fn(";000r3g2\x8540};|g2Me0|}g2N3342;" [foldr] foldr) for-each #fn(";000s2c0q]41;" [#fn(":000r1c0qm02i02\x85J0]\x7fF6A02~\x7fM312\x7fNo015\x1e/5;0|~\x7fi02K322];" [#fn(":000r2}MF6I0|e0c1}32Q22~|e0c2}3242;];" [map
   #.car #.cdr] for-each-n)])] for-each)
-	  free-vars #fn("<000r1|C660|L1;|?17802|Mc0<640_;|Mc1\x82V0e2e3e4|3131e5e6c7e4|31K31e8|\x84313242;e9e5e:e3|N32Q241;" [quote
-  lambda diff free-vars cddr nconc get-defined-vars begin lambda-arg-names
-  delete-duplicates map] free-vars)
 	  get-defined-vars #fn("8000r1e0~|3141;" [delete-duplicates] #1=[#fn("9000r1|?640_;|Mc0<16602|NF6d0|\x84C16702|\x84L117S02|\x84F16E02e1|31C16:02e1|31L117402_;|Mc2\x82>0e3e4~|N32v2;_;" [define
   caadr begin nconc map] #1#) ()])
 	  hex5 #fn("9000r1e0e1|b@32b5c243;" [string.lpad number->string #\0] hex5)
@@ -284,7 +281,7 @@
 	  #fn(":000r2e0}`32640_;|Me1|N}ax32K;" [<= list-head] list-head)
 	  list-ref #fn("8000r2e0|}32M;" [list-tail] list-ref) list-tail
 	  #fn("9000r2e0}`32640|;e1|N}ax42;" [<= list-tail] list-tail) list? #fn("7000r1|A17@02|F16902e0|N41;" [list?] list?)
-	  load #fn("9000r1c0qe1|c23241;" [#fn("7000r1c0qc1qt;" [#fn("9000r0c0q^31]]]43;" [#fn("6000r1c0qm0;" [#fn(":000r3e0i10317C0~e1i1031|e2}3143;e3i10312e2}41;" [io.eof?
+	  load #fn("9000r1c0qe1|c23241;" [#fn("7000r1c0qc1qt;" [#fn("9000r0c0q]31]]]43;" [#fn("6000r1c0qm02|;" [#fn(":000r3e0i10317C0~e1i1031|e2}3143;e3i10312e2}41;" [io.eof?
   read load-process io.close])])]) #fn("9000r1e0~312e1c2i10|L341;" [io.close
 								    raise
 								    load-error])])
@@ -298,8 +295,8 @@
 							macrocall?] macroexpand-1)
 	  make-code-emitter #fn("9000r0_e030`c1Z4;" [table +inf.0] make-code-emitter)
 	  make-label #fn("6000r1e040;" [gensym] make-label)
-	  make-perfect-hash-table #fn("7000r1c0q]41;" [#fn("8000r1c0m02c1q^31e2~3141;" [#fn("9000r2e0e1e2|3131}42;" [mod0
-  abs hash] $hash-keyword) #fn("6000r1c0qm0;" [#fn("9000r1c0qe1b2|T2^3241;" [#fn("7000r1c0q^31i3041;" [#fn("6000r1c0qm0;" [#fn("8000r1|F6=0c0qe1|3141;i10;" [#fn(":000r1c0qb2i50|i3032T241;" [#fn("9000r1i30|[6=0i50i40aw41;i30|~\\2i30|awe0i1031\\2i20i10N41;" [cdar])])
+	  make-perfect-hash-table #fn("7000r1c0q]41;" [#fn("8000r1c0m02c1q]31e2~3141;" [#fn("9000r2e0e1e2|3131}42;" [mod0
+  abs hash] $hash-keyword) #fn("6000r1c0qm02|;" [#fn("9000r1c0qe1b2|T2^3241;" [#fn("7000r1c0q]31i3041;" [#fn("6000r1c0qm02|;" [#fn("8000r1|F6=0c0qe1|3141;i10;" [#fn(":000r1c0qb2i50|i3032T241;" [#fn("9000r1i30|[6=0i50i40aw41;i30|~\\2i30|awe0i1031\\2i20i10N41;" [cdar])])
   caar])])]) vector.alloc])]) length])] make-perfect-hash-table)
 	  make-system-image #fn(";000r1c0e1|c2c3c434c542;" [#fn("8000r2c0qe1e242;" [#fn("7000r2]k02]k12c2qc3q41;" [*print-pretty*
   *print-readably* #fn("7000r1c0qc1qt|302;" [#fn(":000r0c0qe1c2qe3e4303132312e5i2041;" [#fn("=000r1e0e1e2c3|e2e4|3233Q2i20322e5i20e642;" [write
@@ -314,12 +311,8 @@
 						    *print-readably*
 						    *print-level*
 						    *print-length* *os-name*)] make-system-image)
-	  map #fn("=000s2g2\x85<0e0|}_L143;e1|}g2K42;" [map1 mapn] map) map!
-	  #fn("9000r2}]}F6B02}|}M31O2}Nm15\x1d/2;" [] map!) map-int #fn("8000r2e0}`32640_;c1q|`31_K_42;" [<=
-  #fn(":000r2|m12a\x7faxc0qu2|;" [#fn("8000r1\x7fi10|31_KP2\x7fNo01;" [])])] map-int)
-	  map1 #fn("9000r3g2]}F6H02g2|}M31_KPNm22}Nm15\x17/2N;" [] map1) mapn
-	  #fn("<000r2}M\x8540_;|e0c1}_L133Q2e2|e0c3}_L13332K;" [map1 #.car mapn
-								#.cdr] mapn)
+	  map! #fn("9000r2}]}F6B02}|}M31O2}Nm15\x1d/2;" [] map!) map-int
+	  #fn("8000r2e0}`32640_;c1q|`31_K_42;" [<= #fn(":000r2|m12a\x7faxc0qu2|;" [#fn("8000r1\x7fi10|31_KP2\x7fNo01;" [])])] map-int)
 	  mark-label #fn("9000r2e0|c1}43;" [emit label] mark-label) max
 	  #fn("<000s1}\x8540|;e0c1|}43;" [foldl #fn("7000r2|}X640};|;" [])] max)
 	  member #fn("8000r2}?640^;}M|>640};e0|}N42;" [member] member) memv
@@ -362,7 +355,7 @@
 	  random #fn("8000r1e0|316<0e1e230|42;e330|T2;" [integer? mod rand
 							 rand.double] random)
 	  read-all #fn("8000r1e0e1|42;" [read-all-of read] read-all)
-	  read-all-of #fn("9000r2c0q^31_|}3142;" [#fn("6000r1c0qm0;" [#fn("9000r2e0i1131680e1|41;~}|Ki10i113142;" [io.eof?
+	  read-all-of #fn("9000r2c0q]31_|}3142;" [#fn("6000r1c0qm02|;" [#fn("9000r2e0i1131680e1|41;~}|Ki10i113142;" [io.eof?
   reverse!])])] read-all-of)
 	  ref-int16-LE #fn(";000r2e0e1|}`w[`32e1|}aw[b832w41;" [int16 ash] ref-int16-LE)
 	  ref-int32-LE #fn("=000r2e0e1|}`w[`32e1|}aw[b832e1|}b2w[b@32e1|}b3w[bH32R441;" [int32
@@ -377,7 +370,8 @@
 				       #fn("7000r1e0|312];" [top-level-exception-handler])
 				       newline] reploop) newline])] repl)
 	  revappend #fn("8000r2e0e1|31}42;" [nconc reverse] revappend) reverse
-	  #fn("9000r1e0c1_|43;" [foldl #.cons] reverse) reverse! #fn("7000r1c0q_41;" [#fn("9000r1]~F6C02~N~|~m02P2o005\x1c/2|;" [])] reverse!)
+	  #fn("8000r1e0_|42;" [reverse-] reverse) reverse! #fn("7000r1c0q_41;" [#fn("9000r1]~F6C02~N~|~m02P2o005\x1c/2|;" [])] reverse!)
+	  reverse- #fn("8000r2}\x8540|;e0}M|K}N42;" [reverse-] reverse-)
 	  self-evaluating? #fn("8000r1|?16602|C@17K02e0|3116A02|C16:02|e1|31<;" [constant?
   top-level-value] self-evaluating?)
 	  separate #fn("7000r2c0q]41;" [#fn(":000r1c0m02|~\x7f_L1_L144;" [#fn(";000r4c0g2g3K]}F6Z02|}M316?0g2}M_KPNm25<0g3}M_KPNm32}Nm15\x05/241;" [#fn("8000r1e0|MN|NN42;" [values])] separate-)])] separate)
--- a/femtolisp/flisp.c
+++ b/femtolisp/flisp.c
@@ -99,7 +99,7 @@
 static value_t BACKQUOTE, COMMA, COMMAAT, COMMADOT, FUNCTION;
 
 static value_t pairsym, symbolsym, fixnumsym, vectorsym, builtinsym, vu8sym;
-static value_t definesym, defmacrosym, forsym, labelsym, setqsym;
+static value_t definesym, defmacrosym, forsym, setqsym;
 static value_t tsym, Tsym, fsym, Fsym, booleansym, nullsym, evalsym, fnsym;
 // for reading characters
 static value_t nulsym, alarmsym, backspacesym, tabsym, linefeedsym, newlinesym;
@@ -2142,6 +2142,72 @@
     return _stacktrace(fl_throwing_frame ? fl_throwing_frame : curr_frame);
 }
 
+value_t fl_map1(value_t *args, u_int32_t nargs)
+{
+    if (nargs < 2)
+        lerror(ArgError, "map: too few arguments");
+    if (!iscons(args[1])) return NIL;
+    value_t first, last, v;
+    if (nargs == 2) {
+        if (SP+3 > N_STACK) grow_stack();
+        PUSH(args[0]);
+        PUSH(car_(args[1]));
+        v = _applyn(1);
+        PUSH(v);
+        v = mk_cons();
+        car_(v) = POP(); cdr_(v) = NIL;
+        last = first = v;
+        args[1] = cdr_(args[1]);
+        fl_gc_handle(&first);
+        fl_gc_handle(&last);
+        while (iscons(args[1])) {
+            Stack[SP-2] = args[0];
+            Stack[SP-1] = car_(args[1]);
+            v = _applyn(1);
+            PUSH(v);
+            v = mk_cons();
+            car_(v) = POP(); cdr_(v) = NIL;
+            cdr_(last) = v;
+            last = v;
+            args[1] = cdr_(args[1]);
+        }
+        POPN(2);
+        fl_free_gc_handles(2);
+    }
+    else {
+        size_t i;
+        while (SP+nargs+1 > N_STACK) grow_stack();
+        PUSH(args[0]);
+        for(i=1; i < nargs; i++) {
+            PUSH(car(args[i]));
+            args[i] = cdr_(args[i]);
+        }
+        v = _applyn(nargs-1);
+        PUSH(v);
+        v = mk_cons();
+        car_(v) = POP(); cdr_(v) = NIL;
+        last = first = v;
+        fl_gc_handle(&first);
+        fl_gc_handle(&last);
+        while (iscons(args[1])) {
+            Stack[SP-nargs] = args[0];
+            for(i=1; i < nargs; i++) {
+                Stack[SP-nargs+i] = car(args[i]);
+                args[i] = cdr_(args[i]);
+            }
+            v = _applyn(nargs-1);
+            PUSH(v);
+            v = mk_cons();
+            car_(v) = POP(); cdr_(v) = NIL;
+            cdr_(last) = v;
+            last = v;
+        }
+        POPN(nargs);
+        fl_free_gc_handles(2);
+    }
+    return first;
+}
+
 static builtinspec_t core_builtin_info[] = {
     { "function", fl_function },
     { "function:code", fl_function_code },
@@ -2155,6 +2221,7 @@
     { "copy-list", fl_copylist },
     { "append", fl_append },
     { "list*", fl_liststar },
+    { "map", fl_map1 },
     { NULL, NULL }
 };
 
@@ -2201,7 +2268,7 @@
     vectorsym = symbol("vector");     builtinsym = symbol("builtin");
     booleansym = symbol("boolean");   nullsym = symbol("null");
     definesym = symbol("define");     defmacrosym = symbol("define-macro");
-    forsym = symbol("for");           labelsym = symbol("label");
+    forsym = symbol("for");
     setqsym = symbol("set!");         evalsym = symbol("eval");
     vu8sym = symbol("vu8");           fnsym = symbol("fn");
     nulsym = symbol("nul");           alarmsym = symbol("alarm");
--- a/femtolisp/perf.lsp
+++ b/femtolisp/perf.lsp
@@ -18,11 +18,11 @@
 (define (my-append . lsts)
   (cond ((null? lsts) ())
         ((null? (cdr lsts)) (car lsts))
-        (else ((label append2 (lambda (l d)
-				(if (null? l) d
-				    (cons (car l)
-					  (append2 (cdr l) d)))))
-	       (car lsts) (apply my-append (cdr lsts))))))
+        (else (letrec ((append2 (lambda (l d)
+				  (if (null? l) d
+				      (cons (car l)
+					    (append2 (cdr l) d))))))
+		(append2 (car lsts) (apply my-append (cdr lsts)))))))
 
 (princ "append: ")
 (set! L (map-int (lambda (x) (map-int identity 20)) 20))
--- a/femtolisp/print.c
+++ b/femtolisp/print.c
@@ -196,7 +196,7 @@
 {
     // indent these forms 2 spaces, not lined up with the first argument
     if (head == LAMBDA || head == TRYCATCH || head == definesym ||
-        head == defmacrosym || head == forsym || head == labelsym)
+        head == defmacrosym || head == forsym)
         return 2;
     return -1;
 }
@@ -241,7 +241,7 @@
     // indent before every subform of a special form, unless every
     // subform is "small"
     value_t c = car_(v);
-    if (c == LAMBDA || c == labelsym || c == setqsym)
+    if (c == LAMBDA || c == setqsym)
         return 0;
     if (c == IF) // TODO: others
         return !allsmallp(cdr_(v));
@@ -303,7 +303,7 @@
         }
 
         if (!print_pretty ||
-            ((head == LAMBDA || head == labelsym) && n == 0)) {
+            ((head == LAMBDA) && n == 0)) {
             // never break line before lambda-list
             ind = 0;
         }
@@ -318,7 +318,7 @@
                    
                    (est!=-1 && (HPOS+est > SCR_WIDTH-2)) ||
                    
-                   ((head == LAMBDA || head == labelsym) && !nextsmall) ||
+                   ((head == LAMBDA) && !nextsmall) ||
                    
                    (n > 0 && always) ||
                    
--- a/femtolisp/system.lsp
+++ b/femtolisp/system.lsp
@@ -36,10 +36,7 @@
   `(set-syntax! ',(car form)
 		(lambda ,(cdr form) ,@body)))
 
-(define-macro (label name fn)
-  `((lambda (,name) (set! ,name ,fn)) #f))
-
-(define (map1 f lst acc)
+#;(define (map1 f lst acc)
   (cdr
    (prog1 acc
 	  (while (pair? lst)
@@ -47,17 +44,23 @@
 			      (cdr (set-cdr! acc (cons (f (car lst)) ()))))
 			(set! lst (cdr lst)))))))
 
-(define (mapn f lsts)
+#;(define (mapn f lsts)
   (if (null? (car lsts))
       ()
       (cons (apply f (map1 car lsts (list ())))
 	    (mapn  f (map1 cdr lsts (list ()))))))
 
-(define (map f lst . lsts)
+#;(define (map f lst . lsts)
   (if (null? lsts)
       (map1 f lst (list ()))
       (mapn f (cons lst lsts))))
 
+(define-macro (letrec binds . body)
+  `((lambda ,(map car binds)
+      ,.(map (lambda (b) `(set! ,@b)) binds)
+      ,@body)
+    ,.(map (lambda (x) (void)) binds)))
+
 (define-macro (let binds . body)
   (let ((lname #f))
     (if (symbol? binds)
@@ -71,16 +74,10 @@
 	  (theargs
 	   (map (lambda (c) (if (pair? c) (cadr c) (void))) binds)))
       (cons (if lname
-		`(label ,lname ,thelambda)
+		`(letrec ((,lname ,thelambda)) ,lname)
 		thelambda)
 	    theargs))))
 
-(define-macro (letrec binds . body)
-  `((lambda ,(map car binds)
-      ,.(map (lambda (b) `(set! ,@b)) binds)
-      ,@body)
-    ,.(map (lambda (x) (void)) binds)))
-
 (define-macro (cond . clauses)
   (define (cond-clauses->if lst)
     (if (atom? lst)
@@ -322,7 +319,11 @@
   (if (null? lst) zero
       (foldl f (f (car lst) zero) (cdr lst))))
 
-(define (reverse lst) (foldl cons () lst))
+(define (reverse- zero lst)
+  (if (null? lst) zero
+      (reverse- (cons (car lst) zero) (cdr lst))))
+
+(define (reverse lst) (reverse- () lst))
 
 (define (reverse! l)
   (let ((prev ()))
--- a/femtolisp/todo
+++ b/femtolisp/todo
@@ -1195,5 +1195,5 @@
 5/4/10 todo:
 
 - flush and close open files on exit
-- make function versions of opcode builtins by wrapping in a lambda,
+* make function versions of opcode builtins by wrapping in a lambda,
   stored in a table indexed by opcode. use in _applyn
--- a/llt/arraylist.c
+++ b/llt/arraylist.c
@@ -45,7 +45,7 @@
             size_t nm = a->max*2;
             if (nm == 0) nm = 1;
             while (a->len+n > nm) nm*=2;
-            void **p = LLT_REALLOC(a->items, nm);
+            void **p = LLT_REALLOC(a->items, nm*sizeof(void*));
             if (p == NULL) return;
             a->items = p;
             a->max = nm;
--- a/llt/bitvector.c
+++ b/llt/bitvector.c
@@ -49,7 +49,7 @@
     if (p == NULL) return NULL;
     if (initzero && newsz>oldsz) {
         size_t osz = ((oldsz+31)>>5) * sizeof(uint32_t);
-        memset(&p[osz], 0, sz-osz);
+        memset(&p[osz/sizeof(uint32_t)], 0, sz-osz);
     }
     return p;
 }
@@ -95,16 +95,20 @@
 // returns n if no set bits.
 uint32_t bitvector_next(uint32_t *b, uint64_t n0, uint64_t n)
 {
-    if (n == 0) return 0;
+    if (n0 >= n) return n;
 
     uint32_t i = n0>>5;
     uint32_t nb = n0&31;
     uint32_t nw = (n+31)>>5;
+    uint32_t w;
 
-    uint32_t w = b[i]>>nb;
+    if (i < nw-1 || (n&31)==0)
+        w = b[i]>>nb;
+    else
+        w = (b[i]&lomask(n&31))>>nb;
     if (w != 0)
         return ntz(w)+n0;
-    if (nw == 1)
+    if (i == nw-1)
         return n;
     i++;
     while (i < nw-1) {
--- a/llt/ios.c
+++ b/llt/ios.c
@@ -586,11 +586,11 @@
             return NULL;
         if (s->size)
             memcpy(buf, s->buf, s->size);
-        buf[s->size] = '\0';
     }
     else {
         buf = s->buf;
     }
+    buf[s->size] = '\0';
 
     *psize = s->size+1;  // buffer is actually 1 bigger for terminating NUL