unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* How to use-modules within macro?
@ 2019-08-29 14:41 pelzflorian (Florian Pelz)
  2019-08-29 23:04 ` Mark H Weaver
  0 siblings, 1 reply; 7+ messages in thread
From: pelzflorian (Florian Pelz) @ 2019-08-29 14:41 UTC (permalink / raw)
  To: guile-user

Hello,

I am writing a Guile macro to manipulate Scheme code and am stuck on
what I hope is a simple problem and it would be nice if you could
explain.  I try:

(define-syntax O
  (lambda (x)
    (syntax-case x ()
      ((_)
       #`(begin (use-modules (ice-9 local-eval))
                (local-eval 42 (the-environment)))))))
(pk (O))

But it does not work; it cannot resolve local-eval and
the-environment.  Why?  When I write it in the interpreter, a second
call to (pk (O)) works and prints 42.

Using (@ (ice-9 local-eval) …) does not work for looking up
the-environment.

Regards,
Florian



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to use-modules within macro?
  2019-08-29 14:41 How to use-modules within macro? pelzflorian (Florian Pelz)
@ 2019-08-29 23:04 ` Mark H Weaver
  2019-08-30  6:47   ` pelzflorian (Florian Pelz)
  2019-09-04 11:24   ` pelzflorian (Florian Pelz)
  0 siblings, 2 replies; 7+ messages in thread
From: Mark H Weaver @ 2019-08-29 23:04 UTC (permalink / raw)
  To: pelzflorian (Florian Pelz); +Cc: guile-user

Hi Florian,

"pelzflorian (Florian Pelz)" <pelzflorian@pelzflorian.de> writes:

> I am writing a Guile macro to manipulate Scheme code and am stuck on
> what I hope is a simple problem and it would be nice if you could
> explain.  I try:
>
> (define-syntax O
>   (lambda (x)
>     (syntax-case x ()
>       ((_)
>        #`(begin (use-modules (ice-9 local-eval))
>                 (local-eval 42 (the-environment)))))))
> (pk (O))

This approach is misguided and unnecessary.  You don't need to include
'use-modules' in your macro expansion, and it's best avoided.

The references to 'local-eval' and 'the-environment' in the macro
template above will refer to bindings present in the module where 'O' is
defined, *not* the module where 'O' is used.  This is part of what it
means to say that 'O' is a "hygienic" macro.

Therefore, all you need to do is make sure (ice-9 local-eval) is
imported in the module where 'O' is defined, like this:

--8<---------------cut here---------------start------------->8---
(define-module (my-module-that-exports-O)
  #:use-module (ice-9 local-eval)
  #:export (O))

(define-syntax O
  (lambda (x)
    (syntax-case x ()
      ((_)
       #`(local-eval 42 (the-environment))))))
--8<---------------cut here---------------end--------------->8---

Does that work for you?

FYI, the way this works internally is that the macro expander operates
on "syntax objects" instead of plain S-expressions.  The main difference
is that "syntax objects" keep additional information about the lexical
environments where the embedded identifiers were originally found.  So
when a use of (O) expands into (local-eval 42 (the-environment)), the
identifiers 'local-eval' and 'the-environment' are looked up in the
proper environment.

By the way, another consequence of hygiene, which you probably don't
want here, is that the (the-environment) above will capture the lexical
environment where 'O' was *defined*, instead of the environment where
(O) is used.  In other words, in (let ((x 5)) (O)), the captured lexical
environment will not include 'x'.

I should also mention that using (the-environment) will pretty much
disable most compiler optimizations that would otherwise occur with that
top-level form.  That entire mechanism is best avoided if at all
possible.

Can you tell me more broadly what you are trying to accomplish here?
I may be able to suggest an alternate approach.

     Best,
      Mark



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to use-modules within macro?
  2019-08-29 23:04 ` Mark H Weaver
@ 2019-08-30  6:47   ` pelzflorian (Florian Pelz)
  2019-09-04 11:24   ` pelzflorian (Florian Pelz)
  1 sibling, 0 replies; 7+ messages in thread
From: pelzflorian (Florian Pelz) @ 2019-08-30  6:47 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-user

On Thu, Aug 29, 2019 at 07:04:07PM -0400, Mark H Weaver wrote:
> This approach is misguided and unnecessary.  You don't need to include
> 'use-modules' in your macro expansion, and it's best avoided.
> 

:) I suspected I was doing something very wrong.



> FYI, the way this works internally is that the macro expander operates
> on "syntax objects" instead of plain S-expressions.  The main difference
> is that "syntax objects" keep additional information about the lexical
> environments where the embedded identifiers were originally found.  So
> when a use of (O) expands into (local-eval 42 (the-environment)), the
> identifiers 'local-eval' and 'the-environment' are looked up in the
> proper environment.
>

I had read but not understood that syntax carries references, but of
course it does because of hygiene.  Thank you!



> By the way, another consequence of hygiene, which you probably don't
> want here, is that the (the-environment) above will capture the lexical
> environment where 'O' was *defined*, instead of the environment where
> (O) is used.  In other words, in (let ((x 5)) (O)), the captured lexical
> environment will not include 'x'.
> 
> I should also mention that using (the-environment) will pretty much
> disable most compiler optimizations that would otherwise occur with that
> top-level form.  That entire mechanism is best avoided if at all
> possible.
> 
> Can you tell me more broadly what you are trying to accomplish here?
> I may be able to suggest an alternate approach.
> 
>      Best,
>       Mark


What I am actually trying to do is rewriting S-expressions based on a
translated gettext MO file for localization.  I have a gettext POT
file which contains:

#: apps/packages/templates/components.scm:104$
msgid " issue"
msgid_plural " issues"
msgstr[0] ""
msgstr[1] ""



(define (sngettext x)
  "After choosing an identifier for behavior similar to ngettext:1,2,
make it usable like (define-syntax N_ sngettext).  sngettext takes
into account that not all languages have only singular and plural
forms."
  (syntax-case x ()
    ((_ msgid1 msgid2 n) ;three sexps
     ;; sexp->msgid computes a gettext msgid for lookup with gettext
     (let* ((msgstr1 (sexp->msgid (syntax->datum #'msgid1)))
            (msgstr2 (sexp->msgid (syntax->datum #'msgid2))))
       #`(begin
           (use-modules (ice-9 local-eval))
           (local-eval (let ((applicable (if (= #'n 1) #'msgid1 #'msgid2)))
                         ;; deconstruct builds a new sexp from either
                         ;; msgid1 or msgid2 and the translation from
                         ;; the gettext MO file, i.e. it deconstructs
                         ;; the translation to an sexp.
                         (deconstruct (syntax->datum applicable)
                                      (ngettext #,msgstr1 #,msgstr2 n)))
                       (the-environment)))))))


The first argument of sexp->msgid and deconstruct must be the msgid,
which can be a complicated nested sexp.  Macros must not have been
expanded there.  For ngettext, it is important that the n s-expression
be evaluated by ngettext in the evaluation phase and not at expansion
time.

The corresponding sgettext works fine with deconstruct moved to macro
expansion time, therefore there is no need for local-eval.  Moving
deconstruct to macro expansion time would mean I would need to
deconstruct all singular, plural etc. forms, because I do not yet know
the value of n.  I could do this by evaluating the Plural-Forms line
from the MO file, I just wanted to avoid this and let ngettext do the
work.


Thank you!!  I now understand macros better.

Regards,
Florian



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to use-modules within macro?
  2019-08-29 23:04 ` Mark H Weaver
  2019-08-30  6:47   ` pelzflorian (Florian Pelz)
@ 2019-09-04 11:24   ` pelzflorian (Florian Pelz)
  2019-09-04 19:54     ` Mark H Weaver
  1 sibling, 1 reply; 7+ messages in thread
From: pelzflorian (Florian Pelz) @ 2019-09-04 11:24 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-user

On Thu, Aug 29, 2019 at 07:04:07PM -0400, Mark H Weaver wrote:
> Hi Florian,
> 
> "pelzflorian (Florian Pelz)" <pelzflorian@pelzflorian.de> writes:
> 
> > I am writing a Guile macro to manipulate Scheme code and am stuck on
> > what I hope is a simple problem and it would be nice if you could
> > explain.  I try:
> >
> > (define-syntax O
> >   (lambda (x)
> >     (syntax-case x ()
> >       ((_)
> >        #`(begin (use-modules (ice-9 local-eval))
> >                 (local-eval 42 (the-environment)))))))
> > (pk (O))
> 
> This approach is misguided and unnecessary.  You don't need to include
> 'use-modules' in your macro expansion, and it's best avoided.
> 
> […]

Your explanation helped a lot.

To retain unhygienic references, I am now using datum->syntax instead
of local-eval.  It is much better.  For example, to make a macro that
increments all numbers in a given program by one:

(use-modules (ice-9 match))
(define-syntax one-more
  (lambda (x)
    (syntax-case x ()
      ((_ exp)
       (datum->syntax
        #'exp
        (let loop ((y (syntax->datum #'exp)))
          (match y
            ((? number?) (1+ y))
            ((? list?) (map loop y))
            (else y))))))))

(let ((four 4))
  (one-more (* 2 3 four)))

Yields 48.  I hope this is the right approach for rewriting programs.

Regards,
Florian



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to use-modules within macro?
  2019-09-04 11:24   ` pelzflorian (Florian Pelz)
@ 2019-09-04 19:54     ` Mark H Weaver
  2019-09-04 21:55       ` Mark H Weaver
  2019-09-04 22:58       ` pelzflorian (Florian Pelz)
  0 siblings, 2 replies; 7+ messages in thread
From: Mark H Weaver @ 2019-09-04 19:54 UTC (permalink / raw)
  To: pelzflorian (Florian Pelz); +Cc: guile-user

Hi Florian,

"pelzflorian (Florian Pelz)" <pelzflorian@pelzflorian.de> writes:

> To retain unhygienic references, I am now using datum->syntax instead
> of local-eval.  It is much better.  For example, to make a macro that
> increments all numbers in a given program by one:
>
> (use-modules (ice-9 match))
> (define-syntax one-more
>   (lambda (x)
>     (syntax-case x ()
>       ((_ exp)
>        (datum->syntax
>         #'exp
>         (let loop ((y (syntax->datum #'exp)))
>           (match y
>             ((? number?) (1+ y))
>             ((? list?) (map loop y))
>             (else y))))))))
>
> (let ((four 4))
>   (one-more (* 2 3 four)))
>
> Yields 48.  I hope this is the right approach for rewriting programs.

There are some problems above:

(1) The first argument to 'datum->syntax' must be an identifier, which
    is the syntax object corresponding to a symbol.  Here, you are
    passing an entire expression, and in the example usage above, #'exp
    will be the syntax object corresponding to (* 2 3 hour).  Guile
    should ideally raise an error in this case.

(2) The way you are doing things here destroys hygiene within the
    expression that you are rewriting.  You convert the entire
    expression with 'syntax->datum', process the datum, and then convert
    the rewritten expression using 'datum->syntax'.  The problem here is
    that 'syntax->datum' discards all of the extra information about
    lexical environments of identifiers that were kept in the syntax
    object.  This will cause severe problems when 'one-more' is used in
    combination with other macros, including unintended variable
    capture.

To do this properly, you must do the rewriting on the syntax objects
themselves.  It's okay to convert a syntax object to a datum to test
whether it's a literal number, but the important thing is that all
*identifiers* in the rewritten code should be preserved.

So, instead of using 'match' on the result of 'syntax->datum', you
should instead use 'syntax-case' on the syntax object itself, like this
(untested):

  (let loop ((e #'exp))
    (syntax-case e ()
      (num
       (number? (syntax->datum #'num))
       #'(1+ num))
      ((x ...)
       (map loop #'(x ...)))
      (y
       #'y)))

Finally, I should mention that macro expansion is always done from the
outside in, meaning that when 'one-more' is expanded, its operand will
not yet have been expanded.  In general, this means that it's impossible
to comprehend the code within a macro's operands unless the parsing code
knows about every macro that might be used within the operands.  It's
not even possible to know which subparts are expressions and which are
other things like variable binding lists.

For this reason, I think it's generally a mistake to try to parse code
within a macro's operands.  It normally only makes sense for macros to
inspect the parts of operands that are considered part of the macro's
syntax.  For example, it makes sense for a 'let' macro to parse its
binding list, or for a 'match' macro to parse its patterns and
templates, but it does *not* make sense for a macro to try to parse
general subexpressions passed to the macro.

If you could give me a birds-eye view of what you're trying to do here,
I might be able to suggest other approaches.

       Best,
        Mark



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to use-modules within macro?
  2019-09-04 19:54     ` Mark H Weaver
@ 2019-09-04 21:55       ` Mark H Weaver
  2019-09-04 22:58       ` pelzflorian (Florian Pelz)
  1 sibling, 0 replies; 7+ messages in thread
From: Mark H Weaver @ 2019-09-04 21:55 UTC (permalink / raw)
  To: pelzflorian (Florian Pelz); +Cc: guile-user

Hello again,

I wrote earlier:
> So, instead of using 'match' on the result of 'syntax->datum', you
> should instead use 'syntax-case' on the syntax object itself, like this
> (untested):
>
>   (let loop ((e #'exp))
>     (syntax-case e ()
>       (num
>        (number? (syntax->datum #'num))
>        #'(1+ num))
>       ((x ...)
>        (map loop #'(x ...)))
>       (y
>        #'y)))

I should mention that the use of 'map' directly on a syntax object is
only allowable in certain cases.  Here, we assume that the syntax object
produced by #'(x ...) is a normal Scheme list.  That is _not_ the case
for arbitrary syntax objects that correspond to a list.  For example, it
would _not_ be safe to pass 'e' as the list argument to 'map', although
'e' is in some sense equivalent to #(x ...) in the second clause above.

The reason is that syntax objects contain information about the
associated lexical environment which starts at the top of the expression
tree, and is *lazily* pushed down into the subexpressions as the tree is
taken apart using 'syntax-case' and put back together using 'syntax'
(a.k.a. "#'").

As a result, there are only a few cases when you can safely assume that
the top structure of a syntax object is a normal list or pair, and they
are spelled out in the documentation for 'syntax' in the R6RS Standard
Libraries specification:

  http://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-13.html#node_sec_12.4

Here's the relevant excerpt:

  The output produced by syntax is wrapped or unwrapped according to the
  following rules.

  * the copy of (<t1> . <t2>) is a pair if <t1> or <t2> contain any
    pattern variables,

  * the copy of (<t> <ellipsis>) is a list if <t> contains any pattern
    variables,

  * the copy of #(<t1> ... <tn>) is a vector if any of <t1>, ..., <tn>
    contain any pattern variables, and

  * the copy of any portion of <t> not containing any pattern variables
    is a wrapped syntax object.

A "wrapped syntax object" is one where the lexical environment
information has not yet been pushed down into the subexpressions.  It is
a special kind of object that you can only take apart using
'syntax-case'.

So, in the clause above where 'map' is used, 'e' might be a "wrapped
syntax object", but when the elements are extracted from it using the
'syntax-case' pattern (x ...) and then put back together using
#'(x ...), you can then assume that the resulting syntax object is
a normal Scheme list of syntax objects, and therefore it is safe to
use 'map' on it.

       Mark



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: How to use-modules within macro?
  2019-09-04 19:54     ` Mark H Weaver
  2019-09-04 21:55       ` Mark H Weaver
@ 2019-09-04 22:58       ` pelzflorian (Florian Pelz)
  1 sibling, 0 replies; 7+ messages in thread
From: pelzflorian (Florian Pelz) @ 2019-09-04 22:58 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-user

Thank you for giving my approach a kind of “trial by fire”.
Considering what you wrote, I still believe in my datum->syntax
approach in my special case.  After all, datum->syntax exists for a
reason, I suppose.  I am interested in your further comments.  They
have been very helpful.

On Wed, Sep 04, 2019 at 03:54:13PM -0400, Mark H Weaver wrote:
> If you could give me a birds-eye view of what you're trying to do here,
> I might be able to suggest other approaches.
> 

I am trying to i18n the Guix website by writing a gettext that accepts
s-expresions.

For example, the about page of Guix <https://guix.gnu.org/about/>
would use this SHTML:

      ;; TRANSLATORS: Features and Defining Packages are section names
      ;; in the English (en) manual.
      ,(G_
        `(p
          "GNU Guix provides "
          ,(G_ (manual-href "state-of-the-art package management features"
                            (G_ "en")
                            (G_ "Features.html")))
          " such as transactional upgrades and roll-backs, reproducible
            build environments, unprivileged package management, and
            per-user profiles.  It uses low-level mechanisms from the "
          ,(G_ `(a (@ (href "https://nixos.org/nix/")) "Nix"))
          " package manager, but packages are "
          ,(G_ (manual-href "defined" (G_ "en") (G_ "Defining-Packages.html")))
          " as native "
          ,(G_ `(a (@ (href ,(gnu-url "software/guile"))) "Guile"))
          " modules, using extensions to the "
          ,(G_ `(a (@ (href "http://schemers.org")) "Scheme"))
          " language—which makes it nicely hackable."))


Another program I wrote converts it to a POT file from which I make
this German translation PO file:


#. TRANSLATORS: Features and Defining Packages are section names
#. in the English (en) manual.
#: apps/base/templates/about.scm:64
msgid ""
"GNU Guix provides <1>state-of-the-art package management "
"features<1.1>en</1.1><1.2>Features.html</1.2></1> such as transactional "
"upgrades and roll-backs, reproducible\n"
"            build environments, unprivileged package management, and\n"
"            per-user profiles.  It uses low-level mechanisms from the "
"<2>Nix</2> package manager, but packages are "
"<3>defined<3.1>en</3.1><3.2>Defining-Packages.html</3.2></3> as native "
"<4>Guile</4> modules, using extensions to the <5>Scheme</5> language—which "
"makes it nicely hackable."
msgstr ""
"GNU Guix bietet <1>Paketverwaltungsfunktionalitäten auf dem Stand der "
"Technik<1.1>de</1.1><1.2>Funktionalitaten.html</1.2></1>, wie etwa "
"transaktionelle Aktualisierungen und Rücksetzungen, reproduzierbare "
"Erstellungsumgebungen, eine „unprivilegierte“ Paketverwaltung für Nutzer "
"ohne besondere Berechtigungen sowie ein eigenes Paketprofil für jeden "
"Nutzer. Dazu verwendet es dieselben Mechanismen, die dem "
"Paketverwaltungsprogramm <2>Nix</2> zu Grunde liegen, jedoch werden Pakete "
"als reine <4>Guile</4>-Module <3>definiert<3.1>de</3.1><3.2>Pakete-"
"definieren.html</3.2></3>. Dazu erweitert Guix die <5>Scheme</5>-"
"Programmiersprache, wodurch es leicht ist, selbst an diesen zu hacken."


Then the G_ macro takes apart the original SHTML and, using the
translation, reorders and recombines it automatically to this (I
manually added the indentation now):

(quasiquote
 (p "GNU Guix bietet "
    (unquote
     (manual-href "Paketverwaltungsfunktionalitäten auf dem Stand der Technik"
                  "de"
                  ""
                  "Funktionalitaten.html"
                  ""))
    ", wie etwa transaktionelle Aktualisierungen und Rücksetzungen, reproduzierbare Erstellungsumgebungen, eine „unprivilegierte“ Paketverwaltung für Nutzer ohne besondere Berechtigungen sowie ein eigenes Paketprofil für jeden Nutzer. Dazu verwendet es dieselben Mechanismen, die dem Paketverwaltungsprogramm "
    (unquote (quasiquote (a (@ (href "https://nixos.org/nix/"))
                            "Nix")))
    " zu Grunde liegen, jedoch werden Pakete als reine "
    (unquote (quasiquote (a (@ (href (unquote (gnu-url "software/guile"))))
                            "Guile")))
    "-Module "
    (unquote
     (manual-href "definiert"
                  "de"
                  ""
                  "Pakete-definieren.html"
                  ""))
    ". Dazu erweitert Guix die "
    (unquote (quasiquote (a (@ (href "http://schemers.org"))
                            "Scheme")))
    "-Programmiersprache, wodurch es leicht ist, selbst an diesen zu hacken."))



The reason I argued for such a gettext-like approach is that it is
less effort to mark existing SHTML for translation with G_ than if we
were to rewrite everything using something like sirgazil’s format
strings
<https://gitlab.com/sirgazil/guile-lab/blob/master/glab/i18n.scm>, I
think, and that the resulting msgid text in the POT file seems easier
to work with for translators.  Ricardo Wurmus proposed manual XML
without macros that would be easy for translators too, but a G_ macro
is still easier for SHTML authors, I think.  I believe this gettext
approach could be used easily for very many webpages and on other
websites; currently I have a not-yet-submitted completed
internationalization for the entire Guix website but without its very
many blog posts.


Now let me look at your comments:

On Wed, Sep 04, 2019 at 03:54:13PM -0400, Mark H Weaver wrote:
> Hi Florian,
> 
> "pelzflorian (Florian Pelz)" <pelzflorian@pelzflorian.de> writes:
> 
> > […]
> 
> There are some problems above:
> 
> (1) The first argument to 'datum->syntax' must be an identifier, which
>     is the syntax object corresponding to a symbol.  Here, you are
>     passing an entire expression, and in the example usage above, #'exp
>     will be the syntax object corresponding to (* 2 3 hour).  Guile
>     should ideally raise an error in this case.
>

Ahh so in the example above it should be

(define-syntax one-more
  (lambda (x)
    (syntax-case x ()
      ((id exp)
       (datum->syntax
        #'id

instead of

> > (define-syntax one-more
> >   (lambda (x)
> >     (syntax-case x ()
> >       ((_ exp)
> >        (datum->syntax
> >         #'exp

I will change this.



> (2) The way you are doing things here destroys hygiene within the
>     expression that you are rewriting.  You convert the entire
>     expression with 'syntax->datum', process the datum, and then convert
>     the rewritten expression using 'datum->syntax'.  The problem here is
>     that 'syntax->datum' discards all of the extra information about
>     lexical environments of identifiers that were kept in the syntax
>     object.  This will cause severe problems when 'one-more' is used in
>     combination with other macros, including unintended variable
>     capture.
>

Yes, but I do not think capturing everything named G_ is a problem for
this special use case.  If someone were to use the ordinary gettext
for pure strings (let’s say its keyword is G_), it would be just as
much of a problem to use the chosen gettext keyword G_ for anything
other than gettext anywhere in the program, because xgettext would
include that other thing in the POT file for translators.

I acknowledge that error messages for errors within the marked
s-expression may be less precise, I suppose.




> To do this properly, you must do the rewriting on the syntax objects
> themselves.  It's okay to convert a syntax object to a datum to test
> whether it's a literal number, but the important thing is that all
> *identifiers* in the rewritten code should be preserved.
> 
> So, instead of using 'match' on the result of 'syntax->datum', you
> should instead use 'syntax-case' on the syntax object itself, like this
> (untested):
> 
>   (let loop ((e #'exp))
>     (syntax-case e ()
>       (num
>        (number? (syntax->datum #'num))
>        #'(1+ num))
>       ((x ...)
>        (map loop #'(x ...)))
>       (y
>        #'y)))
>

When I look at your second mail:

On Wed, Sep 04, 2019 at 05:55:58PM -0400, Mark H Weaver wrote:
> […]
> I should mention that the use of 'map' directly on a syntax object is
> only allowable in certain cases.
> […]
> As a result, there are only a few cases when you can safely assume that
> the top structure of a syntax object is a normal list or pair, and they
> are spelled out in the documentation for 'syntax' in the R6RS Standard
> Libraries specification:
> […]
>   * the copy of (<t> <ellipsis>) is a list if <t> contains any pattern
>     variables,
> […]

I come to believe that the recommended matching functionality of
syntax-case is not powerful enough for what I want the G_ macro to do.

Another consideration is what you mention last in your first mail:

> Finally, I should mention that macro expansion is always done from the
> outside in, meaning that when 'one-more' is expanded, its operand will
> not yet have been expanded.

This outside-in aspect is vital for what I want to do, and it is the
reason I use macros and not procedures, which I would understand much
better.  For my example above, the inner G_ “macros” within the outer
G_ s-expressions are removed from the output by the outer G_ on
purpose and are only used to distinguish sub-s-expressions with
translatable text from sub-s-expressions without translatable text.
If the inner G_ were evaluated before the outer G_ is evaluated, no
distinction would be possible.




> In general, this means that it's impossible
> to comprehend the code within a macro's operands unless the parsing code
> knows about every macro that might be used within the operands.  It's
> not even possible to know which subparts are expressions and which are
> other things like variable binding lists.
> 
> For this reason, I think it's generally a mistake to try to parse code
> within a macro's operands.  It normally only makes sense for macros to
> inspect the parts of operands that are considered part of the macro's
> syntax.  For example, it makes sense for a 'let' macro to parse its
> binding list, or for a 'match' macro to parse its patterns and
> templates, but it does *not* make sense for a macro to try to parse
> general subexpressions passed to the macro.
> 
> If you could give me a birds-eye view of what you're trying to do here,
> I might be able to suggest other approaches.
> 
>        Best,
>         Mark


I will add a comment to my code that my use of datum->syntax is a very
special use case warranting its use, and that in most cases, one
should not try this at home.

Regards,
Florian



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-09-04 22:58 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-08-29 14:41 How to use-modules within macro? pelzflorian (Florian Pelz)
2019-08-29 23:04 ` Mark H Weaver
2019-08-30  6:47   ` pelzflorian (Florian Pelz)
2019-09-04 11:24   ` pelzflorian (Florian Pelz)
2019-09-04 19:54     ` Mark H Weaver
2019-09-04 21:55       ` Mark H Weaver
2019-09-04 22:58       ` pelzflorian (Florian Pelz)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).