~ chicken-core (chicken-5) cc0625c0a1dd5dcced8f63b9d4030ada49f0f066


commit cc0625c0a1dd5dcced8f63b9d4030ada49f0f066
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Wed Sep 29 08:59:56 2010 -0400
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Wed Sep 29 08:59:56 2010 -0400

    make parameters settable (fixes #315)

diff --git a/library.scm b/library.scm
index c62db6a3..e38a66f8 100644
--- a/library.scm
+++ b/library.scm
@@ -1979,38 +1979,175 @@ EOF
    #:rename new) )
 
 
+;;; Decorate procedure with arbitrary data
+
+(define (##sys#decorate-lambda proc pred decorator)
+  (let ((len (##sys#size proc)))
+    (let loop ((i (fx- len 1)))
+      (cond ((zero? i)
+	     (let ((p2 (make-vector (fx+ len 1))))
+	       (do ((i 1 (fx+ i 1)))
+		   ((fx>= i len)
+		    (##core#inline "C_vector_to_closure" p2)
+		    (##core#inline "C_copy_pointer" proc p2)
+		    (decorator p2 i) )
+		 (##sys#setslot p2 i (##sys#slot proc i)) ) ) )
+	    (else
+	     (let ((x (##sys#slot proc i)))
+	       (if (pred x)
+		   (decorator proc i)
+		   (loop (fx- i 1)) ) ) ) ) ) ) )
+
+(define (##sys#lambda-decoration proc pred)
+  (let loop ((i (fx- (##sys#size proc) 1)))
+    (and (fx> i 0)
+	 (let ((x (##sys#slot proc i)))
+	   (if (pred x)
+	       x
+	       (loop (fx- i 1)) ) ) ) ) )
+
+
+;;; Create lambda-info object
+
+(define (##sys#make-lambda-info str)
+  (let* ((sz (##sys#size str))
+	 (info (##sys#make-string sz)) )
+    (##core#inline "C_copy_memory" info str sz)
+    (##core#inline "C_string_to_lambdainfo" info)
+    info) )
+
+
+;;; Function debug info:
+
+(define (##sys#lambda-info? x)
+  (and (not (##sys#immediate? x)) (##core#inline "C_lambdainfop" x)))
+
+(define (##sys#lambda-info proc)
+  (##sys#lambda-decoration proc ##sys#lambda-info?))
+
+(define (##sys#lambda-info->string info)
+  (let* ((sz (##sys#size info))
+	 (s (##sys#make-string sz)) )
+    (##core#inline "C_copy_memory" s info sz)
+    s) )
+
+(define procedure-information
+  (lambda (x)
+    (##sys#check-closure x 'procedure-information)
+    (and-let* ((info (##sys#lambda-info x)))
+      (##sys#read (open-input-string (##sys#lambda-info->string info)) #f) ) ) )
+
+
+;;; SRFI-17
+
+(define setter-tag (vector 'setter))
+
+(define-inline (setter? x) 
+  (and (pair? x) (eq? setter-tag (##sys#slot x 0))) )
+
+(define ##sys#setter
+  (##sys#decorate-lambda 
+   (lambda (proc)
+     (or (and-let* (((procedure? proc))
+		    (d (##sys#lambda-decoration proc setter?)) )
+	   (##sys#slot d 1) )
+	 (##sys#error 'setter "no setter defined" proc) ) )
+   setter?
+   (lambda (proc i)
+     (##sys#setslot 
+      proc i
+      (cons 
+       setter-tag
+       (lambda (get set)
+	 (if (procedure? get)
+	     (let ((get2 (##sys#decorate-lambda
+			  get
+			  setter?
+			  (lambda (proc i) (##sys#setslot proc i (cons setter-tag set)) proc))))
+	       (if (eq? get get2)
+		   get
+		   (##sys#become! (list (cons get get2))) ) )
+	     (error "can't set setter of non-procedure" get) ) ) ) )
+     proc) ) )
+
+(define setter ##sys#setter)
+
+(define (getter-with-setter get set #!optional info)
+  (let ((getdec (cond (info
+		       (##sys#check-string info 'getter-with-setter)
+		       (##sys#make-lambda-info info))
+		      (else (##sys#lambda-info get))))
+	(p1 (##sys#decorate-lambda
+	     get
+	     setter?
+	     (lambda (proc i)
+	       (##sys#setslot proc i (cons setter-tag set))
+	       proc) )))
+    (if getdec
+	(##sys#decorate-lambda
+	 p1
+	 ##sys#lambda-info?
+	 (lambda (p i)
+	   (##sys#setslot p i getdec)
+	   p))
+	p1)))
+
+(set! car (getter-with-setter car set-car! "(car p)"))
+(set! cdr (getter-with-setter cdr set-cdr! "(cdr p)"))
+(set! caar (getter-with-setter caar (lambda (x y) (set-car! (car x) y)) "(caar p)"))
+(set! cadr (getter-with-setter cadr (lambda (x y) (set-car! (cdr x) y)) "(cadr p)"))
+(set! cdar (getter-with-setter cdar (lambda (x y) (set-cdr! (car x) y)) "(cdar p)"))
+(set! cddr (getter-with-setter cddr (lambda (x y) (set-cdr! (cdr x) y)) "(cddr p)"))
+(set! caaar (getter-with-setter caaar (lambda (x y) (set-car! (caar x) y)) "(caaar p)"))
+(set! caadr (getter-with-setter caadr (lambda (x y) (set-car! (cadr x) y)) "(caadr p)"))
+(set! cadar (getter-with-setter cadar (lambda (x y) (set-car! (cdar x) y)) "(cadar p)"))
+(set! caddr (getter-with-setter caddr (lambda (x y) (set-car! (cddr x) y)) "(caddr p)"))
+(set! cdaar (getter-with-setter cdaar (lambda (x y) (set-cdr! (caar x) y)) "(cdaar p)"))
+(set! cdadr (getter-with-setter cdadr (lambda (x y) (set-cdr! (cadr x) y)) "(cdadr p)"))
+(set! cddar (getter-with-setter cddar (lambda (x y) (set-cdr! (cdar x) y)) "(cddar p)"))
+(set! cdddr (getter-with-setter cdddr (lambda (x y) (set-cdr! (cddr x) y)) "(cdddr p)"))
+(set! string-ref (getter-with-setter string-ref string-set! "(string-ref str i)"))
+(set! vector-ref (getter-with-setter vector-ref vector-set! "(vector-ref vec i)"))
+
+
 ;;; Parameters:
 
 (define ##sys#default-parameter-vector (##sys#make-vector default-parameter-vector-size))
 (define ##sys#current-parameter-vector '#())
 
 (define make-parameter
-  (let ([count 0])
+  (let ((count 0))
     (lambda (init . guard)
-      (let* ([guard (if (pair? guard) (car guard) (lambda (x) x))]
-	     [val (guard init)] 
-	     [i count] )
+      (let* ((guard (if (pair? guard) (car guard) (lambda (x) x)))
+	     (val (guard init))
+	     (i count))
 	(set! count (fx+ count 1))
 	(when (fx>= i (##sys#size ##sys#default-parameter-vector))
 	  (set! ##sys#default-parameter-vector 
 	    (##sys#grow-vector ##sys#default-parameter-vector (fx+ i 1) (##core#undefined)) ) )
 	(##sys#setslot ##sys#default-parameter-vector i val)
-	(lambda arg
-	  (let ([n (##sys#size ##sys#current-parameter-vector)])
-	    (cond [(pair? arg)
-		   (when (fx>= i n)
-		     (set! ##sys#current-parameter-vector
-		       (##sys#grow-vector ##sys#current-parameter-vector (fx+ i 1) ##sys#snafu) ) )
-		   (##sys#setslot ##sys#current-parameter-vector i (guard (##sys#slot arg 0)))
-		   (##core#undefined) ]
-		  [(fx>= i n)
-		   (##sys#slot ##sys#default-parameter-vector i) ]
-		  [else
-		   (let ([val (##sys#slot ##sys#current-parameter-vector i)])
-		     (if (eq? val ##sys#snafu)
-			 (##sys#slot ##sys#default-parameter-vector i) 
-			 val) ) ] ) ) ) ) ) ) )
-
+	(let ((assign 
+	       (lambda (val n)
+		 (when (fx>= i n)
+		   (set! ##sys#current-parameter-vector
+		     (##sys#grow-vector ##sys#current-parameter-vector (fx+ i 1) ##sys#snafu) ) )
+		 (##sys#setslot ##sys#current-parameter-vector i (guard val))
+		 (##core#undefined) )))
+	  (getter-with-setter
+	   (lambda arg
+	     (let ((n (##sys#size ##sys#current-parameter-vector)))
+	       (cond ((pair? arg) (assign (car arg) n))
+		     ((fx>= i n)
+		      (##sys#slot ##sys#default-parameter-vector i) )
+		     (else
+		      (let ((val (##sys#slot ##sys#current-parameter-vector i)))
+			(if (eq? val ##sys#snafu)
+			    (##sys#slot ##sys#default-parameter-vector i) 
+			    val) ) ) ) ) )
+	   (lambda (val)
+	     (let ((n (##sys#size ##sys#current-parameter-vector)))
+	       (assign val n)))))))))
+  
 
 ;;; Input:
 
@@ -4465,137 +4602,6 @@ EOF
     (vector hsize (fx- hsize free) (##sys#slot info 1)) ) )
 
 
-;;; Decorate procedure with arbitrary data
-
-(define (##sys#decorate-lambda proc pred decorator)
-  (let ((len (##sys#size proc)))
-    (let loop ((i (fx- len 1)))
-      (cond ((zero? i)
-	     (let ((p2 (make-vector (fx+ len 1))))
-	       (do ((i 1 (fx+ i 1)))
-		   ((fx>= i len)
-		    (##core#inline "C_vector_to_closure" p2)
-		    (##core#inline "C_copy_pointer" proc p2)
-		    (decorator p2 i) )
-		 (##sys#setslot p2 i (##sys#slot proc i)) ) ) )
-	    (else
-	     (let ((x (##sys#slot proc i)))
-	       (if (pred x)
-		   (decorator proc i)
-		   (loop (fx- i 1)) ) ) ) ) ) ) )
-
-(define (##sys#lambda-decoration proc pred)
-  (let loop ((i (fx- (##sys#size proc) 1)))
-    (and (fx> i 0)
-	 (let ((x (##sys#slot proc i)))
-	   (if (pred x)
-	       x
-	       (loop (fx- i 1)) ) ) ) ) )
-
-
-;;; Create lambda-info object
-
-(define (##sys#make-lambda-info str)
-  (let* ((sz (##sys#size str))
-	 (info (##sys#make-string sz)) )
-    (##core#inline "C_copy_memory" info str sz)
-    (##core#inline "C_string_to_lambdainfo" info)
-    info) )
-
-
-;;; Function debug info:
-
-(define (##sys#lambda-info? x)
-  (and (not (##sys#immediate? x)) (##core#inline "C_lambdainfop" x)))
-
-(define (##sys#lambda-info proc)
-  (##sys#lambda-decoration proc ##sys#lambda-info?))
-
-(define (##sys#lambda-info->string info)
-  (let* ((sz (##sys#size info))
-	 (s (##sys#make-string sz)) )
-    (##core#inline "C_copy_memory" s info sz)
-    s) )
-
-(define procedure-information
-  (lambda (x)
-    (##sys#check-closure x 'procedure-information)
-    (and-let* ((info (##sys#lambda-info x)))
-      (##sys#read (open-input-string (##sys#lambda-info->string info)) #f) ) ) )
-
-
-;;; SRFI-17
-
-(define setter-tag (vector 'setter))
-
-(define-inline (setter? x) 
-  (and (pair? x) (eq? setter-tag (##sys#slot x 0))) )
-
-(define ##sys#setter
-  (##sys#decorate-lambda 
-   (lambda (proc)
-     (or (and-let* (((procedure? proc))
-		    (d (##sys#lambda-decoration proc setter?)) )
-	   (##sys#slot d 1) )
-	 (##sys#error 'setter "no setter defined" proc) ) )
-   setter?
-   (lambda (proc i)
-     (##sys#setslot 
-      proc i
-      (cons 
-       setter-tag
-       (lambda (get set)
-	 (if (procedure? get)
-	     (let ((get2 (##sys#decorate-lambda
-			  get
-			  setter?
-			  (lambda (proc i) (##sys#setslot proc i (cons setter-tag set)) proc))))
-	       (if (eq? get get2)
-		   get
-		   (##sys#become! (list (cons get get2))) ) )
-	     (error "can't set setter of non-procedure" get) ) ) ) )
-     proc) ) )
-
-(define setter ##sys#setter)
-
-(define (getter-with-setter get set #!optional info)
-  (let ((getdec (cond (info
-		       (##sys#check-string info 'getter-with-setter)
-		       (##sys#make-lambda-info info))
-		      (else (##sys#lambda-info get))))
-	(p1 (##sys#decorate-lambda
-	     get
-	     setter?
-	     (lambda (proc i)
-	       (##sys#setslot proc i (cons setter-tag set))
-	       proc) )))
-    (if getdec
-	(##sys#decorate-lambda
-	 p1
-	 ##sys#lambda-info?
-	 (lambda (p i)
-	   (##sys#setslot p i getdec)
-	   p))
-	p1)))
-
-(set! car (getter-with-setter car set-car! "(car p)"))
-(set! cdr (getter-with-setter cdr set-cdr! "(cdr p)"))
-(set! caar (getter-with-setter caar (lambda (x y) (set-car! (car x) y)) "(caar p)"))
-(set! cadr (getter-with-setter cadr (lambda (x y) (set-car! (cdr x) y)) "(cadr p)"))
-(set! cdar (getter-with-setter cdar (lambda (x y) (set-cdr! (car x) y)) "(cdar p)"))
-(set! cddr (getter-with-setter cddr (lambda (x y) (set-cdr! (cdr x) y)) "(cddr p)"))
-(set! caaar (getter-with-setter caaar (lambda (x y) (set-car! (caar x) y)) "(caaar p)"))
-(set! caadr (getter-with-setter caadr (lambda (x y) (set-car! (cadr x) y)) "(caadr p)"))
-(set! cadar (getter-with-setter cadar (lambda (x y) (set-car! (cdar x) y)) "(cadar p)"))
-(set! caddr (getter-with-setter caddr (lambda (x y) (set-car! (cddr x) y)) "(caddr p)"))
-(set! cdaar (getter-with-setter cdaar (lambda (x y) (set-cdr! (caar x) y)) "(cdaar p)"))
-(set! cdadr (getter-with-setter cdadr (lambda (x y) (set-cdr! (cadr x) y)) "(cdadr p)"))
-(set! cddar (getter-with-setter cddar (lambda (x y) (set-cdr! (cdar x) y)) "(cddar p)"))
-(set! cdddr (getter-with-setter cdddr (lambda (x y) (set-cdr! (cddr x) y)) "(cdddr p)"))
-(set! string-ref (getter-with-setter string-ref string-set! "(string-ref str i)"))
-(set! vector-ref (getter-with-setter vector-ref vector-set! "(vector-ref vec i)"))
-
-
 ;;; Property lists
 
 (define (##sys#put! sym prop val)
diff --git a/manual/Parameters b/manual/Parameters
index 2d9b22ca..8e21811f 100644
--- a/manual/Parameters
+++ b/manual/Parameters
@@ -3,11 +3,12 @@
 
 == Parameters
 
-Parameters are Chicken's form of dynamic variables, except that they are
-procedures rather than actual variables.  A parameter is a procedure of
-zero or one arguments. To retrieve the value of a parameter call the
-parameter-procedure with zero arguments. To change the setting of the
-parameter, call the parameter-procedure with the new value as argument:
+Parameters are a form of dynamic variables, except that they are
+procedures rather than actual variables.  A parameter is a procedure
+of zero or one arguments. To retrieve the value of a parameter call
+the parameter-procedure with zero arguments. To change the setting of
+the parameter, call the parameter-procedure with the new value as
+argument:
 
 <enscript highlight=scheme>
 (define foo (make-parameter 123))
@@ -16,11 +17,18 @@ parameter, call the parameter-procedure with the new value as argument:
 (foo)                             ==> 99
 </enscript>
 
-Parameters are fully thread-local, each thread of execution
-owns a local copy of a parameters' value.
+Parameters are fully thread-local, each thread of execution owns a
+local copy of a parameters' value.
 
 CHICKEN implements [[http://srfi.schemers.org/srfi-39/srfi-39.html|SRFI-39]].
 
+Parameters are "settable", in other words, you can also write
+
+<enscript highlight=scheme>
+(set! (foo) 100)
+</enscript>
+
+to assign a new value.
 
 
 === make-parameter
diff --git a/tests/library-tests.scm b/tests/library-tests.scm
index cf3f1f37..58d13e00 100644
--- a/tests/library-tests.scm
+++ b/tests/library-tests.scm
@@ -125,3 +125,15 @@
   (assert (string=? "abc" (symbol->string (with-input-from-string "aBc" read))))
   (assert (string=? "aBc" (symbol->string (with-input-from-string "|aBc|" read))))
   (assert (string=? "aBc" (symbol->string (with-input-from-string "a\\Bc" read)))))
+
+
+;;; setters
+
+(define x '(a b c))
+(define kar car)
+(set! (kar (cdr x)) 99)
+(assert (equal? '(a 99 c) x))
+(define p (make-parameter 100))
+(assert (= 100 (p)))
+(set! (p) 1000)
+(assert (= 1000 (p)))
Trap