shithub: femtolisp

Download patch

ref: 847c49884302779ff704c885fc97b58a895714cc
parent: f510f5f6eaa66e5f6a399f6bc4fa7091e00a6151
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Dec 13 01:02:40 EST 2024

aref/aset! on proper lists

Fixes: https://todo.sr.ht/~ft/femtolisp/21

--- a/flisp.c
+++ b/flisp.c
@@ -1264,17 +1264,29 @@
 		apply_aref:
 			v = FL(stack)[FL(sp)-n];
 			for(i = n-1; i > 0; i--){
+				if(isarray(v)){
+					FL(stack)[FL(sp)-i-1] = v;
+					v = cvalue_array_aref(&FL(stack)[FL(sp)-i-1]);
+					continue;
+				}
+				e = FL(stack)[FL(sp)-i];
+				isz = tosize(e);
 				if(isvector(v)){
-					e = FL(stack)[FL(sp)-i];
-					isz = tosize(e);
 					if(__unlikely(isz >= vector_size(v)))
 						bounds_error(v, e);
 					v = vector_elt(v, isz);
-				}else if(__likely(isarray(v))){
-					FL(stack)[FL(sp)-i-1] = v;
-					v = cvalue_array_aref(&FL(stack)[FL(sp)-i-1]);
-				}else{
+					continue;
+				}
+				if(!iscons(v) && v != FL_nil)
 					type_error("sequence", v);
+				for(value_t v0 = v;; isz--){
+					if(isz == 0){
+						v = car_(v);
+						break;
+					}
+					v = cdr_(v);
+					if(__unlikely(!iscons(v)))
+						bounds_error(v0, e);
 				}
 			}
 			POPN(n);
@@ -1654,28 +1666,50 @@
 		apply_aset:
 				v = FL(stack)[FL(sp)-n];
 				for(i = n-1; i >= 3; i--){
+					if(isarray(v)){
+						FL(stack)[FL(sp)-i-1] = v;
+						v = cvalue_array_aref(&FL(stack)[FL(sp)-i-1]);
+						continue;
+					}
+					e = FL(stack)[FL(sp)-i];
+					isz = tosize(e);
 					if(isvector(v)){
-						e = FL(stack)[FL(sp)-i];
-						isz = tosize(e);
 						if(__unlikely(isz >= vector_size(v)))
 							bounds_error(v, e);
 						v = vector_elt(v, isz);
-					}else if(__likely(isarray(v))){
-						FL(stack)[FL(sp)-i-1] = v;
-						v = cvalue_array_aref(&FL(stack)[FL(sp)-i-1]);
-					}else{
+						continue;
+					}
+					if(!iscons(v) && v != FL_nil)
 						type_error("sequence", v);
+					for(value_t v0 = v;; isz--){
+						if(isz == 0){
+							v = car_(v);
+							break;
+						}
+						v = cdr_(v);
+						if(__unlikely(!iscons(v)))
+							bounds_error(v0, e);
 					}
 				}
 				FL(stack)[FL(sp)-3] = v;
 			}
+			e = FL(stack)[FL(sp)-2];
+			isz = tosize(e);
 			if(isvector(v)){
-				e = FL(stack)[FL(sp)-2];
-				isz = tosize(e);
 				if(__unlikely(isz >= vector_size(v)))
 					bounds_error(v, e);
 				vector_elt(v, isz) = (e = FL(stack)[FL(sp)-1]);
-			}else if(__likely(isarray(v))){
+			}else if(iscons(v) || v == FL_nil){
+				for(value_t v0 = v;; isz--){
+					if(isz == 0){
+						car_(v) = (e = FL(stack)[FL(sp)-1]);
+						break;
+					}
+					v = cdr_(v);
+					if(__unlikely(!iscons(v)))
+						bounds_error(v0, e);
+				}
+			}else if(isarray(v)){
 				e = cvalue_array_aset(&FL(stack)[FL(sp)-3]);
 			}else{
 				type_error("sequence", v);
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -412,7 +412,7 @@
 (assert (equal? (map (λ (x y z) (+ x y z)) '(1 2) '(3) '(4 5)) '(8)))
 
 ;; aref with multiple indices
-(define a #(#(0 1 2) #(3 #(4 5 6) 7)))
+(define a #(#(0 1 2) #(3 (4 5 6) 7)))
 (assert (equal? 0 (aref a 0 0)))
 (assert (equal? 0 (apply aref (list a 0 0))))
 (assert (equal? 2 (aref a 0 2)))
@@ -426,12 +426,12 @@
 (assert-fail (aref #("hello") 1 0))
 
 ;; aset with multiple indices
-(define a #(#(0 1 2) #(3 #(4 5 6) 7)))
+(define a #(#(0 1 2) #(3 (4 5 6) 7)))
 (assert (equal? 8 (apply aset! (list a 0 0 8))))
 (assert (equal? 9 (aset! a 1 1 (1+ 1) 9)))
 (assert (equal? "hello" (aset! a (1+ 0) 2 "hello")))
 (assert-fail (aset! a 1 1 3 "nope"))
-(assert (equal? a #(#(8 1 2) #(3 #(4 5 9) "hello"))))
+(assert (equal? a #(#(8 1 2) #(3 (4 5 9) "hello"))))
 
 ;; apply with multiple args
 (assert (equal? 15 (apply + 1 2 '(3 4 5))))