[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] Per-module reader
From: |
Neil Jerram |
Subject: |
Re: [PATCH] Per-module reader |
Date: |
Mon, 26 Sep 2005 20:05:53 +0100 |
User-agent: |
Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux) |
address@hidden (Ludovic Courtès) writes:
> Hi,
>
> The patch below adds a `#:reader' keyword to `define-module' that allows
> modules to specify the reader that should be used to interpret them:
>
> (define-module (the-module)
> #:reader the-reader-for-my-favorite-syntax)
All looks good, except for concerns about (i) performance; (ii)
whether #:reader fits nicely in the big picture with the transformer
option; (iii) one possible bug.
> This way, module implementors can decide to use whatever syntax variant
> they prefer, while not having any side-effect on the code being read
> from other files or modules. For illustration, here is an example that
> makes use of my `guile-reader' thing:
>
> --8<---------------cut here---------------start------------->8---
> (define-module (module-with-reader)
> #:reader (let* ((elisp-char-tr
> (make-token-reader #\?
> (token-reader-procedure
> (standard-token-reader 'character)))))
> (make-reader (cons elisp-char-tr
> (map standard-token-reader
> '(whitespace
> sexp string number colon-keyword
> semicolon-comment
> symbol-upper-case symbol-lower-case
> quote-quasiquote-unquote)))))
> #:use-module (system reader))
This is nice; but concerns about whether it fits with transformer are:
- Transformer is specified with #:use-syntax followed by module name,
which is a lot different from your syntax. I prefer your syntax,
because use-syntax requires the transformer procedure to have the
same name as the module it's defined in, which seems rubbish. But
on the other hand perhaps there is a reason for forcing the
reader/transformer to be defined in another module - are we missing
some subtlety here?
- As well as the inline definition option shown here, does it also
work if the #:reader arg is a proc defined in one of the used
modules? I guess it can't possibly work in the circular reference
case -- i.e. where module A uses a reader defined in module B, but B
also uses A and B was loaded first -- so this is probably deemed
user error - but how is that error presented to the user?
- Does it make sense to have both #:reader and #:use-syntax? Should
we reimplement use-syntax as a special case of #:reader? Does it
make sense that the places where your reader affects libguile
(i.e. primitive-load) are different from the places where the module
transformer affects libguile (i.e. the various versions of eval)?
> Index: ice-9/boot-9.scm
> ===================================================================
> RCS file: /cvsroot/guile/guile/guile-core/ice-9/boot-9.scm,v
> retrieving revision 1.351
> diff -u -B -b -p -r1.351 boot-9.scm
> --- ice-9/boot-9.scm 31 Jul 2005 23:36:50 -0000 1.351
> +++ ice-9/boot-9.scm 13 Sep 2005 12:28:08 -0000
> @@ -1185,7 +1185,8 @@
> (make-record-type 'module
> '(obarray uses binder eval-closure transformer name kind
> duplicates-handlers duplicates-interface
> - observers weak-observers observer-id)
> + observers weak-observers observer-id
> + reader)
> %print-module))
>
> ;; make-module &opt size uses binder
> @@ -1221,7 +1222,8 @@
> uses binder #f #f #f #f #f #f
> '()
> (make-weak-value-hash-table 31)
> - 0)))
> + 0
> + read)))
Init value "read" here prevents your optimization in load.c from
taking effect - so don't you want #f ?
> Index: libguile/load.c
> ===================================================================
> RCS file: /cvsroot/guile/guile/guile-core/libguile/load.c,v
> retrieving revision 1.86
> diff -u -B -b -p -r1.86 load.c
> --- libguile/load.c 23 May 2005 19:57:20 -0000 1.86
> +++ libguile/load.c 13 Sep 2005 12:28:08 -0000
> @@ -82,15 +82,29 @@ SCM_DEFINE (scm_primitive_load, "primiti
> scm_call_1 (hook, filename);
>
> { /* scope */
> + SCM module = SCM_BOOL_F, reader = SCM_BOOL_F;
> SCM port = scm_open_file (filename, scm_from_locale_string ("r"));
> scm_frame_begin (SCM_F_FRAME_REWINDABLE);
> scm_i_frame_current_load_port (port);
>
> while (1)
> {
> - SCM form = scm_read (port);
> + SCM form;
> +
> + if (scm_current_module () != module)
> + {
> + module = scm_current_module ();
> + reader = SCM_MODULE_READER (module);
> + }
I'm worried that this could reduce performance noticeably, and it
seems unnecessarily inefficient. So ... <pause> ...
Surely the low level concept here is that an alternative reader is a
property of a port? In that case, I would expect that
- the switch to the alternative reader would be implemented inside
scm_read, using a new field on scm_t_port which can be set/read
using set-port-reader!/port-reader
- the module level #:reader option would be implemented by
define-module calling set-port-reader! on current-load-port. (Note
BTW that define-module should also do this when called to switch
context to an already existing module.)
Note that this also raises the question of what to do when someone
types (define-module (module-with-reader)) at the REPL ... perhaps
define-module should set the reader of the current input port also?
> Index: libguile/modules.h
> ===================================================================
> RCS file: /cvsroot/guile/guile/guile-core/libguile/modules.h,v
> retrieving revision 1.28
> diff -u -B -b -p -r1.28 modules.h
> --- libguile/modules.h 31 Jul 2005 23:36:14 -0000 1.28
> +++ libguile/modules.h 13 Sep 2005 12:28:08 -0000
> @@ -45,6 +45,7 @@ SCM_API scm_t_bits scm_module_tag;
> #define scm_module_index_binder 2
> #define scm_module_index_eval_closure 3
> #define scm_module_index_transformer 4
> +#define scm_module_index_reader 12
Why 12? From the context I'd expect 5.
Regards,
Neil