guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: How to use-modules within macro?


From: pelzflorian (Florian Pelz)
Subject: Re: How to use-modules within macro?
Date: Fri, 30 Aug 2019 08:47:34 +0200
User-agent: NeoMutt/20180716

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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]