chicken-hackers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Chicken-hackers] [PATCH] Allow optional functor arguments


From: Felix Winkelmann
Subject: [Chicken-hackers] [PATCH] Allow optional functor arguments
Date: Mon, 07 Jul 2014 22:46:47 +0200 (CEST)

Hello!


Here another (and proper) patch: it allows functor arguments to be
optional, giving the author or a functor a way to provide a default,
which seems to be quite useful. I think this patch was submitted
before, but seems to have been forgotten.

This patch also fixes a bug in the functor-argument matching code:
when verifying whether a module given as argument exports the required
binding, the export-list was previously checked (that's the list given
in a module declaration, specifying the exports). But that was
incorrect, as, for example, builtin modules (like "scheme") do not
have export lists. This change uses the "vexports"/"sexports" lists
of a module instead, that is, the "real" exports.


felix
>From 409f2add49b6ccec225a766c457b5982ed3bb1f9 Mon Sep 17 00:00:00 2001
From: felix <address@hidden>
Date: Mon, 7 Jul 2014 22:46:00 +0200
Subject: [PATCH] Allow functor-arguments to be optional and having defaults,
 and use the correct export-lists when matching functor
 arguments.

---
 chicken-syntax.scm      |   11 +++++++--
 expand.scm              |    2 +-
 manual/Modules          |    5 ++++
 modules.scm             |   27 ++++++++++++++++++---
 tests/functor-tests.scm |   62 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 100 insertions(+), 7 deletions(-)

diff --git a/chicken-syntax.scm b/chicken-syntax.scm
index 7a28158..0120dda 100644
--- a/chicken-syntax.scm
+++ b/chicken-syntax.scm
@@ -1147,10 +1147,11 @@
  'functor '()
  (##sys#er-transformer
   (lambda (x r c)
-    (##sys#check-syntax 'functor x '(_ (symbol . #((symbol _) 0)) _ . _))
+    (##sys#check-syntax 'functor x '(_ (symbol . #((_ _) 0)) _ . _))
     (let* ((x (##sys#strip-syntax x))
           (head (cadr x))
           (name (car head))
+          (args (cdr head))
           (exps (caddr x))
           (body (cdddr x))
           (registration
@@ -1159,8 +1160,14 @@
              ',(map (lambda (arg)
                       (let ((argname (car arg))
                             (exps (##sys#validate-exports (cadr arg) 
'functor)))
+                        (unless (or (symbol? argname)
+                                    (and (list? argname) 
+                                         (= 2 (length argname))
+                                         (symbol? (car argname))
+                                         (symbol? (cadr argname))))
+                          (##sys#syntax-error-hook "invalid functor argument" 
name arg))
                         (cons argname exps)))
-                    (cdr head))
+                    args)
              ',(##sys#validate-exports exps 'functor)
              ',body)))
       `(##core#module
diff --git a/expand.scm b/expand.scm
index 40f0c50..ecfddc9 100644
--- a/expand.scm
+++ b/expand.scm
@@ -1459,7 +1459,7 @@
                             '(##core#undefined))))
                     (else
                      (##sys#check-syntax 
-                      'module x '(_ symbol _ (symbol . #(_ 1))))
+                      'module x '(_ symbol _ (symbol . #(_ 0))))
                      (##sys#instantiate-functor
                       name
                       (car app)        ; functor name
diff --git a/manual/Modules b/manual/Modules
index 758cd80..b4048fc 100644
--- a/manual/Modules
+++ b/manual/Modules
@@ -460,6 +460,11 @@ requirement that a specific export of an argument-module 
must be
 syntax or non-syntax - it can be syntax in one instantiation and a
 procedure definition in another.
 
+{{ARGUMENTMODULE}} may also be a list of the form {{(ALIAS DEFAULT)}}
+to allow specifying a default- or optional functor argument in case
+the instanation doesn't provide one. Optional functor
+arguments may only be followed by non-optional functor arguments.
+
 The common case of using a functor with a single argument module
 that is not used elsewhere can be expressed in the following way:
 
diff --git a/modules.scm b/modules.scm
index 913d448..b79259c 100644
--- a/modules.scm
+++ b/modules.scm
@@ -823,15 +823,33 @@
             (cons name args) (cons fname (map car fargs))))
       `(##core#let-module-alias
        ,(let loop ((as args) (fas fargs))
-          (cond ((null? as) (if (null? fas) '() (merr)))
+          (cond ((null? as) 
+                 ;; use default arguments (if available) or bail out
+                 (let loop2 ((fas fas))
+                   (if (null? fas)
+                       '()
+                       (let ((p (car fas)))
+                         (if (pair? (car p)) ; has default argument?
+                             (let ((alias (caar p))
+                                   (mname (cadar p))
+                                   (exps (cdr p)))
+                               (##sys#match-functor-argument alias name mname 
exps fname)
+                               (cons (list alias mname) (loop2 (cdr fas))))
+                             ;; no default argument, we have too few argument 
modules
+                             (merr))))))
+                ;; more arguments given as defined for the functor
                 ((null? fas) (merr))
                 (else
+                 ;; otherwise match provided argument to functor argument
                  (let* ((p (car fas))
-                        (alias (car p))
+                        (p1 (car p))
+                        (def? (pair? p1))
+                        (alias (if def? (car p1) p1))
                         (mname (car as))
                         (exps (cdr p)))
                    (##sys#match-functor-argument alias name mname exps fname)
-                   (cons (list alias mname) (loop (cdr as) (cdr fas)))))))
+                   (cons (list alias mname) 
+                         (loop (cdr as) (cdr fas)))))))
        (##core#module
         ,name
         ,(if (eq? '* exports) #t exports)
@@ -844,7 +862,8 @@
        (for-each
         (lambda (exp)
           (let ((sym (if (symbol? exp) exp (car exp))))
-            (unless (##sys#find-export sym mod #f)
+            (unless (or (assq sym (module-vexports mod))
+                        (assq sym (module-sexports mod)))
               (set! missing (cons sym missing)))))
         exps)
        (when (pair? missing)
diff --git a/tests/functor-tests.scm b/tests/functor-tests.scm
index 1b307fd..1a05266 100644
--- a/tests/functor-tests.scm
+++ b/tests/functor-tests.scm
@@ -132,6 +132,68 @@
  99)
 
 
+;; Test optional functor arguments
+
+(functor (greet ((X default-writer) (write-greeting))) *
+  (import scheme X)
+  (define (greetings) (write-greeting 'Hello!)))
+
+(module default-writer (write-greeting)
+  (import scheme)
+  (define write-greeting list))
+
+(module writer (write-greeting)
+  (import scheme)
+  (define write-greeting vector))
+
+(module greet1 = (greet writer))
+(module greet2 = (greet))
+
+(test-equal
+ "optional functor argument #1"
+ (module m2 ()
+        (import greet1)
+        (greetings))
+ '#(Hello!))
+
+(test-equal
+ "optional functor argument #2"
+ (module m3 ()
+        (import greet2)
+        (greetings))
+ '(Hello!))
+
+
+;; Optional functor syntax with builtin ("primitive") modules:
+
+(functor (wrapper ((X scheme) (vector))) *
+  (import (except scheme vector) X)
+  (define (wrap x) (vector x)))
+
+(module default-wrapper (vector)
+  (import scheme))
+
+(module list-wrapper (vector)
+  (import (rename (only scheme list) (list vector))))
+
+(module lwrap = (wrapper list-wrapper))
+(module vwrap = (wrapper))
+
+(test-equal
+ "primitive optional functor argument #1"
+ (module m4 ()
+        (import lwrap)
+        (wrap 99))
+ '(99))
+
+(test-equal
+ "primitive optional functor argument #2"
+ (module m5 ()
+        (import vwrap)
+        (wrap 99))
+ '#(99))
+
+
 ;;
 
 (test-end)
-- 
1.7.9.5


reply via email to

[Prev in Thread] Current Thread [Next in Thread]