~ chicken-core (chicken-5) 1f74df5e6dc969459cacc15f890e24e88c303199


commit 1f74df5e6dc969459cacc15f890e24e88c303199
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Mon Mar 21 15:27:06 2011 +0100
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Mon Mar 21 15:27:06 2011 +0100

    started writing functor tests, some syntax fixes

diff --git a/chicken-syntax.scm b/chicken-syntax.scm
index 8b1034fe..4e805295 100644
--- a/chicken-syntax.scm
+++ b/chicken-syntax.scm
@@ -1136,12 +1136,12 @@
  'functor '()
  (##sys#er-transformer
   (lambda (x r c)
-    (##sys#check-syntax 'functor x '(_ (symbol . #((symbol _) 0)) . _))
+    (##sys#check-syntax 'functor x '(_ (symbol . #((symbol _) 0)) _ . _))
     (let* ((x (##sys#strip-syntax x))
 	   (head (cadr x))
 	   (name (car head))
-	   (body (cddr x))
-	   (%quote (r 'quote))
+	   (exps (caddr x))
+	   (body (cdddr x))
 	   (registration
 	    `(##sys#register-functor
 	      ',name
@@ -1150,6 +1150,7 @@
 			     (exps (##sys#validate-exports (cadr arg) 'functor)))
 			 (cons argname exps)))
 		     (cdr head))
+	      ',(##sys#validate-exports exps 'functor)
 	      ',body)))
       `(##core#module
 	,name
diff --git a/expand.scm b/expand.scm
index 4e45422f..be97e5d2 100644
--- a/expand.scm
+++ b/expand.scm
@@ -1314,22 +1314,19 @@
   (lambda (x r c)
     (let ((len (length x)))
       (cond ((and (fx>= len 4) (c (r '=) (caddr x)))
-	     (##sys#check-syntax 'module x '(_ symbol _ (symbol . #(_ 1)) . #(_ 0 1)))
 	     (let* ((x (##sys#strip-syntax x))
 		    (name (cadr x))
 		    (app (cadddr x)))
-	       (##sys#instantiate-functor
-		name
-		(car app)		; functor name
-		(cdr app)		; functor arguments
-		(if (null? (cddddr x))
-		    '*
-		    (##sys#validate-exports (car (cddddr x)) name)))))
-	    ((and (fx= len 3) (symbol? (cadr x)))
-	     (##sys#check-syntax 'module x '(_ symbol symbol))
-	     (let ((x (##sys#strip-syntax x)))
-	       (##sys#register-module-alias (cadr x) (caddr x))
-	       '(##core#undefined)))
+	       (cond ((symbol? app)
+		      (##sys#register-module-alias name app)
+		      '(##core#undefined))
+		     (else
+		      (##sys#check-syntax 
+		       'module x '(_ symbol _ (symbol . #(_ 1)) . #(_ 0 1)))
+		      (##sys#instantiate-functor
+		       name
+		       (car app)		; functor name
+		       (cdr app)))))); functor arguments
 	    (else
 	     (##sys#check-syntax 'module x '(_ symbol _ . #(_ 0)))
 	     ;;XXX use module name in "loc" argument?
diff --git a/manual/Modules b/manual/Modules
index e0b3f0c7..9be38bc3 100644
--- a/manual/Modules
+++ b/manual/Modules
@@ -341,16 +341,53 @@ must be available separately.
 
 === Functors
 
-A ''functor'' is a higher-order module that expands can be
-parameterized with other modules. A functor defines the body of a
-module for a set or argument modules and can be instantiated with
-concrete module names specializing the code contained in the
-functor. This is best explained with an example:
+A ''functor'' is a higher-order module that can be parameterized with
+other modules. A functor defines the body of a module for a set or
+argument modules and can be instantiated with concrete module names
+specializing the code contained in the functor. This is best explained
+with an example:
 
 <enscript highlight=scheme>
 XXX need example here...
 </enscript>
 
+The general syntax of a functor definition looks like this:
+
+<enscript highlight=scheme>
+(functor (FUNCTORNAME (ARGUMENTMODULE1 EXPORTS1) ...) 
+  FUNCTOREXPORTS
+  BODY)
+</enscript>
+
+This functor definition does not generate any code. This is done
+by ''instantiating'' the functor for specific input modules:
+
+<enscript highlight=scheme>
+(module MODULENAME = (FUNCTORNAME MODULENAME1 ...))
+</enscript>
+
+Inside {{BODY}}, references to {{ARGUMENTMODULE}} will be replaced by
+the corresponding {{MODUELNAME}} argument. The instantiation expands
+into the complete functor-code {{BODY}} and as such can be considered
+a particular sort of macro-expansion. Note that there is no
+requirement that a specific export of an argument-module must be
+syntax or non-syntax - it can be syntax in one instantiation and a
+function definition in another.
+
+A "degenerate" form of module assignment is
+
+<enscript highlight=scheme>
+(module MODULENAME1 = MODULENAME2)
+</enscript>
+
+which just defines the alias {{MODULENAME1}} for the module {{MODULENAME2}}.
+
+Since functors exist at compile time, they can be stored in
+import-libraries via {{-emit-import-library FUNCTORNAME}} or
+{{-emit-all-import-libraries}} (see [[Using the compiler]] for more
+information about this). That allows you to import functors for later
+instantiation.
+
 
 ---
 Previous: [[Macros]]
diff --git a/modules.scm b/modules.scm
index 2203ab20..8aea82de 100644
--- a/modules.scm
+++ b/modules.scm
@@ -726,16 +726,17 @@
 			       (err "invalid interface specification" x exps)))
 			  (else (err "invalid export" x exps))))))))))
 
-(define (##sys#register-functor name fargs body)
-  (putp name '##core#functor (cons fargs body)))
+(define (##sys#register-functor name fargs fexps body)
+  (putp name '##core#functor (cons fargs (cons fexps body))))
 
-(define (##sys#instantiate-functor name fname args exports)
+(define (##sys#instantiate-functor name fname args)
   (let ((funcdef (getp fname '##core#functor)))
     (define (err . args)
       (apply ##sys#syntax-error-hook name args))
     (unless funcdef (err "instantation of undefined functor" fname))
     (let ((fargs (car funcdef))
-	  (body (cdr funcdef)))
+	  (exports (cadr funcdef))
+	  (body (cddr funcdef)))
       (define (merr)
 	(err "argument list mismatch in functor instantiation" 
 	     (cons name args) (cons fname (map car fargs))))
diff --git a/tests/QUEUE.scm b/tests/QUEUE.scm
new file mode 100644
index 00000000..b9f79868
--- /dev/null
+++ b/tests/QUEUE.scm
@@ -0,0 +1,9 @@
+;;;; QUEUE.scm
+
+
+(define-interface QUEUE
+  empty-queue
+  enqueue
+  head
+  empty?
+  dequeue)
diff --git a/tests/breadth-first.scm b/tests/breadth-first.scm
new file mode 100644
index 00000000..0b8bac2f
--- /dev/null
+++ b/tests/breadth-first.scm
@@ -0,0 +1,20 @@
+;;;; breadth-first.scm
+
+
+(include "QUEUE")
+
+
+(functor (breadth-first (Q QUEUE)) (search)
+  (import scheme chicken Q)
+  (use srfi-1)
+  
+  (define (enqlist q xs)
+    (fold (lambda (x q) (enqueue q x)) q xs))
+
+  (define (search next x)
+    (define (bfs q)
+      (if (empty? q)
+	  '()
+	  (let ((y (head q)))
+	    (cons y (lambda () (bfs (enqlist (dequeue q) (next y))))))))
+    (bfs (enqueue empty-queue x))) )
diff --git a/tests/functor-tests.scm b/tests/functor-tests.scm
new file mode 100644
index 00000000..6cbadd2c
--- /dev/null
+++ b/tests/functor-tests.scm
@@ -0,0 +1,45 @@
+;;;; functor-tests.scm
+
+
+(include "test-queue")
+(include "breadth-first")
+
+
+(module queue1 ((interface: QUEUE))
+  (import scheme)
+  (define empty-queue '())
+  (define (enqueue q x) (append q (list x)))
+  (define empty? null?)
+  (define head car)
+  (define dequeue cdr) )
+
+
+(module queue2 ((interface: QUEUE))
+  (import scheme chicken)
+  (define-record entry q x)
+  (define empty-queue #f)
+  (define enqueue make-entry)
+  (define empty? not)
+  (define (head q)
+    (let ((q2 (entry-q q)))
+      (if (empty? q2) (entry-x q) (head q2))))
+  (define (dequeue q) 
+    (let ((q2 (entry-q q)))
+      (if (empty? q2) empty-queue (make-queue (dequeue q) x)))) )
+
+
+(module queue3 ((interface: QUEUE))
+  (import scheme chicken)
+  (define-record queue heads tails)
+  (define empty-queue (make-queue '() '()))
+  (define (norm q)
+    (if (null? (queue-heads q))
+	(make-queue (reverse (queue-tails q)) '())
+	q))
+  (define (enqueue q x)
+    (norm (make-queue (queue-heads q) (cons x (queue-tails q)))))
+  (define (empty? q)
+    (and (null? (queue-heads q)) (null? (queue-tails q))))
+  (define (head q) (car (queue-heads q)))
+  (define (dequeue q)
+    (norm (make-queue (cdr (queue-heads q)) (queue-tails q)))) )
diff --git a/tests/simple-functors-test.scm b/tests/simple-functors-test.scm
new file mode 100644
index 00000000..c1dee7c9
--- /dev/null
+++ b/tests/simple-functors-test.scm
@@ -0,0 +1,22 @@
+;;;; simple-functors-test.scm
+
+
+(define-interface stuff (a b))
+
+(module foo ((interface: stuff))
+(import scheme)
+(define a 1)
+(define b 2))
+
+(module f = foo)
+
+(functor 
+ (do-things (arg ((interface: stuff)))) (do-it)
+ (import scheme arg)
+ (define (do-it) (list a b)))
+
+(module bar = (do-things f))
+
+(import bar)
+(assert (equal? '(1 2) (doit)))
+
diff --git a/tests/test-queue.scm b/tests/test-queue.scm
new file mode 100644
index 00000000..aaed0972
--- /dev/null
+++ b/tests/test-queue.scm
@@ -0,0 +1,17 @@
+;;;; test-queue.scm
+
+
+(include "QUEUE")
+
+
+(functor (test-queue (Q QUEUE)) *
+  (import scheme chicken Q)
+  (use srfi-1)
+  
+  (define (list->queue lst)
+    (fold (lambda (x q) (enqueue q x)) empty-queue l))
+
+  (define (queue->list q)
+    (if (empty? q)
+	'()
+	(cons (head q) (queue->list (dequeue q))))) )
Trap