shithub: femtolisp

Download patch

ref: a9b51fb3ace7e855670e737257fd4e15344cd5ca
parent: a7bb3ba3b42eaed8425699bbff9a45510ec895af
author: Sigrid Solveig Haflínudóttir <[email protected]>
date: Mon Dec 9 22:41:46 EST 2024

aset!: support multiple indices

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

--- a/compiler.lsp
+++ b/compiler.lsp
@@ -218,6 +218,17 @@
            (if (and deref (vinfo:heap? (cdr loc)))
                (emit g 'car))))))
 
+(define (compile-aset! g env args)
+  (let ((nref (- (length args) 2)))
+    (cond ((= nref 1)
+           (compile-app g env #f (cons 'aset! args)))
+          ((> nref 1)
+           (compile-app g env #f (cons 'aref (list-head args nref)))
+           (let ((nargs (compile-arglist g env (list-tail args nref))))
+                (bcode:stack g (- nargs))
+                (emit g 'aset!)))
+          (else (argc-error 'aset! 3)))))
+
 (define (compile-set! g env s rhs)
   (let ((loc (lookup-sym s env 0)))
     (if (eq? loc 'global)
@@ -422,7 +433,7 @@
               (emit g 'shift n)))))))
 
 (define (compile-app g env tail? x)
-  (let ((head  (car x)))
+  (let ((head (car x)))
     (let ((head
            (if (and (symbol? head)
                     (not (in-env? head env))
@@ -476,6 +487,8 @@
                ((eof-object? x)
                 (compile-in g env tail? (list (top-level-value 'eof-object))))
                (else        (emit g 'loadv x))))
+        ((eq? (car x) 'aset!)
+         (compile-aset! g env (cdr x)))
         ((or (not (symbol? (car x))) (bound? (car x)) (in-env? (car x) env))
          (compile-app g env tail? x))
         (else
--- a/flisp.boot
+++ b/flisp.boot
@@ -13,7 +13,7 @@
 	      #fn("8000z0700}2:" #(*)) #fn("8000z0700}2:" #(/))
 	      #fn("8000z0700}2:" #(div0))
 	      #fn("6000n201l:" #()) #fn("6000n201m:" #()) 0 #fn("8000z0700}2:" #(vector))
-	      #fn("7000n30182p:" #()) 0 0 0 0 0 0 0 0 0 0 0 #fn("9000n3012082>1|:" #(#fn("6000n1A061:" #())))
+	      #fn("8000z0700}2:" #(aset!)) 0 0 0 0 0 0 0 0 0 0 0 #fn("9000n3012082>1|:" #(#fn("6000n1A061:" #())))
 	      0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 #fn("8000z0700}2:" #(aref)) 0 0 0
 	      0)
 	    *empty-string* "" *runestring-type* (array rune) *string-type* (array
@@ -69,7 +69,7 @@
 	    __start #fn("7000n1705040=B3D00=w14Ow24730T51@C00w14Dw24745047550426E61:" #(__init_globals
   *argv* *interactive* __script __rcscript repl #fn(exit)) __start)
 	    abs #fn("6000n10EL3500U:0:" #() abs) any
-	    #fn("7000n21B;3D0401<51;I:047001=62:" #(any) any) arg-counts #table(bound? 1  function? 1  symbol? 1  aset! 3  car 1  cons 2  < 2  cadr 1  for 3  vector? 1  fixnum? 1  boolean? 1  cdr 1  atom? 1  div0 2  equal? 2  eqv? 2  pair? 1  compare 2  null? 1  not 1  number? 1  = 2  set-cdr! 2  eq? 2  builtin? 1  set-car! 2)
+	    #fn("7000n21B;3D0401<51;I:047001=62:" #(any) any) arg-counts #table(bound? 1  function? 1  symbol? 1  car 1  cons 2  < 2  cadr 1  for 3  vector? 1  fixnum? 1  boolean? 1  cdr 1  atom? 1  div0 2  equal? 2  eqv? 2  pair? 1  compare 2  null? 1  not 1  number? 1  = 2  set-cdr! 2  eq? 2  builtin? 1  set-car! 2)
 	    argc-error #fn(";000n2702102211Kl37023@402465:" #(error "compile error: "
 							      " expects " " argument."
 							      " arguments.") argc-error)
@@ -129,6 +129,9 @@
 	    compile-arglist #fn("8000n3202101>282524228261:" #(#fn(for-each)
 							       #fn("9000n170AFO054471AK62:" #(compile-in
   bcode:stack)) #fn(length)) compile-arglist)
+	    compile-aset! #fn("=000n3208251r2~87Kl3?07101O2282P64:7387K523d07101O2475828752P5447601778287525378088U5247902262:7:22r362:" #(#fn(length)
+  compile-app aset! > aref list-head compile-arglist list-tail bcode:stack emit
+  argc-error) compile-aset!)
 	    compile-begin #fn("9000n483H3?0700182715064:83=H3>070018283<64:7001O83<5447202352474018283=64:" #(compile-in
   void emit pop compile-begin) compile-begin)
 	    compile-builtin-call #fn("=000n7207185O538;3I07283=8;52I=073858;52@30D4858<24CK086El3:07502662:750858663:8<27C[086El3:07502862:86r2l3:07502962:750858663:8<2:Cj086El3:07385K62:86Kl3:07502;62:86r2l3:07502<62:750858663:8<2=CK086El3:07502>62:750858663:8<2?CK086El3:07385K62:750858663:8<2@CM086El3<07502A2B63:750858663:8<2CCW086r2L3;07385r262:750823702D@402C8663:8<2ECc086r2l3:07502F62:7G86r2523?07508586r3~63:7385r262:7508562:" #(#fn(get)
@@ -144,11 +147,11 @@
   encode-byte-code bcode:code const-to-idx-vec bcode:cenv) compile-f-)
 	    compile-if #fn("A000n470051700517005183T718351728351B3;0738351@6074508;DC=07501828<64:8;OC=07501828=64:7501O8;895547602789534780885247501828<544823<07602952@;07602:8:534780895247501828=5447808:62:" #(make-label
   caddr cdddr cadddr void compile-in emit brf mark-label ret jmp) compile-if)
-	    compile-in #fn(">000\x8740005000\x884000I60O?4483R3<0700183D64:83H3\xaf083EC:07102262:83KC:07102362:83DC:07102462:83OC:07102562:83qC:07102662:7783513<0710288363:2983513C07:01822;2<51e164:7102=8363:83<RS;ID0483<Z;I;047>83<1523=07?01828364:83<892@CS07A83T513>07:018283T64:7102=83T63:892BC=07C01828364:892DC>07E018283=64:892FC;07G018363:892HCD07I2J183>22K01>262:892LC@07M018283=8465:892NC>07O018283=64:892PCE07Q0183T2D7R8351P64:892SCE07:01D83T5447102T62:892UCT083TR360O@807V2W5147X0183T7Y835164:892ZCp07:01O2Hq83Te35447[7Y835151360O@807V2\\5147:01O7Y83515447102Z62:7?01828364:" #(compile-sym
+	    compile-in #fn(">000\x8740005000\x884000I60O?4483R3<0700183D64:83H3\xaf083EC:07102262:83KC:07102362:83DC:07102462:83OC:07102562:83qC:07102662:7783513<0710288363:2983513C07:01822;2<51e164:7102=8363:83<2>C<07?0183=63:83<RS;ID0483<Z;I;047@83<1523=07A01828364:83<892BCS07C83T513>07:018283T64:7102=83T63:892DC=07E01828364:892FC>07G018283=64:892HC;07I018363:892JCD07K2L183>22M01>262:892NC@07O018283=8465:892PC>07Q018283=64:892RCE07S0183T2F7T8351P64:892UCE07:01D83T5447102V62:892WCT083TR360O@807X2Y5147Z0183T7[835164:892\\Cp07:01O2Jq83Te35447]7[835151360O@807X2^5147:01O7[83515447102\\62:7A01828364:" #(compile-sym
   emit load0 load1 loadt loadf loadnil fits-i8 loadi8 #fn(eof-object?)
-  compile-in #fn(top-level-value) eof-object loadv in-env? compile-app quote
-  self-evaluating? if compile-if begin compile-begin prog1 compile-prog1 λ
-  call-with-values #fn("7000n070AF62:" #(compile-f-))
+  compile-in #fn(top-level-value) eof-object loadv aset! compile-aset! in-env?
+  compile-app quote self-evaluating? if compile-if begin compile-begin prog1
+  compile-prog1 λ call-with-values #fn("7000n070AF62:" #(compile-f-))
   #fn("9000n270A2105341\x85K02223AF>2152470A242515163:D:" #(emit loadv #fn(for-each)
 							    #fn("9000n170AF0O64:" #(compile-sym))
 							    closure #fn(length)))
--- a/flisp.c
+++ b/flisp.c
@@ -1073,6 +1073,7 @@
 						case OP_MUL:	goto apply_mul;
 						case OP_DIV:	goto apply_div;
 						case OP_AREF:	goto apply_aref;
+						case OP_ASET:	goto apply_aset;
 						default:
 #if defined(COMPUTED_GOTO)
 							goto *ops[i];
@@ -1641,20 +1642,41 @@
 			NEXT_OP;
 
 		OP(OP_ASET)
-			e = FL(stack)[FL(sp)-3];
 			FL(stack)[ipd] = (uintptr_t)ip;
-			if(isvector(e)){
-				i = tofixnum(FL(stack)[FL(sp)-2]);
-				if(__unlikely(i >= vector_size(e)))
-					bounds_error(v, FL(stack)[FL(sp)-1]);
-				vector_elt(e, i) = (v = FL(stack)[FL(sp)-1]);
-			}else if(__likely(isarray(e))){
-				v = cvalue_array_aset(&FL(stack)[FL(sp)-3]);
+			v = FL(stack)[FL(sp)-3];
+			n = 3;
+			if(0){
+		apply_aset:
+				v = FL(stack)[FL(sp)-n];
+				for(i = n-1; i >= 3; i--){
+					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{
+						type_error("sequence", v);
+					}
+				}
+				FL(stack)[FL(sp)-3] = v;
+			}
+			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))){
+				e = cvalue_array_aset(&FL(stack)[FL(sp)-3]);
 			}else{
-				type_error("sequence", e);
+				type_error("sequence", v);
 			}
-			POPN(2);
-			FL(stack)[FL(sp)-1] = v;
+			POPN(n);
+			PUSH(e);
 			NEXT_OP;
 
 		OP(OP_FOR)
--- a/gen.lsp
+++ b/gen.lsp
@@ -64,7 +64,7 @@
     OP_COMPARE        compare   2       (λ (x y) (compare x y))
     OP_ARGC           argc      #f      0
     OP_VECTOR         vector    ANYARGS (λ rest (apply vector rest))
-    OP_ASET           aset!     3       (λ (x y z) (aset! x y z))
+    OP_ASET           aset!     -3      (λ rest (apply aset! rest))
     OP_LOADNIL        loadnil   #f      0
     OP_LOADI8         loadi8    #f      0
     OP_LOADVL         loadv.l   #f      0
--- a/opcodes.h
+++ b/opcodes.h
@@ -109,7 +109,7 @@
 	[OP_EQ] = {"eq?", 2},
 	[OP_APPLY] = {"apply", -2},
 	[OP_NULLP] = {"null?", 1},
-	[OP_ASET] = {"aset!", 3},
+	[OP_ASET] = {"aset!", -3},
 	[OP_ATOMP] = {"atom?", 1},
 	[OP_NOT] = {"not", 1},
 	[OP_LIST] = {"list", ANYARGS},
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -416,14 +416,22 @@
 (assert (equal? 0 (aref a 0 0)))
 (assert (equal? 0 (apply aref (list a 0 0))))
 (assert (equal? 2 (aref a 0 2)))
-(assert (equal? 3 (aref a 1 0)))
+(assert (equal? 3 (aref a (1+ 0) 0)))
 (assert (equal? 7 (aref a 1 2)))
-(assert (equal? 5 (aref a 1 1 1)))
+(assert (equal? 5 (aref a 1 (1+ 0) 1)))
 (assert-fail (aref a 1 1 3) bounds-error)
 (assert (equal? (fixnum #\l) (aref #("hello") 0 2)))
-(assert (equal? (fixnum #\o) (aref #("hello") 0 4)))
+(assert (equal? (fixnum #\o) (aref #("hello") 0 (1+ 3))))
 (assert-fail (aref #("hello") 0 5))
 (assert-fail (aref #("hello") 1 0))
+
+;; aset with multiple indices
+(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"))))
 
 ;; make many initialized tables large enough not to be stored in-line
 (for 1 100 (λ (i)