[racket] A `check-expansion` for rackunit to test macros?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Tue Aug 27 12:59:37 EDT 2013

Thanks for mentioning setting the namespace. Although the updated
version of `check-expansion` was working in Racket 5.3.5 and 5.3.6, it
was eliciting an error under Racket 5.3.2. Explicitly setting the
namespace made it work fine under 5.3.2, too.

I'm still puzzled why DrRacket didn't report the test failing when
raco test did so. I definitely had tests enabled in DrRacket (using
the command on the Racket menu). How DrRacket evaluates the test
submodule is in some respect different from how raco test does so.
This seems like an issue worth fixing.


On Tue, Aug 27, 2013 at 3:21 AM, Tobias Hammer <tobias.hammer at dlr.de> wrote:
> expand-once with a datum argument uses (datum->syntax #f datum) on its
> argument, i.e. the resulting syntax-object has no lexical context. That
> means in this context if-let is unknown, therefore the expansion must fail.
>
> I think passing in syntax with proper context is the right choice.
>
> To [1]: DrRacket 5.3.4 fails too, other versions not tested. Have you
> enabled to run the test submod?
>
> I don't know if its needed, as its use is limited to only very simple macros
> or otherwise writing down the expansion becomes pretty complex. But
> something to test if macros expansions raise certain errors would be neat.
>
> Tobias
>
>
> PS: I you really want to expand a datum, set the namespace as in the sample
> code for expand
>
>
>
>
> On Mon, 26 Aug 2013 16:45:19 +0200, Greg Hendershott
> <greghendershott at gmail.com> wrote:
>
>> I recently got a pull request where someone defined a
>> `check-expansion` form to use with rackunit. Simplified excerpt:
>>
>> #lang racket/base
>>
>> (require syntax/parse/define)
>>
>> (define-simple-macro (if-let [binding:id value:expr] then:expr else:expr)
>>   (let ([binding value])
>>     (if binding then else)))
>>
>> (module+ test
>>   (require rackunit)
>>   (define (check-expansion input expected-output)
>>     (check-equal? (syntax->datum (expand-once input)) expected-output))
>>   (check-expansion '(if-let [x #t] 0 1)   '(let [(x #t)] (if x 0 1))))
>>
>> Although DrRacket doesn't warn that the the test fails, it fails with
>> `raco test`:
>>
>> raco test conditionals.rkt
>> raco test: (submod "conditionals.rkt" test)
>> if-let: unbound identifier;
>>  also, no #%app syntax transformer is bound
>>   at: if-let
>>   in: (if-let (x #t) 0 1)
>>   context...:
>>
>> /Users/greg/src/scheme/collects/rackjure/rackjure/conditionals.rkt:11:2:
>> check-expansion
>>    /Users/greg/src/scheme/collects/rackjure/rackjure/conditionals.rkt:
>> [running body]
>>    /Applications/Racket_v5.3.5/collects/compiler/commands/test.rkt:29:10:
>> for-loop
>>    f8
>>    /Applications/Racket_v5.3.5/collects/compiler/commands/test.rkt:
>> [running body]
>>    /Applications/Racket_v5.3.5/collects/raco/raco.rkt: [running body]
>>    /Applications/Racket_v5.3.5/collects/raco/main.rkt: [running body]
>>
>> Without giving it much time or deep thought, I came up with this
>> version which succeeds in both DrRacket and raco test:
>>
>> (module+ test
>>   (require rackunit)
>>   (define (check-expansion input expected-output)
>>     (check-equal? (syntax->datum (expand-once input))
>>                   (syntax->datum expected-output)))
>>   (check-expansion #'(if-let [x #t] 0 1)   #'(let [(x #t)] (if x 0 1))))
>>
>> In light of that:
>>
>> [1] Why don't DrRacket and `raco test` both succeed for the first version?
>>
>> [2] Is my new version correct?
>>
>> [3] Could/should rackunit provide something like `check-expansion`?
>> ____________________
>>   Racket Users list:
>>   http://lists.racket-lang.org/users
>
>
>
> --
> ---------------------------------------------------------
> Tobias Hammer
> DLR / Robotics and Mechatronics Center (RMC)
> Muenchner Str. 20, D-82234 Wessling
> Tel.: 08153/28-1487
> Mail: tobias.hammer at dlr.de

Posted on the users mailing list.