shithub: femtolisp

Download patch

ref: 14c196a5da48284123d615418c80b6fbc87d7f46
parent: 7392b1c634dd3137b04ada6f6aa2824f34997ec0
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Tue Dec 3 12:59:24 EST 2024

c***r: return empty list if passed empty list

--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@
  * `[` and `]`, `{` and `}` are synonyms to `(` and `)`
  * `λ` as a shorthand for `lambda`
  * some of the previously available (but not merged) patches from the community and [Julia](https://github.com/JuliaLang/julia) are applied
+ * `c***r` of empty list returns empty list
  * "boot" image is built into the executable
  * vm opcode definitions and tables are generated from a single file
  * fixed bootstrap (makes it work properly when opcodes change)
--- a/compiler.lsp
+++ b/compiler.lsp
@@ -23,7 +23,7 @@
 (define (emit e inst . args)
   (let ((bc (aref e 0)))
     (if (null? args)
-        (if (and (eq? inst 'car) (pair? bc)
+        (if (and (eq? inst 'car)
                  (eq? (car bc) 'cdr))
             (set-car! bc 'cadr)
             (aset! e 0 (cons inst bc)))
@@ -55,8 +55,7 @@
                      (set! inst 'loadc1)
                      (set! args ()))))
 
-          (let ((lasti (if (pair? bc)
-                           (car bc) ())))
+          (let ((lasti (car bc)))
             (cond ((and (eq? inst 'brf)
                         (cond ((and (eq? lasti 'not)
                                     (eq? (cadr bc) 'null?))
@@ -312,8 +311,6 @@
 (define (1arg-lambda? func)
   (and (pair? func)
        (is-lambda? (car func))
-       (pair? (cdr func))
-       (pair? (cadr func))
        (length= (cadr func) 1)))
 
 (define (compile-short-circuit g env tail? forms default branch outl)
@@ -445,7 +442,8 @@
                      (length= x 2))
                 (begin (compile-in g env #f (cadr x))
                        (emit g 'cadr))
-                (if (and (pair? head) (is-lambda? (car head))
+                (if (and (pair? head)
+                         (is-lambda? (car head))
                          (inlineable? x))
                     (compile-let g env tail? x)
                     (begin
--- a/flisp.boot
+++ b/flisp.boot
@@ -45,7 +45,7 @@
   let λ prog1 trycatch begin raise))  throw #fn("9000n220212223e201e4e2:" #(raise
   list quote thrown-value))  quasiquote #fn("7000n1700E62:" #(bq-process)))
 	    1+ #fn("6000n10KM:" #() 1+) 1-
-	    #fn("6000n10K~:" #() 1-) 1arg-lambda? #fn("7000n10B;3U04700<51;3J040=B;3B040TB;3:04710TK62:" #(is-lambda?
+	    #fn("6000n10K~:" #() 1-) 1arg-lambda? #fn("7000n10B;3E04700<51;3:04710TK62:" #(is-lambda?
   length=) 1arg-lambda?)
 	    <= #fn("6000n210L;IB0470051;380470151S:" #(nan?) <=) >
 	    #fn("6000n210L:" #() >) >= #fn("6000n201L;IB0470051;380470151S:" #(nan?) >=)
@@ -201,7 +201,7 @@
   keyargs " " brbound (jmp brf brt brne brnn brn) "@" hex5 ref-int16-LE (jmp.l
   brf.l brt.l brne.l brnn.l brn.l)) disassemble)
 	    div #fn("7000n201k0EL;3C041EL;3404K;I504r/;I404EM:" #() div) emit
-	    #fn("P000z20EG82JX0120CH087B3B087<21C:08722_@900E187Pp@\xa8123124523A075082<52e1?2@30D42612752883F07882<29523:088T?1@30D^142612:52883F07882<29523:088T?1@30D^1412;C\\0822<d3=02=?14q?2@F0822>d3=02??14q?2@30O@30D412@C\\0822<d3=02A?14q?2@F0822>d3=02B?14q?2@30O@30D487B38087<@30q12CQ;3\x9b04882DCM087T2ECE00E82<2F7G8751PPp@x0882DCB00E82<2H87=PPp@a0882ICB00E82<2J87=PPp@J0882ECB00E82<2K87=PPp@30O;I]0412HCI0882ECB00E82<2F87=PPp@?00E7L182P8752p^140:" #(car
+	    #fn("O000z20EG82JR0120CB087<21C:08722_@900E187Pp@\x9e123124523A075082<52e1?2@30D42612752883F07882<29523:088T?1@30D^142612:52883F07882<29523:088T?1@30D^1412;C\\0822<d3=02=?14q?2@F0822>d3=02??14q?2@30O@30D412@C\\0822<d3=02A?14q?2@F0822>d3=02B?14q?2@30O@30D487<12CQ;3\x9b04882DCM087T2ECE00E82<2F7G8751PPp@x0882DCB00E82<2H87=PPp@a0882ICB00E82<2J87=PPp@J0882ECB00E82<2K87=PPp@30O;I]0412HCI0882ECB00E82<2F87=PPp@?00E7L182P8752p^140:" #(car
   cdr cadr #fn(memq) (loadv loadg setg) bcode:indexfor #fn(assq)
   ((loadv loadv.l) (loadg loadg.l) (setg setg.l) (loada loada.l) (seta seta.l)
 		   (box box.l)) > 255 ((loadc loadc.l)) loada (0) loada0 (1)
--- a/flisp.c
+++ b/flisp.c
@@ -1167,20 +1167,24 @@
 
 		OP(OP_CAR)
 			v = FL(stack)[FL(sp)-1];
-			if(__unlikely(!iscons(v))){
+			if(__likely(iscons(v)))
+				v = car_(v);
+			else if(__unlikely(v != FL(Nil))){
 				FL(stack)[ipd] = (uintptr_t)ip;
 				type_error("cons", v);
 			}
-			FL(stack)[FL(sp)-1] = car_(v);
+			FL(stack)[FL(sp)-1] = v;
 			NEXT_OP;
 
 		OP(OP_CDR)
 			v = FL(stack)[FL(sp)-1];
-			if(__unlikely(!iscons(v))){
+			if(__likely(iscons(v)))
+				v = cdr_(v);
+			else if(__unlikely(v != FL(Nil))){
 				FL(stack)[ipd] = (uintptr_t)ip;
 				type_error("cons", v);
 			}
-			FL(stack)[FL(sp)-1] = cdr_(v);
+			FL(stack)[FL(sp)-1] = v;
 			NEXT_OP;
 
 		OP(OP_CLOSURE)
@@ -1358,16 +1362,20 @@
 
 		OP(OP_CADR)
 			v = FL(stack)[FL(sp)-1];
-			if(__unlikely(!iscons(v))){
-				FL(stack)[ipd] = (uintptr_t)ip;
-				type_error("cons", v);
+			if(__likely(iscons(v))){
+				v = cdr_(v);
+				if(__likely(iscons(v)))
+					v = car_(v);
+				else
+					goto cadr_nil;
+			}else{
+			cadr_nil:
+				if(__unlikely(v != FL(Nil))){
+					FL(stack)[ipd] = (uintptr_t)ip;
+					type_error("cons", v);
+				}
 			}
-			v = cdr_(v);
-			if(__unlikely(!iscons(v))){
-				FL(stack)[ipd] = (uintptr_t)ip;
-				type_error("cons", v);
-			}
-			FL(stack)[FL(sp)-1] = car_(v);
+			FL(stack)[FL(sp)-1] = v;
 			NEXT_OP;
 
 		OP(OP_NEG)
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -385,6 +385,14 @@
 (assert (equal? (bound? 'abc) #f))
 (assert-fail (eval '(+ abc 1)))
 
+;; c***r of empty list
+(assert (null? (car '())))
+(assert (null? (cdr '())))
+(assert (null? (cadr '())))
+(assert (null? (cdar '())))
+(assert (null? (caaar '())))
+(assert (null? (cdddr '())))
+
 ;; make many initialized tables large enough not to be stored in-line
 (for 1 100 (λ (i)
   (table eq?      2      eqv?     2