Hi all,

I was digging into #1131 again today.  So far, I haven't had much luck
trying to untangle the way modules and macros interact, but I did
manage to find a possible way to simplify the way primitives are
handled by the module system!

First, here's a little background on how things currently work as I
understand it:

When a "primitive" module (like chicken, scheme, extras, etc) is 
registered, it marks all its identifiers as being primitive by creating
an alias which is prefixed with "#%".  This alias doesn't really *do*
anything, except serve as a sort of anchor to ensure that the name won't
be looked up in the current module.  Instead, whenever a primitive
alias is encountered, lookup is short-cut and the alias is replaced by
the core primitive.  This hack is required because the primitives are
not defined inside proper modules (which would cause them to be defined
as, "scheme#foo") but as globals.  This is wired into the module
system by pseudo-modules (the aforementioned "primitive modules").

For example, the "scheme" pseudo-module defines +.  When the module
is registered, it will mark the symbol #%+ as ##core#primitive with
value +.  The module's export list contains "+", which maps to "#%+".
Then, when a module which uses the scheme module is being defined,
all references to + are rewritten to #%+.  When the module is
resolved, all #%+ are rewritten back to +.  So, in the compiled output
where modules don't exist anymore, you only see references to the global
variable "+", which usually holds the procedure implemented by the
C_plus function.

Contrast this with the "numbers" egg.  This module defines +, which is
automatically rewritten to numbers#+ because numbers is a proper module.
Its export list maps "+" to "numbers#+".  When another module is defined
which imports numbers, all its references to + are rewritten to
numbers#+.  This _stays_ like that when the module is resolved and in
the compiled output: the numbers implementation library will define the
global variable "numbers#+" which holds the bignum-aware plus procedure.

Now, when a module like r7rs re-exports a primitive procedure like, say,
"error", its generated import library will map error to #%error.
Then, ##sys#register-compiled-module will detect that this is an aliased
reference to the primitive "error", and cause the module's meta
expressions to register the alias like that (so that when this module
is imported by another, it will know about these aliases).  However,
the r7rs module's import library itself will already load the primitive
"scheme" module as well, which will already take care of registering
the alias.  So I think the primitive detection code can be removed.
This is what the attached patch does; it is a worthwhile simplification
of ##sys#register-compiled-module, I think.  I'm just not 100% sure
whether this analysis is correct because this module stuff still
confuses me.  Any feedback would be appreciated!

This differentiation between primitive and non-primitive values is a
little unfortunate, and I eventually hope to get rid of that, but
that's trickier than you might expect: we want to continue supporting
R5RS code and any program which doesn't make use of modules at all.
And there, you can do things like (set! + "foo") to overwrite the
implementation.  The simplest way I can think of to do this with the
current code base is to change library.scm to actually _define_ a global
variable called #%+, and to make that the primitive.   Any reference
to + in toplevel code gets rewritten to #%+, and the module system can
do the same through the mechanism we already have.  Anyway, that's for
another day but I wanted to put it out there for y'all to consider.

Cheers,
Peter
-- 
http://www.more-magic.net
>From d43d075da57da72522a9db088ae904569df0d795 Mon Sep 17 00:00:00 2001
From: Peter Bex <[email protected]>
Date: Sun, 20 Jul 2014 15:50:02 +0200
Subject: [PATCH] Get rid of explicit marking of primitives re-exported by
 modules.

When importing a module, its dependencies always *must* be imported,
because a re-export could involve a macro which is defined by another
module, and the definitions of macros are handled through the import
library.

Because this is happening anyway, any module re-exporting a primitive
will end up importing the core module which exports it.  This import
will execute ##sys#register-primitive-module which causes the primitives
to be marked though ##sys#primitive-alias.

Because of this recursive module loading, it's unnecessary to detect
primitives at module registration time.  This simplifies the module
registration code a little (which is already hairy enough of itself).
---
 expand.scm  |    5 ----
 modules.scm |   96 ++++++++++++++++++++++++++---------------------------------
 2 files changed, 43 insertions(+), 58 deletions(-)

diff --git a/expand.scm b/expand.scm
index f14c79f..8f922db 100644
--- a/expand.scm
+++ b/expand.scm
@@ -921,11 +921,6 @@
 
 ;;; Macro definitions:
 
-(define (##sys#mark-primitive prims)
-  (for-each
-   (lambda (a) (putp (cdr a) '##core#primitive (car a)))
-   prims))
-
 (##sys#extend-macro-environment
  'import '() 
  (##sys#er-transformer 
diff --git a/modules.scm b/modules.scm
index e102b9d..a59aa5b 100644
--- a/modules.scm
+++ b/modules.scm
@@ -681,59 +681,49 @@
       (for-each
        (lambda (spec)
         (let-values (((vsv vss vsi) (import-spec spec)))
-          (let ((prims '()))
-            (dd `(IMPORT: ,loc))
-            (dd `(V: ,(if cm (module-name cm) '<toplevel>) ,(map-se vsv)))
-            (dd `(S: ,(if cm (module-name cm) '<toplevel>) ,(map-se vss)))
-            (##sys#mark-imported-symbols vsv) ; mark imports as ##core#aliased
-            (for-each
-             (lambda (imp)
-               (let* ((id (car imp))
-                      (aid (cdr imp))
-                      (prim (getp aid '##core#primitive)))
-                 (when prim
-                   (set! prims (cons imp prims)))
-                 (and-let* ((a (assq id (import-env)))
-                            ((not (eq? aid (cdr a)))))
-                   (##sys#notice "re-importing already imported identifier" 
id))))
-             vsv)
-            (for-each
-             (lambda (imp)
-               (and-let* ((a (assq (car imp) (macro-env)))
-                          ((not (eq? (cdr imp) (cdr a)))))
-                 (##sys#notice "re-importing already imported syntax" (car 
imp))) )
-             vss)
-            (when reexp?
-              (unless cm
-                (##sys#syntax-error-hook loc "`reexport' only valid inside a 
module"))
-              (let ((el (module-export-list cm)))
-                (cond ((eq? #t el)
-                       (set-module-sexports! cm (append vss (module-sexports 
cm)))
-                       (set-module-exist-list!
-                        cm
-                        (append (module-exist-list cm)
-                                (map car vsv)
-                                (map car vss))))
-                      (else
-                       (set-module-export-list!
-                        cm
-                        (append
-                         (let ((xl (module-export-list cm)))
-                           (if (eq? #t xl) '() xl))
-                         (map car vsv)
-                         (map car vss))))))
-              (set-module-iexports! 
-               cm
-               (merge-se (module-iexports cm) vsi))
-              (when (pair? prims)
-                (set-module-meta-expressions! 
-                 cm
-                 (append
-                  (module-meta-expressions cm)
-                  `((##sys#mark-primitive ',prims)))))
-              (dm "export-list: " (module-export-list cm)))
-            (import-env (append vsv (import-env)))
-            (macro-env (append vss (macro-env))))))
+          (dd `(IMPORT: ,loc))
+          (dd `(V: ,(if cm (module-name cm) '<toplevel>) ,(map-se vsv)))
+          (dd `(S: ,(if cm (module-name cm) '<toplevel>) ,(map-se vss)))
+          (##sys#mark-imported-symbols vsv) ; mark imports as ##core#aliased
+          (for-each
+           (lambda (imp)
+             (and-let* ((id (car imp))
+                        (a (assq id (import-env)))
+                        (aid (cdr imp))
+                        ((not (eq? aid (cdr a)))))
+               (##sys#notice "re-importing already imported identifier" id)))
+           vsv)
+          (for-each
+           (lambda (imp)
+             (and-let* ((a (assq (car imp) (macro-env)))
+                        ((not (eq? (cdr imp) (cdr a)))))
+               (##sys#notice "re-importing already imported syntax" (car 
imp))) )
+           vss)
+          (when reexp?
+            (unless cm
+              (##sys#syntax-error-hook loc "`reexport' only valid inside a 
module"))
+            (let ((el (module-export-list cm)))
+              (cond ((eq? #t el)
+                     (set-module-sexports! cm (append vss (module-sexports 
cm)))
+                     (set-module-exist-list!
+                      cm
+                      (append (module-exist-list cm)
+                              (map car vsv)
+                              (map car vss))))
+                    (else
+                     (set-module-export-list!
+                      cm
+                      (append
+                       (let ((xl (module-export-list cm)))
+                         (if (eq? #t xl) '() xl))
+                       (map car vsv)
+                       (map car vss))))))
+            (set-module-iexports! 
+             cm
+             (merge-se (module-iexports cm) vsi))
+            (dm "export-list: " (module-export-list cm)))
+          (import-env (append vsv (import-env)))
+          (macro-env (append vss (macro-env)))))
        (cdr x))
       '(##core#undefined))))
 
-- 
1.7.10.4

_______________________________________________
Chicken-hackers mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/chicken-hackers

Reply via email to