[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Recursive Macros generating Definitions
From: |
Frank Terbeck |
Subject: |
Recursive Macros generating Definitions |
Date: |
Mon, 03 Oct 2022 13:32:59 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) |
Good day, good people!
There might be a bug in recursive macro expansion, at least when the
definition of parameters, using (define …) and similar is involved. Here
is a slightly simplified example.
The purpose of this macro is to define a couple of short-hands for a
generic encoder/decoder pair of functions. The intention is to call it
like this:
(generate-shorthands (unsigned-integer twos-complement zig-zag)
(32 64 128 256 512))
…to generate 5*3*2 = 30 functions, that call the generic functions with
the proper concrete arguments. The macro is implemented recursively to
generate all desired combinations.
If called like that, this implementation generates names like:
varint:sint32-decode-ea351ae5fca3566
This seems to be connected to the recursiveness of the macro. If calling
the base case manually (see example at the end to reproduce), the inten-
ded name is generated:
varint:sint32-decode
This happens with guile 3.0.5, 3.0.8 as well as the current git main
branch HEAD. It does not seem to happen in 2.0.0.
I've bisected this down to:
commit de41e56492666801078e73860a358e1c63cbc8c2
Author: Andy Wingo <wingo@pobox.com>
Date: Fri Nov 4 19:34:22 2011 +0100
hygienically rename macro-introduced bindings, reproducibly
* module/ice-9/psyntax.scm (chi-top-sequence): Detect bindings to
identifiers introduced by macros. In that case, in order to preserve
hygiene, uniquify the variable's name, but in a way that is
reproduceable (i.e., yields the same uniquified name after a
recompile).
module/ice-9/psyntax.scm | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
When looking at this, I also saw the following, which might be related
if ‘syntax-rules’ is implemented using ‘syntax-case’ (I didn't check if
this is the case):
(define-syntax-rule (foobar n) (define quux n))
,exp (foobar 23)
→ (define quux-ea7bdcf8675f4a4 23)
Here's the code, that can be loaded into a REPL and example REPL macro
expansion calls to reproduce the issue:
(use-modules (ice-9 match))
(define-syntax generate-shorthands
(lambda (x)
;; This is a helper that makes a name depending on semantics and width. It
is
;; completely inconsequential to the issue and can be ignored.
(define (make-base-name s w)
(symbol-append 'varint:
(match (syntax->datum s)
('unsigned-integer 'uint)
('twos-complement 'int)
('zig-zag 'sint))
(string->symbol (number->string (syntax->datum w)))))
;; The first two cases of this syntax-case recur on generate-shorthands, to
;; iterate on the list input to generate all desired combinations.
(syntax-case x ()
;; (_ LIST-OF-SEMANTICS-SYMBOLS LIST-OF-WIDTH-LITERALS)
((_ (sems ...) (widths ...))
(format #t "# Outer~%") ;; (format #t …) returns #t, so it can be
;; called in guard position to get a trace.
#'(begin (generate-shorthands sems (widths ...)) ...))
;; (_ SEMANTICS-SYMBOL LIST-OF-WIDTH-LITERALS)
((_ sem (widths ...))
(and (format #t "# Middle~%")
(identifier? #'sem))
#'(begin (generate-shorthands sem widths) ...))
;; Base case:
;; (_ SEMANTICS-SYMBOL WIDTH-LITERAL)
((_ s w)
(and (format #t "# Inner~%")
(identifier? #'s)
(integer? (syntax->datum #'w)))
(let ((base (make-base-name #'s #'w)))
(with-syntax ((enc (datum->syntax x (symbol-append base '-encode)))
(dec (datum->syntax x (symbol-append base '-decode))))
#'(begin (define (dec bv) (varint-decode bv w s))
(define (enc n) (varint-encode n w s)))))))))
;; Example expansions:
;; ,exp (generate-shorthands (zig-zag) (32))
;; # Outer
;; # Middle
;; # Inner
;; (begin (define (varint:sint32-decode-ea351ae5fca3566 bv) (varint-decode bv
32 zig-zag))
;; (define (varint:sint32-encode-e47ba11af8c0627 n) (varint-encode n
32 zig-zag)))
;; ,exp (generate-shorthands zig-zag (32))
;; # Middle
;; # Inner
;; (begin (define (varint:sint32-decode-ea351ae5fca3566 bv) (varint-decode bv
32 zig-zag))
;; (define (varint:sint32-encode-e47ba11af8c0627 n) (varint-encode n
32 zig-zag)))
;; ,exp (generate-shorthands zig-zag 32)
;; # Inner
;; (begin (define (varint:sint32-decode bv) (varint-decode bv 32 zig-zag))
;; (define (varint:sint32-encode n) (varint-encode n 32 zig-zag)))
- Recursive Macros generating Definitions,
Frank Terbeck <=