[racket] Dynamic Require of Syntax

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Fri Feb 1 10:44:21 EST 2013

On 02/01/2013 09:39 AM, Tim Brown wrote:
> On 01/02/13 13:13, Matthias Felleisen wrote:
>> Actually what does it mean to access syntactic extensions at run-time?
>
> Just a thought, but is there a case for pulling the syntaxes into a
> "run-time" test suite ("raco test", or even the GUI tester?) and testing
> them there... e.g. do they transform a list of datums or a string of code
> into an expected output of datums? Equally interesting, given an invalid
> form (as a list of datums), to the macros fail, but without busting the
> test environment because there has been a syntax error.

One way to do that would be to construct a namespace and use 'eval'. 
When dealing with macros, you need to think *terms* (really, 
expressions, definitions, etc), not *values*.

> In a previous discussion(*), I have seen "positive" tests for macros...
> I input a form and when run, the output displays the runtime-evaluated
> result of the transformed macro.
>
> Say we have:
> (module+ test (require rackunit))
> (define-syntax-rule
>    (define/test (f x ...) (#:tests t ...) e ...)
>    (begin
>      (module+ test
>        t ...)
>      (define (f x ...) e ...)))
> (define/test (add-two a) (#:tests (check-= (add-two 2) 4 0)) (+ 2 a))
> (define/test (add-three a) (#:tests (check-= (add-three 2) 5 0)) (+ 2 a))
>
> I get no test results (i.e. success) for add-two. I get a test fails for
> add-three. But if I now want to ensure/document (via a test) that the
> following is an invalid syntax (all define/test forms should have a
> #:tests form:
>
> (define/test (add-four a) (check-= (add-four 2) 6 0) (+ 4 a))
>
> This won't compile; I can't get off the starting line.
>
> I have an outstanding question about "unit-testing" syntactic extensions
> from a couple of weeks ago. What do the heavier users of syntaxes use to
> unit test their macros?

Either construct a namespace and use 'eval' or wrap the invalid syntax 
in something that catches compile-time exceptions and produces code that 
raises the same exception at run time.

The error tests for syntax-parse, for example, use the second technique. 
See tests/stxparse/test-error; the macro that turns compile-time 
exceptions into run-time exceptions is 'convert-syntax-errors' in 
tests/stxparse/setup. IIRC, Eli's test macro does this by default, and 
that's probably where I got the idea from.

Ryan


> * http://lists.racket-lang.org/users/archive/2013-January/055983.html
>
>> On Feb 1, 2013, at 2:57 AM, Dan Grossman wrote:
>>
>>> Cody and I would love an answer to this question from 1.5 months ago if
>>> anybody can point us in the right direction and/or ask us to clarify the
>>> question.  Or if the answer is "that is not possible" then we'll do
>>> something else.
>>>
>>> Much thanks!
>>>
>>> --Dan
>>>
>>> On Mon, Dec 17, 2012 at 9:20 PM, Cody Schroeder <codeblack08 at gmail.com
>>> <mailto:codeblack08 at gmail.com>> wrote:
>>>
>>>       I'm in a position that I would like to use dynamic-require
>>>
>>> <http://docs.racket-lang.org/reference/Module_Names_and_Loading.html#(def._((quote._~23~25kernel)._dynamic-require))>
>>> to
>>>     gain access to all of the provides in a module.  This is quite
>>>     straightforward for normal procedures, but I also want this to
>>>     include syntax.  However, I get this error when trying to
>>> dynamically
>>>     require the blah macro from my test module:
>>>
>>>     (dynamic-require "test.rkt" 'blah)
>>>     blah: use does not match pattern: (blah body) in: blah
>>>
>>>       From the spec, it says that "If the module exports provided as
>>>     syntax, then a use of the binding is expanded and evaluated in a
>>>     fresh namespace to which the module is attached" when using
>>>     dynamic-require.  I don't understand how it's being used, though.
>>>
>>>       Is there a way to use dynamic-require how I want?  Is there a
>>>     better way?
>>>     Cody
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users


Posted on the users mailing list.