This works for me:
#lang racket
(define (hex:char x)
(if (number? x)
x
(string->number (symbol->string x) 16)))
(define-syntax-rule (hex num ...) (bytes (hex:char (quote num)) ...))
(hex a b c 1 2 3) ; #"\n\v\f\1\2\3"
It’s almost always a mistake to use a function that manipulate syntax object (syntax-e
, etc.) inside syntax-rules
, because syntax-rules
don’t give you an access to the syntax object. If you do want to manipulate syntax object, use syntax-cases
instead. In your case, however, the problem is easy enough that you don’t need to directly manipulate syntax objects.
--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/6d096642-b770-4655-acc5-08b36e176554%40googlegroups.com.
This works for me:
#lang racket (define (hex:char x) (if (number? x) x (string->number (symbol->string x) 16))) (define-syntax-rule (hex num ...) (bytes (hex:char (quote num)) ...)) (hex a b c 1 2 3) ; #"\n\v\f\1\2\3"
It’s almost always a mistake to use a function that manipulate syntax object (
syntax-e
, etc.) insidesyntax-rules
, becausesyntax-rules
don’t give you an access to the syntax object. If you do want to manipulate syntax object, usesyntax-cases
instead. In your case, however, the problem is easy enough that you don’t need to directly manipulate syntax objects.
On Mon, Sep 9, 2019 at 12:12 PM Simon Haines <simon...@con-amalgamate.net> wrote:
--I'm trying to write a macro that will turn a list of hex literals into a byte string.(hex a b c 1 2 3) ; #"\n\v\f\1\2\3"After many hours I have finally come up with this:#lang racket
(define-syntax hex
(syntax-rules ()
[(_ num ...)
(bytes
(let ([e (syntax-e #'num)])
(if (number? e) num
(string->number (symbol->string e) 16))) ...)]))(hex a b c 1 2 3)Of course there are many issues with checking the parameters etc. My problem is this generates "a: unbound identifier in: a" because the arguments are evaluated? If I remove the last line it works in the REPL OK.I suspect this is a small matter of my phases being mixed up, or a misunderstanding of when macros can be defined and used, or just outright ignorance on my part. I couldn't find any clues in the many, many references and tutorials I have read. I want to master them but I loathe creating macros, they always make me feel like an idiot, and I hope Racket2 simplifies them somehow.Thanks for any help sorting this one out.
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket...@googlegroups.com.
I'm still trying to figure out why my original, terrible macro behaved the way it did, but I suspect I'll never know. I would have wasted a lot of time on that awful construct. I appreciate your help, many thanks.
#lang racket
(define-syntax hex
(syntax-rules ()
[(_ num ...)
(bytes
(let ([e (syntax-e #'num)])
(if (number? e) num
(string->number (symbol->string e) 16))) ...)]))
(hex a)
(bytes
(let ([e (syntax-e #'a)])
(if (number? e)
a
(string->number (symbol->string e) 16))))
#lang racket
(require (for-syntax syntax/parse))
(define-for-syntax (int->hex n)
;; treats n as though it had been written in hex
(let loop ([n n]
[place 0]
[acc 0])
(cond
[(= 0 n)
acc]
[else
(define-values [q r]
(quotient/remainder n 10))
(loop q (add1 place) (+ acc (* r (expt 16 place))))])))
(define-syntax (hex stx)
(define-syntax-class hex-byte
#:description "hexadecimal byte"
#:attributes [n]
(pattern :exact-nonnegative-integer
#:attr n (int->hex (syntax-e this-syntax))
#:fail-when (and (not (byte? (attribute n))) this-syntax)
"not a byte? when interpreted as hexadecimal")
(pattern :id
#:attr n (string->number (symbol->string
(syntax-e this-syntax))
16)
#:fail-when (and (not (attribute n)) this-syntax)
"not a hexadecimal number"
#:fail-when (and (not (byte? (attribute n))) this-syntax)
"hexadecimal number is not a byte?"))
(syntax-parse stx
[(_ :hex-byte ...)
#`(quote #,(apply bytes (attribute n)))]))
(hex a b c 1 2 3 41 42 43) ; #"\n\v\f\1\2\3ABC"
What wasted a lot of time for me is that, despite the macroexpander's results, the macro works as expected in the REPL. If you paste my original macro into DrRacket, run it, then type '(hex a)' into the REPL you get the expected result. In this case, '(expand (hex a))' doesn't help. This is possibly due to something like a combination of phases, environments and top-level bindings, but I couldn't figure it out.
This is a rather unpleasant pitfall of the REPL. If you try to evaluate the expression `(if #f some-unbound-identifier 1)`, you will see that it evaluates to `#f` in the REPL but raises an unbound identifier error in a module. At the REPL, `some-unbound-identifier` refers to a top-level variable, and it is allowed to support, for example, forward references to identifiers that will be defined in a subsequent interaction, or interactive re-definition of variables.
This is a rather unpleasant pitfall of the REPL. If you try to evaluate the expression `(if #f some-unbound-identifier 1)`, you will see that it evaluates to `#f` in the REPL but raises an unbound identifier error in a module. At the REPL, `some-unbound-identifier` refers to a top-level variable, and it is allowed to support, for example, forward references to identifiers that will be defined in a subsequent interaction, or interactive re-definition of variables.When entering '(hex a b c 1 2 3)' into the REPL, I don't think the symbols 'a', 'b' and 'c' are undefined or forward-references as they appear in the taken branch of the conditional. Maybe syntax objects are different coming from the REPL than a module, somehow resulting in the macro working as expected?
(bytes
(let ([e (syntax-e #'a)])
(if (number? e)
a
(string->number (symbol->string e) 16))))
(bytes
(let ([e (string->symbol "a")])
(if (number? e)
a
(string->number (symbol->string e) 16))))