unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Macro for replacing a placeholder in an expression
@ 2022-07-27 23:57 Zelphir Kaltstahl
  2022-07-28  0:55 ` Maxime Devos
  2022-07-28  1:04 ` Maxime Devos
  0 siblings, 2 replies; 14+ messages in thread
From: Zelphir Kaltstahl @ 2022-07-27 23:57 UTC (permalink / raw)
  To: Guile User

Hello Guile Users,

I am trying to write a macro, which replaces all placeholders (in this case <?>) 
with an identifier in an arbitrarily structured expression (arbitrary nesting of 
expressions). I have the following code now:

~~~~
(define-syntax replace-result-placeholder
   (syntax-rules (<?> replace-result-placeholder)
     "Iterate through the parts of an expression, search for the
placeholder and replace the placeholder with the
result-identifier."
     ;; Transform trivial cases, base cases.
     [(_ result-identifier <?>)
      result-identifier]
     [(_ result-identifier (<?>))
      (result-identifier)]

     [(_ result-identifier (op))
      (op)]

     ;; If there already is such a list of transformed args
     ;; and there are still arguments not transformed.
     [(_ res-id-outer
         (op arg
             args* ...
             (list
              ;; Must match a compound expression here, to
              ;; avoid matching of other lists, like lists of
              ;; arguments in a lambda expression or
              ;; similar. Here we must only match a list of
              ;; arguments, which are yet to be transformed.
              (replace-result-placeholder res-id-inner arg-to-transform)
              other-args* ...)))
      (replace-result-placeholder
       res-id-outer
       (op args* ...
           (list (replace-result-placeholder res-id-outer arg-to-transform)
                 other-args* ...
                 (replace-result-placeholder res-id-inner arg))))]

     ;; If there already is such a list of transformed args
     ;; and there are no arguments not yet transformed.
     [(_ res-id-outer
         (op (list
              (replace-result-placeholder res-id-inner arg-to-transform)
              other-args* ...)))
      ((replace-result-placeholder res-id-outer op)
       (replace-result-placeholder res-id-inner arg-to-transform)
       other-args* ...)]

     ;; Create list of transformed args, if it does not yet
     ;; exist.
     [(_ result-identifier (op arg args* ...))
      (replace-result-placeholder
       result-identifier
       (op args* ...
           (list
            (replace-result-placeholder result-identifier arg))))]

     ;; Must place this trivial case last, to avoid
     ;; accidental matching of compound expressions.
     [(_ result-identifier op)
      op]

     ;; Catch all.
     [(_ other* ...)
      (syntax-error "unrecognized form in macro call:"
                    (quote
                     (replace-result-placeholder other* ...)))]
     ))
~~~~

This already seems to work mostly:

~~~~
scheme@(guile-user)> (define res 3)
scheme@(guile-user)> (replace-result-placeholder res <?>)
$18 = 3
scheme@(guile-user)> (replace-result-placeholder res (+ 1 <?>))
$19 = 4
scheme@(guile-user)> (replace-result-placeholder res (+ 1 (- 5 <?>)))
$20 = 3
scheme@(guile-user)> (replace-result-placeholder res (+ 1 (* <?> 2) (- 5 <?>)))
$21 = 9
scheme@(guile-user)>
~~~~

I was already happy, because everything seemed to work. However, when it comes 
to replacing things inside lambda expressions, things seem to not work correctly:

~~~~
scheme@(guile-user)> (replace-result-placeholder res (lambda (a) (+ a <?>)))
While compiling expression:
Syntax error:
unknown file:965:0: lambda: invalid argument list in subform ((a)) of (replace-result-placeholder res (a))
~~~~

I think (but not 100% sure), that the ((a)) comes from the case:

~~~~
...
[(_ result-identifier (op))
      (op)]
...
~~~~

(In this case it is not an "operation", but nevermind the name in that pattern.) 
I do not understand, why it outputs something which is wrapped twice in 
parentheses. I do not understand where that second pair of parentheses comes from.

I tried creating a simpler macro, for the specific case of a lambda expression, 
to maybe find a solution this way. But it has got the same problem. At least it 
now serves to reproduce the problem in a simpler example:

~~~~
scheme@(guile-user)> (define-syntax test
   (syntax-rules (lambda)
     [(_ (op args body* ...))
      ((test op) (test args) (test body* ...))]

     [(_ thing1 thing2 things* ...)
      ((test thing1) (test thing2 things* ...))]

     [(_ (thing))
      (thing)]

     [(_ thing)
      thing]))
scheme@(guile-user)> (test (lambda (a) (+ a 1)))
While compiling expression:
Syntax error:
unknown file:798:0: lambda: invalid argument list in subform ((a)) of (test (a))
~~~~

There seems to be something about a template like (one-thing) that I do not 
understand or something completely different is going on.

What am I doing wrong?

Best regards,
Zelphir

-- 
repositories: https://notabug.org/ZelphirKaltstahl




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

end of thread, other threads:[~2022-08-06 14:28 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-27 23:57 Macro for replacing a placeholder in an expression Zelphir Kaltstahl
2022-07-28  0:55 ` Maxime Devos
2022-07-28 10:23   ` Zelphir Kaltstahl
2022-07-28 10:28     ` Maxime Devos
2022-07-30 15:42     ` Zelphir Kaltstahl
2022-07-30 20:44       ` Maxime Devos
2022-07-30 21:10         ` Maxime Devos
2022-07-30 21:13       ` Maxime Devos
2022-08-05  9:42         ` Linus Björnstam
2022-08-06 14:28           ` Zelphir Kaltstahl
2022-07-28  1:04 ` Maxime Devos
2022-07-28  8:39   ` Zelphir Kaltstahl
2022-07-28  9:48     ` Maxime Devos
2022-07-28 11:26       ` Zelphir Kaltstahl

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).