~ chicken-core (chicken-5) f912e5647a7a410908e0cfbbf5200ae980920364


commit f912e5647a7a410908e0cfbbf5200ae980920364
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Fri Jun 24 17:09:28 2011 +0200
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Fri Jun 24 17:09:28 2011 +0200

    local specializations; added badass define-specialization

diff --git a/chicken-syntax.scm b/chicken-syntax.scm
index 08346d58..a1200aa6 100644
--- a/chicken-syntax.scm
+++ b/chicken-syntax.scm
@@ -1202,6 +1202,59 @@
     ((_ ((var type) ...) body ...)
      (let ((var (##core#the type var)) ...) body ...)))))
 
+(##sys#extend-macro-environment
+ 'define-specialization '()
+ (##sys#er-transformer
+  (lambda (x r c)
+    (cond ((memq #:csi ##sys#features) '(##core#undefined))
+	  (else
+	   (##sys#check-syntax 'define-specialization x '(_ (symbol . #(_ 0)) _ . #(_ 0 1)))
+	   (let* ((head (cadr x))
+		  (name (car head))
+		  (args (cdr head))
+		  (alias (gensym name))
+		  (rtypes (and (pair? (cdddr x)) (caddr x)))
+		  (%define (r 'define))
+		  (body (if rtypes (cadddr x) (caddr x))))
+	     (let loop ((args args) (anames '()) (atypes '()))
+	       (cond ((null? args)
+		      (let ((anames (reverse anames))
+			    (atypes (reverse atypes))
+			    (spec
+			     `(,alias ,@(let loop2 ((anames anames) (i 1))
+					 (if (null? anames)
+					     '()
+					     (cons (vector i)
+						   (loop2 (cdr anames) (fx+ i 1))))))))
+			(##sys#put! 
+			 name '##compiler#local-specializations
+			 (##sys#append
+			  (list
+			   (cons atypes
+				 (if rtypes
+				     (list rtypes spec)
+				     (list spec))))
+			  (or (##compiler#variable-mark 
+			       name '##compiler#local-specializations)
+			      '())))
+			`(##core#begin
+			  (##core#declare (inline ,alias) (hide ,alias))
+			  (,%define (,alias ,@anames)
+				    (##core#let ,(map (lambda (an at)
+							(list an `(##core#the ,at ,an)))
+						      anames atypes)
+						,body)))))
+		     (else
+		      (let ((arg (car args)))
+			(cond ((symbol? arg)
+			       (loop (cdr args) (cons arg anames) (cons '* atypes)))
+			      ((and (list? arg) (fx= 2 (length arg)) (symbol? (car arg)))
+			       (loop (cdr args) (cons (car arg) anames)
+				     (cons (cadr arg) atypes)))
+			      (else (##sys#syntax-error
+				     'define-specialization
+				     "invalid argument syntax" arg head)))))))))))))
+
 
 ;; capture current macro env
 
diff --git a/manual/Types b/manual/Types
index ebddf393..3cd55803 100644
--- a/manual/Types
+++ b/manual/Types
@@ -182,6 +182,26 @@ in unsafe mode any faster: compilation in unsafe mode will omit most
 type checks anyway. But specialization can often improve the
 performance of code compiled in safe (default) mode.
 
+Specializations can also be defined by the user:
+
+===== define-specialization
+
+<syntax>(define-specialization (NAME ARGUMENT ...) [RESULTS] BODY)</syntax>
+
+{{NAME}} should have a declared type (for example by using {{:}}).
+Declares the calls to the procedure {{NAME}} with arguments matching
+the types given in {{ARGUMENTS}} should be replaced by {{BODY}} (a
+single expression). If given, {{RESULTS}} (which follows the syntax
+given above under "Type Syntax") narrows the result type(s) if it
+differs from the result types previously declared for {{NAME}}.
+{{ARGUMENT}} should be an identifier naming the formal parameter or a
+list of the form {{(IDENTIFIER TYPE)}}. In the former case, this
+argument specializes on the {{*}} type. User-defined specializations
+are always local to the compilation unit in which they occur and can
+not be exported. When encountered in the interpreter,
+{{define-specialization}} does nothing and returns an unspecified
+result.
+
 
 ---
 Previous: [[Modules]]
diff --git a/scrutinizer.scm b/scrutinizer.scm
index 6ce2190b..bf0ed22d 100755
--- a/scrutinizer.scm
+++ b/scrutinizer.scm
@@ -72,6 +72,7 @@
 ;   ##compiler#declared-type   ->  BOOL
 ;   ##compiler#predicate       ->  TYPESPEC
 ;   ##compiler#specializations ->  (SPECIALIZATION ...)
+;   ##compiler#local-specializations ->  (SPECIALIZATION ...)
 ;   ##compiler#enforce         ->  BOOL
 ;   ##compiler#special-result-type -> PROCEDURE
 ;   ##compiler#escape          ->  #f | 'yes | 'no
@@ -471,6 +472,12 @@
 	 (lambda ()
 	   (pp (fragment x))))))
 
+    (define (get-specializations name)
+      (let* ((a (variable-mark name '##compiler#specializations))
+	     (b (variable-mark name '##compiler#local-specializations))
+	     (c (append (or a '()) (or b '()))))
+	(and (pair? c) c)))
+
     (define (call-result node args e loc params)
       (define (pname)
 	(sprintf "~ain procedure call to `~s', " 
@@ -550,7 +557,7 @@
 					       node
 					       `(let ((#(tmp) #(1))) '#f))
 					      (set! op (list pt `(not ,pt))))))))
-			     ((and specialize (variable-mark pn '##compiler#specializations)) =>
+			     ((and specialize (get-specializations pn)) =>
 			      (lambda (specs)
 				(let loop ((specs specs))
 				  (cond ((null? specs))
@@ -1092,8 +1099,7 @@
        (lambda (sym plist)
 	 (when (variable-visible? sym)
 	   (when (variable-mark sym '##compiler#declared-type)
-	     (let ((specs
-		    (or (variable-mark sym '##compiler#specializations) '()))
+	     (let ((specs (or (variable-mark sym '##compiler#specializations) '()))
 		   (type (variable-mark sym '##compiler#type))
 		   (pred (variable-mark sym '##compiler#predicate))
 		   (enforce (variable-mark sym '##compiler#enforce)))
Trap