From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: ludovic.courtes@laas.fr (Ludovic =?iso-8859-1?Q?Court=E8s?=) Newsgroups: gmane.lisp.guile.devel Subject: Re: [PATCH] Per-module reader, take #3 Date: Mon, 07 Nov 2005 17:06:13 +0100 Organization: LAAS-CNRS Message-ID: <87pspch28a.fsf_-_@laas.fr> References: <87u0gp9lm3.fsf@laas.fr> <877jd3lkdq.fsf@ossau.uklinux.net> <87hdc62a6c.fsf@laas.fr> <87irw49twc.fsf@laas.fr> <87irw3prgp.fsf@ossau.uklinux.net> <8764rw7b9q.fsf_-_@laas.fr> <871x2j98qb.fsf@ossau.uklinux.net> <87u0ffnudk.fsf@laas.fr> <87sluxb0xt.fsf@ossau.uklinux.net> <87r7agvdb1.fsf@laas.fr> <87wtk796xk.fsf@ossau.uklinux.net> <87br1jiacq.fsf@laas.fr> <87d5lp9vv4.fsf@ossau.uklinux.net> <871x258dxd.fsf@zip.com.au> <87zmos8zt4.fsf@ossau.uklinux.net> <87ll0a3hlk.fsf@ossau.uklinux.net> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1131379739 8708 80.91.229.2 (7 Nov 2005 16:08:59 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Mon, 7 Nov 2005 16:08:59 +0000 (UTC) Cc: guile-devel@gnu.org Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Mon Nov 07 17:08:56 2005 Return-path: Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1EZ9Vw-0006C5-CN for guile-devel@m.gmane.org; Mon, 07 Nov 2005 17:06:33 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1EZ9Vv-0005Vf-H3 for guile-devel@m.gmane.org; Mon, 07 Nov 2005 11:06:31 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1EZ9Vo-0005VM-Tc for guile-devel@gnu.org; Mon, 07 Nov 2005 11:06:25 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1EZ9Vo-0005V8-5T for guile-devel@gnu.org; Mon, 07 Nov 2005 11:06:24 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1EZ9Vo-0005V3-19 for guile-devel@gnu.org; Mon, 07 Nov 2005 11:06:24 -0500 Original-Received: from [140.93.0.15] (helo=laas.laas.fr) by monty-python.gnu.org with esmtp (TLS-1.0:DHE_RSA_3DES_EDE_CBC_SHA:24) (Exim 4.34) id 1EZ9Vn-0000tI-Jq for guile-devel@gnu.org; Mon, 07 Nov 2005 11:06:24 -0500 Original-Received: by laas.laas.fr (8.13.1/8.13.4) with SMTP id jA7G6GRk017917; Mon, 7 Nov 2005 17:06:22 +0100 (CET) Original-To: Neil Jerram X-URL: http://www.laas.fr/~lcourtes/ X-Revolutionary-Date: 17 Brumaire an 214 de la =?iso-8859-1?Q?R=E9volution?= X-PGP-Key-ID: 0xEB1F5364 X-PGP-Key: http://www.laas.fr/~lcourtes/ludovic.asc X-PGP-Fingerprint: 821D 815D 902A 7EAB 5CEE D120 7FBA 3D4F EB1F 5364 X-OS: powerpc-unknown-linux-gnu Mail-Followup-To: Neil Jerram , guile-devel@gnu.org In-Reply-To: <87ll0a3hlk.fsf@ossau.uklinux.net> (Neil Jerram's message of "Sun, 30 Oct 2005 19:55:19 +0000") User-Agent: Gnus/5.110004 (No Gnus v0.4) Emacs/21.4 (gnu/linux) X-Spam-Score: 0 () X-Scanned-By: MIMEDefang at CNRS-LAAS X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:5377 Archived-At: Hi Neil, Thanks for your detailed analysis of the `load' procedure stack. Neil Jerram writes: > So one possibility for adding custom reader support to all this is... > > - Don't put any current-reader framing code in primitive-load. In > other words, don't reset current-reader to #f (or anything else) at > the start of primitive-load, and don't use framing to restore the > value of the current-reader at the end if the loaded code has > changed it. This means that primitive-load keeps its existing > primitiveness - i.e. it isn't much more than just a read eval loop. > > - Add an optional reader arg to both r4rs's load and boot-9's > load-module, and treat as #f if not specified. In r4rs load, do > (with-fluids ((the-reader reader)) ...) around the existing code. In > load-module, just pass the reader through to basic-load. > > This would preserve existing behaviour for any calls to load or > use-modules, which are the mainline cases, even when the caller has > installed a non-default reader, but it also allows developers to > achieve different behaviour when they want it by using primitive-load > and the optional reader arg to load. Agreed, this approach is consistent with the current `load' stack. The patch below does what you described. I left the `#:reader' option to `define-module' as an alternative, higher-level approach to choosing an alternate reader. Please let me know what you think about it. And sorry for consuming so much of your time! ;-) Thanks, Ludovic. PS: I can prepare ChangeLog entries if it looks good to commit. --- orig/doc/ref/api-evaluation.texi +++ mod/doc/ref/api-evaluation.texi @@ -409,12 +409,21 @@ @subsection Loading Scheme Code from File @rnindex load -@deffn {Scheme Procedure} load filename +@deffn {Scheme Procedure} load filename [reader] Load @var{filename} and evaluate its contents in the top-level -environment. The load paths are not searched. If the variable -@code{%load-hook} is defined, it should be bound to a procedure that -will be called before any code is loaded. See documentation for -@code{%load-hook} later in this section. +environment. The load paths are not searched. If @var{reader} is +provided, then it should be either @code{#f}, in which case the +built-in @code{read} procedure (@pxref{Scheme Read}) is used to load +the file, or a reader procedure to use when reading data from file +@var{filename}. Such a reader procedure must work like @code{read} +(@pxref{Scheme Read}). + +The Scheme code in file @var{filename} may change the reader procedure +used by @code{load} using @code{set-current-reader} (see below). + +If the variable @code{%load-hook} is defined, it should be bound to a +procedure that will be called before any code is loaded. See +documentation for @code{%load-hook} later in this section. @end deffn @deffn {Scheme Procedure} load-from-path filename @@ -431,6 +440,8 @@ @code{%load-hook} is defined, it should be bound to a procedure that will be called before any code is loaded. See the documentation for @code{%load-hook} later in this section. +The reader procedure used to read the file named @var{filename} is the +one specified using @code{set-current-reader} (see below). @end deffn @deffn {Scheme Procedure} primitive-load-path filename @@ -475,6 +486,23 @@ The load port is used internally by @code{primitive-load}. @end deffn +@deffn {Scheme Procedure} current-reader +@deffnx {C Function} scm_current_reader () +Return the reader procedure used by @code{primitive-load} (and +@code{load}) during the dynamic extent of the current frame (see +@xref{Dynamic Wind}, and @pxref{Frames}). +@end deffn + +@deffn {Scheme Procedure} set-current-reader reader +@deffnx {C Function} scm_set_current_reader (reader) +During the dynamic extent of the current frame, set the reader +procedure used by @code{primitive-load} (and @code{load}) to +@var{reader}. If @var{reader} is a procedure, is must follow the +interface of @code{read} (@pxref{Scheme Read}). If @var{reader} is +@code{#f}, it is assumed that Guile's built-in @code{read} procedure +will be used. +@end deffn + @defvar %load-extensions A list of default file extensions for files containing Scheme code. @code{%search-load-path} tries each of these extensions when looking for --- orig/ice-9/boot-9.scm +++ mod/ice-9/boot-9.scm @@ -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,9 @@ uses binder #f #f #f #f #f #f '() (make-weak-value-hash-table 31) - 0))) + 0 + #f ;; the default reader + ))) ;; We can't pass this as an argument to module-constructor, ;; because we need it to close over a pointer to the module @@ -1247,6 +1250,8 @@ (define set-module-name! (record-modifier module-type 'name)) (define module-kind (record-accessor module-type 'kind)) (define set-module-kind! (record-modifier module-type 'kind)) +(define module-reader (record-accessor module-type 'reader)) +(define set-module-reader! (record-modifier module-type 'reader)) (define module-duplicates-handlers (record-accessor module-type 'duplicates-handlers)) (define set-module-duplicates-handlers! @@ -1633,19 +1638,28 @@ (set-current-module outer-module) (set! outer-module #f))))) +;; Rename R4RS' `load'. (define basic-load load) -(define (load-module filename) +(define (load-module filename . reader) (save-module-excursion (lambda () (let ((oldname (and (current-load-port) - (port-filename (current-load-port))))) + (port-filename (current-load-port)))) + (reader (if (null? reader) + #f + (if (null? (cdr reader)) + (car reader) + (scm-error 'wrong-number-of-args "load-module" + "too many arguments: ~A" + (list reader) #f))))) (basic-load (if (and oldname (> (string-length filename) 0) (not (char=? (string-ref filename 0) #\/)) (not (string=? (dirname oldname) "."))) (string-append (dirname oldname) "/" filename) - filename)))))) + filename) + reader))))) @@ -2042,10 +2056,22 @@ (call-with-deferred-observers (lambda () (module-use-interfaces! module (reverse reversed-interfaces)) + ;; Evaluate the `#:reader' argument in the context of the module + ;; being defined. + (set-module-reader! module + (eval (module-reader module) module)) (module-export! module exports) (module-replace! module replacements) (module-re-export! module re-exports))) (case (car kws) + ((#:reader) + ;; The argument to `#:reader' will be evaluated eventually. + (set-module-reader! module (cadr kws)) + (loop (cddr kws) + reversed-interfaces + exports + re-exports + replacements)) ((#:use-module #:use-syntax) (or (pair? (cdr kws)) (unrecognized kws)) @@ -2138,7 +2164,7 @@ (set-car! (memq a (module-uses module)) i) (module-local-variable i sym)))))) (module-constructor (make-hash-table 0) '() b #f #f name 'autoload #f #f - '() (make-weak-value-hash-table 31) 0))) + '() (make-weak-value-hash-table 31) 0 read))) ;;; {Compiled module} @@ -2538,7 +2564,7 @@ (display prompt) (force-output) (run-hook before-read-hook) - (read (current-input-port)))) + ((or (current-reader) read) (current-input-port)))) (define (scm-style-repl) @@ -2851,6 +2877,7 @@ (let ((m (process-define-module (list ,@(compile-define-module-args args))))) (set-current-module m) + (set-current-reader (module-reader m)) m)) (else (error "define-module can only be used at the top level")))) --- orig/ice-9/r4rs.scm +++ mod/ice-9/r4rs.scm @@ -206,6 +206,19 @@ (set! %load-hook %load-announce) -(define (load name) - (start-stack 'load-stack - (primitive-load name))) +(define (load name . reader) + (let ((previous-reader (current-reader)) + (reader (if (null? reader) + #f ;; use the built-in reader + (if (null? (cdr reader)) + (car reader) + (scm-error 'wrong-number-of-args "load-module" + "too many arguments: ~A" + (list reader) #f))))) + (dynamic-wind + (lambda () (set-current-reader reader)) + (lambda () + (start-stack 'load-stack + (primitive-load name))) + (lambda () (set-current-reader previous-reader))))) + --- orig/libguile/load.c +++ mod/libguile/load.c @@ -42,6 +42,7 @@ #include "libguile/validate.h" #include "libguile/load.h" +#include "libguile/fluids.h" #include #include @@ -55,13 +56,59 @@ #endif +/* The current reader (a fluid). */ + +static SCM the_reader = SCM_BOOL_F; +static size_t the_reader_fluid_num = 0; + +#define CURRENT_READER() SCM_FAST_FLUID_REF (the_reader_fluid_num) +#define SET_CURRENT_READER(_val) \ +do \ +{ \ + SCM_FAST_FLUID_SET_X (the_reader_fluid_num, (_val)); \ +} \ +while (0) + + +SCM_DEFINE (scm_current_reader, "current-reader", 0, 0, 0, + (void), + "Return the current reader.") +#define FUNC_NAME s_scm_current_reader +{ + return CURRENT_READER (); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_set_current_reader, "set-current-reader", 1, 0, 0, + (SCM reader), + "Set the current reader to @var{reader} and return the " + "previous current reader.") +#define FUNC_NAME s_scm_set_current_reader +{ + SCM previous; + + /* The value `#f' is a special allowed value for READER which means ``use + Guile's built-in reader''. See how `primitive-load' uses it as an + optimization. */ + if (reader != SCM_BOOL_F) + SCM_VALIDATE_PROC (1, reader); + + previous = CURRENT_READER (); + SET_CURRENT_READER (reader); + + return previous; +} +#undef FUNC_NAME + + + /* Loading a file, given an absolute filename. */ /* Hook to run when we load a file, perhaps to announce the fact somewhere. Applied to the full name of the file. */ static SCM *scm_loc_load_hook; -SCM_DEFINE (scm_primitive_load, "primitive-load", 1, 0, 0, +SCM_DEFINE (scm_primitive_load, "primitive-load", 1, 0, 0, (SCM filename), "Load the file named @var{filename} and evaluate its contents in\n" "the top-level environment. The load paths are not searched;\n" @@ -88,9 +135,19 @@ while (1) { - SCM form = scm_read (port); + SCM reader, form; + + /* Use whatever the current reader is. */ + reader = CURRENT_READER (); + + if (reader == SCM_BOOL_F) + form = scm_read (port); + else + form = scm_call_1 (reader, port); + if (SCM_EOF_OBJECT_P (form)) break; + scm_primitive_eval_x (form); } @@ -501,6 +558,10 @@ scm_nullstr))); scm_loc_load_hook = SCM_VARIABLE_LOC (scm_c_define ("%load-hook", SCM_BOOL_F)); + the_reader = scm_permanent_object (scm_make_fluid ()); + the_reader_fluid_num = SCM_FLUID_NUM (the_reader); + SET_CURRENT_READER (SCM_BOOL_F); + init_build_info (); #include "libguile/load.x" --- orig/libguile/load.h +++ mod/libguile/load.h @@ -38,6 +38,9 @@ SCM_API SCM scm_c_primitive_load_path (const char *filename); SCM_API void scm_init_load (void); +SCM_API SCM scm_current_reader (void); +SCM_API SCM scm_set_current_reader (SCM reader); + #endif /* SCM_LOAD_H */ /* --- orig/libguile/modules.h +++ mod/libguile/modules.h @@ -45,6 +45,7 @@ #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 #define SCM_MODULE_OBARRAY(module) \ SCM_PACK (SCM_STRUCT_DATA (module) [scm_module_index_obarray]) @@ -56,6 +57,8 @@ SCM_PACK (SCM_STRUCT_DATA (module)[scm_module_index_eval_closure]) #define SCM_MODULE_TRANSFORMER(module) \ SCM_PACK (SCM_STRUCT_DATA (module)[scm_module_index_transformer]) +#define SCM_MODULE_READER(module) \ + SCM_PACK (SCM_STRUCT_DATA (module)[scm_module_index_reader]) SCM_API scm_t_bits scm_tc16_eval_closure; _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel