Re: Reference documentation of modules and library
Hi Mike, I think “Standard Library” should eventually be merged into “Guile Modules”. The reason it’s separate currently is that its contents are automatically extracted from the module comments, which is inherited from Guile-Lib. But merging them also means improving their integration with the rest of the manual, possibly rewriting parts, IMO. Would you like to work on it? :-) Regarding standard/extended/3rd-party library, how about adding second-level sections to sort by theme? For instance, formatted output, pretty-printing, and expect could be grouped together; sxml, and (sxml match), and perhaps Texinfo ditto; etc. WDYT? As for SLIB and Jacal, I’m not sure they even run with Guile 2.0. Has anyone tried lately? Thanks, Ludo’.
Re: Reference documentation of modules and library
From: Ludovic Courtès l...@gnu.org Hi Mike, I think “Standard Library” should eventually be merged into “Guile Modules”. I could try it. It'll take me a few weeks to geto to it, though. Regarding standard/extended/3rd-party library, how about adding second-level sections to sort by theme? For instance, formatted output, pretty-printing, and expect could be grouped together; sxml, and (sxml match), and perhaps Texinfo ditto; etc. They could definitly use a better ordering: sxml and sxml-match should be together. Second-level sections might help, but they might feel excessive. As for SLIB and Jacal, I’m not sure they even run with Guile 2.0. Has anyone tried lately? Much of Slib still works. It does use some removed functions. The installation has problems. Its makefile installs slib into a directory that Guile doesn't search, and the makefile needs to be modified to run at all if Jaffer's scm is not installed. I ended up writing my own autotools wrapper for slib to get it to install. Thanks, Mike
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
Mark H Weaver m...@netris.org writes: Here's the third version of my simple `local-eval' patch. Notable changes from last time: * Pattern variables are now captured properly. * `the-environment' now works as advertised within macro definitions. * Added doc strings for `local-eval' and `local-compile'. I am open to reimplementing this in a different way for 2.0.5, along the lines suggested by Andy. I'd like to capture all bindings, not just the ones reachable by symbols. I'd like to support _all_ lexical bindings, including local syntax transformers. I'm also warming to the idea of standardizing on variable objects as a way to represent mutable lexicals. However, there's no time to do this for 2.0.4. That job depends on other big jobs, notably a major overhaul of the evaluator. Nonetheless, I think it is very important to include this simple implementation in 2.0.4. This is a BUG FIX, the bug being that `local-eval' was removed from underneath Lilypond's feet. A partial implementation (that almost certainly does everything they need) is _far_ better than none at all. Lilypond can only depend on `local-eval' if installations of Guile without it are quite rare. If we can get this in 2.0.4, there's hope that we can make Guile 2.0.[0-3] rare. Please consider it. This implementation is quite robust. I am not altogether comfortable with pushing a temporary fix for the sake of LilyPond when we'll get another behavioral change with the next version. LilyPond would be mostly left in the rain for older versions unless we made that implementation a fallback within our own sources. However, there would be no point in adopting a fallback implementation that would not also work with 2.0.0-2.0.3. As far as I understand, this implementation could be pulled into a separate file and used for bridging the 2.0.0-2.0.3 gap. If it is solid enough to be maintained as 2.0.4, it would likely be a reasonably good bet. Of course, a version that would be tighter integrated with the compiler and optimizer would seem like a more powerful prospect, but it also sounds that it would need more thorough maintenance to not fall into bit rot. I am not sure that the reasons for not permitting definition context in local-eval are not of somewhat more theoretical than practical nature, and in particular it sounds to me like I'm also warming to the idea of standardizing on variable objects as a way to represent mutable lexicals could suggest that the strength of even the theoretical reasons might get eroded further. Of course, _calling_ mutual recursive functions in execution before the second part has been defined will remain unfeasible. -- David Kastrup
syntax-local-binding
Hi list, Attached is a patch that implements a new accessor, syntax-local-binding. It's like syntax-local-value, but can also determine if an identifier is a pattern var or a normal lexical. (define-syntax local-binding (lambda (x) (syntax-case x () ((_ id) (identifier? #'id) (call-with-values (lambda () (syntax-local-binding #'id)) (lambda (x y) (with-syntax ((type (datum-syntax #'here x))) #''type))) (let-syntax ((x (lambda (x) 10))) (local-binding x)) $3 = local-macro (syntax-case #'(foo) () ((id) (local-binding id))) $4 = pattern-variable (let ((x 10)) (local-binding x)) $5 = lexical It returns two values. The first is a symbol, either `local-macro', `lexical', or `pattern-variable'. The second is specific to the type. For local-macro it is the transformer binding. For lexical it is the gensym name of the lexical. For pattern variables, it is something opaque that identifies that pattern var. Inspired by a patch by Stefan Israelsson Tampe. I'm going to try to implement the-environment with this. We'll see how it goes! Andy -- http://wingolog.org/
Re: GNU Guile branch, master, updated. v2.1.0-102-g0f9f51a
Hi Mark, On Sat 14 Jan 2012 21:37, Mark H Weaver m...@netris.org writes: If a top-level variable needs to be expanded in user code, then you'd better explicitly choose a stable name for it. Indeed, this is the best solution, for interface stability. But what should happen when users do introduce top-level variables in their macros, against our recommendations? My point is that the answer cannot be, generate a truly random identifier. Simply advising users not to introduce bindings is not a great answer. In the general case, where a macro may have been considerably reworked from one version to the next, it's _impossible_, even in principle, for the system to reliably decide the correspondence between top-level gensyms in the new code vs the old code. Even your method is only a heuristic that will often do the wrong thing, in both directions: it will cause unintended name collisions in R5RS standard code, and it will also sometimes change the name of a top-level when you didn't want it to. Of course. It's a heuristic. We document the heuristic and move on, no? If users really find themselves caring about this, they will have to learn the heuristic. There's another option: we could properly track the compile-time dependencies of each module, and automatically consider a .go file stale if _any_ of its compile-time dependencies are newer than it. We do need to do this, yes. This would be a great thing to add, once we switch to ELF as our format of compiled files. (You would add a section for this.) Furthermore, we could provide distros with the necessary infrastructure to automatically recompile guile modules as needed after package upgrades. That is orthogonal to this question. Recompilation can be triggered on package dependencies, instead of embedded expansion dependencies. That's what I was planning on doing for the guildhall, for example. Regards, Andy -- http://wingolog.org/
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
David Kastrup d...@gnu.org writes: I am not altogether comfortable with pushing a temporary fix for the sake of LilyPond when we'll get another behavioral change with the next version. But there would _not_ be a behavioral change in the next version. It would only be a change in the internal implementation. As far as I understand, this implementation could be pulled into a separate file and used for bridging the 2.0.0-2.0.3 gap. Unfortunately, any implementation of `local-eval' requires changes to psyntax.scm, which is not something that you could reasonably do as an external package. I am not sure that the reasons for not permitting definition context in local-eval are not of somewhat more theoretical than practical nature, There's at least one practical reason not to allow it, namely that it is _impossible_ to implement. Consider this: (let ((x 1)) (define (get-x) x) (the-environment)) If we allow (the-environment) to add definitions to the implicit `letrec', then (get-x) cannot know which binding of `x' to use. In fact, it cannot lookup _any_ bindings, because absolutely any identifier (even syntactic keywords) could be redefined within this implicit `letrec'. This means that it's impossible to compile or evaluate anything within the body of the outer `let', which means it's not even possible to evaluate (the-environment) itself. So there's no way to run the code above if we allow (the-environment) to add definitions. Mark
Re: syntax-local-binding
On Sun 15 Jan 2012 18:00, Andy Wingo wi...@pobox.com writes: Attached is a patch that implements a new accessor, syntax-local-binding. Here 'tis! From 09ba44abeb47cdf4ec61df6f7386217f0cbe30c7 Mon Sep 17 00:00:00 2001 From: Andy Wingo wi...@pobox.com Date: Sun, 15 Jan 2012 17:51:02 +0100 Subject: [PATCH] add syntax-local-binding * module/ice-9/boot-9.scm (syntax-local-binding): New binding. * module/ice-9/psyntax.scm: Locally define a fluid that holds the transformer environment. with-transformer-environment calls a procedure with the transformer environment, or raises an error if called outside the extent of a transformer. Bind transformer-environment in expand-macro. (syntax-local-binding): New procedure to return binding information of a lexially bound identifier (a lexical, local macro, or pattern variable). --- module/ice-9/boot-9.scm |1 + module/ice-9/psyntax.scm | 39 +-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm index f661d08..9cdd8d1 100644 --- a/module/ice-9/boot-9.scm +++ b/module/ice-9/boot-9.scm @@ -389,6 +389,7 @@ If there is no handler at all, Guile prints an error and then exits. (define generate-temporaries #f) (define bound-identifier=? #f) (define free-identifier=? #f) +(define syntax-local-binding #f) ;; $sc-dispatch is an implementation detail of psyntax. It is used by ;; expanded macros, to dispatch an input against a set of patterns. diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm index 1bf3c32..dcabafe 100644 --- a/module/ice-9/psyntax.scm +++ b/module/ice-9/psyntax.scm @@ -786,6 +786,14 @@ id)) (else (syntax-violation 'id-var-name invalid id id) +(define transformer-environment + (make-fluid + (lambda (k) + (error called outside the dynamic extent of a syntax transformer + +(define (with-transformer-environment k) + ((fluid-ref transformer-environment) k)) + ;; free-id=? must be passed fully wrapped ids since (free-id=? x y) ;; may be true even if (free-id=? (wrap x w) (wrap y w)) is not. @@ -1321,8 +1329,10 @@ (syntax-violation #f encountered raw symbol in macro output (source-wrap e w (wrap-subst w) mod) x)) (else (decorate-source x s) -(rebuild-macro-output (p (source-wrap e (anti-mark w) s mod)) - (new-mark +(with-fluids ((transformer-environment + (lambda (k) (k e r w s rib mod + (rebuild-macro-output (p (source-wrap e (anti-mark w) s mod)) +(new-mark) (define expand-body ;; In processing the forms of the body, we create a new, empty wrap. @@ -2435,6 +2445,31 @@ (set! syntax-source (lambda (x) (source-annotation x))) +(set! syntax-local-binding + (lambda (id) +(arg-check nonsymbol-id? id 'syntax-local-value) +(with-transformer-environment + (lambda (e r w s rib mod) + (define (strip-anti-mark w) + (let ((ms (wrap-marks w)) (s (wrap-subst w))) + (if (and (pair? ms) (eq? (car ms) the-anti-mark)) + ;; output is from original text + (make-wrap (cdr ms) (if rib (cons rib (cdr s)) (cdr s))) + ;; output introduced by macro + (error what!!! + (let ((label (id-var-name (syntax-object-expression id) + (strip-anti-mark (syntax-object-wrap id) + (if (not (string? label)) + (error identifier not lexically bound id)) + (let ((b (assq-ref r label))) + (if (not b) + (error displaced lexical id)) + (case (binding-type b) + ((lexical) (values 'lexical (binding-value b))) + ((macro) (values 'local-macro (binding-value b))) + ((syntax) (values 'pattern-variable (binding-value b))) + (else (error unpossible! b) + (set! generate-temporaries (lambda (ls) (arg-check list? ls 'generate-temporaries) -- 1.7.8.3 -- http://wingolog.org/
Throw without catch before boot:
Well, deciding to use my guile checkout not just for reference, I tried ./autogen.sh, ./configure and make on master. For one thing it is an aggravation that configure stops at the first unfound library dependency instead of going on and creating a report for all of them. That means that it takes O(n^2) time to get n dependencies in place. For another, I end up with make[3]: Entering directory `/usr/local/tmp/guile/libguile' GENguile-procedures.texi Throw without catch before boot: Throw to key misc-error with args (module-transformer no module, and `macroexpand' unbound () #f)Aborting. /bin/bash: line 1: 8604 Broken pipe cat alist.doc arbiters.doc array-handle.doc array-map.doc arrays.doc async.doc backtrace.doc boolean.doc bitvectors.doc bytevectors.doc chars.doc control.doc continuations.doc debug.doc deprecated.doc deprecation.doc dynl.doc dynwind.doc eq.doc error.doc eval.doc evalext.doc expand.doc extensions.doc feature.doc filesys.doc fluids.doc foreign.doc fports.doc gc-malloc.doc gc.doc gettext.doc generalized-arrays.doc generalized-vectors.doc goops.doc gsubr.doc guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc ioext.doc keywords.doc list.doc load.doc macros.doc mallocs.doc memoize.doc modules.doc numbers.doc objprop.doc options.doc pairs.doc ports.doc print.doc procprop.doc procs.doc promises.doc r6rs-ports.doc random.doc rdelim.doc read.doc root.doc rw.doc scmsigs.doc script.doc simpos.doc smob.doc sort.doc srcprop.doc srfi-1.doc srfi-4.doc srfi-13.doc srfi-14.doc srfi-60.doc stackchk.doc stacks.doc stime.doc strings.doc strorder.doc strports.doc struct.doc symbols.doc threads.doc throw.doc trees.doc uniform.doc values.doc variable.doc vectors.doc version.doc vports.doc weak-set.doc weak-table.doc weak-vector.doc dynl.doc posix.doc net_db.doc socket.doc regex-posix.doc 8605 Aborted | GUILE_AUTO_COMPILE=0 ../meta/uninstalled-env guild snarf-check-and-output-texi guile-procedures.texi make[3]: *** [guile-procedures.texi] Error 1 make[3]: Leaving directory `/usr/local/tmp/guile/libguile' make[2]: *** [all] Error 2 make[2]: Leaving directory `/usr/local/tmp/guile/libguile' make[1]: *** [all-recursive] Error 1 make[1]: Leaving directory `/usr/local/tmp/guile' make: *** [all] Error 2 Is that expected? -- David Kastrup
Re: Throw without catch before boot:
David Kastrup d...@gnu.org writes: Well, deciding to use my guile checkout not just for reference, I tried ./autogen.sh, ./configure and make on master. For now, it's best to stay on the stable-2.0 branch. That's our current focus. Mark
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
Mark H Weaver m...@netris.org writes: David Kastrup d...@gnu.org writes: Mark H Weaver m...@netris.org writes: David Kastrup d...@gnu.org writes: I am not sure that the reasons for not permitting definition context in local-eval are not of somewhat more theoretical than practical nature, There's at least one practical reason not to allow it, namely that it is _impossible_ to implement. Consider this: (let ((x 1)) (define (get-x) x) (the-environment)) If we allow (the-environment) to add definitions to the implicit `letrec', Then just let's not allow it. Consider the body of local-eval to be wrapped inside of an implicit (begin ...). I think you mean an implicit (let () ...). If that's what you want, then you can do it yourself, and the result will be less likely to confuse. What is confusing here? Obviously, definitions made in the scope of local-eval can't retroactively affect the environment where the-environment was called. And now instead of continuing with the unfriendly For this reason, they are prohibited. we continue with You may consider the local-eval body as being wrapped inside of an implicit (let () ...). I repeat: is there any valid construct under the currently proposed local-eval code that would change its behavior? Is there any currently valid construct that would change its behavior? If not, you _gain_ functionality, and the resulting semantics are still straightforward to explain as far as I can see. I don't understand this at all. Change what behavior? The behavior of local-eval given arbitrary expressions. Are there any expressions currently valid that would change their behavior if the body of local-eval were wrapped in an implicit (let () ...)? What functionality do you gain? The ability to make definitions valid in the local-eval without having to write (let () ...). Again: any drawback that is more substantial than I just don't want you to do that? -- David Kastrup
Re: Throw without catch before boot:
Mark H Weaver m...@netris.org writes: David Kastrup d...@gnu.org writes: Well, deciding to use my guile checkout not just for reference, I tried ./autogen.sh, ./configure and make on master. For now, it's best to stay on the stable-2.0 branch. That's our current focus. Interesting. -- David Kastrup
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
David Kastrup d...@gnu.org writes: Mark H Weaver m...@netris.org writes: David Kastrup d...@gnu.org writes: Mark H Weaver m...@netris.org writes: David Kastrup d...@gnu.org writes: I am not sure that the reasons for not permitting definition context in local-eval are not of somewhat more theoretical than practical nature, There's at least one practical reason not to allow it, namely that it is _impossible_ to implement. Consider this: (let ((x 1)) (define (get-x) x) (the-environment)) If we allow (the-environment) to add definitions to the implicit `letrec', Then just let's not allow it. Consider the body of local-eval to be wrapped inside of an implicit (begin ...). I think you mean an implicit (let () ...). If that's what you want, then you can do it yourself, and the result will be less likely to confuse. What is confusing here? Obviously, definitions made in the scope of local-eval can't retroactively affect the environment where the-environment was called. And now instead of continuing with the unfriendly For this reason, they are prohibited. we continue with You may consider the local-eval body as being wrapped inside of an implicit (let () ...). If you want to include local definitions, then you'll need to wrap the form passed to `local-eval' within (begin ...) anyway. If you're doing that, why not just wrap them in (let () ...) instead? Is it really more work to type #`(let () #,@forms) than #`(begin #,@forms) ? I would like for users to be able to use the simple mental model that the local expression is simply put in place of (the-environment). I'd also like to achieve the following source-level equivalence: expr == (local-eval 'expr (the-environment)) You are suggesting that we wrap the expression within a (let () ...), for the dubious benefit of allowing you to wrap the local forms in (begin ...) instead of (let () ...). I don't see any compelling benefit to this. On the other hand, I see less elegant semantics and potential confusion among users, who might reasonably expect the definitions in their (begin ...) to be added to the implicit `letrec', as would happen if the (begin ...) were put in place of (the-environment). Mark
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
David Kastrup d...@gnu.org writes: You are suggesting that we wrap the expression within a (let () ...), for the dubious benefit of allowing you to wrap the local forms in (begin ...) instead of (let () ...). Are there even situations where you could put definitions after begin? How are they different from the situation where you can't? I don't see any compelling benefit to this. On the other hand, I see less elegant semantics and potential confusion among users, who might reasonably expect the definitions in their (begin ...) to be added to the implicit `letrec', as would happen if the (begin ...) were put in place of (the-environment). begin can start with definitions, but not always? But (let () ...) can? Scheme is weird. `begin' is indeed quite weird in Scheme. Its meaning depends on the context where it is found: * In expression context, it is like `progn' in Lisp. It evaluates the expressions in order from left to right, and returns the value(s) of the last expression. * At the top-level, or within an internal body where local definitions are allowed (i.e. if every form above it in the internal body is a definition), it is a _splicing_ operator: it acts as if the contents of the begin were spliced into the surrounding context. This is mainly for the benefit of macros, so that they may expand into multiple definitions. For example: (let ((x 1)) (define (get-x) x) (begin (define x 2) (get-x))) is equivalent to: (let ((x 1)) (define (get-x) x) (define x 2) (get-x)) which is equivalent to: (let ((x 1)) (letrec ((get-x (lambda () x)) (x 2)) (get-x))) and therefore the result is 2, because the reference to `x' within (get-x) refers to the inner binding of `x'. Mark
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
Mark H Weaver m...@netris.org writes: David Kastrup d...@gnu.org writes: You are suggesting that we wrap the expression within a (let () ...), for the dubious benefit of allowing you to wrap the local forms in (begin ...) instead of (let () ...). Are there even situations where you could put definitions after begin? How are they different from the situation where you can't? I don't see any compelling benefit to this. On the other hand, I see less elegant semantics and potential confusion among users, who might reasonably expect the definitions in their (begin ...) to be added to the implicit `letrec', as would happen if the (begin ...) were put in place of (the-environment). begin can start with definitions, but not always? But (let () ...) can? Scheme is weird. `begin' is indeed quite weird in Scheme. Its meaning depends on the context where it is found: * In expression context, it is like `progn' in Lisp. It evaluates the expressions in order from left to right, and returns the value(s) of the last expression. * At the top-level, or within an internal body where local definitions are allowed (i.e. if every form above it in the internal body is a definition), it is a _splicing_ operator: it acts as if the contents of the begin were spliced into the surrounding context. This is mainly for the benefit of macros, so that they may expand into multiple definitions. Well, what if begin were able to splice definitions into the original lexical context of the-environment? I think it would be strange if a continuation taken in that context would get to see new definitions. And if a continuation there does not get to see it, it would be strange if successive calls of local-eval on the same environment got to see it. So there is not much of a sensible option except an implicit (let () ...) wrapper for the sake of splicing begin, or bugging out for new definitions. In the light of local-eval evaluating a _form_ rather than a _body_ (stupid of me to forget), and seeing the weird semantics of begin, I agree that an implicit (let () ...) wrapper for a single form does not really appear to add significant gains. It would be marginally convenient and marginally confusing. So one might as well forget about it. -- David Kastrup
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
David Kastrup d...@gnu.org writes: In the light of local-eval evaluating a _form_ rather than a _body_ (stupid of me to forget), and seeing the weird semantics of begin, I agree that an implicit (let () ...) wrapper for a single form does not really appear to add significant gains. It would be marginally convenient and marginally confusing. So one might as well forget about it. Except possibly for symmetry: how does plain eval handle it? guile (let ((x 2)) (eval '(begin (define x 4) x) (current-module))) 4 guile x 4 guile Right through to the top. And we couldn't do that in local-eval. But it also has no qualms just because previously evaluated forms would have used a previous definition of x. But that's because of top-level. Eval is always top-level, and define acts like set! there. What if the-environment had been taken at top-level (basically just carrying the information of (current-module))? Should local-eval then behave accordingly? If so, could we not just fold eval and local-eval into one function? And one could then define (define current-module (let ((top-level (the-environment))) (lambda () (eval '(the-environment) top-level if the-environment just returns the current module when at top level? Basically, I can accept your reasoning. This is just putting out a bit of brainstorming. -- David Kastrup
Re: Reference documentation of modules and library
Hi Mike! Mike Gran spk...@yahoo.com skribis: Much of Slib still works. It does use some removed functions. Good to know. Though if it “uses” removed functions, it doesn’t completely work? :-) The installation has problems. Its makefile installs slib into a directory that Guile doesn't search, and the makefile needs to be modified to run at all if Jaffer's scm is not installed. I ended up writing my own autotools wrapper for slib to get it to install. Perhaps you should submit to SLIB, since SLIB is now a GNU project. Thanks, Ludo’.
local-eval on syntax-local-binding, bound-identifiers
Hi Mark, I had made some noise about preferring an implementation of local-eval based on primitives from psyntax. But, I didn't clarify my argument by providing the primitives. Here are some patches that provide syntax-local-binding, as I noted in my previous mail, and also a procedure to get all identifiers that are visible within the scope of another identifier. I then refactored your patch to implement local-eval entirely in terms of these primitives and other normal macrology. What do you think? In the interests of time and debugging, I removed the support for pattern variables; it should be easy to add back. These are preliminary patches, but if this approach proves to be viable, I would prefer it to one that bakes the-environment into psyntax. WDYT? Regards, Andy From 48d8e52e316984f2bf9380df85079bb5fa142253 Mon Sep 17 00:00:00 2001 From: Andy Wingo wi...@pobox.com Date: Sun, 15 Jan 2012 17:51:02 +0100 Subject: [PATCH 1/3] add syntax-local-binding * module/ice-9/boot-9.scm (syntax-local-binding): New binding. * module/ice-9/psyntax.scm: Locally define a fluid that holds the transformer environment. with-transformer-environment calls a procedure with the transformer environment, or raises an error if called outside the extent of a transformer. Bind transformer-environment in expand-macro. (syntax-local-binding): New procedure to return binding information of a lexically bound identifier (a lexical, local macro, a pattern variable, or a displaced lexical). --- module/ice-9/boot-9.scm |1 + module/ice-9/psyntax.scm | 39 +-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm index f661d08..9cdd8d1 100644 --- a/module/ice-9/boot-9.scm +++ b/module/ice-9/boot-9.scm @@ -389,6 +389,7 @@ If there is no handler at all, Guile prints an error and then exits. (define generate-temporaries #f) (define bound-identifier=? #f) (define free-identifier=? #f) +(define syntax-local-binding #f) ;; $sc-dispatch is an implementation detail of psyntax. It is used by ;; expanded macros, to dispatch an input against a set of patterns. diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm index 1bf3c32..30685bc 100644 --- a/module/ice-9/psyntax.scm +++ b/module/ice-9/psyntax.scm @@ -786,6 +786,14 @@ id)) (else (syntax-violation 'id-var-name invalid id id) +(define transformer-environment + (make-fluid + (lambda (k) + (error called outside the dynamic extent of a syntax transformer + +(define (with-transformer-environment k) + ((fluid-ref transformer-environment) k)) + ;; free-id=? must be passed fully wrapped ids since (free-id=? x y) ;; may be true even if (free-id=? (wrap x w) (wrap y w)) is not. @@ -1321,8 +1329,10 @@ (syntax-violation #f encountered raw symbol in macro output (source-wrap e w (wrap-subst w) mod) x)) (else (decorate-source x s) -(rebuild-macro-output (p (source-wrap e (anti-mark w) s mod)) - (new-mark +(with-fluids ((transformer-environment + (lambda (k) (k e r w s rib mod + (rebuild-macro-output (p (source-wrap e (anti-mark w) s mod)) +(new-mark) (define expand-body ;; In processing the forms of the body, we create a new, empty wrap. @@ -2435,6 +2445,31 @@ (set! syntax-source (lambda (x) (source-annotation x))) +(set! syntax-local-binding + (lambda (id) +(arg-check nonsymbol-id? id 'syntax-local-value) +(with-transformer-environment + (lambda (e r w s rib mod) + (define (strip-anti-mark w) + (let ((ms (wrap-marks w)) (s (wrap-subst w))) + (if (and (pair? ms) (eq? (car ms) the-anti-mark)) + ;; output is from original text + (make-wrap (cdr ms) (if rib (cons rib (cdr s)) (cdr s))) + ;; output introduced by macro + (make-wrap ms (if rib (cons rib s) s) + (let ((label (id-var-name (syntax-object-expression id) + (strip-anti-mark (syntax-object-wrap id) + (if (not (string? label)) + (error identifier not lexically bound id)) + (let ((b (assq-ref r label))) + (if b + (case (binding-type b) + ((lexical) (values 'lexical (binding-value b))) + ((macro) (values 'local-macro (binding-value b))) + ((syntax) (values 'pattern-variable (binding-value b))) + (else (error unpossible! b))) + (values
Re: local-eval on syntax-local-binding, bound-identifiers
Hi Andy, Thanks very much for heeding my call for `local-eval' in 2.0.4, and for putting so much time into this. For the record, I still think it's better for `the-environment' to be implemented within psyntax as a core form. It's a fundamental syntactic construct with clean semantics, and it belongs in psyntax with its brethren. Your desire to remove it from psyntax has caused you to add far less elegant interfaces that have been hastily designed, and that may not even be sufficient for a full implementation of `the-environment' that captures mutually-recursive local macros. That said, there's a lot to like in your implementation, and it has some notable improvements over mine. It also has some problems, not all of which are trivial. Please see below, where I have inserted specific questions and comments into your patch. Thanks again, Mark [... skipped the first patch, which looks very well implemented, though I'm still not sure that we should be exposing this in our API ...] From 2c3da44320019453115811af386febaa7eb241c3 Mon Sep 17 00:00:00 2001 From: Andy Wingo wi...@pobox.com Date: Sun, 15 Jan 2012 18:39:44 +0100 Subject: [PATCH 2/3] add bound-identifiers * module/ice-9/boot-9.scm (bound-identifiers): Declare variable. * module/ice-9/psyntax.scm: Add all-bound-identifiers helper, and define bound-identifiers. The identifiers are anti-marked so that syntax transformers can introduce them, as-is. --- module/ice-9/boot-9.scm |1 + module/ice-9/psyntax.scm | 49 ++ 2 files changed, 50 insertions(+), 0 deletions(-) diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm index 9cdd8d1..b8aa842 100644 --- a/module/ice-9/boot-9.scm +++ b/module/ice-9/boot-9.scm @@ -389,6 +389,7 @@ If there is no handler at all, Guile prints an error and then exits. (define generate-temporaries #f) (define bound-identifier=? #f) (define free-identifier=? #f) +(define bound-identifiers #f) (define syntax-local-binding #f) ;; $sc-dispatch is an implementation detail of psyntax. It is used by diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm index 30685bc..25543e0 100644 --- a/module/ice-9/psyntax.scm +++ b/module/ice-9/psyntax.scm @@ -786,6 +786,48 @@ id)) (else (syntax-violation 'id-var-name invalid id id) +;; +;; all-bound-identifiers returns a list of all lexically bound +;; identifiers, as syntax objects. They are in order from outer to +;; inner. +;; +(define all-bound-identifiers + (lambda (w mod) +(define scan + (lambda (subst results) +(if (null? subst) +results +(let ((fst (car subst))) + (if (eq? fst 'shift) + (scan (cdr subst) results) + (let ((symnames (ribcage-symnames fst)) +(marks (ribcage-marks fst))) +(if (vector? symnames) +(scan-vector-rib subst symnames marks results) +(scan-list-rib subst symnames marks results +(define scan-list-rib + (lambda (subst symnames marks results) +(let f ((symnames symnames) (marks marks) (results results)) + (if (null? symnames) + (scan (cdr subst) results) + (f (cdr symnames) (cdr marks) + (cons (wrap (car symnames) + (anti-mark (make-wrap (car marks) subst)) * Why are you adding anti-marks here? + mod) + results)) +(define scan-vector-rib + (lambda (subst symnames marks results) +(let ((n (vector-length symnames))) + (let f ((i 0) (results results)) +(if (fx= i n) +(scan (cdr subst) results) +(f (fx+ i 1) + (cons (wrap (vector-ref symnames i) + (anti-mark (make-wrap (vector-ref marks i) subst)) * Ditto. + mod) + results))) +(scan (wrap-subst w) '( + (define transformer-environment (make-fluid (lambda (k) @@ -2470,6 +2512,13 @@ (else (error unpossible! b))) (values 'displaced-lexical #f +(set! bound-identifiers + (lambda (x) +(arg-check nonsymbol-id? x 'bound-identifiers) +(reverse + (all-bound-identifiers (syntax-object-wrap x) +(syntax-object-module x) + (set! generate-temporaries (lambda (ls) (arg-check list? ls 'generate-temporaries) --
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
Mark H Weaver m...@netris.org writes: What if the-environment had been taken at top-level (basically just carrying the information of (current-module))? Should local-eval then behave accordingly? If so, could we not just fold eval and local-eval into one function? This is a good question. Unfortunately, there is a non-trivial difference in the semantics of `eval' vs `local-eval'. `eval' temporarily sets the (current-module) to its second argument during evaluation of the expression. `local-eval' does not do this, and as I recall that was something you felt strongly about (and I agree). I don't think I would feel as strong about it if the argument was a module, implicating top-level. It is probably not all that easy to get the-environment at top level. And one could then define (define current-module (let ((top-level (the-environment))) (lambda () (eval '(the-environment) top-level if the-environment just returns the current module when at top level? I see what you're getting at, but this would be a bad idea, because it still makes sense to have `module' be an independent type. It might come handy to have local-eval not balk upon getting a module, but without letting it set the current module. At times, this functionality might come in handy. It would also be clear then why eval would have to balk on every non-module (== non-top-level) environment. Also, in the code above, `top-level' would not actually be a top-level environment, because (the-environment) is not a top-level form. If you put (define x 5) in place of (the-environment), it would not set a top-level variable; it would produce an error. I am not saying that the actual code would need to work. It was more intended as a show of equivalences. -- David Kastrup
Re: [PATCH] local-eval, local-compile, and the-environment (v3)
David Kastrup d...@gnu.org writes: It might come handy to have local-eval not balk upon getting a module, but without letting it set the current module. Agreed, and my implementation of `local-eval' does exactly that. Mark