1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-19 19:20:23 +02:00

Associate #:replace info with modules, not variables

* doc/ref/api-modules.texi (Creating Guile Modules): Document
  #:re-export-and-replace.
* module/ice-9/boot-9.scm (module-replacements): New module field.
  (make-module, make-autoload-interface): Initialize replacements to an
  empty hash table.
  (resolve-interface): Propagate replacement info when making custom
  interfaces.
  (define-module): Parse a #:re-export-and-replace keyword arg.
  (define-module*): Handle #:re-export-and-replace.
  (module-export!, module-re-export!): Add a keyword arg to indicate
  whether to replace or not.
  (module-replace!): Call module-export! with #:replace? #t.
  (duplicate-handlers): Update replace duplicate handler to look for
  replacement info on the interfaces.
* module/srfi/srfi-18.scm (srfi):
* module/srfi/srfi-34.scm (srfi): Update to #:re-export-and-replace
  raise-continuable as raise.
This commit is contained in:
Andy Wingo 2019-11-29 11:51:29 +01:00
parent 8304b15807
commit cf08dbdc18
4 changed files with 72 additions and 60 deletions

View file

@ -354,6 +354,11 @@ in the module body.
The @code{#:duplicates} (see below) provides fine-grain control about
duplicate binding handling on the module-user side.
@item #:re-export-and-replace @var{list}
@cindex re-export-and-replace
Like @code{#:re-export}, but also marking the bindings as replacements
in the sense of @code{#:replace}.
@item #:version @var{list}
@cindex module version
Specify a version for the module in the form of @var{list}, a list of

View file

@ -2464,7 +2464,8 @@ name extensions listed in %load-extensions."
submodule-binder
public-interface
filename
next-unique-id)))
next-unique-id
(replacements #:no-setter))))
;; make-module &opt size uses binder
@ -2489,7 +2490,8 @@ initial uses list, or binding procedure."
(make-hash-table)
'()
(make-weak-key-hash-table) #f
(make-hash-table) #f #f #f 0))
(make-hash-table) #f #f #f 0
(make-hash-table)))
@ -3294,7 +3296,10 @@ error if selected binding does not exist in the used module."
hide)
(define (maybe-export! src dst var)
(unless (memq src hide)
(module-add! custom-i (renamer dst) var)))
(let ((name (renamer dst)))
(when (hashq-ref (module-replacements public-i) src)
(hashq-set! (module-replacements custom-i) name #t))
(module-add! custom-i name var))))
(cond
(select
(for-each
@ -3326,8 +3331,8 @@ error if selected binding does not exist in the used module."
(define* (define-module* name
#:key filename pure version (imports '()) (exports '())
(replacements '()) (re-exports '()) (autoloads '())
(duplicates #f) transformer declarative?)
(replacements '()) (re-exports '()) (re-export-replacements '())
(autoloads '()) (duplicates #f) transformer declarative?)
(define (list-of pred l)
(or (null? l)
(and (pair? l) (pred (car l)) (list-of pred (cdr l)))))
@ -3371,6 +3376,7 @@ error if selected binding does not exist in the used module."
imports)))
(module-use-interfaces! module imports)))
(module-re-export! module re-exports)
(module-re-export! module re-export-replacements #:replace? #t)
;; FIXME: Avoid use of `apply'.
(apply module-autoload! module autoloads)
(let ((duplicates (or duplicates
@ -3421,7 +3427,7 @@ error if selected binding does not exist in the used module."
#:warning "Failed to autoload ~a in ~a:\n" sym name))))
(module-constructor (make-hash-table 0) '() b #f #f name 'autoload #f
(make-hash-table 0) '() (make-weak-value-hash-table) #f
(make-hash-table 0) #f #f #f 0)))
(make-hash-table 0) #f #f #f 0 (make-hash-table 0))))
(define (module-autoload! module . args)
"Have @var{module} automatically load the module named @var{name} when one
@ -3768,7 +3774,7 @@ but it fails to load."
((kw val . in)
(loop #'in (cons* #'val #'kw out))))))
(define (parse args imp exp rex rep aut dec)
(define (parse args imp exp rex rep rxp aut dec)
;; Just quote everything except #:use-module and #:use-syntax. We
;; need to know about all arguments regardless since we want to turn
;; symbols that look like keywords into real keywords, and the
@ -3780,58 +3786,61 @@ but it fails to load."
(exp (if (null? exp) '() #`(#:exports '#,exp)))
(rex (if (null? rex) '() #`(#:re-exports '#,rex)))
(rep (if (null? rep) '() #`(#:replacements '#,rep)))
(rxp (if (null? rxp) '() #`(#:re-export-replacements '#,rxp)))
(aut (if (null? aut) '() #`(#:autoloads '#,aut)))
(dec (if dec '() #`(#:declarative?
#,(user-modules-declarative?)))))
#`(#,@imp #,@exp #,@rex #,@rep #,@aut #,@dec)))
#`(#,@imp #,@exp #,@rex #,@rep #,@rxp #,@aut #,@dec)))
;; The user wanted #:foo, but wrote :foo. Fix it.
((sym . args) (keyword-like? #'sym)
(parse #`(#,(->keyword (syntax->datum #'sym)) . args)
imp exp rex rep aut dec))
imp exp rex rep rxp aut dec))
((kw . args) (not (keyword? (syntax->datum #'kw)))
(syntax-violation 'define-module "expected keyword arg" x #'kw))
((#:no-backtrace . args)
;; Ignore this one.
(parse #'args imp exp rex rep aut dec))
(parse #'args imp exp rex rep rxp aut dec))
((#:pure . args)
#`(#:pure #t . #,(parse #'args imp exp rex rep aut dec)))
#`(#:pure #t . #,(parse #'args imp exp rex rep rxp aut dec)))
((kw)
(syntax-violation 'define-module "keyword arg without value" x #'kw))
((#:version (v ...) . args)
#`(#:version '(v ...) . #,(parse #'args imp exp rex rep aut dec)))
#`(#:version '(v ...) . #,(parse #'args imp exp rex rep rxp aut dec)))
((#:duplicates (d ...) . args)
#`(#:duplicates '(d ...) . #,(parse #'args imp exp rex rep aut dec)))
#`(#:duplicates '(d ...) . #,(parse #'args imp exp rex rep rxp aut dec)))
((#:filename f . args)
#`(#:filename 'f . #,(parse #'args imp exp rex rep aut dec)))
#`(#:filename 'f . #,(parse #'args imp exp rex rep rxp aut dec)))
((#:declarative? d . args)
#`(#:declarative? 'd . #,(parse #'args imp exp rex rep aut #t)))
#`(#:declarative? 'd . #,(parse #'args imp exp rex rep rxp aut #t)))
((#:use-module (name name* ...) . args)
(and (and-map symbol? (syntax->datum #'(name name* ...))))
(parse #'args #`(#,@imp ((name name* ...))) exp rex rep aut dec))
(parse #'args #`(#,@imp ((name name* ...))) exp rex rep rxp aut dec))
((#:use-syntax (name name* ...) . args)
(and (and-map symbol? (syntax->datum #'(name name* ...))))
#`(#:transformer '(name name* ...)
. #,(parse #'args #`(#,@imp ((name name* ...))) exp rex
rep aut dec)))
rep rxp aut dec)))
((#:use-module ((name name* ...) arg ...) . args)
(and (and-map symbol? (syntax->datum #'(name name* ...))))
(parse #'args
#`(#,@imp ((name name* ...) #,@(parse-iface #'(arg ...))))
exp rex rep aut dec))
exp rex rep rxp aut dec))
((#:export (ex ...) . args)
(parse #'args imp #`(#,@exp ex ...) rex rep aut dec))
(parse #'args imp #`(#,@exp ex ...) rex rep rxp aut dec))
((#:export-syntax (ex ...) . args)
(parse #'args imp #`(#,@exp ex ...) rex rep aut dec))
(parse #'args imp #`(#,@exp ex ...) rex rep rxp aut dec))
((#:re-export (re ...) . args)
(parse #'args imp exp #`(#,@rex re ...) rep aut dec))
(parse #'args imp exp #`(#,@rex re ...) rep rxp aut dec))
((#:re-export-syntax (re ...) . args)
(parse #'args imp exp #`(#,@rex re ...) rep aut dec))
(parse #'args imp exp #`(#,@rex re ...) rep rxp aut dec))
((#:replace (r ...) . args)
(parse #'args imp exp rex #`(#,@rep r ...) aut dec))
(parse #'args imp exp rex #`(#,@rep r ...) rxp aut dec))
((#:replace-syntax (r ...) . args)
(parse #'args imp exp rex #`(#,@rep r ...) aut dec))
(parse #'args imp exp rex #`(#,@rep r ...) rxp aut dec))
((#:re-export-and-replace (r ...) . args)
(parse #'args imp exp rex rep #`(#,@rxp r ...) aut dec))
((#:autoload name bindings . args)
(parse #'args imp exp rex rep #`(#,@aut name bindings) dec))
(parse #'args imp exp rex rep rxp #`(#,@aut name bindings) dec))
((kw val . args)
(syntax-violation 'define-module "unknown keyword or bad argument"
#'kw #'val))))
@ -3840,7 +3849,7 @@ but it fails to load."
((_ (name name* ...) arg ...)
(and-map symbol? (syntax->datum #'(name name* ...)))
(with-syntax (((quoted-arg ...)
(parse #'(arg ...) '() '() '() '() '() #f))
(parse #'(arg ...) '() '() '() '() '() '() #f))
;; Ideally the filename is either a string or #f;
;; this hack is to work around a case in which
;; port-filename returns a symbol (`socket') for
@ -3941,27 +3950,20 @@ but it fails to load."
;; This function is called from "modules.c". If you change it, be
;; sure to update "modules.c" as well.
(define (module-export! m names)
(define* (module-export! m names #:key replace?)
"Export a local variable."
(let ((public-i (module-public-interface m)))
(for-each (lambda (name)
(let* ((internal-name (if (pair? name) (car name) name))
(external-name (if (pair? name) (cdr name) name))
(var (module-ensure-local-variable! m internal-name)))
(when replace?
(hashq-set! (module-replacements public-i) external-name #t))
(module-add! public-i external-name var)))
names)))
(define (module-replace! m names)
(let ((public-i (module-public-interface m)))
(for-each (lambda (name)
(let* ((internal-name (if (pair? name) (car name) name))
(external-name (if (pair? name) (cdr name) name))
(var (module-ensure-local-variable! m internal-name)))
;; FIXME: use a bit on variables instead of object
;; properties.
(set-object-property! var 'replace #t)
(module-add! public-i external-name var)))
names)))
(module-export! m names #:replace? #t))
(define (module-export-all! mod)
"Export all local variables from a module."
@ -3976,20 +3978,24 @@ but it fails to load."
(fresh-interface!))))
(set-module-obarray! iface (module-obarray mod))))
(define (module-re-export! m names)
(define* (module-re-export! m names #:key replace?)
"Re-export an imported variable."
(let ((public-i (module-public-interface m)))
(for-each (lambda (name)
(let* ((internal-name (if (pair? name) (car name) name))
(external-name (if (pair? name) (cdr name) name))
(var (module-variable m internal-name)))
(cond ((not var)
(error "Undefined variable:" internal-name))
((eq? var (module-local-variable m internal-name))
(error "re-exporting local variable:" internal-name))
(else
(module-add! public-i external-name var)))))
names)))
(for-each
(lambda (name)
(let* ((internal-name (if (pair? name) (car name) name))
(external-name (if (pair? name) (cdr name) name))
(var (module-variable m internal-name)))
(cond
((not var)
(error "Undefined variable:" internal-name))
((eq? var (module-local-variable m internal-name))
(error "re-exporting local variable:" internal-name))
(else
(when replace?
(hashq-set! (module-replacements public-i) external-name #t))
(module-add! public-i external-name var)))))
names)))
(define-syntax-rule (export name ...)
(eval-when (expand load eval)
@ -4073,15 +4079,15 @@ but it fails to load."
#f)
(define (replace module name int1 val1 int2 val2 var val)
(let ((old (or (and var (object-property var 'replace) var)
(module-variable int1 name)))
(new (module-variable int2 name)))
(if (object-property old 'replace)
(and (or (eq? old new)
(not (object-property new 'replace)))
(let* ((replace1 (hashq-ref (module-replacements int1) name))
(replace2 (hashq-ref (module-replacements int2) name))
(old (or (and replace1 var)
(module-variable int1 name)))
(new (module-variable int2 name)))
(if replace1
(and (or (eq? old new) (not replace2))
old)
(and (object-property new 'replace)
new))))
(and replace2 new))))
(define (warn-override-core module name int1 val1 int2 val2 var val)
(and (eq? int1 the-scm-module)

View file

@ -76,8 +76,8 @@
terminated-thread-exception?
uncaught-exception?
uncaught-exception-reason)
#:re-export ((raise-continuable . raise)
with-exception-handler)
#:re-export (with-exception-handler)
#:re-export-and-replace ((raise-continuable . raise))
#:replace (current-time
current-thread
thread?

View file

@ -1,6 +1,6 @@
;;; srfi-34.scm --- Exception handling for programs
;; Copyright (C) 2003, 2006, 2008, 2010 Free Software Foundation, Inc.
;; Copyright (C) 2003, 2006, 2008, 2010, 2019 Free Software Foundation, Inc.
;;
;; This library is free software; you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public
@ -29,6 +29,7 @@
(define-module (srfi srfi-34)
#:re-export (with-exception-handler
(raise-exception . raise))
#:re-export-and-replace ((raise-exception . raise))
#:export-syntax (guard))
(cond-expand-provide (current-module) '(srfi-34))